The branch main has been updated by kbowling:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5f78d024695b39208a6c92f6a96017bae53cdf2c

commit 5f78d024695b39208a6c92f6a96017bae53cdf2c
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-27 06:22:56 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-27 22:49:56 +0000

    acpi_pci: Cache PCI proximity domains
    
    A PCI function's _PXM is stable for the lifetime of its device
    instance, but CPU and DMA locality queries may evaluate it repeatedly.
    SR-IOV amplifies this because every VF resolves locality through the
    same PF.
    
    Cache successful mappings and the stable absence of _PXM on the
    locality source device, and share that result between CPU and domain
    queries. Continue to retry generic evaluation or mapping errors rather
    than making a potentially transient failure permanent.
    
    Reviewed by:    jhb
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
    Differential Revision:  https://reviews.freebsd.org/D59207
---
 sys/dev/acpica/acpi.c     | 22 +++++++++++++++-------
 sys/dev/acpica/acpi_pci.c | 37 ++++++++++++++++++++++++++++++++-----
 sys/dev/acpica/acpivar.h  |  3 +++
 3 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 5469df01fd35..8b897defe6ce 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -1402,20 +1402,19 @@ acpi_pxm_parse(device_t dev)
 }
 
 int
-acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, size_t setsize,
-    cpuset_t *cpuset)
+acpi_get_cpus_for_domain(device_t dev, device_t child, int domain,
+    enum cpu_sets op, size_t setsize, cpuset_t *cpuset)
 {
-       int d, error;
+       int error;
 
-       d = acpi_pxm_parse(child);
-       if (d < 0)
+       if (domain < 0)
                return (bus_generic_get_cpus(dev, child, op, setsize, cpuset));
 
        switch (op) {
        case LOCAL_CPUS:
                if (setsize != sizeof(cpuset_t))
                        return (EINVAL);
-               *cpuset = cpuset_domain[d];
+               *cpuset = cpuset_domain[domain];
                return (0);
        case INTR_CPUS:
                error = bus_generic_get_cpus(dev, child, op, setsize, cpuset);
@@ -1423,13 +1422,22 @@ acpi_get_cpus(device_t dev, device_t child, enum 
cpu_sets op, size_t setsize,
                        return (error);
                if (setsize != sizeof(cpuset_t))
                        return (EINVAL);
-               CPU_AND(cpuset, cpuset, &cpuset_domain[d]);
+               CPU_AND(cpuset, cpuset, &cpuset_domain[domain]);
                return (0);
        default:
                return (bus_generic_get_cpus(dev, child, op, setsize, cpuset));
        }
 }
 
+int
+acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, size_t setsize,
+    cpuset_t *cpuset)
+{
+
+       return (acpi_get_cpus_for_domain(dev, child, acpi_pxm_parse(child), op,
+           setsize, cpuset));
+}
+
 static int
 acpi_get_domain_method(device_t dev, device_t child, int *domain)
 {
diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c
index 8b6aeb69f593..1f04de54ac44 100644
--- a/sys/dev/acpica/acpi_pci.c
+++ b/sys/dev/acpica/acpi_pci.c
@@ -61,8 +61,12 @@ struct acpi_pci_devinfo {
        struct pci_devinfo      ap_dinfo;
        ACPI_HANDLE             ap_handle;
        int                     ap_flags;
+       int                     ap_domain;
 };
 
+/* acpi_pxm_parse() returns -2, -1, or a non-negative domain. */
+#define        ACPI_PCI_DOMAIN_UNSET   (-3)
+
 ACPI_SERIAL_DECL(pci_powerstate, "ACPI PCI power methods");
 
 /* Be sure that ACPI and PCI power states are equivalent. */
@@ -132,6 +136,7 @@ acpi_pci_alloc_devinfo(device_t dev)
        struct acpi_pci_devinfo *dinfo;
 
        dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
+       dinfo->ap_domain = ACPI_PCI_DOMAIN_UNSET;
        return (&dinfo->ap_dinfo);
 }
 
@@ -217,16 +222,38 @@ acpi_pci_get_locality_device(device_t child)
        return (pf != NULL ? pf : child);
 }
 
+/* Cache locality on its source device; all of a PF's VFs share its result. */
+static int
+acpi_pci_get_locality_domain(device_t child)
+{
+       struct acpi_pci_devinfo *dinfo;
+       device_t locality;
+       int domain;
+
+       locality = acpi_pci_get_locality_device(child);
+       dinfo = device_get_ivars(locality);
+       domain = dinfo->ap_domain;
+       if (domain == ACPI_PCI_DOMAIN_UNSET) {
+               domain = acpi_pxm_parse(locality);
+               /* Do not make a generic evaluation or mapping error permanent. 
*/
+               if (domain != -1)
+                       dinfo->ap_domain = domain;
+       }
+       return (domain);
+}
+
 static int
 acpi_pci_get_cpus(device_t dev, device_t child, enum cpu_sets op,
     size_t setsize, cpuset_t *cpuset)
 {
+       device_t locality;
 
        /* BUS_GET_CPUS may preserve a descendant below the PCI function. */
        if (device_get_parent(child) != dev)
                return (acpi_get_cpus(dev, child, op, setsize, cpuset));
-       child = acpi_pci_get_locality_device(child);
-       return (acpi_get_cpus(dev, child, op, setsize, cpuset));
+       locality = acpi_pci_get_locality_device(child);
+       return (acpi_get_cpus_for_domain(dev, locality,
+           acpi_pci_get_locality_domain(locality), op, setsize, cpuset));
 }
 
 /*
@@ -242,8 +269,7 @@ acpi_pci_get_domain(device_t dev, device_t child, int 
*domain)
 {
        int d;
 
-       child = acpi_pci_get_locality_device(child);
-       d = acpi_pxm_parse(child);
+       d = acpi_pci_get_locality_domain(child);
        if (d >= 0) {
                *domain = d;
                return (0);
@@ -252,7 +278,8 @@ acpi_pci_get_domain(device_t dev, device_t child, int 
*domain)
                return (ENOENT);
 
        /* No _PXM node; go up a level */
-       return (bus_generic_get_domain(dev, child, domain));
+       return (bus_generic_get_domain(dev,
+           acpi_pci_get_locality_device(child), domain));
 }
 
 /*
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 27300a00b8d1..028b39637a45 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -603,6 +603,9 @@ void                acpi_pxm_set_mem_locality(void);
 void           acpi_pxm_set_cpu_locality(void);
 int            acpi_pxm_get_cpu_locality(int apic_id);
 int            acpi_pxm_parse(device_t dev);
+int            acpi_get_cpus_for_domain(device_t dev, device_t child,
+                   int domain, enum cpu_sets op, size_t setsize,
+                   cpuset_t *cpuset);
 
 /*
  * Map a PXM to a VM domain.

Reply via email to