>-----Original Message-----
>From: Intel-wired-lan <[email protected]> On Behalf Of Vivek
>Behera
>Sent: Friday, December 12, 2025 5:32 PM
>To: Loktionov, Aleksandr <[email protected]>; Keller, Jacob E
><[email protected]>; Nguyen, Anthony L <[email protected]>;
>Kitszel, Przemyslaw <[email protected]>
>Cc: [email protected]; [email protected]; Behera, Vivek
><[email protected]>
>Subject: [Intel-wired-lan] [PATCH v7 iwl-net] 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: fc9df2a0b520 ("igc: Enable RX via AF_XDP zero-copy")
>Fixes: 15fd021bc427 ("igc: Add Tx hardware timestamp request for AF_XDP
>zero-copy packet")
>Signed-off-by: Vivek Behera <[email protected]>
>Reviewed-by: Jacob Keller <[email protected]>
>Reviewed-by: Aleksandr loktinov <[email protected]>
>Reviewed-by: Przemyslaw Kitszel <[email protected]>
>Reviewed-by: Tony Nguyen <[email protected]>
>---
>v1:
>https://lore.kernel.org/intel-wired-lan/as1pr10mb5392b7268416db8a1624fdb88f...@as1pr10mb5392.eurprd10.prod.outlook.com/
>v2:
>https://lore.kernel.org/intel-wired-lan/as1pr10mb539280b1427da0abe9d65e628f...@as1pr10mb5392.eurprd10.prod.outlook.com/
>v3:
>https://lore.kernel.org/intel-wired-lan/ia3pr11mb8986e4acb7f264cf2dd1d750e5...@ia3pr11mb8986.namprd11.prod.outlook.com/
>v4:
>https://lore.kernel.org/intel-wired-lan/as1pr10mb53926cb955fbd4f9f4a018818f...@as1pr10mb5392.eurprd10.prod.outlook.com/
>v5:
>https://lore.kernel.org/intel-wired-lan/as1pr10mb5392fca415a38b9dd7bb5f218f...@as1pr10mb5392.eurprd10.prod.outlook.com/
>v6:
>https://lore.kernel.org/intel-wired-lan/[email protected]/
>
>changelog:
>v1
>- Inital description of the Bug and steps to reproduce with RTC Testbench
>- Test results after applying the patch
>v1 -> v2
>- Handling of RX and TX Wakeup in igc_xsk_wakeup for a split IRQ configuration
>- Removal of igc_trigger_rxtxq_interrupt (now redundant)
>- Added flag to igc_xsk_wakeup function call in igc_ptp_free_tx_buffer
>v2 -> v3
>- Added 'Fixes:' tags for the relevant commits.
>- Added reviewer
>v3 -> v4
>- Added reviewer
>v4 -> v5
>- Updated comment style from multi-star to standard linux convention
>v5 -> v6
>- Resolve formatting issues highlighted by reviewers
>- Try to include version histroy as defined in netdev guidelines
>- Included review suggestions from Przemyslaw
>- Added reviewers
>v6 -> v7
>- Included review suggestions from Przemyslaw missed in v6
>---
> drivers/net/ethernet/intel/igc/igc_main.c | 78 ++++++++++++++++++-----
> drivers/net/ethernet/intel/igc/igc_ptp.c | 2 +-
> 2 files changed, 62 insertions(+), 18 deletions(-)
>
>diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
>b/drivers/net/ethernet/intel/igc/igc_main.c
>index 7aafa60ba0c8..620b9f9bd3aa 100644
>--- a/drivers/net/ethernet/intel/igc/igc_main.c
>+++ b/drivers/net/ethernet/intel/igc/igc_main.c
>@@ -6908,21 +6908,13 @@ 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)
>-{
>- struct igc_hw *hw = &adapter->hw;
>- u32 eics = 0;
>-
>- eics |= q_vector->eims_value;
>- wr32(IGC_EICS, eics);
>-}
>-
> int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags) {
> struct igc_adapter *adapter = netdev_priv(dev);
>+ struct igc_hw *hw = &adapter->hw;
> struct igc_q_vector *q_vector;
> struct igc_ring *ring;
>+ u32 eics = 0;
>
> if (test_bit(__IGC_DOWN, &adapter->state))
> return -ENETDOWN;
>@@ -6930,18 +6922,70 @@ int igc_xsk_wakeup(struct net_device *dev, u32
>queue_id, u32 flags)
> if (!igc_xdp_is_enabled(adapter))
> return -ENXIO;
>
>- if (queue_id >= adapter->num_rx_queues)
>- return -EINVAL;
>+ if ((flags & XDP_WAKEUP_RX) && (flags & XDP_WAKEUP_TX)) {
>+ /* If both TX and RX need to be woken up */
>+ /* check if queue pairs are active. */
>+ if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS)) {
>+ /* Just get the ring params from Rx */
>+ if (queue_id >= adapter->num_rx_queues)
>+ return -EINVAL;
>+ ring = adapter->rx_ring[queue_id];
>+ } else {
>+ /* Two irqs for Rx AND Tx need to be triggered */
>+ if (queue_id >= adapter->num_rx_queues)
>+ return -EINVAL;
>+
>+ if (queue_id >= adapter->num_tx_queues)
>+ return -EINVAL;
>+
>+ /* IRQ trigger preparation for Rx */
>+ ring = adapter->rx_ring[queue_id];
>+ if (!ring->xsk_pool)
>+ return -ENXIO;
>
>- ring = adapter->rx_ring[queue_id];
>+ q_vector = ring->q_vector;
>+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
>+ eics |= q_vector->eims_value;
>+ /* IRQ trigger preparation for Tx */
>+ ring = adapter->tx_ring[queue_id];
>+
>+ if (!ring->xsk_pool)
>+ return -ENXIO;
>+
>+ /* Retrieve the q_vector saved in the ring */
Thank you for addressing the previous comments. I believe this one was
accidentally missed. Please remove as redundant.
Piotr
>+ q_vector = ring->q_vector;
>+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
>+ eics |= q_vector->eims_value; /* Extend the BIT
>mask for eics */
>
>+ /* Now we trigger the split irqs for Rx and Tx over
>eics */
>+ if (eics)
>+ wr32(IGC_EICS, eics);
>+
>+ return 0;
>+ }
>+ } else if (flags & XDP_WAKEUP_TX) {
>+ if (queue_id >= adapter->num_tx_queues)
>+ return -EINVAL;
>+ /* Get the ring params from Tx */
>+ ring = adapter->tx_ring[queue_id];
>+ } else if (flags & XDP_WAKEUP_RX) {
>+ if (queue_id >= adapter->num_rx_queues)
>+ return -EINVAL;
>+ /* Get the ring params from Rx */
>+ ring = adapter->rx_ring[queue_id];
>+ } else {
>+ /* Invalid Flags */
>+ return -EINVAL;
>+ }
>+ /* Prepare to trigger single irq */
> 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);
>-
>+ q_vector = ring->q_vector;
>+ if (!napi_if_scheduled_mark_missed(&q_vector->napi)) {
>+ eics |= q_vector->eims_value;
>+ wr32(IGC_EICS, eics);
>+ }
> return 0;
> }
>
>diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c
>b/drivers/net/ethernet/intel/igc/igc_ptp.c
>index b7b46d863bee..6d8c2d639cd7 100644
>--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
>+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
>@@ -550,7 +550,7 @@ 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;
> }
>--
>2.34.1