mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-28 13:34:38 +08:00
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: 6a9ddb36ee
("i40e: disable IOV before freeing resources")
Signed-off-by: Slawomir Laba <slawomirx.laba@intel.com>
Signed-off-by: Brett Creeley <brett.creeley@intel.com>
Signed-off-by: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Tested-by: Konrad Jankowski <konrad0.jankowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://lore.kernel.org/r/20201120180640.3654474-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
3fe356d58e
commit
2980cbd4dc
@ -140,6 +140,7 @@ enum i40e_state_t {
|
||||
__I40E_CLIENT_RESET,
|
||||
__I40E_VIRTCHNL_OP_PENDING,
|
||||
__I40E_RECOVERY_MODE,
|
||||
__I40E_VF_RESETS_DISABLED, /* disable resets during i40e_remove */
|
||||
/* This must be last as it determines the size of the BITMAP */
|
||||
__I40E_STATE_SIZE__,
|
||||
};
|
||||
|
@ -4010,8 +4010,16 @@ static irqreturn_t i40e_intr(int irq, void *data)
|
||||
}
|
||||
|
||||
if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
|
||||
ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
|
||||
set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
|
||||
/* disable any further VFLR event notifications */
|
||||
if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) {
|
||||
u32 reg = rd32(hw, I40E_PFINT_ICR0_ENA);
|
||||
|
||||
reg &= ~I40E_PFINT_ICR0_VFLR_MASK;
|
||||
wr32(hw, I40E_PFINT_ICR0_ENA, reg);
|
||||
} else {
|
||||
ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
|
||||
set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
|
||||
}
|
||||
}
|
||||
|
||||
if (icr0 & I40E_PFINT_ICR0_GRST_MASK) {
|
||||
@ -15311,6 +15319,11 @@ static void i40e_remove(struct pci_dev *pdev)
|
||||
while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
|
||||
set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
|
||||
i40e_free_vfs(pf);
|
||||
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
|
||||
}
|
||||
/* no more scheduling of any task */
|
||||
set_bit(__I40E_SUSPENDED, pf->state);
|
||||
set_bit(__I40E_DOWN, pf->state);
|
||||
@ -15337,11 +15350,6 @@ static void i40e_remove(struct pci_dev *pdev)
|
||||
*/
|
||||
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
|
||||
|
||||
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
|
||||
i40e_free_vfs(pf);
|
||||
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
|
||||
}
|
||||
|
||||
i40e_fdir_teardown(pf);
|
||||
|
||||
/* If there is a switch structure or any orphans, remove them.
|
||||
|
@ -1403,7 +1403,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
|
||||
* @vf: pointer to the VF structure
|
||||
* @flr: VFLR was issued or not
|
||||
*
|
||||
* Returns true if the VF is reset, false otherwise.
|
||||
* Returns true if the VF is in reset, resets successfully, or resets
|
||||
* are disabled and false otherwise.
|
||||
**/
|
||||
bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
|
||||
{
|
||||
@ -1413,11 +1414,14 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state))
|
||||
return true;
|
||||
|
||||
/* If the VFs have been disabled, this means something else is
|
||||
* resetting the VF, so we shouldn't continue.
|
||||
*/
|
||||
if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
i40e_trigger_vf_reset(vf, flr);
|
||||
|
||||
@ -1581,6 +1585,15 @@ void i40e_free_vfs(struct i40e_pf *pf)
|
||||
|
||||
i40e_notify_client_of_vf_enable(pf, 0);
|
||||
|
||||
/* Disable IOV before freeing resources. This lets any VF drivers
|
||||
* running in the host get themselves cleaned up before we yank
|
||||
* the carpet out from underneath their feet.
|
||||
*/
|
||||
if (!pci_vfs_assigned(pf->pdev))
|
||||
pci_disable_sriov(pf->pdev);
|
||||
else
|
||||
dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
|
||||
|
||||
/* Amortize wait time by stopping all VFs at the same time */
|
||||
for (i = 0; i < pf->num_alloc_vfs; i++) {
|
||||
if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
|
||||
@ -1596,15 +1609,6 @@ void i40e_free_vfs(struct i40e_pf *pf)
|
||||
i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
|
||||
}
|
||||
|
||||
/* Disable IOV before freeing resources. This lets any VF drivers
|
||||
* running in the host get themselves cleaned up before we yank
|
||||
* the carpet out from underneath their feet.
|
||||
*/
|
||||
if (!pci_vfs_assigned(pf->pdev))
|
||||
pci_disable_sriov(pf->pdev);
|
||||
else
|
||||
dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
|
||||
|
||||
/* free up VF resources */
|
||||
tmp = pf->num_alloc_vfs;
|
||||
pf->num_alloc_vfs = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user