git: 5f78d024695b - main - acpi_pci: Cache PCI proximity domains
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 27 Aug 2026 22:50:43 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=5f78d024695b39208a6c92f6a96017bae53cdf2c
commit 5f78d024695b39208a6c92f6a96017bae53cdf2c
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-27 06:22:56 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
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.