Skip to content

Commit 2980cbd

Browse files
sylwesterdziedziuchkuba-moo
authored andcommitted
i40e: Fix removing driver while bare-metal VFs pass traffic
Prevent VFs from resetting when PF driver is being unloaded: - introduce new pf state: __I40E_VF_RESETS_DISABLED; - check if pf state has __I40E_VF_RESETS_DISABLED state set, if so, disable any further VFLR event notifications; - when i40e_remove (rmmod i40e) is called, disable any resets on the VFs; Previously if there were bare-metal VFs passing traffic and PF driver was removed, there was a possibility of VFs triggering a Tx timeout right before iavf_remove. This was causing iavf_close to not be called because there is a check in the beginning of iavf_remove that bails out early if adapter->state < IAVF_DOWN_PENDING. This makes it so some resources do not get cleaned up. Fixes: 6a9ddb3 ("i40e: disable IOV before freeing resources") Signed-off-by: Slawomir Laba <[email protected]> Signed-off-by: Brett Creeley <[email protected]> Signed-off-by: Sylwester Dziedziuch <[email protected]> Tested-by: Konrad Jankowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 3fe356d commit 2980cbd

File tree

3 files changed

+31
-18
lines changed

3 files changed

+31
-18
lines changed

drivers/net/ethernet/intel/i40e/i40e.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ enum i40e_state_t {
140140
__I40E_CLIENT_RESET,
141141
__I40E_VIRTCHNL_OP_PENDING,
142142
__I40E_RECOVERY_MODE,
143+
__I40E_VF_RESETS_DISABLED, /* disable resets during i40e_remove */
143144
/* This must be last as it determines the size of the BITMAP */
144145
__I40E_STATE_SIZE__,
145146
};

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,8 +4010,16 @@ static irqreturn_t i40e_intr(int irq, void *data)
40104010
}
40114011

40124012
if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
4013-
ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
4014-
set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
4013+
/* disable any further VFLR event notifications */
4014+
if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) {
4015+
u32 reg = rd32(hw, I40E_PFINT_ICR0_ENA);
4016+
4017+
reg &= ~I40E_PFINT_ICR0_VFLR_MASK;
4018+
wr32(hw, I40E_PFINT_ICR0_ENA, reg);
4019+
} else {
4020+
ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
4021+
set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
4022+
}
40154023
}
40164024

40174025
if (icr0 & I40E_PFINT_ICR0_GRST_MASK) {
@@ -15311,6 +15319,11 @@ static void i40e_remove(struct pci_dev *pdev)
1531115319
while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
1531215320
usleep_range(1000, 2000);
1531315321

15322+
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
15323+
set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
15324+
i40e_free_vfs(pf);
15325+
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
15326+
}
1531415327
/* no more scheduling of any task */
1531515328
set_bit(__I40E_SUSPENDED, pf->state);
1531615329
set_bit(__I40E_DOWN, pf->state);
@@ -15337,11 +15350,6 @@ static void i40e_remove(struct pci_dev *pdev)
1533715350
*/
1533815351
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
1533915352

15340-
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
15341-
i40e_free_vfs(pf);
15342-
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
15343-
}
15344-
1534515353
i40e_fdir_teardown(pf);
1534615354

1534715355
/* If there is a switch structure or any orphans, remove them.

drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
14031403
* @vf: pointer to the VF structure
14041404
* @flr: VFLR was issued or not
14051405
*
1406-
* Returns true if the VF is reset, false otherwise.
1406+
* Returns true if the VF is in reset, resets successfully, or resets
1407+
* are disabled and false otherwise.
14071408
**/
14081409
bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
14091410
{
@@ -1413,11 +1414,14 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
14131414
u32 reg;
14141415
int i;
14151416

1417+
if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state))
1418+
return true;
1419+
14161420
/* If the VFs have been disabled, this means something else is
14171421
* resetting the VF, so we shouldn't continue.
14181422
*/
14191423
if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
1420-
return false;
1424+
return true;
14211425

14221426
i40e_trigger_vf_reset(vf, flr);
14231427

@@ -1581,6 +1585,15 @@ void i40e_free_vfs(struct i40e_pf *pf)
15811585

15821586
i40e_notify_client_of_vf_enable(pf, 0);
15831587

1588+
/* Disable IOV before freeing resources. This lets any VF drivers
1589+
* running in the host get themselves cleaned up before we yank
1590+
* the carpet out from underneath their feet.
1591+
*/
1592+
if (!pci_vfs_assigned(pf->pdev))
1593+
pci_disable_sriov(pf->pdev);
1594+
else
1595+
dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
1596+
15841597
/* Amortize wait time by stopping all VFs at the same time */
15851598
for (i = 0; i < pf->num_alloc_vfs; i++) {
15861599
if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
@@ -1596,15 +1609,6 @@ void i40e_free_vfs(struct i40e_pf *pf)
15961609
i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
15971610
}
15981611

1599-
/* Disable IOV before freeing resources. This lets any VF drivers
1600-
* running in the host get themselves cleaned up before we yank
1601-
* the carpet out from underneath their feet.
1602-
*/
1603-
if (!pci_vfs_assigned(pf->pdev))
1604-
pci_disable_sriov(pf->pdev);
1605-
else
1606-
dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
1607-
16081612
/* free up VF resources */
16091613
tmp = pf->num_alloc_vfs;
16101614
pf->num_alloc_vfs = 0;

0 commit comments

Comments
 (0)