i40e: queue-specific settings for interrupt moderation
authorKan Liang <kan.liang@intel.com>
Fri, 19 Feb 2016 14:24:04 +0000 (09:24 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sat, 20 Feb 2016 03:54:10 +0000 (22:54 -0500)
For i40e driver, each vector has its own ITR register. However, there
are no concept of queue-specific settings in the driver proper. Only
global variable is used to store ITR values. That will cause problems
especially when resetting the vector. The specific ITR values could be
lost.
This patch move rx_itr_setting and tx_itr_setting to i40e_ring to store
specific ITR register for each queue.
i40e_get_coalesce and i40e_set_coalesce are also modified accordingly to
support queue-specific settings. To make it compatible with old ethtool,
if user doesn't specify the queue number, i40e_get_coalesce will return
queue 0's value. While i40e_set_coalesce will apply value to all queues.

Signed-off-by: Kan Liang <kan.liang@intel.com>
Acked-by: Shannon Nelson <shannon.nelson@intel.com>
Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
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 e99be9f696c39215ec13ee667db7ae1c394241ab..2f6210ae8ba0f3cf2621035b314d33ced74e0068 100644 (file)
@@ -521,13 +521,6 @@ struct i40e_vsi {
        struct i40e_ring **tx_rings;
 
        u16 work_limit;
-       /* high bit set means dynamic, use accessor routines to read/write.
-        * hardware only supports 2us resolution for the ITR registers.
-        * these values always store the USER setting, and must be converted
-        * before programming to a register.
-        */
-       u16 rx_itr_setting;
-       u16 tx_itr_setting;
        u16 int_rate_limit;  /* value in usecs */
 
        u16 rss_table_size; /* HW RSS table size */
index 2a44f2e25a26e9d4077136d8a5479f817d4e36e6..0c97733d253c45226b6dc702ecbd8357842fbf68 100644 (file)
@@ -302,6 +302,10 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         "    rx_rings[%i]: vsi = %p, q_vector = %p\n",
                         i, rx_ring->vsi,
                         rx_ring->q_vector);
+               dev_info(&pf->pdev->dev,
+                        "    rx_rings[%i]: rx_itr_setting = %d (%s)\n",
+                        i, rx_ring->rx_itr_setting,
+                        ITR_IS_DYNAMIC(rx_ring->rx_itr_setting) ? "dynamic" : "fixed");
        }
        for (i = 0; i < vsi->num_queue_pairs; i++) {
                struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[i]);
@@ -352,14 +356,15 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                dev_info(&pf->pdev->dev,
                         "    tx_rings[%i]: DCB tc = %d\n",
                         i, tx_ring->dcb_tc);
+               dev_info(&pf->pdev->dev,
+                        "    tx_rings[%i]: tx_itr_setting = %d (%s)\n",
+                        i, tx_ring->tx_itr_setting,
+                        ITR_IS_DYNAMIC(tx_ring->tx_itr_setting) ? "dynamic" : "fixed");
        }
        rcu_read_unlock();
        dev_info(&pf->pdev->dev,
-                "    work_limit = %d, rx_itr_setting = %d (%s), tx_itr_setting = %d (%s)\n",
-                vsi->work_limit, vsi->rx_itr_setting,
-                ITR_IS_DYNAMIC(vsi->rx_itr_setting) ? "dynamic" : "fixed",
-                vsi->tx_itr_setting,
-                ITR_IS_DYNAMIC(vsi->tx_itr_setting) ? "dynamic" : "fixed");
+                "    work_limit = %d\n",
+                vsi->work_limit);
        dev_info(&pf->pdev->dev,
                 "    max_frame = %d, rx_hdr_len = %d, rx_buf_len = %d dtype = %d\n",
                 vsi->max_frame, vsi->rx_hdr_len, vsi->rx_buf_len, vsi->dtype);
index a85bc94cdf87d01b0045e059325603dc16c4c556..a4705999cbc95fe67d3988febb496f8be3110437 100644 (file)
@@ -1879,8 +1879,9 @@ static int i40e_set_phys_id(struct net_device *netdev,
  * 125us (8000 interrupts per second) == ITR(62)
  */
 
-static int i40e_get_coalesce(struct net_device *netdev,
-                            struct ethtool_coalesce *ec)
+static int __i40e_get_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec,
+                              int queue)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
@@ -1888,14 +1889,24 @@ static int i40e_get_coalesce(struct net_device *netdev,
        ec->tx_max_coalesced_frames_irq = vsi->work_limit;
        ec->rx_max_coalesced_frames_irq = vsi->work_limit;
 
-       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
+       /* rx and tx usecs has per queue value. If user doesn't specify the queue,
+        * return queue 0's value to represent.
+        */
+       if (queue < 0) {
+               queue = 0;
+       } else if (queue >= vsi->num_queue_pairs) {
+               return -EINVAL;
+       }
+
+       if (ITR_IS_DYNAMIC(vsi->rx_rings[queue]->rx_itr_setting))
                ec->use_adaptive_rx_coalesce = 1;
 
-       if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
+       if (ITR_IS_DYNAMIC(vsi->tx_rings[queue]->tx_itr_setting))
                ec->use_adaptive_tx_coalesce = 1;
 
-       ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC;
-       ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+       ec->rx_coalesce_usecs = vsi->rx_rings[queue]->rx_itr_setting & ~I40E_ITR_DYNAMIC;
+       ec->tx_coalesce_usecs = vsi->tx_rings[queue]->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+
        /* we use the _usecs_high to store/set the interrupt rate limit
         * that the hardware supports, that almost but not quite
         * fits the original intent of the ethtool variable,
@@ -1908,15 +1919,57 @@ static int i40e_get_coalesce(struct net_device *netdev,
        return 0;
 }
 
-static int i40e_set_coalesce(struct net_device *netdev,
+static int i40e_get_coalesce(struct net_device *netdev,
                             struct ethtool_coalesce *ec)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       return __i40e_get_coalesce(netdev, ec, -1);
+}
+
+static void i40e_set_itr_per_queue(struct i40e_vsi *vsi,
+                                  struct ethtool_coalesce *ec,
+                                  int queue)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
        struct i40e_q_vector *q_vector;
+       u16 vector, intrl;
+
+       intrl = INTRL_USEC_TO_REG(vsi->int_rate_limit);
+
+       vsi->rx_rings[queue]->rx_itr_setting = ec->rx_coalesce_usecs;
+       vsi->tx_rings[queue]->tx_itr_setting = ec->tx_coalesce_usecs;
+
+       if (ec->use_adaptive_rx_coalesce)
+               vsi->rx_rings[queue]->rx_itr_setting |= I40E_ITR_DYNAMIC;
+       else
+               vsi->rx_rings[queue]->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
+
+       if (ec->use_adaptive_tx_coalesce)
+               vsi->tx_rings[queue]->tx_itr_setting |= I40E_ITR_DYNAMIC;
+       else
+               vsi->tx_rings[queue]->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
+
+       q_vector = vsi->rx_rings[queue]->q_vector;
+       q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[queue]->rx_itr_setting);
+       vector = vsi->base_vector + q_vector->v_idx;
+       wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), q_vector->rx.itr);
+
+       q_vector = vsi->tx_rings[queue]->q_vector;
+       q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[queue]->tx_itr_setting);
+       vector = vsi->base_vector + q_vector->v_idx;
+       wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), q_vector->tx.itr);
+
+       wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
+       i40e_flush(hw);
+}
+
+static int __i40e_set_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec,
+                              int queue)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
-       struct i40e_hw *hw = &pf->hw;
-       u16 vector;
        int i;
 
        if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
@@ -1933,59 +1986,49 @@ static int i40e_set_coalesce(struct net_device *netdev,
                return -EINVAL;
        }
 
-       vector = vsi->base_vector;
-       if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
-           (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
-               vsi->rx_itr_setting = ec->rx_coalesce_usecs;
-       } else if (ec->rx_coalesce_usecs == 0) {
-               vsi->rx_itr_setting = ec->rx_coalesce_usecs;
+       if (ec->rx_coalesce_usecs == 0) {
                if (ec->use_adaptive_rx_coalesce)
                        netif_info(pf, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
-       } else {
-               netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
-               return -EINVAL;
+       } else if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                  (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+                       netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
+                       return -EINVAL;
        }
 
        vsi->int_rate_limit = ec->rx_coalesce_usecs_high;
 
-       if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
-           (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
-               vsi->tx_itr_setting = ec->tx_coalesce_usecs;
-       } else if (ec->tx_coalesce_usecs == 0) {
-               vsi->tx_itr_setting = ec->tx_coalesce_usecs;
+       if (ec->tx_coalesce_usecs == 0) {
                if (ec->use_adaptive_tx_coalesce)
                        netif_info(pf, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
-       } else {
-               netif_info(pf, drv, netdev,
-                          "Invalid value, tx-usecs range is 0-8160\n");
-               return -EINVAL;
+       } else if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                  (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+                       netif_info(pf, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
+                       return -EINVAL;
        }
 
-       if (ec->use_adaptive_rx_coalesce)
-               vsi->rx_itr_setting |= I40E_ITR_DYNAMIC;
-       else
-               vsi->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
-
-       if (ec->use_adaptive_tx_coalesce)
-               vsi->tx_itr_setting |= I40E_ITR_DYNAMIC;
-       else
-               vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
-
-       for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
-               u16 intrl = INTRL_USEC_TO_REG(vsi->int_rate_limit);
-
-               q_vector = vsi->q_vectors[i];
-               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
-               wr32(hw, I40E_PFINT_ITRN(0, vector - 1), q_vector->rx.itr);
-               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
-               wr32(hw, I40E_PFINT_ITRN(1, vector - 1), q_vector->tx.itr);
-               wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
-               i40e_flush(hw);
+       /* rx and tx usecs has per queue value. If user doesn't specify the queue,
+        * apply to all queues.
+        */
+       if (queue < 0) {
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       i40e_set_itr_per_queue(vsi, ec, i);
+       } else if (queue < vsi->num_queue_pairs) {
+               i40e_set_itr_per_queue(vsi, ec, queue);
+       } else {
+               netif_info(pf, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
+                          vsi->num_queue_pairs - 1);
+               return -EINVAL;
        }
 
        return 0;
 }
 
+static int i40e_set_coalesce(struct net_device *netdev,
+                            struct ethtool_coalesce *ec)
+{
+       return __i40e_set_coalesce(netdev, ec, -1);
+}
+
 /**
  * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
  * @pf: pointer to the physical function struct
index 3c8d8c4491f80e1adc03adf69eadf995c63aa23b..70d9605a0d9e712f1bb89a38da053c8b07ee9a83 100644 (file)
@@ -3124,11 +3124,11 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
                struct i40e_q_vector *q_vector = vsi->q_vectors[i];
 
                q_vector->itr_countdown = ITR_COUNTDOWN_START;
-               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+               q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[i]->rx_itr_setting);
                q_vector->rx.latency_range = I40E_LOW_LATENCY;
                wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
                     q_vector->rx.itr);
-               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+               q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[i]->tx_itr_setting);
                q_vector->tx.latency_range = I40E_LOW_LATENCY;
                wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
                     q_vector->tx.itr);
@@ -3220,10 +3220,10 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
 
        /* set the ITR configuration */
        q_vector->itr_countdown = ITR_COUNTDOWN_START;
-       q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+       q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[0]->rx_itr_setting);
        q_vector->rx.latency_range = I40E_LOW_LATENCY;
        wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.itr);
-       q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+       q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[0]->tx_itr_setting);
        q_vector->tx.latency_range = I40E_LOW_LATENCY;
        wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
 
@@ -7322,8 +7322,6 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
        set_bit(__I40E_DOWN, &vsi->state);
        vsi->flags = 0;
        vsi->idx = vsi_idx;
-       vsi->rx_itr_setting = pf->rx_itr_default;
-       vsi->tx_itr_setting = pf->tx_itr_default;
        vsi->int_rate_limit = 0;
        vsi->rss_table_size = (vsi->type == I40E_VSI_MAIN) ?
                                pf->rss_table_size : 64;
@@ -7490,6 +7488,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                tx_ring->dcb_tc = 0;
                if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE)
                        tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
+               tx_ring->tx_itr_setting = pf->tx_itr_default;
                vsi->tx_rings[i] = tx_ring;
 
                rx_ring = &tx_ring[1];
@@ -7506,6 +7505,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                        set_ring_16byte_desc_enabled(rx_ring);
                else
                        clear_ring_16byte_desc_enabled(rx_ring);
+               rx_ring->rx_itr_setting = pf->rx_itr_default;
                vsi->rx_rings[i] = rx_ring;
        }
 
index cb52f39d514a4edc9173709d4ef672a5c9bb6cf6..084d0ab316b796b5d5af2ab87b7a5bee193b5a84 100644 (file)
@@ -1882,6 +1882,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
        bool rx = false, tx = false;
        u32 rxval, txval;
        int vector;
+       int idx = q_vector->v_idx;
 
        vector = (q_vector->v_idx + vsi->base_vector);
 
@@ -1891,17 +1892,17 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
        rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
 
        if (q_vector->itr_countdown > 0 ||
-           (!ITR_IS_DYNAMIC(vsi->rx_itr_setting) &&
-            !ITR_IS_DYNAMIC(vsi->tx_itr_setting))) {
+           (!ITR_IS_DYNAMIC(vsi->rx_rings[idx]->rx_itr_setting) &&
+            !ITR_IS_DYNAMIC(vsi->tx_rings[idx]->tx_itr_setting))) {
                goto enable_int;
        }
 
-       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) {
+       if (ITR_IS_DYNAMIC(vsi->rx_rings[idx]->rx_itr_setting)) {
                rx = i40e_set_new_dynamic_itr(&q_vector->rx);
                rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
        }
 
-       if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) {
+       if (ITR_IS_DYNAMIC(vsi->tx_rings[idx]->tx_itr_setting)) {
                tx = i40e_set_new_dynamic_itr(&q_vector->tx);
                txval = i40e_buildreg_itr(I40E_TX_ITR, q_vector->tx.itr);
        }
index 56009709528a10a9d22183971ad68fcf7ae5344e..cdd5dc00aec519972dd3af6166666a0d3c65766f 100644 (file)
@@ -248,6 +248,14 @@ struct i40e_ring {
        u8 dcb_tc;                      /* Traffic class of ring */
        u8 __iomem *tail;
 
+       /* high bit set means dynamic, use accessor routines to read/write.
+        * hardware only supports 2us resolution for the ITR registers.
+        * these values always store the USER setting, and must be converted
+        * before programming to a register.
+        */
+       u16 rx_itr_setting;
+       u16 tx_itr_setting;
+
        u16 count;                      /* Number of descriptors */
        u16 reg_idx;                    /* HW register index of the ring */
        u16 rx_hdr_len;