diff options
| author | Kevin Bowling <kbowling@FreeBSD.org> | 2026-08-27 06:23:42 +0000 |
|---|---|---|
| committer | Kevin Bowling <kbowling@FreeBSD.org> | 2026-08-27 22:51:10 +0000 |
| commit | f1f58bdf7b5fc58e6011c6ac2ae2ba129dc41991 (patch) | |
| tree | d231a2948c07d779f88d8ce1c1d876d196749f84 /sys/dev | |
| parent | 5f78d024695b39208a6c92f6a96017bae53cdf2c (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.c | 56 |
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 |
