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