diff options
| author | Kevin Bowling <kbowling@FreeBSD.org> | 2026-08-27 06:23:42 +0000 |
|---|---|---|
| committer | Kevin Bowling <kbowling@FreeBSD.org> | 2026-09-10 05:53:16 +0000 |
| commit | f006f9ee93feb77e8fc4723d6c2e386b3956bb51 (patch) | |
| tree | 36b5ffacaba16ee9a2b8b422b19e6bcaa3c2cf5c /sys | |
| parent | 44f0c9d2f89f1712de294c39c6e48bd6d6f388f0 (diff) | |
acpi_pci: Honor device proximity for DMA tagsstable/14
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
Sponsored by: BBOX.io
Differential Revision: https://reviews.freebsd.org/D59063
(cherry picked from commit f1f58bdf7b5fc58e6011c6ac2ae2ba129dc41991)
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/dev/acpica/acpi_pci.c | 59 |
1 files changed, 36 insertions, 23 deletions
diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c index 9a9e36848977..525128756e66 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,11 +50,6 @@ #include <dev/pci/pcivar.h> #include <dev/pci/pci_private.h> -#include <dev/iommu/iommu.h> - -#include "pcib_if.h" -#include "pci_if.h" - /* Hooks for the ACPI CA debugging infrastructure. */ #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("PCI") @@ -63,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; }; @@ -182,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); @@ -562,26 +559,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); - return (pci_get_dma_tag(bus, child)); + /* + * 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)); + + 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 |
