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); }