From: Ashok Raj <ashok.raj@xxxxxxxxx> commit 3f9a7a13fe4cb6e119e4e4745fbf975d30bfac9b upstream. For SR-IOV, the PF PRI is shared between the PF and any associated VFs, and the PRI Capability is allowed for PFs but not for VFs. Searching for the PRI Capability on a VF always fails, even if its associated PF supports PRI. Add pci_pri_supported() to check whether device or its associated PF supports PRI. [bhelgaas: commit log, avoid "!!"] Fixes: b16d0cb9e2fc ("iommu/vt-d: Always enable PASID/PRI PCI capabilities before ATS") Link: https://lore.kernel.org/r/1595543849-19692-1-git-send-email-ashok.raj@xxxxxxxxx Signed-off-by: Ashok Raj <ashok.raj@xxxxxxxxx> Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Reviewed-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> Acked-by: Joerg Roedel <jroedel@xxxxxxx> Cc: stable@xxxxxxxxxxxxxxx # v4.4+ Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/iommu/intel-iommu.c | 2 +- drivers/pci/ats.c | 15 +++++++++++++++ include/linux/pci-ats.h | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2645,7 +2645,7 @@ static struct dmar_domain *dmar_insert_o } if (info->ats_supported && ecap_prs(iommu->ecap) && - pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI)) + pci_pri_supported(pdev)) info->pri_supported = 1; } } --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -309,6 +309,21 @@ int pci_prg_resp_pasid_required(struct p return pdev->pasid_required; } + +/** + * pci_pri_supported - Check if PRI is supported. + * @pdev: PCI device structure + * + * Returns true if PRI capability is present, false otherwise. + */ +bool pci_pri_supported(struct pci_dev *pdev) +{ + /* VFs share the PF PRI */ + if (pci_physfn(pdev)->pri_cap) + return true; + return false; +} +EXPORT_SYMBOL_GPL(pci_pri_supported); #endif /* CONFIG_PCI_PRI */ #ifdef CONFIG_PCI_PASID --- a/include/linux/pci-ats.h +++ b/include/linux/pci-ats.h @@ -25,6 +25,10 @@ int pci_enable_pri(struct pci_dev *pdev, void pci_disable_pri(struct pci_dev *pdev); int pci_reset_pri(struct pci_dev *pdev); int pci_prg_resp_pasid_required(struct pci_dev *pdev); +bool pci_pri_supported(struct pci_dev *pdev); +#else +static inline bool pci_pri_supported(struct pci_dev *pdev) +{ return false; } #endif /* CONFIG_PCI_PRI */ #ifdef CONFIG_PCI_PASID