Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e88c2a1e authored by Sylwester Dziedziuch's avatar Sylwester Dziedziuch Committed by Greg Kroah-Hartman
Browse files

i40e: Fix VF hang when reset is triggered on another VF



[ Upstream commit 52424f974bc53c26ba3f00300a00e9de9afcd972 ]

When a reset was triggered on one VF with i40e_reset_vf
global PF state __I40E_VF_DISABLE was set on a PF until
the reset finished. If immediately after triggering reset
on one VF there is a request to reset on another
it will cause a hang on VF side because VF will be notified
of incoming reset but the reset will never happen because
of this global state, we will get such error message:

[  +4.890195] iavf 0000:86:02.1: Never saw reset

and VF will hang waiting for the reset to be triggered.

Fix this by introducing new VF state I40E_VF_STATE_RESETTING
that will be set on a VF if it is currently resetting instead of
the global __I40E_VF_DISABLE PF state.

Fixes: 3ba9bcb4 ("i40e: add locking around VF reset")
Signed-off-by: default avatarSylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Signed-off-by: default avatarMateusz Palczewski <mateusz.palczewski@intel.com>
Tested-by: default avatarKonrad Jankowski <konrad0.jankowski@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Link: https://lore.kernel.org/r/20221024100526.1874914-2-jacob.e.keller@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 28c47fd2
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -1352,10 +1352,12 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
	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))
	/* Bail out if VFs are disabled. */
	if (test_bit(__I40E_VF_DISABLE, pf->state))
		return true;

	/* If VF is being reset already we don't need to continue. */
	if (test_and_set_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
		return true;

	i40e_trigger_vf_reset(vf, flr);
@@ -1392,7 +1394,7 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
	i40e_cleanup_reset_vf(vf);

	i40e_flush(hw);
	clear_bit(__I40E_VF_DISABLE, pf->state);
	clear_bit(I40E_VF_STATE_RESETTING, &vf->vf_states);

	return true;
}
@@ -1425,8 +1427,12 @@ 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++)
	for (v = 0; v < pf->num_alloc_vfs; v++) {
		vf = &pf->vf[v];
		/* 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);
	}

	/* HW requires some time to make sure it can flush the FIFO for a VF
	 * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
@@ -1442,9 +1448,11 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
		 */
		while (v < pf->num_alloc_vfs) {
			vf = &pf->vf[v];
			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))
					break;
			}

			/* If the current VF has finished resetting, move on
			 * to the next VF in sequence.
@@ -1472,6 +1480,10 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
		if (pf->vf[v].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]);
	}

@@ -1483,6 +1495,10 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
		if (pf->vf[v].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]);
	}

@@ -1492,8 +1508,13 @@ 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 (v = 0; v < pf->num_alloc_vfs; v++) {
		/* 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_flush(hw);
	clear_bit(__I40E_VF_DISABLE, pf->state);
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ enum i40e_vf_states {
	I40E_VF_STATE_MC_PROMISC,
	I40E_VF_STATE_UC_PROMISC,
	I40E_VF_STATE_PRE_ENABLE,
	I40E_VF_STATE_RESETTING
};

/* VF capabilities */