On Friday, December 19, 2025 6:44 AM, Nguyen, Anthony L 
<[email protected]> wrote:
>On 12/17/2025 11:21 PM, Behera, VIVEK wrote:
>> Hello colleagues,
>>

[...]

>>>>
>>>> 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.
>>>>

Thank you, Vivek, for the fix.
Overall, your patch looks good to me, just some minor changes are needed.

>>>> 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]>
>
>Unless you have received a Reviewed-by tag explicitly from the person,
>you shouldn't add it.
>
>...
>
>>>> drivers/net/ethernet/intel/igc/igc_main.c | 90 ++++++++++++++++++-----
>>>> drivers/net/ethernet/intel/igc/igc_ptp.c  |  2 +-
>>>> 2 files changed, 73 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
>>>> b/drivers/net/ethernet/intel/igc/igc_main.c
>>>> index 7aafa60ba0c8..76e4790bd3c0 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,80 @@ 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)

num_rx_queues and num_tx_queues always having the same value. Thus, it is safe 
for
you to keep the original queue_id checking at the beginning of the function, as 
below,
and remove all the other queue_id check in your code.

        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. */
>
>nit: This can just be one comment, no need to break it into two comment
>blocks
>
>               /* 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 */
>>>> +                  u32 eics_tx = 0;
>>>> +                  u32 eics_rx = 0;
>>>> +                  struct napi_struct *rx_napi;
>>>> +                  struct napi_struct *tx_napi;
>
>This should be RCT, longest argument to shortest, so the structs should
>be first.
>
>>>> +
>>>> +                  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;
>>>> +                  q_vector = ring->q_vector;
>>>> +                  rx_napi = &q_vector->napi;
>>>> +                  /* Extend the BIT mask for eics */
>>>> +                  eics_rx |= ring->q_vector->eims_value;

IMHO, " eics_rx = ring->q_vector->eims_value " will be more readable,
cause you just OR with zero.

>>>> +
>>>> +                  /* IRQ trigger preparation for Tx */
>>>> +                  ring = adapter->tx_ring[queue_id];
>>>> +                  if (!ring->xsk_pool)
>>>> +                          return -ENXIO;
>>>> +                  q_vector = ring->q_vector;
>>>> +                  tx_napi = &q_vector->napi;
>>>> +                  /* Extend the BIT mask for eics */
>>>> +                  eics_tx |= ring->q_vector->eims_value;

IMHO, " eics_tx = ring->q_vector->eims_value " will be more readable,
cause you just OR with zero.

>>>> +
>>>> +                  /* Check and update napi states for rx and tx */
>>>> +                  if (!napi_if_scheduled_mark_missed(rx_napi))
>>>> +                          eics |= eics_rx;
>>>> +                  if (!napi_if_scheduled_mark_missed(tx_napi))
>>>> +                          eics |= eics_tx;
>>>> +
>>>> +                  /* Now we trigger the required irqs for Rx and Tx */
>>>> +                  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;
>>>> -
>>>> -  ring = adapter->rx_ring[queue_id];
>>>> -
>>>> +  }
>>>> +  /* 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;

IMHO, "eics = q_vector->eims_value" will be more readable,
cause you just OR with zero.

>>>> +          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);
>>>>

The preferred limit on the length of a single line is 80 columns, please move 
XDP_WAKEUP_TX to new line as below:

                igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
                               XDP_WAKEUP_TX);

>>>>            return;
>>>>    }
>>>> --
>>>> 2.34.1
>>>
>>> Reviewed-by: Piotr Kwapulinski <[email protected]>
>>
>> Thanks for all the reviews. Are there any suggestions before I add netdev@ 
>> and
>linux-kernel@ to the list for further review
>
>For this patch, I don't think I would re-add them. As part of normal
>process (future patches), yes, but this one was asked to be excluded
>while the kinks of the upstream process were worked out. As this is the
>list you're targeting your patch for and I'll be sending this to netdev
>following our validation, it will get its review from netdev at that time.
>
>Also, adding Siang who is one of the authors from the Fixes:
>

Thank you, Tony, for bringing this patch to my attention.

>Thanks,
>Tony
>>
>> Regards
>>
>> Vivek

Thanks & Regards
Siang

Reply via email to