mirror of https://gitee.com/openkylin/linux.git
i40e: queue-specific settings for interrupt moderation
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>
This commit is contained in:
parent
f38d138a7d
commit
a75e8005d5
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
struct i40e_q_vector *q_vector;
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
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;
|
||||
u16 vector;
|
||||
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;
|
||||
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 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;
|
||||
}
|
||||
|
||||
/* 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 value, tx-usecs range is 0-8160\n");
|
||||
netif_info(pf, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
|
||||
vsi->num_queue_pairs - 1);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue