PERFORCE change 37652 for review
Marcel Moolenaar
marcel at FreeBSD.org
Sat Sep 6 00:15:29 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=37652
Change 37652 by marcel at marcel_nfs on 2003/09/06 00:15:16
Fix the receive logic. The flow control testing exposed serious
data corruption and hangs. After digging into the matter I
found out that:
1. The RBCL register does not hold the number of bytes in the
FIFO. It is in fact a running counter (as the datasheet
mentions rather casually). A very nice feature of the
counter is that a completely filled FIFO will always re-
align the counter to a multiple of the threshold. Thus,
we can always read RBCL, mask the lower X bits and if the
result is 0, we have a completely filled FIFO. Yay!
2. It is vitally important to check if there's any data in
the FIFO before we use the counter in RBCL. A receive FIFO
reset will cause an interrupt without there being any new
data. Not only is the RBCL unchanged by this, but we also
interpret 0 as a full. If we do not check in STAR first,
we'll be reading junk.
3. It is also important to send the RMC command to the chip
if there's no data. Otherwise the FIFO will lock up, only
to be released by a FIFO reset.
It is possible that I can enable input flow control again...
Affected files ...
.. //depot/projects/uart/dev/uart/uart_dev_sab82532.c#25 edit
Differences ...
==== //depot/projects/uart/dev/uart/uart_dev_sab82532.c#25 (text+ko) ====
@@ -580,28 +580,28 @@
sab82532_bus_receive(struct uart_softc *sc)
{
struct uart_bas *bas;
- int count, xc;
+ int i, rbcl, xc;
uint8_t s;
bas = &sc->sc_bas;
- count = uart_getreg(bas, SAB_RBCL);
- while (count && !uart_rx_full(sc)) {
- xc = uart_getreg(bas, SAB_RFIFO);
- s = uart_getreg(bas, SAB_RFIFO);
- if (s & SAB_RSTAT_FE)
- xc |= UART_STAT_FRAMERR;
- if (s & SAB_RSTAT_PE)
- xc |= UART_STAT_PARERR;
- uart_rx_put(sc, xc);
- count -= 2;
+ if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE) {
+ rbcl = uart_getreg(bas, SAB_RBCL) & 31;
+ if (rbcl == 0)
+ rbcl = 32;
+ for (i = 0; i < rbcl; i += 2) {
+ if (uart_rx_full(sc)) {
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ break;
+ }
+ xc = uart_getreg(bas, SAB_RFIFO);
+ s = uart_getreg(bas, SAB_RFIFO + 1);
+ if (s & SAB_RSTAT_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (s & SAB_RSTAT_PE)
+ xc |= UART_STAT_PARERR;
+ uart_rx_put(sc, xc);
+ }
}
- /*
- * Oops, we couldn't get all data from the FIFO. Mark an overflow
- * condition and let upper layers deal with this. We need to free
- * the Rx FIFO. Sorry...
- */
- if (count)
- sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
;
More information about the p4-projects
mailing list