diff options
-rw-r--r-- | sys/dev/dc/if_dc.c | 55 | ||||
-rw-r--r-- | sys/pci/if_dc.c | 55 | ||||
-rw-r--r-- | sys/pci/if_xl.c | 33 |
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) |