[PATCH iwl-next v2 2/8] ixgbe: add ixgbe_container_is_rx() helper and refine RX adaptive ITR

Aleksandr Loktionov
2026-04-08T13:12:22Z

From: Alexander Duyck <alexander.h.duyck@intel.com>

Add an ixgbe_container_is_rx() helper to cleanly distinguish RX from TX
ring containers inside ixgbe_update_itr().

Refine the RX-specific latency-detection path:

- Replace the shared "packets < 4 or bytes < 9000" threshold with an
RX-specific check of "1..23 packets and bytes < 12112". When that
condition holds, target 8x the observed byte count in the next
interval by computing avg_wire_size = (bytes + packets * 24) * 2,
clamped to [2560, 12800], and jumping directly to the speed-based
ITR calculation. This provides finer-grained control over low-rate
RX latency workloads without affecting TX.

- Remove the separate "no packets" special-case block. When packets
is 0 it falls into the "< 48" branch. The mode-tracking logic in
that branch is extended: fewer than 8 packets forces latency mode;
8..47 packets preserves the current mode. This replaces the old
unconditional "add LATENCY flag from ring_container->itr" carried
over from the removed block.

- Remove the adjust_by_size label and the associated "halve
avg_wire_size in latency mode" step. The Rx latency path now
pre-calculates avg_wire_size independently and the bulk path no
longer needs the halving to compensate for incorrect thresholds.
Rename the jump target to adjust_for_speed to reflect its purpose.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Split from monolithic ITR cleanup; adds ixgbe_container_is_rx(),
refines RX latency thresholds (24 pkts / 12112 B), and removes the
separate no-packet and adjust_by_size code paths.

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 72 ++++++++++--------
1 file changed, 41 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..b3f4a72 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2711,6 +2711,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
}

+static bool ixgbe_container_is_rx(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring_container *rc)
+{
+ return &q_vector->rx == rc;
+}
+
/**
* ixgbe_update_itr - update the dynamic ITR value based on statistics
* @q_vector: structure containing interrupt and ring information
@@ -2747,35 +2753,24 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
goto clear_counts;

packets = ring_container->total_packets;
-
- /* We have no packets to actually measure against. This means
- * either one of the other queues on this vector is active or
- * we are a Tx queue doing TSO with too high of an interrupt rate.
- *
- * When this occurs just tick up our delay by the minimum value
- * and hope that this extra delay will prevent us from being called
- * without any work on our queue.
- */
- if (!packets) {
- itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
- if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
- itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
- itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
- goto clear_counts;
- }
-
bytes = ring_container->total_bytes;

- /* If packets are less than 4 or bytes are less than 9000 assume
- * insufficient data to use bulk rate limiting approach. We are
- * likely latency driven.
- */
- if (packets < 4 && bytes < 9000) {
- itr = IXGBE_ITR_ADAPTIVE_LATENCY;
- goto adjust_by_size;
+ if (ixgbe_container_is_rx(q_vector, ring_container)) {
+ /* If Rx and there are 1 to 23 packets and bytes are less than
+ * 12112 assume insufficient data to use bulk rate limiting
+ * approach. Instead we will focus on simply trying to target
+ * receiving 8 times as much data in the next interrupt.
+ */
+ if (packets && packets < 24 && bytes < 12112) {
+ itr = IXGBE_ITR_ADAPTIVE_LATENCY;
+ avg_wire_size = (bytes + packets * 24) * 2;
+ avg_wire_size = clamp_t(unsigned int,
+ avg_wire_size, 2560, 12800);
+ goto adjust_for_speed;
+ }
}

- /* Between 4 and 48 we can assume that our current interrupt delay
+ /* Less than 48 packets we can assume that our current interrupt delay
* is only slightly too low. As such we should increase it by a small
* fixed amount.
*/
@@ -2783,6 +2778,20 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
+
+ /* If sample size is 0 - 7 we should probably switch
+ * to latency mode instead of trying to control
+ * things as though we are in bulk.
+ *
+ * Otherwise if the number of packets is less than 48
+ * we should maintain whatever mode we are currently
+ * in. The range between 8 and 48 is the cross-over
+ * point between latency and bulk traffic.
+ */
+ if (packets < 8)
+ itr += IXGBE_ITR_ADAPTIVE_LATENCY;
+ else
+ itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
goto clear_counts;
}

@@ -2813,7 +2822,6 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
*/
itr = IXGBE_ITR_ADAPTIVE_BULK;

-adjust_by_size:
/* If packet counts are 256 or greater we can assume we have a gross
* overestimation of what the rate should be. Instead of trying to fine
* tune it just use the formula below to try and dial in an exact value
@@ -2856,12 +2864,7 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
avg_wire_size = 32256;
}

- /* If we are in low latency mode half our delay which doubles the rate
- * to somewhere between 100K to 16K ints/sec
- */
- if (itr & IXGBE_ITR_ADAPTIVE_LATENCY)
- avg_wire_size >>= 1;
-
+adjust_for_speed:
/* Resultant value is 256 times larger than it needs to be. This
* gives us room to adjust the value as needed to either increase
* or decrease the value based on link speeds of 10G, 2.5G, 1G, etc.
--
2.52.0