git: 55153512e9ab - stable/14 - iflib: Do not ring the transmit doorbell when nothing is pending

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Wed, 28 Oct 2026 20:41:30 UTC
The branch stable/14 has been updated by rcm:

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

commit 55153512e9abd9ec4daa7888a6a62fc8038d70ce
Author:     R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-10-05 15:17:13 +0000
Commit:     R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-10-28 20:38:05 +0000

    iflib: Do not ring the transmit doorbell when nothing is pending
    
    For a lightly used ring iflib_txd_db_check() may defer zero descriptors,
    so its "pending >= limit" test is true even when nothing has been queued
    since the last doorbell.  iflib_txq_drain() calls it before, inside and
    after its loop, so a sender that drains its own packet wrote the tail
    register three times per packet, twice with the value the hardware
    already had.
    
    The log of 81be655266fa ("iflib: ensure that tx interrupts enabled and
    cleanups") calls skipping the doorbell when db_pending is zero "an
    obvious missing optimization"; the comparison against a limit of zero
    defeated it.  vmx(4) and mgb(4) have dropped such repeated requests in
    the driver since 2019.  Return early when nothing is pending.
    
    Reviewed by:            gallatin
    MFC after:              2 weeks
    Sponsored by:           Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D60290
    
    (cherry picked from commit 4a0ec469934a5de60b9b540689703a698ac44105)
---
 sys/net/iflib.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index e90709e84e6f..ed2813458ebe 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -3134,6 +3134,13 @@ iflib_txd_db_check(iflib_txq_t txq, int ring)
 	if_ctx_t ctx = txq->ift_ctx;
 	qidx_t dbval, max;
 
+	/*
+	 * Nothing has been queued since the last doorbell.  The threshold is
+	 * zero for a lightly used ring, so the test below would not catch this.
+	 */
+	if (txq->ift_db_pending == 0)
+		return (false);
+
 	max = TXQ_MAX_DB_DEFERRED(txq, txq->ift_in_use);
 
 	/* force || threshold exceeded || at the edge of the ring */