git: 0b1dea8f51e4 - stable/15 - LinuxKPI: implement dma_{alloc,free}_{noncoherent,attrs}

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sat, 19 Sep 2026 14:40:28 UTC
The branch stable/15 has been updated by bz:

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

commit 0b1dea8f51e41fa602294cf2526481c49123e2da
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-08-16 21:54:36 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-09-19 09:34:10 +0000

    LinuxKPI: implement dma_{alloc,free}_{noncoherent,attrs}
    
    We use one to implement the other given direction stays unused.
    
    This is needed by an upcoming wifi driver.
    
    Reviewed by:    dumbbell
    Differential Revision: https://reviews.freebsd.org/D58880
    
    (cherry picked from commit c3fa17a6a331db8aad03e9cb89ba97e1811ab381)
---
 .../linuxkpi/common/include/linux/dma-mapping.h    | 36 ++++++++++++++++
 sys/compat/linuxkpi/common/src/linux_pci.c         | 50 ++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
index 173b3e8d3c96..bb1ef678e621 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -98,6 +98,14 @@ 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);
+void *linuxkpi_dma_alloc_noncoherent(struct device *, size_t, dma_addr_t *,
+    enum dma_data_direction, gfp_t);
+void linuxkpi_dma_free_noncoherent(struct device *, size_t, void *,
+    dma_addr_t, enum dma_data_direction);
+void *linuxkpi_dma_alloc_attrs(struct device *, size_t, dma_addr_t *,
+    gfp_t, unsigned long);
+void linuxkpi_dma_free_attrs(struct device *, size_t, void *,
+    dma_addr_t, unsigned long);
 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);
@@ -191,6 +199,34 @@ dmam_free_coherent(struct device *dev, size_t size, void *addr,
 	linuxkpi_dmam_free_coherent(dev, size, addr, dma_handle);
 }
 
+static inline void *
+dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+    enum dma_data_direction direction, gfp_t gfp)
+{
+	return (linuxkpi_dma_alloc_noncoherent(dev, size, dma_handle, direction, gfp));
+}
+
+static inline void
+dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+    dma_addr_t dma_handle, enum dma_data_direction direction)
+{
+	linuxkpi_dma_free_noncoherent(dev, size, vaddr, dma_handle, direction);
+}
+
+static inline void *
+dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+    gfp_t gfp, unsigned long attrs)
+{
+	return (linuxkpi_dma_alloc_attrs(dev, size, dma_handle, gfp, attrs));
+}
+
+static inline void
+dma_free_attrs(struct device *dev, size_t size, void *vaddr,
+    dma_addr_t dma_handle, unsigned long attrs)
+{
+	linuxkpi_dma_free_attrs(dev, size, vaddr, dma_handle, attrs);
+}
+
 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 4909b52150ae..ab8d5cf98534 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -1989,6 +1989,56 @@ linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_ha
 	return (dr->mem);
 }
 
+void *
+linuxkpi_dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+    enum dma_data_direction direction, gfp_t gfp)
+{
+	struct linux_dma_priv *priv;
+	size_t align;
+	void *mem;
+
+	size = PAGE_ALIGN(size);
+	align = PAGE_SIZE << get_order(size);
+	mem = kmem_alloc_contig(size, gfp & GFP_NATIVE_MASK, 0, BUS_SPACE_MAXADDR,
+	    align, 0, VM_MEMATTR_DEFAULT);
+	if (mem == NULL) {
+		*dma_handle = 0;
+		return (NULL);
+	}
+
+	priv = dev->dma_priv;
+	*dma_handle = linux_dma_map_phys_common(dev, vtophys(mem), size, priv->dmat);
+	if (*dma_handle == 0) {
+		kmem_free(mem, size);
+		mem = NULL;
+	}
+	return (mem);
+}
+
+void
+linuxkpi_dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+    dma_addr_t dma_handle, enum dma_data_direction direction)
+{
+	lkpi_dma_unmap(dev, dma_handle, size, direction, 0);
+	kmem_free(vaddr, size);
+}
+
+void *
+linuxkpi_dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+    gfp_t gfp, unsigned long attrs)
+{
+	return (linuxkpi_dma_alloc_noncoherent(dev, size, dma_handle,
+	    DMA_BIDIRECTIONAL, gfp));
+}
+
+void
+linuxkpi_dma_free_attrs(struct device *dev, size_t size, void *vaddr,
+    dma_addr_t dma_handle, unsigned long attrs)
+{
+	linuxkpi_dma_free_noncoherent(dev, size, vaddr, dma_handle,
+	    DMA_BIDIRECTIONAL);
+}
+
 void
 linuxkpi_dma_sync(struct device *dev, dma_addr_t dma_addr, size_t size,
     bus_dmasync_op_t op)