git: 4a0ec469934a - main - iflib: Do not ring the transmit doorbell when nothing is pending

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Mon, 05 Oct 2026 15:19:05 UTC
The branch main has been updated by rcm:

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

commit 4a0ec469934a5de60b9b540689703a698ac44105
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-05 15:19:01 +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
---
 sys/net/iflib.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index c2e70d946bf6..834cc37cb6ab 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -3457,6 +3457,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 */