]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
i40e: Restore VF MSI-X state during PCI reset
authorAndrii Staikov <andrii.staikov@intel.com>
Thu, 21 Dec 2023 13:27:35 +0000 (14:27 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 10 Jan 2024 16:10:25 +0000 (17:10 +0100)
[ 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: 19b7960b2da1 ("i40e: implement split PCI error reset handler")
Co-developed-by: Karen Ostrowska <karen.ostrowska@intel.com>
Signed-off-by: Karen Ostrowska <karen.ostrowska@intel.com>
Co-developed-by: Mateusz Palczewski <mateusz.palczewski@intel.com>
Signed-off-by: Mateusz Palczewski <mateusz.palczewski@intel.com>
Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Andrii Staikov <andrii.staikov@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h

index cdc68b78bd9ea20eca2ff61a72cf755de685235d..63d43ef86f9b946c6e01bf87b153d1ee0129ff14 100644 (file)
@@ -16450,6 +16450,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev)
                return;
 
        i40e_reset_and_rebuild(pf, false, false);
+#ifdef CONFIG_PCI_IOV
+       i40e_restore_all_vfs_msi_state(pdev);
+#endif /* CONFIG_PCI_IOV */
 }
 
 /**
index 3c38129a5224a82f3a99fda76231155324c0e74d..c7d761426d6cec84f51db223fa658e28ec4807e0 100644 (file)
@@ -152,6 +152,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
index 358bbdb5879511a581c2cebb54b74ff4f83a37a8..bd497cc5303a18d0434d98de19efe251c07e5389 100644 (file)
@@ -135,6 +135,9 @@ 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 */
 int i40e_get_vf_stats(struct net_device *netdev, int vf_id,
                      struct ifla_vf_stats *vf_stats);