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://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fintel-wired-lan%2FAS1PR10MB5392B7268416DB8A1624FDB88FA7A%40AS1PR10MB5392.EURPRD10.PROD.OUTLOOK.COM%2F&data=05%7C02%7Cvivek.behera%40siemens.com%7Cb609a859d19b47e8f47808de38d77627%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C639010695226787962%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=S1060xzCOGrJo0cO2enNhDmCIJUcCLZd%2F%2BmKLByazm8%3D&reserved=0
v2: 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fintel-wired-lan%2FAS1PR10MB539280B1427DA0ABE9D65E628FA5A%40AS1PR10MB5392.EURPRD10.PROD.OUTLOOK.COM%2F&data=05%7C02%7Cvivek.behera%40siemens.com%7Cb609a859d19b47e8f47808de38d77627%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C639010695226846016%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=ksDVfndVlbafyexZ2%2B3j9GccO9hupybvtl1twZs5OSk%3D&reserved=0
v3: 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fintel-wired-lan%2FIA3PR11MB8986E4ACB7F264CF2DD1D750E5A0A%40IA3PR11MB8986.namprd11.prod.outlook.com%2F&data=05%7C02%7Cvivek.behera%40siemens.com%7Cb609a859d19b47e8f47808de38d77627%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C639010695226890990%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=zEWhj7N2%2BmwsShmoy1ACAjb3vi7yJgbA077fISIOZiM%3D&reserved=0
v4: 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fintel-wired-lan%2FAS1PR10MB53926CB955FBD4F9F4A018818FA0A%40AS1PR10MB5392.EURPRD10.PROD.OUTLOOK.COM%2F&data=05%7C02%7Cvivek.behera%40siemens.com%7Cb609a859d19b47e8f47808de38d77627%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C639010695226933538%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=23aTM4TNsnyzoS%2FpSM1GcluaWzLPNbrPKEo%2BOrm9hZQ%3D&reserved=0
v5: 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fintel-wired-lan%2FAS1PR10MB5392FCA415A38B9DD7BB5F218FA0A%40AS1PR10MB5392.EURPRD10.PROD.OUTLOOK.COM%2F&data=05%7C02%7Cvivek.behera%40siemens.com%7Cb609a859d19b47e8f47808de38d77627%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C639010695227205026%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=JdY3aHzIcIWtir9fAV%2BMELNWtiyLJYRU7IMxLZ0mPqQ%3D&reserved=0
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 */
+                       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

Reply via email to