PCI/ATS: Handle sharing of PF PRI Capability with all VFs

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>
This commit is contained in:
Kuppuswamy Sathyanarayanan 2019-09-05 14:31:42 -05:00 committed by Bjorn Helgaas
parent 8cbb8a9374
commit 9bf49e36d7

View 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;