diff options
author | Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> | 2019-09-05 14:31:43 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2019-10-15 16:39:09 -0500 |
commit | 2b0ae7cc3bfc3fae124c25870f41291c670b4549 (patch) | |
tree | d7697f2f7d2004feff281a03731339469f453903 /drivers/pci/ats.c | |
parent | 9bf49e36d7183a170a9906d19acc5254818fc574 (diff) | |
download | linux-stable-2b0ae7cc3bfc3fae124c25870f41291c670b4549.tar.gz linux-stable-2b0ae7cc3bfc3fae124c25870f41291c670b4549.tar.bz2 linux-stable-2b0ae7cc3bfc3fae124c25870f41291c670b4549.zip |
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 <ashok.raj@intel.com>
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 <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Ashok Raj <ashok.raj@intel.com>
Cc: Keith Busch <keith.busch@intel.com>
Diffstat (limited to 'drivers/pci/ats.c')
-rw-r--r-- | drivers/pci/ats.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index b0f68c0ea91e..fb5cfd27dd3c 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; |