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

Commit 863ca421 authored by Andrii Staikov's avatar Andrii Staikov Committed by Greg Kroah-Hartman
Browse files

i40e: Restore VF MSI-X state during PCI reset



[ Upstream commit 371e576ff3e8580d91d49026e5d5faebf5565558 ]

During a PCI FLR the MSI-X Enable flag in the VF PCI MSI-X capability
register will be cleared. This can lead to issues when a VF is
assigned to a VM because in these cases the VF driver receives no
indication of the PF PCI error/reset and additionally it is incapable
of restoring the cleared flag in the hypervisor configuration space
without fully reinitializing the driver interrupt functionality.

Since the VF driver is unable to easily resolve this condition on its own,
restore the VF MSI-X flag during the PF PCI reset handling.

Fixes: 19b7960b ("i40e: implement split PCI error reset handler")
Co-developed-by: default avatarKaren Ostrowska <karen.ostrowska@intel.com>
Signed-off-by: default avatarKaren Ostrowska <karen.ostrowska@intel.com>
Co-developed-by: default avatarMateusz Palczewski <mateusz.palczewski@intel.com>
Signed-off-by: default avatarMateusz Palczewski <mateusz.palczewski@intel.com>
Reviewed-by: default avatarWojciech Drewek <wojciech.drewek@intel.com>
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: default avatarAndrii Staikov <andrii.staikov@intel.com>
Tested-by: default avatarRafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 01c2d73a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -15716,6 +15716,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev)
	struct i40e_pf *pf = pci_get_drvdata(pdev);

	i40e_reset_and_rebuild(pf, false, false);
#ifdef CONFIG_PCI_IOV
	i40e_restore_all_vfs_msi_state(pdev);
#endif /* CONFIG_PCI_IOV */
}

/**
+26 −0
Original line number Diff line number Diff line
@@ -99,6 +99,32 @@ void i40e_vc_notify_reset(struct i40e_pf *pf)
			     (u8 *)&pfe, sizeof(struct virtchnl_pf_event));
}

#ifdef CONFIG_PCI_IOV
void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev)
{
	u16 vf_id;
	u16 pos;

	/* Continue only if this is a PF */
	if (!pdev->is_physfn)
		return;

	if (!pci_num_vf(pdev))
		return;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
	if (pos) {
		struct pci_dev *vf_dev = NULL;

		pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id);
		while ((vf_dev = pci_get_device(pdev->vendor, vf_id, vf_dev))) {
			if (vf_dev->is_virtfn && vf_dev->physfn == pdev)
				pci_restore_msi_state(vf_dev);
		}
	}
}
#endif /* CONFIG_PCI_IOV */

/**
 * i40e_vc_notify_vf_reset
 * @vf: pointer to the VF structure
+3 −0
Original line number Diff line number Diff line
@@ -141,5 +141,8 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);

void i40e_vc_notify_link_state(struct i40e_pf *pf);
void i40e_vc_notify_reset(struct i40e_pf *pf);
#ifdef CONFIG_PCI_IOV
void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev);
#endif /* CONFIG_PCI_IOV */

#endif /* _I40E_VIRTCHNL_PF_H_ */