git: 0a575891211e - main - LinuxKPI: implement dmam_free_coherent()

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 25 Jan 2026 12:35:52 UTC
The branch main has been updated by bz:

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

commit 0a575891211eff545bab1e4de5e2b7adf4a4c1da
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-01-21 13:57:55 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-01-25 12:35:22 +0000

    LinuxKPI: implement dmam_free_coherent()
    
    dmam_free_coherent() is used by an updated mt76 driver at v6.19-rc6.
    We need to surgically find the devres information and destroy it before
    calling dma_free_coherent.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
    Reviewed by:    emaste
    Differential Revision: https://reviews.freebsd.org/D54810
---
 .../linuxkpi/common/include/linux/dma-mapping.h    |  9 ++++++
 sys/compat/linuxkpi/common/src/linux_pci.c         | 36 ++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
index 2d8e1196d3d3..76efbfd51074 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -96,6 +96,8 @@ void *linux_dma_alloc_coherent(struct device *dev, size_t size,
     dma_addr_t *dma_handle, gfp_t flag);
 void *linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size,
     dma_addr_t *dma_handle, gfp_t flag);
+void linuxkpi_dmam_free_coherent(struct device *dev, size_t size,
+    void *addr, dma_addr_t dma_handle);
 dma_addr_t linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len);	/* backward compat */
 dma_addr_t lkpi_dma_map_phys(struct device *, vm_paddr_t, size_t,
     enum dma_data_direction, unsigned long);
@@ -181,6 +183,13 @@ dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
 	kmem_free(cpu_addr, size);
 }
 
+static inline void
+dmam_free_coherent(struct device *dev, size_t size, void *addr,
+    dma_addr_t dma_handle)
+{
+	linuxkpi_dmam_free_coherent(dev, size, addr, dma_handle);
+}
+
 static inline dma_addr_t
 dma_map_page_attrs(struct device *dev, struct page *page, size_t offset,
     size_t size, enum dma_data_direction direction, unsigned long attrs)
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index df5255d8a6ca..9e4fad45433a 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -1796,6 +1796,42 @@ lkpi_dmam_free_coherent(struct device *dev, void *p)
 	dma_free_coherent(dev, dr->size, dr->mem, *dr->handle);
 }
 
+static int
+lkpi_dmam_coherent_match(struct device *dev, void *dr, void *mp)
+{
+	struct lkpi_devres_dmam_coherent *a, *b;
+
+	a = dr;
+	b = mp;
+
+	if (a->mem != b->mem)
+		return (0);
+	if (a->size != b->size || a->handle != b->handle)
+		dev_WARN(dev, "for mem %p: size %zu != %zu || handle %#jx != %#jx\n",
+		    a->mem, a->size, b->size,
+		    (uintmax_t)a->handle, (uintmax_t)b->handle);
+	return (1);
+}
+
+void
+linuxkpi_dmam_free_coherent(struct device *dev, size_t size,
+    void *addr, dma_addr_t dma_handle)
+{
+	struct lkpi_devres_dmam_coherent match = {
+		.size		= size,
+		.handle		= &dma_handle,
+		.mem		= addr
+	};
+	int error;
+
+	error = devres_destroy(dev, lkpi_dmam_free_coherent,
+	    lkpi_dmam_coherent_match, &match);
+	if (error != 0)
+		dev_WARN(dev, "devres_destroy returned %d, size %zu addr %p "
+		    "dma_handle %#jx\n", error, size, addr, (uintmax_t)dma_handle);
+	dma_free_coherent(dev, size, addr, dma_handle);
+}
+
 void *
 linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
     gfp_t flag)