Current way of handling XDP RxQ info in i40e has following problems:
* when xsk_buff_pool is detached, memory model is not unregistered before
  registering a new one, this leads to a dangling xsk_buff_pool in the
  memory model table
* frag_size is not updated when xsk_buff_pool is detached or when MTU is
  changed, this leads to growing tail always failing for multi-buffer
  packets.

Couple XDP RxQ info registering with buffer allocations and unregistering
with cleaning the ring.

Fixes: a045d2f2d03d ("i40e: set xdp_rxq_info::frag_size")
Signed-off-by: Larysa Zaremba <[email protected]>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 34 ++++++++++++---------
 drivers/net/ethernet/intel/i40e/i40e_txrx.c |  5 +--
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index d3bc3207054f..eaa5b65e6daf 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3577,18 +3577,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
        if (ring->vsi->type != I40E_VSI_MAIN)
                goto skip;
 
-       if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
-               err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
-                                        ring->queue_index,
-                                        ring->q_vector->napi.napi_id,
-                                        ring->rx_buf_len);
-               if (err)
-                       return err;
-       }
-
        ring->xsk_pool = i40e_xsk_pool(ring);
        if (ring->xsk_pool) {
-               xdp_rxq_info_unreg(&ring->xdp_rxq);
                ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
                err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
                                         ring->queue_index,
@@ -3600,17 +3590,23 @@ static int i40e_configure_rx_ring(struct i40e_ring 
*ring)
                                                 MEM_TYPE_XSK_BUFF_POOL,
                                                 NULL);
                if (err)
-                       return err;
+                       goto unreg_xdp;
                dev_info(&vsi->back->pdev->dev,
                         "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx 
ring %d\n",
                         ring->queue_index);
 
        } else {
+               err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+                                        ring->queue_index,
+                                        ring->q_vector->napi.napi_id,
+                                        ring->rx_buf_len);
+               if (err)
+                       return err;
                err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
                                                 MEM_TYPE_PAGE_SHARED,
                                                 NULL);
                if (err)
-                       return err;
+                       goto unreg_xdp;
        }
 
 skip:
@@ -3648,7 +3644,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
                dev_info(&vsi->back->pdev->dev,
                         "Failed to clear LAN Rx queue context on Rx ring %d 
(pf_q %d), error: %d\n",
                         ring->queue_index, pf_q, err);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto unreg_xdp;
        }
 
        /* set the context in the HMC */
@@ -3657,7 +3654,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
                dev_info(&vsi->back->pdev->dev,
                         "Failed to set LAN Rx queue context on Rx ring %d 
(pf_q %d), error: %d\n",
                         ring->queue_index, pf_q, err);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto unreg_xdp;
        }
 
        /* configure Rx buffer alignment */
@@ -3665,7 +3663,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
                if (I40E_2K_TOO_SMALL_WITH_PADDING) {
                        dev_info(&vsi->back->pdev->dev,
                                 "2k Rx buffer is too small to fit standard MTU 
and skb_shared_info\n");
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       goto unreg_xdp;
                }
                clear_ring_build_skb_enabled(ring);
        } else {
@@ -3695,6 +3694,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
        }
 
        return 0;
+unreg_xdp:
+       if (ring->vsi->type == I40E_VSI_MAIN)
+               xdp_rxq_info_unreg(&ring->xdp_rxq);
+
+       return err;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c 
b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index cc0b9efc2637..816179c7e271 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1470,6 +1470,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
        if (!rx_ring->rx_bi)
                return;
 
+       if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+               xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
        if (rx_ring->xsk_pool) {
                i40e_xsk_clean_rx_ring(rx_ring);
                goto skip_free;
@@ -1527,8 +1530,6 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
 void i40e_free_rx_resources(struct i40e_ring *rx_ring)
 {
        i40e_clean_rx_ring(rx_ring);
-       if (rx_ring->vsi->type == I40E_VSI_MAIN)
-               xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
        rx_ring->xdp_prog = NULL;
        kfree(rx_ring->rx_bi);
        rx_ring->rx_bi = NULL;
-- 
2.52.0


Reply via email to