git: 15a93289f114 - stable/15 - re(4): re-arm the Tx doorbell when re_txeof() leaves a non-empty ring

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 17:33:03 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=15a93289f114871817bbd0ef0420fd9e234eef6c

commit 15a93289f114871817bbd0ef0420fd9e234eef6c
Author:     Jérémie Jourdin <jeremie@jourdin.org>
AuthorDate: 2026-07-19 18:42:22 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-10-30 17:32:22 +0000

    re(4): re-arm the Tx doorbell when re_txeof() leaves a non-empty ring
    
    On PCIe parts a TxPoll request can be lost when packets are queued
    in quick succession, leaving owned descriptors with no transfer in
    progress until the watchdog fires. re_txeof() runs from the interrupt
    handlers, re_tick() and re_watchdog(), so re-writing TXSTART whenever
    the ring is still non-empty turns a potential 5-second stall into at
    most one tick.
    
    One register write on a path that already took an interrupt;
    fast path untouched.
    
    * Sustained bidirectional load on RTL8168H; no Tx stalls, no throughput
      regression at 941 Mbps line rate.
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D58277
    PR: kern/166724
    
    (cherry picked from commit 4bff6b9f5cef13df8540fa6869bd6707f8e7575d)
---
 sys/dev/re/if_re.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index eaa9d0ca934b..6bce5432a1bc 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -2464,6 +2464,17 @@ re_txeof(struct rl_softc *sc)
 	/* No changes made to the TX ring, so no flush needed */
 
 	if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt) {
+		/*
+		 * Some descriptors are still owned by the controller.  On PCIe
+		 * parts a TxPoll request can be lost when Tx packets are queued
+		 * too close together, leaving a non-empty ring with no transfer
+		 * in progress.  Re-arm the transmitter here -- this routine is
+		 * reached from the interrupt handlers, re_tick() and
+		 * re_watchdog() -- so a lost poll cannot stall the ring until
+		 * the watchdog fires.
+		 */
+		if ((sc->rl_flags & RL_FLAG_PCIE) != 0)
+			CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
 #ifdef RE_TX_MODERATION
 		/*
 		 * If not all descriptors have been reaped yet, reload