mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-28 21:33:52 +00:00
i40e: fix vf may be used uninitialized in this function warning
commitf37c4eac99
upstream. To fix the regression introduced by commit52424f974b
, which causes servers hang in very hard to reproduce conditions with resets races. Using two sources for the information is the root cause. In this function before the fix bumping v didn't mean bumping vf pointer. But the code used this variables interchangeably, so stale vf could point to different/not intended vf. Remove redundant "v" variable and iterate via single VF pointer across whole function instead to guarantee VF pointer validity. Fixes:52424f974b
("i40e: Fix VF hang when reset is triggered on another VF") Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de> Tested-by: Rafal Romanowski <rafal.romanowski@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
89e29416cf
commit
0dcf573f99
1 changed files with 16 additions and 18 deletions
|
@ -1628,8 +1628,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)
|
||||
|
@ -1640,11 +1640,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
|
||||
|
@ -1653,14 +1652,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))
|
||||
|
@ -1670,7 +1668,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1680,39 +1678,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
|
||||
|
@ -1721,12 +1719,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);
|
||||
|
|
Loading…
Reference in a new issue