The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=d11f124e932bfa4fabdc6c5b67735181615a0630
commit d11f124e932bfa4fabdc6c5b67735181615a0630 Author: Jérémie Jourdin <[email protected]> AuthorDate: 2026-07-19 18:45:47 +0000 Commit: Adrian Chadd <[email protected]> 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); }
