|
@@ -296,92 +296,206 @@ static int i40evf_set_ringparam(struct net_device *netdev,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * i40evf_get_coalesce - Get interrupt coalescing settings
|
|
|
- * @netdev: network interface device structure
|
|
|
- * @ec: ethtool coalesce structure
|
|
|
+ * __i40evf_get_coalesce - get per-queue coalesce settings
|
|
|
+ * @netdev: the netdev to check
|
|
|
+ * @ec: ethtool coalesce data structure
|
|
|
+ * @queue: which queue to pick
|
|
|
*
|
|
|
- * Returns current coalescing settings. This is referred to elsewhere in the
|
|
|
- * driver as Interrupt Throttle Rate, as this is how the hardware describes
|
|
|
- * this functionality.
|
|
|
+ * Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs
|
|
|
+ * are per queue. If queue is <0 then we default to queue 0 as the
|
|
|
+ * representative value.
|
|
|
**/
|
|
|
-static int i40evf_get_coalesce(struct net_device *netdev,
|
|
|
- struct ethtool_coalesce *ec)
|
|
|
+static int __i40evf_get_coalesce(struct net_device *netdev,
|
|
|
+ struct ethtool_coalesce *ec,
|
|
|
+ int queue)
|
|
|
{
|
|
|
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
struct i40e_vsi *vsi = &adapter->vsi;
|
|
|
+ struct i40e_ring *rx_ring, *tx_ring;
|
|
|
|
|
|
ec->tx_max_coalesced_frames = vsi->work_limit;
|
|
|
ec->rx_max_coalesced_frames = vsi->work_limit;
|
|
|
|
|
|
- if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
|
|
|
+ /* Rx and Tx usecs 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 >= adapter->num_active_queues)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ rx_ring = &adapter->rx_rings[queue];
|
|
|
+ tx_ring = &adapter->tx_rings[queue];
|
|
|
+
|
|
|
+ if (ITR_IS_DYNAMIC(rx_ring->rx_itr_setting))
|
|
|
ec->use_adaptive_rx_coalesce = 1;
|
|
|
|
|
|
- if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
|
|
|
+ if (ITR_IS_DYNAMIC(tx_ring->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 = rx_ring->rx_itr_setting & ~I40E_ITR_DYNAMIC;
|
|
|
+ ec->tx_coalesce_usecs = tx_ring->tx_itr_setting & ~I40E_ITR_DYNAMIC;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * i40evf_set_coalesce - Set interrupt coalescing settings
|
|
|
+ * i40evf_get_coalesce - Get interrupt coalescing settings
|
|
|
* @netdev: network interface device structure
|
|
|
* @ec: ethtool coalesce structure
|
|
|
*
|
|
|
- * Change current coalescing settings.
|
|
|
+ * Returns current coalescing settings. This is referred to elsewhere in the
|
|
|
+ * driver as Interrupt Throttle Rate, as this is how the hardware describes
|
|
|
+ * this functionality. Note that if per-queue settings have been modified this
|
|
|
+ * only represents the settings of queue 0.
|
|
|
**/
|
|
|
-static int i40evf_set_coalesce(struct net_device *netdev,
|
|
|
+static int i40evf_get_coalesce(struct net_device *netdev,
|
|
|
struct ethtool_coalesce *ec)
|
|
|
{
|
|
|
- struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
- struct i40e_hw *hw = &adapter->hw;
|
|
|
+ return __i40evf_get_coalesce(netdev, ec, -1);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * i40evf_get_per_queue_coalesce - get coalesce values for specific queue
|
|
|
+ * @netdev: netdev to read
|
|
|
+ * @ec: coalesce settings from ethtool
|
|
|
+ * @queue: the queue to read
|
|
|
+ *
|
|
|
+ * Read specific queue's coalesce settings.
|
|
|
+ **/
|
|
|
+static int i40evf_get_per_queue_coalesce(struct net_device *netdev,
|
|
|
+ u32 queue,
|
|
|
+ struct ethtool_coalesce *ec)
|
|
|
+{
|
|
|
+ return __i40evf_get_coalesce(netdev, ec, queue);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * i40evf_set_itr_per_queue - set ITR values for specific queue
|
|
|
+ * @vsi: the VSI to set values for
|
|
|
+ * @ec: coalesce settings from ethtool
|
|
|
+ * @queue: the queue to modify
|
|
|
+ *
|
|
|
+ * Change the ITR settings for a specific queue.
|
|
|
+ **/
|
|
|
+static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter,
|
|
|
+ struct ethtool_coalesce *ec,
|
|
|
+ int queue)
|
|
|
+{
|
|
|
struct i40e_vsi *vsi = &adapter->vsi;
|
|
|
+ struct i40e_hw *hw = &adapter->hw;
|
|
|
struct i40e_q_vector *q_vector;
|
|
|
+ u16 vector;
|
|
|
+
|
|
|
+ adapter->rx_rings[queue].rx_itr_setting = ec->rx_coalesce_usecs;
|
|
|
+ adapter->tx_rings[queue].tx_itr_setting = ec->tx_coalesce_usecs;
|
|
|
+
|
|
|
+ if (ec->use_adaptive_rx_coalesce)
|
|
|
+ adapter->rx_rings[queue].rx_itr_setting |= I40E_ITR_DYNAMIC;
|
|
|
+ else
|
|
|
+ adapter->rx_rings[queue].rx_itr_setting &= ~I40E_ITR_DYNAMIC;
|
|
|
+
|
|
|
+ if (ec->use_adaptive_tx_coalesce)
|
|
|
+ adapter->tx_rings[queue].tx_itr_setting |= I40E_ITR_DYNAMIC;
|
|
|
+ else
|
|
|
+ adapter->tx_rings[queue].tx_itr_setting &= ~I40E_ITR_DYNAMIC;
|
|
|
+
|
|
|
+ q_vector = adapter->rx_rings[queue].q_vector;
|
|
|
+ q_vector->rx.itr = ITR_TO_REG(adapter->rx_rings[queue].rx_itr_setting);
|
|
|
+ vector = vsi->base_vector + q_vector->v_idx;
|
|
|
+ wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, vector - 1), q_vector->rx.itr);
|
|
|
+
|
|
|
+ q_vector = adapter->tx_rings[queue].q_vector;
|
|
|
+ q_vector->tx.itr = ITR_TO_REG(adapter->tx_rings[queue].tx_itr_setting);
|
|
|
+ vector = vsi->base_vector + q_vector->v_idx;
|
|
|
+ wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, vector - 1), q_vector->tx.itr);
|
|
|
+
|
|
|
+ i40e_flush(hw);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * __i40evf_set_coalesce - set coalesce settings for particular queue
|
|
|
+ * @netdev: the netdev to change
|
|
|
+ * @ec: ethtool coalesce settings
|
|
|
+ * @queue: the queue to change
|
|
|
+ *
|
|
|
+ * Sets the coalesce settings for a particular queue.
|
|
|
+ **/
|
|
|
+static int __i40evf_set_coalesce(struct net_device *netdev,
|
|
|
+ struct ethtool_coalesce *ec,
|
|
|
+ int queue)
|
|
|
+{
|
|
|
+ struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
+ struct i40e_vsi *vsi = &adapter->vsi;
|
|
|
int i;
|
|
|
|
|
|
if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
|
|
|
vsi->work_limit = ec->tx_max_coalesced_frames_irq;
|
|
|
|
|
|
- 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) {
|
|
|
+ if (ec->use_adaptive_rx_coalesce)
|
|
|
+ netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
|
|
|
+ } else if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
|
|
|
+ (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
|
|
|
+ netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- 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->use_adaptive_tx_coalesce)
|
|
|
- vsi->tx_itr_setting = (I40E_ITR_DYNAMIC |
|
|
|
- ITR_REG_TO_USEC(I40E_ITR_RX_DEF));
|
|
|
else
|
|
|
+ if (ec->tx_coalesce_usecs == 0) {
|
|
|
+ if (ec->use_adaptive_tx_coalesce)
|
|
|
+ netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
|
|
|
+ } else if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
|
|
|
+ (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
|
|
|
+ netif_info(adapter, 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 < adapter->num_msix_vectors - NONQ_VECS; i++) {
|
|
|
- q_vector = &adapter->q_vectors[i];
|
|
|
- q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
|
|
|
- wr32(hw, I40E_VFINT_ITRN1(0, i), q_vector->rx.itr);
|
|
|
- q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
|
|
|
- wr32(hw, I40E_VFINT_ITRN1(1, i), q_vector->tx.itr);
|
|
|
- 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 < adapter->num_active_queues; i++)
|
|
|
+ i40evf_set_itr_per_queue(adapter, ec, i);
|
|
|
+ } else if (queue < adapter->num_active_queues) {
|
|
|
+ i40evf_set_itr_per_queue(adapter, ec, queue);
|
|
|
+ } else {
|
|
|
+ netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
|
|
|
+ adapter->num_active_queues - 1);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40evf_set_coalesce - Set interrupt coalescing settings
|
|
|
+ * @netdev: network interface device structure
|
|
|
+ * @ec: ethtool coalesce structure
|
|
|
+ *
|
|
|
+ * Change current coalescing settings for every queue.
|
|
|
+ **/
|
|
|
+static int i40evf_set_coalesce(struct net_device *netdev,
|
|
|
+ struct ethtool_coalesce *ec)
|
|
|
+{
|
|
|
+ return __i40evf_set_coalesce(netdev, ec, -1);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * i40evf_set_per_queue_coalesce - set specific queue's coalesce settings
|
|
|
+ * @netdev: the netdev to change
|
|
|
+ * @ec: ethtool's coalesce settings
|
|
|
+ * @queue: the queue to modify
|
|
|
+ *
|
|
|
+ * Modifies a specific queue's coalesce settings.
|
|
|
+ */
|
|
|
+static int i40evf_set_per_queue_coalesce(struct net_device *netdev,
|
|
|
+ u32 queue,
|
|
|
+ struct ethtool_coalesce *ec)
|
|
|
+{
|
|
|
+ return __i40evf_set_coalesce(netdev, ec, queue);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* i40evf_get_rxnfc - command to get RX flow classification rules
|
|
|
* @netdev: network interface device structure
|
|
@@ -533,6 +647,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = {
|
|
|
.set_msglevel = i40evf_set_msglevel,
|
|
|
.get_coalesce = i40evf_get_coalesce,
|
|
|
.set_coalesce = i40evf_set_coalesce,
|
|
|
+ .get_per_queue_coalesce = i40evf_get_per_queue_coalesce,
|
|
|
+ .set_per_queue_coalesce = i40evf_set_per_queue_coalesce,
|
|
|
.get_rxnfc = i40evf_get_rxnfc,
|
|
|
.get_rxfh_indir_size = i40evf_get_rxfh_indir_size,
|
|
|
.get_rxfh = i40evf_get_rxfh,
|