summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/gem.c44
1 files changed, 31 insertions, 13 deletions
diff --git a/sys/dev/ic/gem.c b/sys/dev/ic/gem.c
index c1c34e68b4f..ced354c5b15 100644
--- a/sys/dev/ic/gem.c
+++ b/sys/dev/ic/gem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gem.c,v 1.122 2017/06/08 01:34:00 dlg Exp $ */
+/* $OpenBSD: gem.c,v 1.123 2018/02/07 22:35:14 bluhm Exp $ */
/* $NetBSD: gem.c,v 1.1 2001/09/16 00:11:43 eeh Exp $ */
/*
@@ -423,6 +423,7 @@ gem_tick(void *arg)
int s;
u_int32_t v;
+ s = splnet();
/* unload collisions counters */
v = bus_space_read_4(t, mac, GEM_MAC_EXCESS_COLL_CNT) +
bus_space_read_4(t, mac, GEM_MAC_LATE_COLL_CNT);
@@ -448,7 +449,15 @@ gem_tick(void *arg)
bus_space_write_4(t, mac, GEM_MAC_RX_CRC_ERR_CNT, 0);
bus_space_write_4(t, mac, GEM_MAC_RX_CODE_VIOL, 0);
- s = splnet();
+ /*
+ * If buffer allocation fails, the receive ring may become
+ * empty. There is no receive interrupt to recover from that.
+ */
+ if (if_rxr_inuse(&sc->sc_rx_ring) == 0) {
+ gem_fill_rx_ring(sc);
+ bus_space_write_4(t, mac, GEM_RX_KICK, sc->sc_rx_prod);
+ }
+
mii_tick(&sc->sc_mii);
splx(s);
@@ -1200,17 +1209,26 @@ gem_rx_watchdog(void *arg)
rx_fifo_wr_ptr = bus_space_read_4(t, h, GEM_RX_FIFO_WR_PTR);
rx_fifo_rd_ptr = bus_space_read_4(t, h, GEM_RX_FIFO_RD_PTR);
state = bus_space_read_4(t, h, GEM_MAC_MAC_STATE);
- if ((state & GEM_MAC_STATE_OVERFLOW) == GEM_MAC_STATE_OVERFLOW &&
- ((rx_fifo_wr_ptr == rx_fifo_rd_ptr) ||
- ((sc->sc_rx_fifo_wr_ptr == rx_fifo_wr_ptr) &&
- (sc->sc_rx_fifo_rd_ptr == rx_fifo_rd_ptr)))) {
- /*
- * The RX state machine is still in overflow state and
- * the RX FIFO write and read pointers seem to be
- * stuck. Whack the chip over the head to get things
- * going again.
- */
- gem_init(ifp);
+ if ((state & GEM_MAC_STATE_OVERFLOW) == GEM_MAC_STATE_OVERFLOW) {
+ if ((rx_fifo_wr_ptr == rx_fifo_rd_ptr) ||
+ ((sc->sc_rx_fifo_wr_ptr == rx_fifo_wr_ptr) &&
+ (sc->sc_rx_fifo_rd_ptr == rx_fifo_rd_ptr))) {
+ /*
+ * The RX state machine is still in overflow state and
+ * the RX FIFO write and read pointers seem to be
+ * stuck. Whack the chip over the head to get things
+ * going again.
+ */
+ gem_init(ifp);
+ } else {
+ /*
+ * We made some progress, but is not certain that the
+ * overflow condition has been resolved. Check again.
+ */
+ sc->sc_rx_fifo_wr_ptr = rx_fifo_wr_ptr;
+ sc->sc_rx_fifo_rd_ptr = rx_fifo_rd_ptr;
+ timeout_add_msec(&sc->sc_rx_watchdog, 400);
+ }
}
}