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
This commit is contained in:
Bjoern A. Zeeb
2026-01-21 13:57:55 +00:00
parent bf4aa758dd
commit 0a57589121
2 changed files with 45 additions and 0 deletions
@@ -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)
@@ -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)