diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-03-01 10:02:45 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-03-01 10:02:45 +0000 |
commit | b9da46258ed19c240e791f8696ff97a5ec4bb94a (patch) | |
tree | 80720db41a937ab0a7650f2c3ad12ae4e5d26e90 /sys/dev/pci/if_em.c | |
parent | 8b18066adb684e14a24bbf162082713266c76e62 (diff) |
use a timeout to refill the rx ring when it's empty.
em had rxr, but didn't use a timeout cos it claimed to generate an
RX overflow interrupt when packets fell off slots in the ring. turns
out that's a lie on at least one chip, so add the timeout like other
drivers.
this was hit by mlarkin@, who had nfs and bufs steal all the packets
and memory for packets from em, which didn't recover after the
memory had been released back to the system.
Diffstat (limited to 'sys/dev/pci/if_em.c')
-rw-r--r-- | sys/dev/pci/if_em.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index eed5efe3fde..14a90e70ca1 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.341 2018/04/07 11:56:40 sf Exp $ */ +/* $OpenBSD: if_em.c,v 1.342 2019/03/01 10:02:44 dlg Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include <dev/pci/if_em.h> @@ -250,6 +250,7 @@ void em_txeof(struct em_softc *); int em_allocate_receive_structures(struct em_softc *); int em_allocate_transmit_structures(struct em_softc *); int em_rxfill(struct em_softc *); +void em_rxrefill(void *); int em_rxeof(struct em_softc *); void em_receive_checksum(struct em_softc *, struct em_rx_desc *, struct mbuf *); @@ -375,6 +376,7 @@ em_attach(struct device *parent, struct device *self, void *aux) timeout_set(&sc->timer_handle, em_local_timer, sc); timeout_set(&sc->tx_fifo_timer_handle, em_82547_move_tail, sc); + timeout_set(&sc->rx_refill, em_rxrefill, sc); /* Determine hardware revision */ em_identify_hardware(sc); @@ -959,13 +961,8 @@ em_intr(void *arg) if (ifp->if_flags & IFF_RUNNING) { em_txeof(sc); - - if (em_rxeof(sc) || ISSET(reg_icr, E1000_ICR_RXO)) { - if (em_rxfill(sc)) { - E1000_WRITE_REG(&sc->hw, RDT, - sc->sc_rx_desc_head); - } - } + if (em_rxeof(sc)) + em_rxrefill(sc); } /* Link status change */ @@ -1534,6 +1531,7 @@ em_stop(void *arg, int softonly) INIT_DEBUGOUT("em_stop: begin"); + timeout_del(&sc->rx_refill); timeout_del(&sc->timer_handle); timeout_del(&sc->tx_fifo_timer_handle); @@ -2755,6 +2753,17 @@ em_rxfill(struct em_softc *sc) return (post); } +void +em_rxrefill(void *arg) +{ + struct em_softc *sc = arg; + + if (em_rxfill(sc)) + E1000_WRITE_REG(&sc->hw, RDT, sc->sc_rx_desc_head); + else if (if_rxr_inuse(&sc->sc_rx_ring) == 0) + timeout_add(&sc->rx_refill, 1); +} + /********************************************************************* * * This routine executes in interrupt context. It replenishes |