PCI/ATS: Handle sharing of PF PRI Capability with all VFs
authorKuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Thu, 5 Sep 2019 19:31:42 +0000 (14:31 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 15 Oct 2019 21:39:09 +0000 (16:39 -0500)
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@intel.com>
Link: https://lore.kernel.org/r/b971e31f8695980da8e4a7f93e3b6a3edba3edaa.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com
Link: https://lore.kernel.org/r/20190905193146.90250-2-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>
drivers/pci/ats.c

index 0d06177..b0f68c0 100644 (file)
@@ -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;
 
@@ -293,6 +314,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;