From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> 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@xxxxxxxxx> Link: https://lore.kernel.org/r/8ba1ac192e4ac737508b6ac15002158e176bab91.1567029860.git.sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Cc: Ashok Raj <ashok.raj@xxxxxxxxx> Cc: Keith Busch <keith.busch@xxxxxxxxx> --- drivers/pci/ats.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 3b1c9a2305c1..ab928f8267cf 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -318,6 +318,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; @@ -355,6 +365,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; @@ -377,6 +391,9 @@ void pci_restore_pasid_state(struct pci_dev *pdev) u16 control; int pos; + if (pdev->is_virtfn) + return; + if (!pdev->pasid_enabled) return; @@ -404,6 +421,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; @@ -463,6 +483,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.23.0.187.g17f5b7556c-goog