summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/dc/if_dc.c55
-rw-r--r--sys/pci/if_dc.c55
-rw-r--r--sys/pci/if_xl.c33
3 files changed, 138 insertions, 5 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index cc7eee6..758554f 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -198,6 +198,7 @@ static int dc_newbuf __P((struct dc_softc *, int, struct mbuf *));
static int dc_encap __P((struct dc_softc *, struct mbuf *,
u_int32_t *));
static void dc_pnic_rx_bug_war __P((struct dc_softc *, int));
+static int dc_rx_resync __P((struct dc_softc *));
static void dc_rxeof __P((struct dc_softc *));
static void dc_txeof __P((struct dc_softc *));
static void dc_tick __P((void *));
@@ -1919,6 +1920,42 @@ static void dc_pnic_rx_bug_war(sc, idx)
}
/*
+ * This routine searches the RX ring for dirty descriptors in the
+ * event that the rxeof routine falls out of sync with the chip's
+ * current descriptor pointer. This may happen sometimes as a result
+ * of a "no RX buffer available" condition that happens when the chip
+ * consumes all of the RX buffers before the driver has a chance to
+ * process the RX ring. This routine may need to be called more than
+ * once to bring the driver back in sync with the chip, however we
+ * should still be getting RX DONE interrupts to drive the search
+ * for new packets in the RX ring, so we should catch up eventually.
+ */
+static int dc_rx_resync(sc)
+ struct dc_softc *sc;
+{
+ int i, pos;
+ struct dc_desc *cur_rx;
+
+ pos = sc->dc_cdata.dc_rx_prod;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ cur_rx = &sc->dc_ldata->dc_rx_list[pos];
+ if (!(cur_rx->dc_status & DC_RXSTAT_OWN))
+ break;
+ DC_INC(pos, DC_RX_LIST_CNT);
+ }
+
+ /* If the ring really is empty, then just return. */
+ if (i == DC_RX_LIST_CNT)
+ return(0);
+
+ /* We've fallen behing the chip: catch it. */
+ sc->dc_cdata.dc_rx_prod = pos;
+
+ return(EAGAIN);
+}
+
+/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
*/
@@ -2204,8 +2241,15 @@ static void dc_intr(arg)
CSR_WRITE_4(sc, DC_ISR, status);
- if (status & DC_ISR_RX_OK)
+ if (status & DC_ISR_RX_OK) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
dc_txeof(sc);
@@ -2241,8 +2285,15 @@ static void dc_intr(arg)
}
if ((status & DC_ISR_RX_WATDOGTIMEO)
- || (status & DC_ISR_RX_NOBUF))
+ || (status & DC_ISR_RX_NOBUF)) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
if (status & DC_ISR_BUS_ERR) {
dc_reset(sc);
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
index cc7eee6..758554f 100644
--- a/sys/pci/if_dc.c
+++ b/sys/pci/if_dc.c
@@ -198,6 +198,7 @@ static int dc_newbuf __P((struct dc_softc *, int, struct mbuf *));
static int dc_encap __P((struct dc_softc *, struct mbuf *,
u_int32_t *));
static void dc_pnic_rx_bug_war __P((struct dc_softc *, int));
+static int dc_rx_resync __P((struct dc_softc *));
static void dc_rxeof __P((struct dc_softc *));
static void dc_txeof __P((struct dc_softc *));
static void dc_tick __P((void *));
@@ -1919,6 +1920,42 @@ static void dc_pnic_rx_bug_war(sc, idx)
}
/*
+ * This routine searches the RX ring for dirty descriptors in the
+ * event that the rxeof routine falls out of sync with the chip's
+ * current descriptor pointer. This may happen sometimes as a result
+ * of a "no RX buffer available" condition that happens when the chip
+ * consumes all of the RX buffers before the driver has a chance to
+ * process the RX ring. This routine may need to be called more than
+ * once to bring the driver back in sync with the chip, however we
+ * should still be getting RX DONE interrupts to drive the search
+ * for new packets in the RX ring, so we should catch up eventually.
+ */
+static int dc_rx_resync(sc)
+ struct dc_softc *sc;
+{
+ int i, pos;
+ struct dc_desc *cur_rx;
+
+ pos = sc->dc_cdata.dc_rx_prod;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ cur_rx = &sc->dc_ldata->dc_rx_list[pos];
+ if (!(cur_rx->dc_status & DC_RXSTAT_OWN))
+ break;
+ DC_INC(pos, DC_RX_LIST_CNT);
+ }
+
+ /* If the ring really is empty, then just return. */
+ if (i == DC_RX_LIST_CNT)
+ return(0);
+
+ /* We've fallen behing the chip: catch it. */
+ sc->dc_cdata.dc_rx_prod = pos;
+
+ return(EAGAIN);
+}
+
+/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
*/
@@ -2204,8 +2241,15 @@ static void dc_intr(arg)
CSR_WRITE_4(sc, DC_ISR, status);
- if (status & DC_ISR_RX_OK)
+ if (status & DC_ISR_RX_OK) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
dc_txeof(sc);
@@ -2241,8 +2285,15 @@ static void dc_intr(arg)
}
if ((status & DC_ISR_RX_WATDOGTIMEO)
- || (status & DC_ISR_RX_NOBUF))
+ || (status & DC_ISR_RX_NOBUF)) {
+ int curpkts;
+ curpkts = ifp->if_ipackets;
dc_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while(dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ }
if (status & DC_ISR_BUS_ERR) {
dc_reset(sc);
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index 4730185..a48823c 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -205,6 +205,7 @@ static int xl_encap_90xB __P((struct xl_softc *, struct xl_chain *,
struct mbuf * ));
static void xl_rxeof __P((struct xl_softc *));
+static int xl_rx_resync __P((struct xl_softc *));
static void xl_txeof __P((struct xl_softc *));
static void xl_txeof_90xB __P((struct xl_softc *));
static void xl_txeoc __P((struct xl_softc *));
@@ -1676,6 +1677,28 @@ static int xl_newbuf(sc, c)
return(0);
}
+static int xl_rx_resync(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_onefrag *pos;
+ int i;
+
+ pos = sc->xl_cdata.xl_rx_head;
+
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ if (pos->xl_ptr->xl_status)
+ break;
+ pos = pos->xl_next;
+ }
+
+ if (i == XL_RX_LIST_CNT)
+ return(0);
+
+ sc->xl_cdata.xl_rx_head = pos;
+
+ return(EAGAIN);
+}
+
/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
@@ -1981,8 +2004,16 @@ static void xl_intr(arg)
CSR_WRITE_2(sc, XL_COMMAND,
XL_CMD_INTR_ACK|(status & XL_INTRS));
- if (status & XL_STAT_UP_COMPLETE)
+ if (status & XL_STAT_UP_COMPLETE) {
+ int curpkts;
+
+ curpkts = ifp->if_ipackets;
xl_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while (xl_rx_resync(sc))
+ xl_rxeof(sc);
+ }
+ }
if (status & XL_STAT_DOWN_COMPLETE) {
if (sc->xl_type == XL_TYPE_905B)
OpenPOWER on IntegriCloud