Skip site navigation (1)Skip section navigation (2)
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>