Commit 50ba9d7e authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2024-03-26 (i40e)

This series contains updates to i40e driver only.

Ivan Vecera resolves an issue where descriptors could be missed when
exiting busy poll.

Aleksandr corrects counting of MAC filters to only include new or active
filters and resolves possible use of incorrect/stale 'vf' variable.

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  i40e: fix vf may be used uninitialized in this function warning
  i40e: fix i40e_count_filters() to count only active/new filters
  i40e: Enforce software interrupt during busy-poll exit
====================

Link: https://lore.kernel.org/r/20240326162358.1224145-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 62fc3357 f37c4eac
......@@ -955,6 +955,7 @@ struct i40e_q_vector {
struct rcu_head rcu; /* to avoid race with update stats on free */
char name[I40E_INT_NAME_STR_LEN];
bool arm_wb_state;
bool in_busy_poll;
int irq_num; /* IRQ assigned to this q_vector */
} ____cacheline_internodealigned_in_smp;
......
......@@ -1253,8 +1253,11 @@ int i40e_count_filters(struct i40e_vsi *vsi)
int bkt;
int cnt = 0;
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_NEW ||
f->state == I40E_FILTER_ACTIVE)
++cnt;
}
return cnt;
}
......@@ -3911,6 +3914,12 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
q_vector->tx.target_itr >> 1);
q_vector->tx.current_itr = q_vector->tx.target_itr;
/* Set ITR for software interrupts triggered after exiting
* busy-loop polling.
*/
wr32(hw, I40E_PFINT_ITRN(I40E_SW_ITR, vector - 1),
I40E_ITR_20K);
wr32(hw, I40E_PFINT_RATEN(vector - 1),
i40e_intrl_usec_to_reg(vsi->int_rate_limit));
......
......@@ -333,8 +333,11 @@
#define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3
#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)
#define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5
#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT)
#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24
#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT)
#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25
#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT)
#define I40E_PFINT_ICR0 0x00038780 /* Reset: CORER */
#define I40E_PFINT_ICR0_INTEVENT_SHIFT 0
#define I40E_PFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_INTEVENT_SHIFT)
......
......@@ -2630,7 +2630,22 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
return failure ? budget : (int)total_rx_packets;
}
static inline u32 i40e_buildreg_itr(const int type, u16 itr)
/**
* i40e_buildreg_itr - build a value for writing to I40E_PFINT_DYN_CTLN register
* @itr_idx: interrupt throttling index
* @interval: interrupt throttling interval value in usecs
* @force_swint: force software interrupt
*
* The function builds a value for I40E_PFINT_DYN_CTLN register that
* is used to update interrupt throttling interval for specified ITR index
* and optionally enforces a software interrupt. If the @itr_idx is equal
* to I40E_ITR_NONE then no interval change is applied and only @force_swint
* parameter is taken into account. If the interval change and enforced
* software interrupt are not requested then the built value just enables
* appropriate vector interrupt.
**/
static u32 i40e_buildreg_itr(enum i40e_dyn_idx itr_idx, u16 interval,
bool force_swint)
{
u32 val;
......@@ -2644,23 +2659,33 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr)
* an event in the PBA anyway so we need to rely on the automask
* to hold pending events for us until the interrupt is re-enabled
*
* The itr value is reported in microseconds, and the register
* value is recorded in 2 microsecond units. For this reason we
* only need to shift by the interval shift - 1 instead of the
* full value.
* We have to shift the given value as it is reported in microseconds
* and the register value is recorded in 2 microsecond units.
*/
itr &= I40E_ITR_MASK;
interval >>= 1;
/* 1. Enable vector interrupt
* 2. Update the interval for the specified ITR index
* (I40E_ITR_NONE in the register is used to indicate that
* no interval update is requested)
*/
val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
(type << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
(itr << (I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT - 1));
FIELD_PREP(I40E_PFINT_DYN_CTLN_ITR_INDX_MASK, itr_idx) |
FIELD_PREP(I40E_PFINT_DYN_CTLN_INTERVAL_MASK, interval);
/* 3. Enforce software interrupt trigger if requested
* (These software interrupts rate is limited by ITR2 that is
* set to 20K interrupts per second)
*/
if (force_swint)
val |= I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK |
FIELD_PREP(I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK,
I40E_SW_ITR);
return val;
}
/* a small macro to shorten up some long lines */
#define INTREG I40E_PFINT_DYN_CTLN
/* The act of updating the ITR will cause it to immediately trigger. In order
* to prevent this from throwing off adaptive update statistics we defer the
* update so that it can only happen so often. So after either Tx or Rx are
......@@ -2679,8 +2704,10 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr)
static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
struct i40e_q_vector *q_vector)
{
enum i40e_dyn_idx itr_idx = I40E_ITR_NONE;
struct i40e_hw *hw = &vsi->back->hw;
u32 intval;
u16 interval = 0;
u32 itr_val;
/* If we don't have MSIX, then we only need to re-enable icr0 */
if (!test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) {
......@@ -2702,8 +2729,8 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
*/
if (q_vector->rx.target_itr < q_vector->rx.current_itr) {
/* Rx ITR needs to be reduced, this is highest priority */
intval = i40e_buildreg_itr(I40E_RX_ITR,
q_vector->rx.target_itr);
itr_idx = I40E_RX_ITR;
interval = q_vector->rx.target_itr;
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
} else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) ||
......@@ -2712,25 +2739,36 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
/* Tx ITR needs to be reduced, this is second priority
* Tx ITR needs to be increased more than Rx, fourth priority
*/
intval = i40e_buildreg_itr(I40E_TX_ITR,
q_vector->tx.target_itr);
itr_idx = I40E_TX_ITR;
interval = q_vector->tx.target_itr;
q_vector->tx.current_itr = q_vector->tx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
} else if (q_vector->rx.current_itr != q_vector->rx.target_itr) {
/* Rx ITR needs to be increased, third priority */
intval = i40e_buildreg_itr(I40E_RX_ITR,
q_vector->rx.target_itr);
itr_idx = I40E_RX_ITR;
interval = q_vector->rx.target_itr;
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
} else {
/* No ITR update, lowest priority */
intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
if (q_vector->itr_countdown)
q_vector->itr_countdown--;
}
if (!test_bit(__I40E_VSI_DOWN, vsi->state))
wr32(hw, INTREG(q_vector->reg_idx), intval);
/* Do not update interrupt control register if VSI is down */
if (test_bit(__I40E_VSI_DOWN, vsi->state))
return;
/* Update ITR interval if necessary and enforce software interrupt
* if we are exiting busy poll.
*/
if (q_vector->in_busy_poll) {
itr_val = i40e_buildreg_itr(itr_idx, interval, true);
q_vector->in_busy_poll = false;
} else {
itr_val = i40e_buildreg_itr(itr_idx, interval, false);
}
wr32(hw, I40E_PFINT_DYN_CTLN(q_vector->reg_idx), itr_val);
}
/**
......@@ -2845,6 +2883,8 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
*/
if (likely(napi_complete_done(napi, work_done)))
i40e_update_enable_itr(vsi, q_vector);
else
q_vector->in_busy_poll = true;
return min(work_done, budget - 1);
}
......
......@@ -68,6 +68,7 @@ enum i40e_dyn_idx {
/* these are indexes into ITRN registers */
#define I40E_RX_ITR I40E_IDX_ITR0
#define I40E_TX_ITR I40E_IDX_ITR1
#define I40E_SW_ITR I40E_IDX_ITR2
/* Supported RSS offloads */
#define I40E_DEFAULT_RSS_HENA ( \
......
......@@ -1624,8 +1624,8 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
{
struct i40e_hw *hw = &pf->hw;
struct i40e_vf *vf;
int i, v;
u32 reg;
int i;
/* If we don't have any VFs, then there is nothing to reset */
if (!pf->num_alloc_vfs)
......@@ -1636,11 +1636,10 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
return false;
/* Begin reset on all VFs at once */
for (v = 0; v < pf->num_alloc_vfs; v++) {
vf = &pf->vf[v];
for (vf = &pf->vf[0]; vf < &pf->vf[pf->num_alloc_vfs]; ++vf) {
/* If VF is being reset no need to trigger reset again */
if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
i40e_trigger_vf_reset(&pf->vf[v], flr);
i40e_trigger_vf_reset(vf, flr);
}
/* HW requires some time to make sure it can flush the FIFO for a VF
......@@ -1649,14 +1648,13 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
* the VFs using a simple iterator that increments once that VF has
* finished resetting.
*/
for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) {
for (i = 0, vf = &pf->vf[0]; i < 10 && vf < &pf->vf[pf->num_alloc_vfs]; ++i) {
usleep_range(10000, 20000);
/* Check each VF in sequence, beginning with the VF to fail
* the previous check.
*/
while (v < pf->num_alloc_vfs) {
vf = &pf->vf[v];
while (vf < &pf->vf[pf->num_alloc_vfs]) {
if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) {
reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK))
......@@ -1666,7 +1664,7 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
/* If the current VF has finished resetting, move on
* to the next VF in sequence.
*/
v++;
++vf;
}
}
......@@ -1676,39 +1674,39 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
/* Display a warning if at least one VF didn't manage to reset in
* time, but continue on with the operation.
*/
if (v < pf->num_alloc_vfs)
if (vf < &pf->vf[pf->num_alloc_vfs])
dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
pf->vf[v].vf_id);
vf->vf_id);
usleep_range(10000, 20000);
/* Begin disabling all the rings associated with VFs, but do not wait
* between each VF.
*/
for (v = 0; v < pf->num_alloc_vfs; v++) {
for (vf = &pf->vf[0]; vf < &pf->vf[pf->num_alloc_vfs]; ++vf) {
/* On initial reset, we don't have any queues to disable */
if (pf->vf[v].lan_vsi_idx == 0)
if (vf->lan_vsi_idx == 0)
continue;
/* If VF is reset in another thread just continue */
if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
continue;
i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[v].lan_vsi_idx]);
i40e_vsi_stop_rings_no_wait(pf->vsi[vf->lan_vsi_idx]);
}
/* Now that we've notified HW to disable all of the VF rings, wait
* until they finish.
*/
for (v = 0; v < pf->num_alloc_vfs; v++) {
for (vf = &pf->vf[0]; vf < &pf->vf[pf->num_alloc_vfs]; ++vf) {
/* On initial reset, we don't have any queues to disable */
if (pf->vf[v].lan_vsi_idx == 0)
if (vf->lan_vsi_idx == 0)
continue;
/* If VF is reset in another thread just continue */
if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
continue;
i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[v].lan_vsi_idx]);
i40e_vsi_wait_queues_disabled(pf->vsi[vf->lan_vsi_idx]);
}
/* Hw may need up to 50ms to finish disabling the RX queues. We
......@@ -1717,12 +1715,12 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
mdelay(50);
/* Finish the reset on each VF */
for (v = 0; v < pf->num_alloc_vfs; v++) {
for (vf = &pf->vf[0]; vf < &pf->vf[pf->num_alloc_vfs]; ++vf) {
/* If VF is reset in another thread just continue */
if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
continue;
i40e_cleanup_reset_vf(&pf->vf[v]);
i40e_cleanup_reset_vf(vf);
}
i40e_flush(hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment