aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérémie Jourdin <jeremie@jourdin.org>2026-07-19 18:39:49 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2026-07-19 18:44:36 +0000
commit38187938f52283143308dd219db35d889da55ea4 (patch)
treefe519cc98e56af31099aee1e3ba04ce4853c1885
parentc325b4024d61fe20f8140d6891074ca7276c4d58 (diff)
-rw-r--r--sys/dev/re/if_re.c41
-rw-r--r--sys/dev/rl/if_rlreg.h8
2 files changed, 48 insertions, 1 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 50e7e1cad16c..cf7ba90c9a5a 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -3630,7 +3630,37 @@ re_stop(struct rl_softc *sc)
0x00080000);
}
- if ((sc->rl_flags & RL_FLAG_WAIT_TXPOLL) != 0) {
+ if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) {
+ /*
+ * RTL8168G and later. The STOPREQ command is defined only for
+ * earlier controllers; issuing it on these parts can leave the
+ * MAC wedged. With the RXDV gate enabled above, drain the TX
+ * descriptor queue and the on-chip TX/RX FIFOs and clear the
+ * TX/RX enable bits so the DMA engine is idle before the reset
+ * and buffer free below. All waits are bounded.
+ */
+ DELAY(2000);
+ for (i = RL_TIMEOUT; i > 0; i--) {
+ if ((CSR_READ_4(sc, RL_TXCFG) &
+ RL_TXCFG_QUEUE_EMPTY) != 0)
+ break;
+ DELAY(100);
+ }
+ if (i == 0)
+ device_printf(sc->rl_dev, "stopping TXQ timed out!\n");
+ CSR_WRITE_1(sc, RL_COMMAND, CSR_READ_1(sc, RL_COMMAND) &
+ ~(RL_CMD_TX_ENB | RL_CMD_RX_ENB));
+ for (i = RL_TIMEOUT * 3; i > 0; i--) {
+ if ((CSR_READ_1(sc, RL_MCU_CMD) &
+ (RL_MCU_TXFIFO_EMPTY | RL_MCU_RXFIFO_EMPTY)) ==
+ (RL_MCU_TXFIFO_EMPTY | RL_MCU_RXFIFO_EMPTY))
+ break;
+ DELAY(20);
+ }
+ if (i == 0)
+ device_printf(sc->rl_dev,
+ "TX/RX FIFO drain timed out!\n");
+ } else if ((sc->rl_flags & RL_FLAG_WAIT_TXPOLL) != 0) {
for (i = RL_TIMEOUT; i > 0; i--) {
if ((CSR_READ_1(sc, sc->rl_txstart) &
RL_TXSTART_START) == 0)
@@ -3661,6 +3691,15 @@ re_stop(struct rl_softc *sc)
CSR_WRITE_2(sc, RL_IMR, 0x0000);
CSR_WRITE_2(sc, RL_ISR, 0xFFFF);
+ /*
+ * Reset the controller before freeing the DMA buffers below. A
+ * controller that has not fully quiesced can keep fetching stale,
+ * still-owned descriptors that point at about-to-be-freed mbufs.
+ * re_init_locked() resets again on the reinit path; the extra reset
+ * is idempotent and cheap.
+ */
+ re_reset(sc);
+
if (sc->rl_head != NULL) {
m_freem(sc->rl_head);
sc->rl_head = sc->rl_tail = NULL;
diff --git a/sys/dev/rl/if_rlreg.h b/sys/dev/rl/if_rlreg.h
index 10e25fcb5373..0db4b2066ce6 100644
--- a/sys/dev/rl/if_rlreg.h
+++ b/sys/dev/rl/if_rlreg.h
@@ -146,6 +146,14 @@
#define RL_MISC 0x00F0
/*
+ * MCU command / FIFO status register (RTL8168G and later). Polled to
+ * confirm the on-chip TX/RX FIFOs have drained before a controller reset.
+ */
+#define RL_MCU_CMD 0x00D3
+#define RL_MCU_TXFIFO_EMPTY 0x20 /* bit 5 */
+#define RL_MCU_RXFIFO_EMPTY 0x10 /* bit 4 */
+
+/*
* TX config register bits
*/
#define RL_TXCFG_CLRABRT 0x00000001 /* retransmit aborted pkt */