summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_em.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2019-03-01 10:02:45 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2019-03-01 10:02:45 +0000
commitb9da46258ed19c240e791f8696ff97a5ec4bb94a (patch)
tree80720db41a937ab0a7650f2c3ad12ae4e5d26e90 /sys/dev/pci/if_em.c
parent8b18066adb684e14a24bbf162082713266c76e62 (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.c25
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