--- v1
+++ v6
@@ -1,31 +1,40 @@
-Some non-CXL NVIDIA GPU devices support non-PASID ATS function when their
-RIDs are IOMMU bypassed. This is slightly different than the default ATS
-policy which would only enable ATS on demand: when a non-zero PASID line
-is enabled in SVA use cases.
+Some NVIDIA GPU/NIC devices, though they don't implement CXL config space,
+have many CXL-like properties. Call this kind "pre-CXL".
-Introduce a pci_dev_specific_ats_always_on() quirk function to support a
-list of IDs for these device. Then, include it pci_ats_always_on().
+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>
---
drivers/pci/pci.h | 9 +++++++++
drivers/pci/ats.c | 3 ++-
- drivers/pci/quirks.c | 23 +++++++++++++++++++++++
- 3 files changed, 34 insertions(+), 1 deletion(-)
+ drivers/pci/quirks.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
-index 0e67014aa001..1391df064983 100644
+index 4a14f88e543a2..e8ad27abb1cfe 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
-@@ -1032,6 +1032,15 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
+@@ -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_always_on(struct pci_dev *dev);
++bool pci_dev_specific_ats_required(struct pci_dev *dev);
+#else
-+static inline bool pci_dev_specific_ats_always_on(struct pci_dev *dev)
++static inline bool pci_dev_specific_ats_required(struct pci_dev *dev)
+{
+ return false;
+}
@@ -35,45 +44,64 @@
int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
struct resource *res);
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
-index 1795131f0697..6db45ae2cc8e 100644
+index 84cd06d74fc9c..96efa00d97433 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
-@@ -245,7 +245,8 @@ bool pci_ats_always_on(struct pci_dev *pdev)
+@@ -247,7 +247,8 @@ bool pci_ats_required(struct pci_dev *pdev)
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
-- return pci_cxl_ats_always_on(pdev);
-+ return pci_cxl_ats_always_on(pdev) ||
-+ pci_dev_specific_ats_always_on(pdev);
+- return pci_cxl_ats_required(pdev);
++ return pci_cxl_ats_required(pdev) ||
++ pci_dev_specific_ats_required(pdev);
}
- EXPORT_SYMBOL_GPL(pci_ats_always_on);
+ EXPORT_SYMBOL_GPL(pci_ats_required);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
-index b9c252aa6fe0..afc1d2adb13a 100644
+index caaed1a01dc02..c0242f3e9f063 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
-@@ -5654,6 +5654,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats);
+@@ -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 const struct pci_dev_ats_always_on {
++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;
-+} pci_dev_ats_always_on[] = {
-+ { PCI_VENDOR_ID_NVIDIA, 0x2e12, },
-+ { PCI_VENDOR_ID_NVIDIA, 0x2e2a, },
-+ { PCI_VENDOR_ID_NVIDIA, 0x2e2b, },
++ 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 non-CXL devices support ATS on RID when it is IOMMU-bypassed */
-+bool pci_dev_specific_ats_always_on(struct pci_dev *pdev)
++/*
++ * 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_always_on *i;
++ const struct pci_dev_ats_required *i;
+
-+ for (i = pci_dev_ats_always_on; i->vendor; i++) {
-+ if (i->vendor == pdev->vendor && i->device == pdev->device)
++ 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;
+ }
+