Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jul 2026 18:50:50 +0000
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        =?utf-8?Q?J=C3=A9r=C3=A9mie?= Jourdin <jeremie@jourdin.org>
Subject:   git: d11f124e932b - main - re(4): recover Tx completions whose MSI was swallowed in re_intr_msi()
Message-ID:  <6a5d1c8a.3e1f9.34bfee7e@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by adrian:

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

commit d11f124e932bfa4fabdc6c5b67735181615a0630
Author:     Jérémie Jourdin <jeremie@jourdin.org>
AuthorDate: 2026-07-19 18:45:47 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-19 18:45:49 +0000

    re(4): recover Tx completions whose MSI was swallowed in re_intr_msi()
    
    A Tx completion that raises a status bit between the ISR ack at the top
    of re_intr_msi() and the IMR re-enable at the bottom is never re-signalled:
    these controllers do not re-assert MSI for an already-set status bit
    (this is why hw.re.msi_disable is a known workaround in the PR).
    
    Re-read ISR before re-enabling; if a Tx bit is pending, ack just that bit,
    reap the ring and restart the queue. Rx bits are deliberately left set so
    they re-arm the interrupt normally and Rx moderation state is untouched.
    
    Also flush the posted IMR write. Mirrors what the INTx path already
    achieves via the loop in re_intr().
    
    * MSI interrupt mode on RTL8168H under load; "missed Tx interrupts"
      watchdog recoveries no longer occur.
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D58278
    PR: kern/166724
---
 sys/dev/re/if_re.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 4df75474bce3..b04dc3cbaf4a 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -2731,7 +2731,34 @@ re_intr_msi(void *xsc)
 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
 		if (!if_sendq_empty(ifp))
 			re_start_locked(ifp);
+		/*
+		 * A Tx completion can set a Tx status bit between the ISR ack
+		 * near the top of this routine and re-enabling interrupts
+		 * below.  These controllers do not re-assert the MSI for a
+		 * status bit that is already set, so the completion would not
+		 * be serviced until the next interrupt or the 1 Hz re_tick()
+		 * reclaim (this is why hw.re.msi_disable is a known
+		 * workaround).  If a Tx bit is pending, clear just that bit and
+		 * reap the ring now; leave any Rx bits set so they re-arm the
+		 * interrupt normally and the Rx moderation state is untouched.
+		 */
+		status = CSR_READ_2(sc, RL_ISR);
+		if ((status & (RL_ISR_TX_OK | RL_ISR_TX_ERR |
+		    RL_ISR_TX_DESC_UNAVAIL)) != 0) {
+			CSR_WRITE_2(sc, RL_ISR, status & (RL_ISR_TX_OK |
+			    RL_ISR_TX_ERR | RL_ISR_TX_DESC_UNAVAIL));
+			if ((status & (RL_ISR_TX_OK |
+			    RL_ISR_TX_DESC_UNAVAIL)) != 0 &&
+			    (sc->rl_flags & RL_FLAG_PCIE) != 0)
+				CSR_WRITE_1(sc, sc->rl_txstart,
+				    RL_TXSTART_START);
+			re_txeof(sc);
+			if (!if_sendq_empty(ifp))
+				re_start_locked(ifp);
+		}
 		CSR_WRITE_2(sc, RL_IMR, intrs);
+		/* Flush the posted IMR write. */
+		(void)CSR_READ_2(sc, RL_ISR);
 	}
 	RL_UNLOCK(sc);
 }


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a5d1c8a.3e1f9.34bfee7e>