Date: Sat, 6 Sep 2003 00:15:27 -0700 (PDT) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 37652 for review Message-ID: <200309060715.h867FRA0007355@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=37652 Change 37652 by marcel@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) ;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200309060715.h867FRA0007355>