Subject: kern/31837: sip driver receive buffer overrun diminishes the receive capabilities of the driver
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <john32979@gmail.com>
List: netbsd-bugs
Date: 10/16/2005 17:46:00
>Number:         31837
>Category:       kern
>Synopsis:       sip driver receive buffer overrun diminishes the receive capabilities of the driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Oct 16 17:46:00 +0000 2005
>Originator:     John Yau
>Release:        NetBSD 2.0
>Organization:
>Environment:
>Description:
After a receive buffer overrun, the throughput of the sip interface halves.  Setting the buffer ownership back to the sip card if the device is idle after detecting a buffer overrun seems to fix the problem.


>How-To-Repeat:
Trigger a receive buffer overrun by sending large amounts of data on a PC Engines WRAP board.  After recovering from the buffer overrun, performance degrades severely.

>Fix:
Index: if_sip.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_sip.c,v
retrieving revision 1.87.2.1
diff -u -r1.87.2.1 if_sip.c
--- if_sip.c	28 May 2004 07:10:38 -0000	1.87.2.1
+++ if_sip.c	16 Oct 2005 17:38:54 -0000
@@ -1504,8 +1504,10 @@
 {
 	struct sip_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	u_int32_t isr;
+	u_int32_t isr, cmdsts;
 	int handled = 0;
+	int i;
+	struct sip_rxsoft *rxs;
 
 	for (;;) {
 		/* Reading clears interrupt. */
@@ -1536,7 +1538,35 @@
 			if (isr & ISR_RXIDLE) {
 				printf("%s: receive ring overrun\n",
 				    sc->sc_dev.dv_xname);
-
+				/* jyau
+				 * 
+				 * Go through the receive descriptors and 
+				 * reset the ownership back to the card.
+				 * We drop all the packets currently in the
+				 * receive queue.
+				 */
+				for (i = sc->sc_rxptr;; i = SIP_NEXTRX(i)) {
+					rxs = &sc->sc_rxsoft[i];
+					SIP_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+					cmdsts = le32toh(sc->sc_rxdescs[i].sipd_cmdsts);
+					/*
+					 * NOTE: OWN is set if owned by _consumer_.  We're the
+					 * consumer of the receive ring, so if the bit is clear,
+					 * we have processed all of the packets.
+					 */
+					if ((cmdsts & CMDSTS_OWN) == 0) {
+					/*
+					 * We have processed all of the receive buffers.
+					 */
+						break;
+					}
+					ifp->if_ierrors++;
+					SIP_INIT_RXDESC(sc, i);
+					bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
+						rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+					printf("%s, Cleared rx desc %d\n",
+						sc->sc_dev.dv_xname, i);
+				}
 				/* Get the receive process going again. */
 				bus_space_write_4(sc->sc_st, sc->sc_sh,
 				    SIP_RXDP, SIP_CDRXADDR(sc, sc->sc_rxptr));