Hi Bastien, Le jeudi 10 avril 2025 à 16:53 +0200, Bastien Curutchet a écrit : > Some UIO users need to access DMA addresses from userspace to be able to > configure DMA done by the UIO device. Currently there is no way of doing > this. > > Add a UIO_DMABUF_HEAP Kconfig option. When selected, a dma-heap > allocator is created for every new UIO device. This allocator only > implements 4 basic operations: allocate, release, mmap and get_dma_addr. > The buffer allocation is done through dma_alloc_coherent().
This is quite redundant with the CMA heap. I believe a better design is to make UIO devices dmabuf importers. This will make your UIO dmabuf implementation a lot more useful. As for the physical addresses, everywhere you currently pass a physical address, you should be able to add ioctl to pass a DMABuf FD, or a handle to an UIO specific object (similar to buffer objects in DRM) and hide these. regards, Nicolas > > Signed-off-by: Bastien Curutchet <bastien.curutc...@bootlin.com> > --- > drivers/uio/Kconfig | 9 ++++ > drivers/uio/Makefile | 1 + > drivers/uio/uio.c | 4 ++ > drivers/uio/uio_heap.c | 120 > +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/uio_driver.h | 2 + > 5 files changed, 136 insertions(+) > > diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig > index > b060dcd7c6350191726c0830a1ae7b9a388ca4bb..2f3b1e57fceb01354b65cc4d39f342f645a238db > 100644 > --- a/drivers/uio/Kconfig > +++ b/drivers/uio/Kconfig > @@ -164,4 +164,13 @@ config UIO_DFL > opae-sdk/tools/libopaeuio/ > > If you compile this as a module, it will be called uio_dfl. > + > +config UIO_DMABUF_HEAP > + bool "DMA-BUF UIO Heap" > + select DMABUF_HEAPS > + help > + Choose this option to enable DMA-BUF UIO heap. It will create a new > + heap allocator under /dev/dma_heap/ for every UIO device. This > + allocator allows userspace applications to allocate DMA buffers and > + access their DMA addresses thanks to the DMA_BUF_IOCTL_GET_DMA_HANDLE > endif > diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile > index > 1c5f3b5a95cf5b681a843b745a046d7ce123255d..f6696daa36567a4e5d18b1b89ba688057e758400 > 100644 > --- a/drivers/uio/Makefile > +++ b/drivers/uio/Makefile > @@ -11,3 +11,4 @@ obj-$(CONFIG_UIO_MF624) += uio_mf624.o > obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o > obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o > obj-$(CONFIG_UIO_DFL) += uio_dfl.o > +obj-$(CONFIG_UIO_DMABUF_HEAP) += uio_heap.o > diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c > index > d93ed4e86a174b5bad193a61aa522cd833fe7bb5..f31936a897805a284165cccfee3d66e96acd4b39 > 100644 > --- a/drivers/uio/uio.c > +++ b/drivers/uio/uio.c > @@ -1046,7 +1046,11 @@ int __uio_register_device(struct module *owner, > } > } > > +#if defined(CONFIG_UIO_DMABUF_HEAP) > + return add_uio_heap(idev); > +#else > return 0; > +#endif > > err_request_irq: > uio_dev_del_attributes(idev); > diff --git a/drivers/uio/uio_heap.c b/drivers/uio/uio_heap.c > new file mode 100644 > index > 0000000000000000000000000000000000000000..2e836b503458e280babba0e0adc4f6d8344efc82 > --- /dev/null > +++ b/drivers/uio/uio_heap.c > @@ -0,0 +1,120 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include <linux/dma-buf.h> > +#include <linux/dma-heap.h> > +#include <linux/uio_driver.h> > + > +struct uio_heap { > + struct dma_heap *heap; > + struct device *dev; > +}; > + > +struct uio_heap_buffer { > + struct uio_heap *heap; > + dma_addr_t dma_addr; > + unsigned long len; > + void *vaddr; > +}; > + > +static int uio_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) > +{ > + struct uio_heap_buffer *buffer = dmabuf->priv; > + > + return dma_mmap_coherent(buffer->heap->dev, vma, buffer->vaddr, > + buffer->dma_addr, buffer->len); > +} > + > +static void uio_heap_dma_buf_release(struct dma_buf *dmabuf) > +{ > + struct uio_heap_buffer *buffer = dmabuf->priv; > + > + dma_free_coherent(buffer->heap->dev, buffer->len, buffer->vaddr, > + buffer->dma_addr); > + kfree(buffer); > +} > + > +static int uio_heap_get_dma_addr(struct dma_buf *dmabuf, u64 *addr) > +{ > + struct uio_heap_buffer *buffer = dmabuf->priv; > + > + *addr = buffer->dma_addr; > + return 0; > +} > + > +static const struct dma_buf_ops uio_heap_buf_ops = { > + .mmap = uio_heap_mmap, > + .release = uio_heap_dma_buf_release, > + .get_dma_addr = uio_heap_get_dma_addr, > +}; > + > +static struct dma_buf *uio_heap_allocate(struct dma_heap *heap, > + unsigned long len, > + u32 fd_flags, > + u64 heap_flags) > +{ > + struct uio_heap *uio_heap = dma_heap_get_drvdata(heap); > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct uio_heap_buffer *buffer; > + struct dma_buf *dmabuf; > + > + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); > + if (!buffer) > + return ERR_PTR(-ENOMEM); > + > + dma_set_coherent_mask(uio_heap->dev, DMA_BIT_MASK(32)); > + > + buffer->heap = uio_heap; > + buffer->len = len; > + buffer->vaddr = dma_alloc_coherent(uio_heap->dev, buffer->len, > + &buffer->dma_addr, GFP_KERNEL); > + if (IS_ERR(buffer->vaddr)) > + goto free_buf; > + > + exp_info.exp_name = dma_heap_get_name(heap); > + exp_info.ops = &uio_heap_buf_ops; > + exp_info.size = buffer->len; > + exp_info.flags = fd_flags; > + exp_info.priv = buffer; > + dmabuf = dma_buf_export(&exp_info); > + if (IS_ERR(dmabuf)) > + goto free_dma; > + > + return dmabuf; > + > +free_dma: > + dma_free_coherent(uio_heap->dev, buffer->len, buffer->vaddr, > buffer->dma_addr); > +free_buf: > + kfree(buffer); > + > + return ERR_PTR(-ENOMEM); > +} > + > +static const struct dma_heap_ops uio_heap_ops = { > + .allocate = uio_heap_allocate, > +}; > + > +int add_uio_heap(struct uio_device *uio) > +{ > + struct dma_heap_export_info exp_info; > + struct uio_heap *uio_heap; > + > + uio_heap = kzalloc(sizeof(*uio_heap), GFP_KERNEL); > + if (!uio_heap) > + return -ENOMEM; > + > + uio_heap->dev = &uio->dev; > + > + /* Use device name as heap name */ > + exp_info.name = uio_heap->dev->kobj.name; > + exp_info.ops = &uio_heap_ops; > + exp_info.priv = uio_heap; > + > + uio_heap->heap = dma_heap_add(&exp_info); > + if (IS_ERR(uio_heap->heap)) { > + int ret = PTR_ERR(uio_heap->heap); > + > + kfree(uio_heap); > + return ret; > + } > + > + return 0; > +} > diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h > index > 18238dc8bfd356a20996ba6cd84f1ff508bbb81c..f8b774d2fa1c7de4b6af881f1e53dfa9f25b3dbf > 100644 > --- a/include/linux/uio_driver.h > +++ b/include/linux/uio_driver.h > @@ -143,6 +143,8 @@ extern int __must_check > struct device *parent, > struct uio_info *info); > > +extern int add_uio_heap(struct uio_device *uio); > + > /* use a define to avoid include chaining to get THIS_MODULE */ > > /**