git: 5d9f99143690 - main - igc: Count packets dropped for want of a receive descriptor

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Mon, 02 Nov 2026 17:12:43 UTC
The branch main has been updated by rcm:

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

commit 5d9f99143690dcd18e326937769f03514eee2652
Author:     R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-11-02 17:10:17 +0000
Commit:     R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-11-02 17:10:17 +0000

    igc: Count packets dropped for want of a receive descriptor
    
    When a receive ring is full the hardware drops the packet and counts it
    in RQDPC, a per-queue register the driver never read. Such drops were
    invisible: MPC counts packet buffer overflows, not descriptor
    exhaustion, so an overloaded queue lost packets with nothing to show for
    it. With several receive queues this is the common overload signature,
    since RSS loads the queues unevenly and one saturated queue drops while
    the others idle.
    
    Read RQDPC for each queue with the other statistics and account the
    drops per queue as dev.igc.N.queue_rx_M.rx_drops and in total as the
    interface's input queue drop counter (netstat -d, Idrop), as ixgbe does
    with QPRDC. Write the register back to zero after reading; the I210
    documents it as read/write rather than read-to-clear.
    
    Reviewed by:            kbowling
    MFC after:              2 weeks
    Sponsored by:           Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D61004
---
 sys/dev/igc/if_igc.c | 23 +++++++++++++++++++++++
 sys/dev/igc/if_igc.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
index 7bfbf1c9d1a7..b8a9bd91c2f5 100644
--- a/sys/dev/igc/if_igc.c
+++ b/sys/dev/igc/if_igc.c
@@ -3142,6 +3142,19 @@ igc_update_stats_counters(struct igc_softc *sc)
 	sc->stats.htdpmc += IGC_READ_REG(&sc->hw, IGC_HTDPMC);
 	sc->stats.tsctc += IGC_READ_REG(&sc->hw, IGC_TSCTC);
 
+	/*
+	 * Packets dropped because a queue's descriptor ring was full.  The
+	 * register does not clear on read.
+	 */
+	for (int i = 0; i < sc->rx_num_queues; i++) {
+		u32 rqdpc = IGC_READ_REG(&sc->hw, IGC_RQDPC(i));
+
+		if (rqdpc != 0) {
+			IGC_WRITE_REG(&sc->hw, IGC_RQDPC(i), 0);
+			sc->rx_queues[i].rx_drops += rqdpc;
+		}
+	}
+
 	igc_update_ecc_stats(sc);
 }
 
@@ -3166,6 +3179,13 @@ igc_if_get_counter(if_ctx_t ctx, ift_counter cnt)
 	case IFCOUNTER_OERRORS:
 		return (if_get_counter_default(ifp, cnt) +
 		    sc->stats.ecol + sc->stats.latecol);
+	case IFCOUNTER_IQDROPS: {
+		uint64_t drops = if_get_counter_default(ifp, cnt);
+
+		for (int i = 0; i < sc->rx_num_queues; i++)
+			drops += sc->rx_queues[i].rx_drops;
+		return (drops);
+	}
 	default:
 		return (if_get_counter_default(ifp, cnt));
 	}
@@ -3367,6 +3387,9 @@ igc_add_hw_stats(struct igc_softc *sc)
 		SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "rx_irq",
 		    CTLFLAG_RD, &rxr->rx_irq,
 		    "Queue MSI-X Receive Interrupts");
+		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_drops",
+		    CTLFLAG_RD, &rx_que->rx_drops,
+		    "Packets dropped for want of a receive descriptor");
 	}
 
 	/* MAC stats get their own sub node */
diff --git a/sys/dev/igc/if_igc.h b/sys/dev/igc/if_igc.h
index 5b728b6b1193..7c3b90ccee78 100644
--- a/sys/dev/igc/if_igc.h
+++ b/sys/dev/igc/if_igc.h
@@ -333,6 +333,7 @@ struct igc_rx_queue {
 	u32                    eitr_setting;
 	struct rx_ring         rxr;
 	u64                    irqs;
+	u64                    rx_drops;
 	struct if_irq          que_irq;
 };