From 2b0ae7cc3bfc3fae124c25870f41291c670b4549 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:43 -0500 Subject: [PATCH] PCI/ATS: Handle sharing of PF PASID Capability with all VFs Per PCIe r5.0, sec 9.3.7.14, if a PF implements the PASID Capability, the PF PASID configuration is shared by its VFs. VFs must not implement their own PASID Capability. Since VFs don't have a PASID Capability, pci_enable_pasid() always failed, which caused IOMMU setup to fail. Update the PASID interfaces so for VFs they reflect the state of the PF PASID. [bhelgaas: rebase without pasid_cap caching, commit log] Suggested-by: Ashok Raj Link: https://lore.kernel.org/r/8ba1ac192e4ac737508b6ac15002158e176bab91.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-3-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Cc: Ashok Raj Cc: Keith Busch --- drivers/pci/ats.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index b0f68c0..fb5cfd2 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -346,6 +346,16 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) u16 control, supported; int pos; + /* + * VFs must not implement the PASID Capability, but if a PF + * supports PASID, its VFs share the PF PASID configuration. + */ + if (pdev->is_virtfn) { + if (pci_physfn(pdev)->pasid_enabled) + return 0; + return -EINVAL; + } + if (WARN_ON(pdev->pasid_enabled)) return -EBUSY; @@ -383,6 +393,10 @@ void pci_disable_pasid(struct pci_dev *pdev) u16 control = 0; int pos; + /* VFs share the PF PASID configuration */ + if (pdev->is_virtfn) + return; + if (WARN_ON(!pdev->pasid_enabled)) return; @@ -405,6 +419,9 @@ void pci_restore_pasid_state(struct pci_dev *pdev) u16 control; int pos; + if (pdev->is_virtfn) + return; + if (!pdev->pasid_enabled) return; @@ -432,6 +449,9 @@ int pci_pasid_features(struct pci_dev *pdev) u16 supported; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); if (!pos) return -EINVAL; @@ -458,6 +478,9 @@ int pci_max_pasids(struct pci_dev *pdev) u16 supported; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); if (!pos) return -EINVAL; -- 2.7.4