PCI: Allow ATS to be always on for pre-CXL devices

Some NVIDIA GPU/NIC devices, though they don't implement CXL config space,
have many CXL-like properties. Call this kind "pre-CXL".

Similar to CXL.cache capability, these pre-CXL devices also require the ATS
function even when their RIDs are IOMMU bypassed, i.e. keep ATS "always on"
v.s. "on demand" when a non-zero PASID line gets enabled in SVA use cases.

Introduce pci_dev_specific_ats_required() quirk function to scan a list of
IDs for these devices. Then, include it in pci_ats_required().

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nirmoy Das <nirmoyd@nvidia.com>
Tested-by: Nirmoy Das <nirmoyd@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Nicolin Chen 2026-05-21 13:34:21 -07:00 committed by Joerg Roedel
parent 91561e1dc9
commit 073e638125
3 changed files with 53 additions and 1 deletions

View File

@ -247,7 +247,8 @@ bool pci_ats_required(struct pci_dev *pdev)
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
return pci_cxl_ats_required(pdev);
return pci_cxl_ats_required(pdev) ||
pci_dev_specific_ats_required(pdev);
}
EXPORT_SYMBOL_GPL(pci_ats_required);

View File

@ -1155,6 +1155,15 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
}
#endif
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_PCI_ATS)
bool pci_dev_specific_ats_required(struct pci_dev *dev);
#else
static inline bool pci_dev_specific_ats_required(struct pci_dev *dev)
{
return false;
}
#endif
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
struct resource *res);

View File

@ -5715,6 +5715,48 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1459, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145a, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145c, quirk_intel_e2000_no_ats);
static bool quirk_nvidia_gpu_ats_required(struct pci_dev *pdev)
{
switch (pdev->device) {
case 0x2e00 ... 0x2e3f: /* GB20B */
return true;
}
return false;
}
static const struct pci_dev_ats_required {
u16 vendor;
u16 device;
bool (*ats_required)(struct pci_dev *dev);
} pci_dev_ats_required[] = {
/* NVIDIA GPUs */
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, quirk_nvidia_gpu_ats_required },
/* NVIDIA CX10 Family NVlink-C2C */
{ PCI_VENDOR_ID_MELLANOX, 0x2101, NULL },
{ 0 }
};
/*
* Some NVIDIA devices do not implement CXL config space, but present as PCIe
* devices that can issue CXL-like cache operations like CXL.cache. Thus, they
* require ATS to obtain host physical addresses, like pci_cxl_ats_required().
*/
bool pci_dev_specific_ats_required(struct pci_dev *pdev)
{
const struct pci_dev_ats_required *i;
for (i = pci_dev_ats_required; i->vendor; i++) {
if (i->vendor != pdev->vendor)
continue;
if (i->ats_required && i->ats_required(pdev))
return true;
if (!i->ats_required && i->device == pdev->device)
return true;
}
return false;
}
#endif /* CONFIG_PCI_ATS */
/* Freescale PCIe doesn't support MSI in RC mode */