Skip to content

Commit

Permalink
i40e/i40evf: Split container ITR into current_itr and target_itr
Browse files Browse the repository at this point in the history
This patch is mostly prep-work for replacing the current approach to
programming the dynamic aka adaptive ITR. Specifically here what we are
doing is splitting the Tx and Rx ITR each into two separate values.

The first value current_itr represents the current value of the register.

The second value target_itr represents the desired value of the register.

The general plan by doing this is to allow for deferring the update of the
ITR value under certain circumstances. For now we will work with what we
have, but in the future I hope to change the behavior so that we always
only update one ITR at a time using some simple logic to determine which
ITR requires an update.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Alexander Duyck authored and Jeff Kirsher committed Feb 12, 2018
1 parent d4942d5 commit 556fdfd
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 86 deletions.
13 changes: 7 additions & 6 deletions drivers/net/ethernet/intel/i40e/i40e_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2329,14 +2329,15 @@ static void i40e_set_itr_per_queue(struct i40e_vsi *vsi,
tx_ring->itr_setting &= ~I40E_ITR_DYNAMIC;

q_vector = rx_ring->q_vector;
q_vector->rx.itr = ITR_TO_REG(rx_ring->itr_setting);
wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, q_vector->reg_idx),
q_vector->rx.itr);
q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);

q_vector = tx_ring->q_vector;
q_vector->tx.itr = ITR_TO_REG(tx_ring->itr_setting);
wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, q_vector->reg_idx),
q_vector->tx.itr);
q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);

/* The interrupt handler itself will take care of programming
* the Tx and Rx ITR values based on the values we have entered
* into the q_vector, no need to write the values now.
*/

wr32(hw, I40E_PFINT_RATEN(q_vector->reg_idx), intrl);
i40e_flush(hw);
Expand Down
22 changes: 14 additions & 8 deletions drivers/net/ethernet/intel/i40e/i40e_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3450,14 +3450,18 @@ 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_rings[i]->itr_setting);
q_vector->rx.target_itr =
ITR_TO_REG(vsi->rx_rings[i]->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_rings[i]->itr_setting);
q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->tx.target_itr =
ITR_TO_REG(vsi->tx_rings[i]->itr_setting);
q_vector->tx.latency_range = I40E_LOW_LATENCY;
wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
q_vector->tx.itr);
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
wr32(hw, I40E_PFINT_RATEN(vector - 1),
i40e_intrl_usec_to_reg(vsi->int_rate_limit));

Expand Down Expand Up @@ -3559,12 +3563,14 @@ 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_rings[0]->itr_setting);
q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[0]->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_rings[0]->itr_setting);
wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[0]->itr_setting);
q_vector->tx.latency_range = I40E_LOW_LATENCY;
wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;

i40e_enable_misc_int_causes(pf);

Expand Down
68 changes: 39 additions & 29 deletions drivers/net/ethernet/intel/i40e/i40e_txrx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,17 +1012,16 @@ void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
{
enum i40e_latency_range new_latency_range = rc->latency_range;
u32 new_itr = rc->itr;
int bytes_per_usec;
unsigned int usecs, estimated_usecs;

if (!rc->ring || !ITR_IS_DYNAMIC(rc->ring->itr_setting))
return false;

if (rc->total_packets == 0 || !rc->itr)
if (!rc->total_packets || !rc->current_itr)
return false;

usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
usecs = (rc->current_itr << 1) * ITR_COUNTDOWN_START;
bytes_per_usec = rc->total_bytes / usecs;

/* The calculations in this algorithm depend on interrupts actually
Expand Down Expand Up @@ -1070,13 +1069,13 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)

switch (new_latency_range) {
case I40E_LOWEST_LATENCY:
new_itr = I40E_ITR_50K;
rc->target_itr = I40E_ITR_50K;
break;
case I40E_LOW_LATENCY:
new_itr = I40E_ITR_20K;
rc->target_itr = I40E_ITR_20K;
break;
case I40E_BULK_LATENCY:
new_itr = I40E_ITR_18K;
rc->target_itr = I40E_ITR_18K;
break;
default:
break;
Expand All @@ -1086,11 +1085,7 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
rc->total_packets = 0;
rc->last_itr_update = jiffies;

if (new_itr != rc->itr) {
rc->itr = new_itr;
return true;
}
return false;
return rc->target_itr != rc->current_itr;
}

/**
Expand Down Expand Up @@ -2319,16 +2314,14 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
{
struct i40e_hw *hw = &vsi->back->hw;
bool rx = false, tx = false;
u32 txval;
u32 intval;

/* If we don't have MSIX, then we only need to re-enable icr0 */
if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED)) {
i40e_irq_dynamic_enable_icr0(vsi->back);
return;
}

txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);

/* avoid dynamic calculation if in countdown mode */
if (q_vector->itr_countdown > 0)
goto enable_int;
Expand All @@ -2342,26 +2335,43 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
* use the same value for both ITR registers
* when in adaptive mode (Rx and/or Tx)
*/
u16 itr = max(q_vector->tx.itr, q_vector->rx.itr);
u32 rxval;

q_vector->tx.itr = q_vector->rx.itr = itr;

/* set the INTENA_MSK_MASK so that this first write
* won't actually enable the interrupt, instead just
* updating the ITR (it's bit 31 PF and VF)
*/
rxval = i40e_buildreg_itr(I40E_RX_ITR, itr) | BIT(31);
u16 itr = max(q_vector->tx.target_itr,
q_vector->rx.target_itr);

/* don't check _DOWN because interrupt isn't being enabled */
wr32(hw, INTREG(q_vector->reg_idx), rxval);

txval = i40e_buildreg_itr(I40E_TX_ITR, itr);
q_vector->tx.target_itr = itr;
q_vector->rx.target_itr = itr;
}

enable_int:
if (q_vector->rx.target_itr != q_vector->rx.current_itr) {
intval = i40e_buildreg_itr(I40E_RX_ITR,
q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;

if (q_vector->tx.target_itr != q_vector->tx.current_itr) {
/* set the INTENA_MSK_MASK so that this first write
* won't actually enable the interrupt, instead just
* updating the ITR (it's bit 31 PF and VF)
*
* don't check _DOWN because interrupt isn't being
* enabled
*/
wr32(hw, INTREG(q_vector->reg_idx),
intval | BIT(31));
/* now that Rx is done process Tx update */
goto update_tx;
}
} else if (q_vector->tx.target_itr != q_vector->tx.current_itr) {
update_tx:
intval = i40e_buildreg_itr(I40E_TX_ITR,
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
} else {
intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
}

if (!test_bit(__I40E_VSI_DOWN, vsi->state))
wr32(hw, INTREG(q_vector->reg_idx), txval);
wr32(hw, INTREG(q_vector->reg_idx), intval);

if (q_vector->itr_countdown)
q_vector->itr_countdown--;
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/i40e/i40e_txrx.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ struct i40e_ring_container {
unsigned long last_itr_update; /* jiffies of last ITR update */
u16 count;
enum i40e_latency_range latency_range;
u16 itr;
u16 target_itr; /* target ITR setting for ring(s) */
u16 current_itr; /* current ITR setting for ring(s) */
};

/* iterator for handling rings in ring container */
Expand Down
68 changes: 39 additions & 29 deletions drivers/net/ethernet/intel/i40evf/i40e_txrx.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,17 +409,16 @@ void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
{
enum i40e_latency_range new_latency_range = rc->latency_range;
u32 new_itr = rc->itr;
int bytes_per_usec;
unsigned int usecs, estimated_usecs;

if (!rc->ring || !ITR_IS_DYNAMIC(rc->ring->itr_setting))
return false;

if (rc->total_packets == 0 || !rc->itr)
if (!rc->total_packets || !rc->current_itr)
return false;

usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
usecs = (rc->current_itr << 1) * ITR_COUNTDOWN_START;
bytes_per_usec = rc->total_bytes / usecs;

/* The calculations in this algorithm depend on interrupts actually
Expand Down Expand Up @@ -467,13 +466,13 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)

switch (new_latency_range) {
case I40E_LOWEST_LATENCY:
new_itr = I40E_ITR_50K;
rc->target_itr = I40E_ITR_50K;
break;
case I40E_LOW_LATENCY:
new_itr = I40E_ITR_20K;
rc->target_itr = I40E_ITR_20K;
break;
case I40E_BULK_LATENCY:
new_itr = I40E_ITR_18K;
rc->target_itr = I40E_ITR_18K;
break;
default:
break;
Expand All @@ -483,11 +482,7 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
rc->total_packets = 0;
rc->last_itr_update = jiffies;

if (new_itr != rc->itr) {
rc->itr = new_itr;
return true;
}
return false;
return rc->target_itr != rc->current_itr;
}

/**
Expand Down Expand Up @@ -1502,9 +1497,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
{
struct i40e_hw *hw = &vsi->back->hw;
bool rx = false, tx = false;
u32 txval;

txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
u32 intval;

/* avoid dynamic calculation if in countdown mode */
if (q_vector->itr_countdown > 0)
Expand All @@ -1519,26 +1512,43 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
* use the same value for both ITR registers
* when in adaptive mode (Rx and/or Tx)
*/
u16 itr = max(q_vector->tx.itr, q_vector->rx.itr);
u32 rxval;

q_vector->tx.itr = q_vector->rx.itr = itr;

/* set the INTENA_MSK_MASK so that this first write
* won't actually enable the interrupt, instead just
* updating the ITR (it's bit 31 PF and VF)
*/
rxval = i40e_buildreg_itr(I40E_RX_ITR, itr) | BIT(31);
u16 itr = max(q_vector->tx.target_itr,
q_vector->rx.target_itr);

/* don't check _DOWN because interrupt isn't being enabled */
wr32(hw, INTREG(q_vector->reg_idx), rxval);

txval = i40e_buildreg_itr(I40E_TX_ITR, itr);
q_vector->tx.target_itr = itr;
q_vector->rx.target_itr = itr;
}

enable_int:
if (q_vector->rx.target_itr != q_vector->rx.current_itr) {
intval = i40e_buildreg_itr(I40E_RX_ITR,
q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;

if (q_vector->tx.target_itr != q_vector->tx.current_itr) {
/* set the INTENA_MSK_MASK so that this first write
* won't actually enable the interrupt, instead just
* updating the ITR (it's bit 31 PF and VF)
*
* don't check _DOWN because interrupt isn't being
* enabled
*/
wr32(hw, INTREG(q_vector->reg_idx),
intval | BIT(31));
/* now that Rx is done process Tx update */
goto update_tx;
}
} else if (q_vector->tx.target_itr != q_vector->tx.current_itr) {
update_tx:
intval = i40e_buildreg_itr(I40E_TX_ITR,
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
} else {
intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
}

if (!test_bit(__I40E_VSI_DOWN, vsi->state))
wr32(hw, INTREG(q_vector->reg_idx), txval);
wr32(hw, INTREG(q_vector->reg_idx), intval);

if (q_vector->itr_countdown)
q_vector->itr_countdown--;
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/i40evf/i40e_txrx.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,8 @@ struct i40e_ring_container {
unsigned long last_itr_update; /* jiffies of last ITR update */
u16 count;
enum i40e_latency_range latency_range;
u16 itr;
u16 target_itr; /* target ITR setting for ring(s) */
u16 current_itr; /* current ITR setting for ring(s) */
};

/* iterator for handling rings in ring container */
Expand Down
14 changes: 6 additions & 8 deletions drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter,
{
struct i40e_ring *rx_ring = &adapter->rx_rings[queue];
struct i40e_ring *tx_ring = &adapter->tx_rings[queue];
struct i40e_hw *hw = &adapter->hw;
struct i40e_q_vector *q_vector;

rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
Expand All @@ -529,16 +528,15 @@ static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter,
tx_ring->itr_setting ^= I40E_ITR_DYNAMIC;

q_vector = rx_ring->q_vector;
q_vector->rx.itr = ITR_TO_REG(rx_ring->itr_setting);
wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx),
q_vector->rx.itr);
q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);

q_vector = tx_ring->q_vector;
q_vector->tx.itr = ITR_TO_REG(tx_ring->itr_setting);
wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx),
q_vector->tx.itr);
q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);

i40e_flush(hw);
/* The interrupt handler itself will take care of programming
* the Tx and Rx ITR values based on the values we have entered
* into the q_vector, no need to write the values now.
*/
}

/**
Expand Down
10 changes: 6 additions & 4 deletions drivers/net/ethernet/intel/i40evf/i40evf_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,12 @@ i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
q_vector->rx.ring = rx_ring;
q_vector->rx.count++;
q_vector->rx.latency_range = I40E_LOW_LATENCY;
q_vector->rx.itr = ITR_TO_REG(rx_ring->itr_setting);
q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
q_vector->ring_mask |= BIT(r_idx);
q_vector->itr_countdown = ITR_COUNTDOWN_START;
wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx),
q_vector->rx.itr);
q_vector->rx.current_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
}

/**
Expand All @@ -380,11 +381,12 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
q_vector->tx.ring = tx_ring;
q_vector->tx.count++;
q_vector->tx.latency_range = I40E_LOW_LATENCY;
q_vector->tx.itr = ITR_TO_REG(tx_ring->itr_setting);
q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
q_vector->itr_countdown = ITR_COUNTDOWN_START;
q_vector->num_ringpairs++;
wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx),
q_vector->tx.itr);
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
}

/**
Expand Down

0 comments on commit 556fdfd

Please sign in to comment.