The branch main has been updated by kbowling:

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

commit e35533457530bb9db655e6137c2eea790e18b97b
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-07-25 23:58:58 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-07-26 01:00:02 +0000

    igc: synchronize interrupt moderation state
    
    Keep the saved EITR value synchronized with hardware across
    reinitialization.  Correct EITR encoding, decoding, and MSI-X register
    selection, and reject nonpositive fallback rates.
    
    Apply the packet-buffer fallback without permanently disabling AIM.
    
    MFC after:      1 week
---
 sys/dev/igc/if_igc.c | 35 +++++++++++++++++++++++++----------
 sys/dev/igc/if_igc.h |  6 ++++--
 2 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
index d0e9ad3b7a8d..3e4c0228619a 100644
--- a/sys/dev/igc/if_igc.c
+++ b/sys/dev/igc/if_igc.c
@@ -165,6 +165,7 @@ static int  igc_sysctl_eee(SYSCTL_HANDLER_ARGS);
 static int     igc_get_regs(SYSCTL_HANDLER_ARGS);
 
 static void    igc_configure_queues(struct igc_softc *);
+static void    igc_initialize_interrupt_rate(struct igc_softc *);
 
 
 /*********************************************************************
@@ -469,6 +470,13 @@ igc_if_attach_pre(if_ctx_t ctx)
        dev = iflib_get_dev(ctx);
        sc = iflib_get_softc(ctx);
 
+       if (igc_max_interrupt_rate <= 0) {
+               device_printf(dev,
+                   "Invalid max_interrupt_rate %d; using default %d\n",
+                   igc_max_interrupt_rate, IGC_INTS_DEFAULT);
+               igc_max_interrupt_rate = IGC_INTS_DEFAULT;
+       }
+
        sc->ctx = sc->osdep.ctx = ctx;
        sc->dev = sc->osdep.dev = dev;
        scctx = sc->shared = iflib_get_softc_ctx(ctx);
@@ -880,6 +888,7 @@ igc_if_init(if_ctx_t ctx)
 
        if (sc->intr_type == IFLIB_INTR_MSIX) /* Set up queue routing */
                igc_configure_queues(sc);
+       igc_initialize_interrupt_rate(sc);
 
        /* this clears any pending interrupts */
        IGC_READ_REG(&sc->hw, IGC_ICR);
@@ -990,7 +999,6 @@ igc_neweitr(struct igc_softc *sc, struct igc_rx_queue *que,
                /* Want at least enough packet buffer for two frames to AIM */
                if (sc->shared->isc_max_frame_size * 2 > (sc->pba << 10)) {
                        neweitr = igc_max_interrupt_rate;
-                       sc->enable_aim = 0;
                        goto igc_set_next_eitr;
                }
 
@@ -1640,7 +1648,7 @@ igc_configure_queues(struct igc_softc *sc)
        struct igc_hw *hw = &sc->hw;
        struct igc_rx_queue *rx_que;
        struct igc_tx_queue *tx_que;
-       u32 ivar = 0, newitr = 0;
+       u32 ivar = 0;
 
        /* First turn on RSS capability */
        IGC_WRITE_REG(hw, IGC_GPIE,
@@ -1683,18 +1691,25 @@ igc_configure_queues(struct igc_softc *sc)
        sc->link_mask = 1 << sc->linkvec;
        IGC_WRITE_REG(hw, IGC_IVAR_MISC, ivar);
 
-       /* Set the starting interrupt rate */
-       if (igc_max_interrupt_rate > 0)
-               newitr = IGC_INTS_TO_EITR(igc_max_interrupt_rate);
+       return;
+}
+
+static void
+igc_initialize_interrupt_rate(struct igc_softc *sc)
+{
+       struct igc_hw *hw = &sc->hw;
+       struct igc_rx_queue *rx_que;
+       u32 newitr;
 
+       newitr = IGC_INTS_TO_EITR(igc_max_interrupt_rate);
        newitr |= IGC_EITR_CNT_IGNR;
 
        for (int i = 0; i < sc->rx_num_queues; i++) {
                rx_que = &sc->rx_queues[i];
-               IGC_WRITE_REG(hw, IGC_EITR(rx_que->msix), newitr);
+               rx_que->eitr_setting = newitr;
+               IGC_WRITE_REG(hw, IGC_EITR(rx_que->msix),
+                   rx_que->eitr_setting);
        }
-
-       return;
 }
 
 static void
@@ -2693,7 +2708,7 @@ igc_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
        if (tx) {
                tque = oidp->oid_arg1;
                hw = &tque->sc->hw;
-               reg = IGC_READ_REG(hw, IGC_EITR(tque->me));
+               reg = IGC_READ_REG(hw, IGC_EITR(tque->msix));
        } else {
                rque = oidp->oid_arg1;
                hw = &rque->sc->hw;
@@ -2702,7 +2717,7 @@ igc_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
 
        usec = (reg & IGC_QVECTOR_MASK);
        if (usec > 0)
-               rate = IGC_INTS_TO_EITR(usec);
+               rate = IGC_EITR_TO_INTS(usec);
        else
                rate = 0;
 
diff --git a/sys/dev/igc/if_igc.h b/sys/dev/igc/if_igc.h
index d8d5d5b251fa..4af08e03fedb 100644
--- a/sys/dev/igc/if_igc.h
+++ b/sys/dev/igc/if_igc.h
@@ -171,8 +171,10 @@
 #define IGC_EITR_DIVIDEND      1000000
 #define IGC_EITR_SHIFT         2
 #define IGC_QVECTOR_MASK       0x7FFC
-#define IGC_INTS_TO_EITR(i)    (((IGC_EITR_DIVIDEND/i) & IGC_QVECTOR_MASK) << \
-                                   IGC_EITR_SHIFT)
+#define IGC_INTS_TO_EITR(i)    \
+       (((IGC_EITR_DIVIDEND / (i)) << IGC_EITR_SHIFT) & IGC_QVECTOR_MASK)
+#define IGC_EITR_TO_INTS(i)    ((IGC_EITR_DIVIDEND << IGC_EITR_SHIFT) / \
+                                           ((i) & IGC_QVECTOR_MASK))
 
 /*
  * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be

Reply via email to