i40e: Replace ring container array with linked list
authorAlexander Duyck <alexander.h.duyck@intel.com>
Sat, 28 Sep 2013 06:00:53 +0000 (06:00 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 10 Oct 2013 05:39:30 +0000 (22:39 -0700)
This replaces the ring container array with a linked list.  The idea is
to make the logic much easier to deal with since this will allow us to
call a simple helper function from the q_vectors to go through the
entire list.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h

index a090815a6dd9791d4951c4d238fb5e11488c76cc..c74ac585c639533c932662e6d3c667f41df696dc 100644 (file)
@@ -2516,7 +2516,7 @@ static irqreturn_t i40e_msix_clean_rings(int irq, void *data)
 {
        struct i40e_q_vector *q_vector = data;
 
-       if (!q_vector->tx.ring[0] && !q_vector->rx.ring[0])
+       if (!q_vector->tx.ring && !q_vector->rx.ring)
                return IRQ_HANDLED;
 
        napi_schedule(&q_vector->napi);
@@ -2533,7 +2533,7 @@ static irqreturn_t i40e_fdir_clean_rings(int irq, void *data)
 {
        struct i40e_q_vector *q_vector = data;
 
-       if (!q_vector->tx.ring[0] && !q_vector->rx.ring[0])
+       if (!q_vector->tx.ring && !q_vector->rx.ring)
                return IRQ_HANDLED;
 
        pr_info("fdir ring cleaning needed\n");
@@ -2560,14 +2560,14 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
        for (vector = 0; vector < q_vectors; vector++) {
                struct i40e_q_vector *q_vector = vsi->q_vectors[vector];
 
-               if (q_vector->tx.ring[0] && q_vector->rx.ring[0]) {
+               if (q_vector->tx.ring && q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                                 "%s-%s-%d", basename, "TxRx", rx_int_idx++);
                        tx_int_idx++;
-               } else if (q_vector->rx.ring[0]) {
+               } else if (q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                                 "%s-%s-%d", basename, "rx", rx_int_idx++);
-               } else if (q_vector->tx.ring[0]) {
+               } else if (q_vector->tx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                                 "%s-%s-%d", basename, "tx", tx_int_idx++);
                } else {
@@ -2778,40 +2778,26 @@ static irqreturn_t i40e_intr(int irq, void *data)
 }
 
 /**
- * i40e_map_vector_to_rxq - Assigns the Rx queue to the vector
+ * i40e_map_vector_to_qp - Assigns the queue pair to the vector
  * @vsi: the VSI being configured
  * @v_idx: vector index
- * @r_idx: rx queue index
+ * @qp_idx: queue pair index
  **/
-static void map_vector_to_rxq(struct i40e_vsi *vsi, int v_idx, int r_idx)
+static void map_vector_to_qp(struct i40e_vsi *vsi, int v_idx, int qp_idx)
 {
        struct i40e_q_vector *q_vector = vsi->q_vectors[v_idx];
-       struct i40e_ring *rx_ring = &(vsi->rx_rings[r_idx]);
-
-       rx_ring->q_vector = q_vector;
-       q_vector->rx.ring[q_vector->rx.count] = rx_ring;
-       q_vector->rx.count++;
-       q_vector->rx.latency_range = I40E_LOW_LATENCY;
-       q_vector->vsi = vsi;
-}
-
-/**
- * i40e_map_vector_to_txq - Assigns the Tx queue to the vector
- * @vsi: the VSI being configured
- * @v_idx: vector index
- * @t_idx: tx queue index
- **/
-static void map_vector_to_txq(struct i40e_vsi *vsi, int v_idx, int t_idx)
-{
-       struct i40e_q_vector *q_vector = vsi->q_vectors[v_idx];
-       struct i40e_ring *tx_ring = &(vsi->tx_rings[t_idx]);
+       struct i40e_ring *tx_ring = &(vsi->tx_rings[qp_idx]);
+       struct i40e_ring *rx_ring = &(vsi->rx_rings[qp_idx]);
 
        tx_ring->q_vector = q_vector;
-       q_vector->tx.ring[q_vector->tx.count] = tx_ring;
+       tx_ring->next = q_vector->tx.ring;
+       q_vector->tx.ring = tx_ring;
        q_vector->tx.count++;
-       q_vector->tx.latency_range = I40E_LOW_LATENCY;
-       q_vector->num_ringpairs++;
-       q_vector->vsi = vsi;
+
+       rx_ring->q_vector = q_vector;
+       rx_ring->next = q_vector->rx.ring;
+       q_vector->rx.ring = rx_ring;
+       q_vector->rx.count++;
 }
 
 /**
@@ -2827,7 +2813,7 @@ static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi)
 {
        int qp_remaining = vsi->num_queue_pairs;
        int q_vectors = vsi->num_q_vectors;
-       int qp_per_vector;
+       int num_ringpairs;
        int v_start = 0;
        int qp_idx = 0;
 
@@ -2835,11 +2821,21 @@ static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi)
         * group them so there are multiple queues per vector.
         */
        for (; v_start < q_vectors && qp_remaining; v_start++) {
-               qp_per_vector = DIV_ROUND_UP(qp_remaining, q_vectors - v_start);
-               for (; qp_per_vector;
-                    qp_per_vector--, qp_idx++, qp_remaining--) {
-                       map_vector_to_rxq(vsi, v_start, qp_idx);
-                       map_vector_to_txq(vsi, v_start, qp_idx);
+               struct i40e_q_vector *q_vector = vsi->q_vectors[v_start];
+
+               num_ringpairs = DIV_ROUND_UP(qp_remaining, q_vectors - v_start);
+
+               q_vector->num_ringpairs = num_ringpairs;
+
+               q_vector->rx.count = 0;
+               q_vector->tx.count = 0;
+               q_vector->rx.ring = NULL;
+               q_vector->tx.ring = NULL;
+
+               while (num_ringpairs--) {
+                       map_vector_to_qp(vsi, v_start, qp_idx);
+                       qp_idx++;
+                       qp_remaining--;
                }
        }
 }
@@ -3179,16 +3175,17 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
 static void i40e_free_q_vector(struct i40e_vsi *vsi, int v_idx)
 {
        struct i40e_q_vector *q_vector = vsi->q_vectors[v_idx];
-       int r_idx;
+       struct i40e_ring *ring;
 
        if (!q_vector)
                return;
 
        /* disassociate q_vector from rings */
-       for (r_idx = 0; r_idx < q_vector->tx.count; r_idx++)
-               q_vector->tx.ring[r_idx]->q_vector = NULL;
-       for (r_idx = 0; r_idx < q_vector->rx.count; r_idx++)
-               q_vector->rx.ring[r_idx]->q_vector = NULL;
+       i40e_for_each_ring(ring, q_vector->tx)
+               ring->q_vector = NULL;
+
+       i40e_for_each_ring(ring, q_vector->rx)
+               ring->q_vector = NULL;
 
        /* only VSI w/ an associated netdev is set up w/ NAPI */
        if (vsi->netdev)
@@ -5312,6 +5309,9 @@ static int i40e_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
                netif_napi_add(vsi->netdev, &q_vector->napi,
                               i40e_napi_poll, vsi->work_limit);
 
+       q_vector->rx.latency_range = I40E_LOW_LATENCY;
+       q_vector->tx.latency_range = I40E_LOW_LATENCY;
+
        /* tie q_vector and vsi together */
        vsi->q_vectors[v_idx] = q_vector;
 
index 3e73bc093737bc164b16eff99f0a064c3af6d18c..f153f3770346d7151f7de82e10d005964da1c5b1 100644 (file)
@@ -1100,27 +1100,28 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
        struct i40e_q_vector *q_vector =
                               container_of(napi, struct i40e_q_vector, napi);
        struct i40e_vsi *vsi = q_vector->vsi;
+       struct i40e_ring *ring;
        bool clean_complete = true;
        int budget_per_ring;
-       int i;
 
        if (test_bit(__I40E_DOWN, &vsi->state)) {
                napi_complete(napi);
                return 0;
        }
 
+       /* Since the actual Tx work is minimal, we can give the Tx a larger
+        * budget and be more aggressive about cleaning up the Tx descriptors.
+        */
+       i40e_for_each_ring(ring, q_vector->tx)
+               clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
+
        /* We attempt to distribute budget to each Rx queue fairly, but don't
         * allow the budget to go below 1 because that would exit polling early.
-        * Since the actual Tx work is minimal, we can give the Tx a larger
-        * budget and be more aggressive about cleaning up the Tx descriptors.
         */
        budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
-       for (i = 0; i < q_vector->num_ringpairs; i++) {
-               clean_complete &= i40e_clean_tx_irq(q_vector->tx.ring[i],
-                                                   vsi->work_limit);
-               clean_complete &= i40e_clean_rx_irq(q_vector->rx.ring[i],
-                                                   budget_per_ring);
-       }
+
+       i40e_for_each_ring(ring, q_vector->rx)
+               clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring);
 
        /* If work not completed, return budget and polling will return */
        if (!clean_complete)
index 7f3f7e3e4238b8a3d2a2833c0031f5f3b7588599..c2a6746a5ec9082dcd567a90607f23d4ecc0810d 100644 (file)
@@ -180,6 +180,7 @@ enum i40e_ring_state_t {
 
 /* struct that defines a descriptor ring, associated with a VSI */
 struct i40e_ring {
+       struct i40e_ring *next;         /* pointer to next ring in q_vector */
        void *desc;                     /* Descriptor ring memory */
        struct device *dev;             /* Used for DMA mapping */
        struct net_device *netdev;      /* netdev ring maps to */
@@ -236,9 +237,8 @@ enum i40e_latency_range {
 };
 
 struct i40e_ring_container {
-#define I40E_MAX_RINGPAIR_PER_VECTOR 8
        /* array of pointers to rings */
-       struct i40e_ring *ring[I40E_MAX_RINGPAIR_PER_VECTOR];
+       struct i40e_ring *ring;
        unsigned int total_bytes;       /* total bytes processed this int */
        unsigned int total_packets;     /* total packets processed this int */
        u16 count;
@@ -246,6 +246,10 @@ struct i40e_ring_container {
        u16 itr;
 };
 
+/* iterator for handling rings in ring container */
+#define i40e_for_each_ring(pos, head) \
+       for (pos = (head).ring; pos != NULL; pos = pos->next)
+
 void i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
 netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void i40e_clean_tx_ring(struct i40e_ring *tx_ring);