igc: Fix trigger of incorrect irq in igc_xsk_wakeup function

This patch addresses the issue where the igc_xsk_wakeup function
was triggering an incorrect IRQ for tx-0 when the i226 is configured
with only 2 combined queues or in an environment with 2 active CPU cores.
This prevented XDP Zero-copy send functionality in such split IRQ
configurations.

The fix implements the correct logic for extracting q_vectors saved
during rx and tx ring allocation and utilizes flags provided by the
ndo_xsk_wakeup API to trigger the appropriate IRQ.

Fixes: fc9df2a0b5 ("igc: Enable RX via AF_XDP zero-copy")
Fixes: 15fd021bc4 ("igc: Add Tx hardware timestamp request for AF_XDP zero-copy packet")
Signed-off-by: Vivek Behera <vivek.behera@siemens.com>
Reviewed-by: Jacob Keller <jacob.keller@intel.com>
Reviewed-by: Aleksandr loktinov <aleksandr.loktionov@intel.com>
Reviewed-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
Reviewed-by: Song Yoong Siang <yoong.siang.song@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
Vivek Behera 2026-01-20 08:52:16 +01:00 committed by Tony Nguyen
parent d4c13ab362
commit 554a1c34c1
2 changed files with 26 additions and 11 deletions

View file

@ -6906,28 +6906,29 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
struct igc_q_vector *q_vector)
static u32 igc_sw_irq_prep(struct igc_q_vector *q_vector)
{
struct igc_hw *hw = &adapter->hw;
u32 eics = 0;
eics |= q_vector->eims_value;
wr32(IGC_EICS, eics);
if (!napi_if_scheduled_mark_missed(&q_vector->napi))
eics = q_vector->eims_value;
return eics;
}
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
{
struct igc_adapter *adapter = netdev_priv(dev);
struct igc_q_vector *q_vector;
struct igc_hw *hw = &adapter->hw;
struct igc_ring *ring;
u32 eics = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return -ENETDOWN;
if (!igc_xdp_is_enabled(adapter))
return -ENXIO;
/* Check if queue_id is valid. Tx and Rx queue numbers are always same */
if (queue_id >= adapter->num_rx_queues)
return -EINVAL;
@ -6936,9 +6937,22 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
if (!ring->xsk_pool)
return -ENXIO;
q_vector = adapter->q_vector[queue_id];
if (!napi_if_scheduled_mark_missed(&q_vector->napi))
igc_trigger_rxtxq_interrupt(adapter, q_vector);
if (flags & XDP_WAKEUP_RX)
eics |= igc_sw_irq_prep(ring->q_vector);
if (flags & XDP_WAKEUP_TX) {
/* If IGC_FLAG_QUEUE_PAIRS is active, the q_vector
* and NAPI is shared between RX and TX.
* If NAPI is already running it would be marked as missed
* from the RX path, making this TX call a NOP
*/
ring = adapter->tx_ring[queue_id];
eics |= igc_sw_irq_prep(ring->q_vector);
}
if (eics)
/* Cause software interrupt */
wr32(IGC_EICS, eics);
return 0;
}

View file

@ -550,7 +550,8 @@ static void igc_ptp_free_tx_buffer(struct igc_adapter *adapter,
tstamp->buffer_type = 0;
/* Trigger txrx interrupt for transmit completion */
igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index, 0);
igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
XDP_WAKEUP_TX);
return;
}