git: df6bbc9b17dc - main - ofw_pcibus: Honor device proximity for DMA tags

Kevin Bowling <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src,gmane.os.freebsd.current.scm
Message-ID <[email protected]>
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=df6bbc9b17dcb75e220b9ab44f5a6483b47c562e

commit df6bbc9b17dcb75e220b9ab44f5a6483b47c562e
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-21 03:08:13 +0000
Commit:     Kevin Bowling <[email protected]>
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);
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.