aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorKevin Bowling <kbowling@FreeBSD.org>2026-08-27 06:23:42 +0000
committerKevin Bowling <kbowling@FreeBSD.org>2026-08-27 22:51:10 +0000
commitf1f58bdf7b5fc58e6011c6ac2ae2ba129dc41991 (patch)
treed231a2948c07d779f88d8ce1c1d876d196749f84 /sys/dev
parent5f78d024695b39208a6c92f6a96017bae53cdf2c (diff)
acpi_pci: Honor device proximity for DMA tags
A PCI function with its own _PXM still inherits a DMA tag carrying the upstream bridge's proximity domain. Resolving an SR-IOV VF's locality through its PF therefore does not affect the domain used for DMA allocations. Create and cache a private child tag when the function, or a VF's owning PF, has an explicit _PXM. Parent it to the existing PCI or IOMMU tag so its constraints remain intact, then apply the function's domain without mutating a shared tag. pci_get_dma_tag() already performs the IOMMU lookup, so remove the duplicated lookup in the ACPI subclass while here. Reviewed by: jhb MFC after: 2 weeks Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59063
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpica/acpi_pci.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c
index 1f04de54ac44..347a68e17e53 100644
--- a/sys/dev/acpica/acpi_pci.c
+++ b/sys/dev/acpica/acpi_pci.c
@@ -28,7 +28,6 @@
#include <sys/cdefs.h>
#include "opt_acpi.h"
-#include "opt_iommu.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -51,8 +50,6 @@
#include <dev/pci/pcivar.h>
#include <dev/pci/pci_private.h>
-#include <dev/iommu/iommu.h>
-
/* Hooks for the ACPI CA debugging infrastructure. */
#define _COMPONENT ACPI_BUS
ACPI_MODULE_NAME("PCI")
@@ -60,6 +57,7 @@ ACPI_MODULE_NAME("PCI")
struct acpi_pci_devinfo {
struct pci_devinfo ap_dinfo;
ACPI_HANDLE ap_handle;
+ bus_dma_tag_t ap_dma_tag;
int ap_flags;
int ap_domain;
};
@@ -179,6 +177,8 @@ acpi_pci_child_deleted(device_t dev, device_t child)
{
struct acpi_pci_devinfo *dinfo = device_get_ivars(child);
+ if (dinfo->ap_dma_tag != NULL)
+ bus_dma_tag_destroy(dinfo->ap_dma_tag);
if (acpi_get_device(dinfo->ap_handle) == child)
AcpiDetachData(dinfo->ap_handle, acpi_fake_objhandler);
pci_child_deleted(dev, child);
@@ -560,26 +560,42 @@ acpi_pci_detach(device_t dev)
return (pci_detach(dev));
}
-#ifdef IOMMU
static bus_dma_tag_t
acpi_pci_get_dma_tag(device_t bus, device_t child)
{
- bus_dma_tag_t tag;
+ struct acpi_pci_devinfo *dinfo;
+ bus_dma_tag_t parent, tag;
+ int domain, error;
- if (device_get_parent(child) == bus) {
- /* try iommu and return if it works */
- tag = iommu_get_dma_tag(bus, child);
- } else
- tag = NULL;
- if (tag == NULL)
- tag = pci_get_dma_tag(bus, child);
- return (tag);
-}
-#else
-static bus_dma_tag_t
-acpi_pci_get_dma_tag(device_t bus, device_t child)
-{
+ if (device_get_parent(child) != bus)
+ return (pci_get_dma_tag(bus, child));
+ dinfo = device_get_ivars(child);
+ if (dinfo->ap_dma_tag != NULL)
+ return (dinfo->ap_dma_tag);
+
+ /*
+ * The parent tag already carries the upstream bridge's proximity
+ * domain. Only create a private tag when this function (or its PF,
+ * for a VF) supplies a more specific _PXM. In particular, do not
+ * change the shared PCI or IOMMU tag in place.
+ */
+ domain = acpi_pci_get_locality_domain(child);
+ if (domain < 0)
+ return (pci_get_dma_tag(bus, child));
- return (pci_get_dma_tag(bus, child));
+ parent = pci_get_dma_tag(bus, child);
+ if (parent == NULL)
+ return (NULL);
+ error = bus_dma_tag_create(parent, 1, 0, BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE,
+ BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &tag);
+ if (error != 0)
+ return (parent);
+ error = bus_dma_tag_set_domain(tag, domain);
+ if (error != 0) {
+ bus_dma_tag_destroy(tag);
+ return (parent);
+ }
+ dinfo->ap_dma_tag = tag;
+ return (tag);
}
-#endif