git: ac364c3b368c - stable/14 - ofw_pcibus: Honor device proximity for DMA tags
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 05 Sep 2026 00:31:19 UTC
The branch stable/14 has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=ac364c3b368c520930328d3a363f3aa921519b6c
commit ac364c3b368c520930328d3a363f3aa921519b6c
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-21 03:08:13 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-05 00:30:37 +0000
ofw_pcibus: Honor device proximity for DMA tags
BUS_GET_DOMAIN can report a PCI function's firmware locality, including
an SR-IOV VF's inherited PF locality, but ordinary OFW PCI functions
still use the shared bus DMA tag. Consequently, busdma metadata and
coherent memory can be allocated from the bus's domain instead of the
function's domain.
Create and cache a child tag for each function that requests a DMA tag
and apply its reported domain without modifying the shared parent tag.
Apply the same domain to the private IOMMU tag already created by the
pSeries PCI bus. Destroy cached tags when PCI children are removed so
VF create and destroy cycles do not leak them.
Reviewed by: PowerPC (jhibbits)
Sponsored by: BBOX.io
Differential Revision: https://reviews.freebsd.org/D59065
(cherry picked from commit df6bbc9b17dcb75e220b9ab44f5a6483b47c562e)
---
sys/powerpc/ofw/ofw_pcibus.c | 31 +++++++++++++++++++++++++++++++
sys/powerpc/pseries/plpar_pcibus.c | 3 +++
2 files changed, 34 insertions(+)
diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c
index cd1f0bd09483..9c2f09f24d75 100644
--- a/sys/powerpc/ofw/ofw_pcibus.c
+++ b/sys/powerpc/ofw/ofw_pcibus.c
@@ -65,6 +65,7 @@ static pci_alloc_devinfo_t ofw_pcibus_alloc_devinfo;
static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo;
static bus_child_deleted_t ofw_pcibus_child_deleted;
+static bus_get_dma_tag_t ofw_pcibus_get_dma_tag;
static int ofw_pcibus_child_pnpinfo_method(device_t cbdev, device_t child,
struct sbuf *sb);
@@ -81,6 +82,7 @@ static device_method_t ofw_pcibus_methods[] = {
DEVMETHOD(bus_child_pnpinfo, ofw_pcibus_child_pnpinfo_method),
DEVMETHOD(bus_rescan, bus_null_rescan),
DEVMETHOD(bus_get_cpus, ofw_pcibus_get_cpus),
+ DEVMETHOD(bus_get_dma_tag, ofw_pcibus_get_dma_tag),
DEVMETHOD(bus_get_domain, ofw_pcibus_get_domain),
/* PCI interface */
@@ -293,10 +295,39 @@ ofw_pcibus_child_deleted(device_t dev, device_t child)
struct ofw_pcibus_devinfo *dinfo;
dinfo = device_get_ivars(child);
+ if (dinfo->opd_dma_tag != NULL)
+ bus_dma_tag_destroy(dinfo->opd_dma_tag);
ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
pci_child_deleted(dev, child);
}
+static bus_dma_tag_t
+ofw_pcibus_get_dma_tag(device_t bus, device_t child)
+{
+ struct ofw_pcibus_devinfo *dinfo;
+ bus_dma_tag_t parent, tag;
+ int domain, error;
+
+ if (device_get_parent(child) != bus)
+ return (pci_get_dma_tag(bus, child));
+ dinfo = device_get_ivars(child);
+ if (dinfo->opd_dma_tag != NULL)
+ return (dinfo->opd_dma_tag);
+
+ 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);
+ if (bus_get_domain(child, &domain) == 0)
+ (void)bus_dma_tag_set_domain(tag, domain);
+ dinfo->opd_dma_tag = tag;
+ return (tag);
+}
+
static int
ofw_pcibus_child_pnpinfo_method(device_t cbdev, device_t child, struct sbuf *sb)
{
diff --git a/sys/powerpc/pseries/plpar_pcibus.c b/sys/powerpc/pseries/plpar_pcibus.c
index 60f4e0ec8785..e9360ae0871a 100644
--- a/sys/powerpc/pseries/plpar_pcibus.c
+++ b/sys/powerpc/pseries/plpar_pcibus.c
@@ -92,6 +92,7 @@ static bus_dma_tag_t
plpar_pcibus_get_dma_tag(device_t dev, device_t child)
{
struct ofw_pcibus_devinfo *dinfo;
+ int domain;
while (device_get_parent(child) != dev)
child = device_get_parent(child);
@@ -106,6 +107,8 @@ plpar_pcibus_get_dma_tag(device_t dev, device_t child)
NULL, NULL, BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED,
BUS_SPACE_MAXSIZE, 0, NULL, NULL, &dinfo->opd_dma_tag);
phyp_iommu_set_dma_tag(dev, child, dinfo->opd_dma_tag);
+ if (bus_get_domain(child, &domain) == 0)
+ (void)bus_dma_tag_set_domain(dinfo->opd_dma_tag, domain);
return (dinfo->opd_dma_tag);
}