From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> Per PCIe r5.0, sec 9.3.7.11, VFs must not implement the PRI Capability. If the PF implements PRI, it is shared by the VFs. Since VFs don't have a PRI Capability, pci_enable_pri() always failed, which caused IOMMU setup to fail. Update the PRI interfaces so for VFs they reflect the state of the PF PRI. [bhelgaas: rebase without pri_cap caching, commit log] Suggested-by: Ashok Raj <ashok.raj@xxxxxxxxx> Link: https://lore.kernel.org/r/b971e31f8695980da8e4a7f93e3b6a3edba3edaa.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 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index e18499243f84..3b1c9a2305c1 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -182,6 +182,17 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) u32 max_requests; int pos; + /* + * VFs must not implement the PRI Capability. If their PF + * implements PRI, it is shared by the VFs, so if the PF PRI is + * enabled, it is also enabled for the VF. + */ + if (pdev->is_virtfn) { + if (pci_physfn(pdev)->pri_enabled) + return 0; + return -EINVAL; + } + if (WARN_ON(pdev->pri_enabled)) return -EBUSY; @@ -218,6 +229,10 @@ void pci_disable_pri(struct pci_dev *pdev) u16 control; int pos; + /* VFs share the PF PRI */ + if (pdev->is_virtfn) + return; + if (WARN_ON(!pdev->pri_enabled)) return; @@ -243,6 +258,9 @@ void pci_restore_pri_state(struct pci_dev *pdev) u32 reqs = pdev->pri_reqs_alloc; int pos; + if (pdev->is_virtfn) + return; + if (!pdev->pri_enabled) return; @@ -267,6 +285,9 @@ int pci_reset_pri(struct pci_dev *pdev) u16 control; int pos; + if (pdev->is_virtfn) + return 0; + if (WARN_ON(pdev->pri_enabled)) return -EBUSY; @@ -412,6 +433,9 @@ int pci_prg_resp_pasid_required(struct pci_dev *pdev) u16 status; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (!pos) return 0; -- 2.23.0.187.g17f5b7556c-goog