Skip to content

Commit beff3e9

Browse files
Robert KonklewskiJeff Kirsher
authored andcommitted
i40e: Fixed race conditions in VF reset
First, this patch eliminates IOMMU DMAR Faults caused by VF hardware. This is done by enabling VF hardware only after VSI resources are freed. Otherwise, hardware could DMA into memory that is (or just has been) being freed. Then, the VF driver is activated only after VSI resources have been reallocated. That's because the VF driver can request resources immediately after it's activated. So they need to be ready at that point. The second race condition happens when the OS initiates a VF reset, and then before it's finished modifies VF's settings by changing its MAC, VLAN ID, bandwidth allocation, anti-spoof checking, etc. These functions needed to be blocked while VF is undergoing reset. Otherwise, they could operate on data structures that had just been freed or not yet fully initialized. Change-ID: I43ba5a7ae2c9a1cce3911611ffc4598ae33ae3ff Signed-off-by: Robert Konklewski <[email protected]> Tested-by: Andrew Bowers <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 741b8b8 commit beff3e9

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

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

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,11 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
809809
u32 reg_idx, reg;
810810
int i, msix_vf;
811811

812+
/* Start by disabling VF's configuration API to prevent the OS from
813+
* accessing the VF's VSI after it's freed / invalidated.
814+
*/
815+
clear_bit(I40E_VF_STAT_INIT, &vf->vf_states);
816+
812817
/* free vsi & disconnect it from the parent uplink */
813818
if (vf->lan_vsi_idx) {
814819
i40e_vsi_release(pf->vsi[vf->lan_vsi_idx]);
@@ -848,7 +853,6 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
848853
/* reset some of the state variables keeping track of the resources */
849854
vf->num_queue_pairs = 0;
850855
vf->vf_states = 0;
851-
clear_bit(I40E_VF_STAT_INIT, &vf->vf_states);
852856
}
853857

854858
/**
@@ -939,6 +943,14 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
939943
/* warn the VF */
940944
clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
941945

946+
/* Disable VF's configuration API during reset. The flag is re-enabled
947+
* in i40e_alloc_vf_res(), when it's safe again to access VF's VSI.
948+
* It's normally disabled in i40e_free_vf_res(), but it's safer
949+
* to do it earlier to give some time to finish to any VF config
950+
* functions that may still be running at this point.
951+
*/
952+
clear_bit(I40E_VF_STAT_INIT, &vf->vf_states);
953+
942954
/* In the case of a VFLR, the HW has already reset the VF and we
943955
* just need to clean up, so don't hit the VFRTRIG register.
944956
*/
@@ -982,20 +994,31 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
982994
if (!rsd)
983995
dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
984996
vf->vf_id);
985-
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_COMPLETED);
986-
/* clear the reset bit in the VPGEN_VFRTRIG reg */
987-
reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
988-
reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
989-
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
990997

991998
/* On initial reset, we won't have any queues */
992999
if (vf->lan_vsi_idx == 0)
9931000
goto complete_reset;
9941001

9951002
i40e_vsi_stop_rings(pf->vsi[vf->lan_vsi_idx]);
9961003
complete_reset:
997-
/* reallocate VF resources to reset the VSI state */
1004+
/* free VF resources to begin resetting the VSI state */
9981005
i40e_free_vf_res(vf);
1006+
1007+
/* Enable hardware by clearing the reset bit in the VPGEN_VFRTRIG reg.
1008+
* By doing this we allow HW to access VF memory at any point. If we
1009+
* did it any sooner, HW could access memory while it was being freed
1010+
* in i40e_free_vf_res(), causing an IOMMU fault.
1011+
*
1012+
* On the other hand, this needs to be done ASAP, because the VF driver
1013+
* is waiting for this to happen and may report a timeout. It's
1014+
* harmless, but it gets logged into Guest OS kernel log, so best avoid
1015+
* it.
1016+
*/
1017+
reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
1018+
reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
1019+
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
1020+
1021+
/* reallocate VF resources to finish resetting the VSI state */
9991022
if (!i40e_alloc_vf_res(vf)) {
10001023
int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
10011024
i40e_enable_vf_mappings(vf);
@@ -1006,7 +1029,11 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
10061029
i40e_notify_client_of_vf_reset(pf, abs_vf_id);
10071030
vf->num_vlan = 0;
10081031
}
1009-
/* tell the VF the reset is done */
1032+
1033+
/* Tell the VF driver the reset is done. This needs to be done only
1034+
* after VF has been fully initialized, because the VF driver may
1035+
* request resources immediately after setting this flag.
1036+
*/
10101037
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
10111038

10121039
i40e_flush(hw);

0 commit comments

Comments
 (0)