|
@@ -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
|