git: df6bbc9b17dc - main - ofw_pcibus: Honor device proximity for DMA tags
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 22 Aug 2026 01:05:30 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=df6bbc9b17dcb75e220b9ab44f5a6483b47c562e
commit df6bbc9b17dcb75e220b9ab44f5a6483b47c562e
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-21 03:08:13 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-22 01:04:49 +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)
MFC after: 2 weeks
Sponsored by: BBOX.io
Differential Revision: https://reviews.freebsd.org/D59065
---
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 2c759f35cb69..e6ddbdf0e835 100644
--- a/sys/powerpc/ofw/ofw_pcibus.c
+++ b/sys/powerpc/ofw/ofw_pcibus.c
@@ -64,6 +64,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);
@@ -80,6 +81,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 653bb83b397a..b1c20237bf15 100644
--- a/sys/powerpc/pseries/plpar_pcibus.c
+++ b/sys/powerpc/pseries/plpar_pcibus.c
@@ -91,6 +91,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);
@@ -105,6 +106,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);
}