diff options
| author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-01-21 13:57:55 +0000 |
|---|---|---|
| committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-01-25 12:35:22 +0000 |
| commit | 0a575891211eff545bab1e4de5e2b7adf4a4c1da (patch) | |
| tree | a422840e115d24813ec6967e874ae6050d57186e | |
| parent | bf4aa758dd79dcb3f5d5abde79d679d17b18afa0 (diff) | |
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
| -rw-r--r-- | sys/compat/linuxkpi/common/include/linux/dma-mapping.h | 9 | ||||
| -rw-r--r-- | sys/compat/linuxkpi/common/src/linux_pci.c | 36 |
2 files changed, 45 insertions, 0 deletions
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) |
