Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

uio: introduce UIO_MEM_DMA_COHERENT type

Add a UIO memtype specifically for sharing dma_alloc_coherent
memory with userspace, backed by dma_mmap_coherent.

This is mainly for the bnx2/bnx2x/bnx2i "cnic" interface, although there
are a few other uio drivers which map dma_alloc_coherent memory and will
be converted to use dma_mmap_coherent as well.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Chris Leech <cleech@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20240205200137.138302-1-cleech@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Chris Leech and committed by
Greg Kroah-Hartman
576882ef 0e439ba3

+60
+47
drivers/uio/uio.c
··· 24 24 #include <linux/kobject.h> 25 25 #include <linux/cdev.h> 26 26 #include <linux/uio_driver.h> 27 + #include <linux/dma-mapping.h> 27 28 28 29 #define UIO_MAX_DEVICES (1U << MINORBITS) 29 30 ··· 760 759 vma->vm_page_prot); 761 760 } 762 761 762 + static int uio_mmap_dma_coherent(struct vm_area_struct *vma) 763 + { 764 + struct uio_device *idev = vma->vm_private_data; 765 + struct uio_mem *mem; 766 + void *addr; 767 + int ret = 0; 768 + int mi; 769 + 770 + mi = uio_find_mem_index(vma); 771 + if (mi < 0) 772 + return -EINVAL; 773 + 774 + mem = idev->info->mem + mi; 775 + 776 + if (mem->addr & ~PAGE_MASK) 777 + return -ENODEV; 778 + if (mem->dma_addr & ~PAGE_MASK) 779 + return -ENODEV; 780 + if (!mem->dma_device) 781 + return -ENODEV; 782 + if (vma->vm_end - vma->vm_start > mem->size) 783 + return -EINVAL; 784 + 785 + dev_warn(mem->dma_device, 786 + "use of UIO_MEM_DMA_COHERENT is highly discouraged"); 787 + 788 + /* 789 + * UIO uses offset to index into the maps for a device. 790 + * We need to clear vm_pgoff for dma_mmap_coherent. 791 + */ 792 + vma->vm_pgoff = 0; 793 + 794 + addr = (void *)mem->addr; 795 + ret = dma_mmap_coherent(mem->dma_device, 796 + vma, 797 + addr, 798 + mem->dma_addr, 799 + vma->vm_end - vma->vm_start); 800 + vma->vm_pgoff = mi; 801 + 802 + return ret; 803 + } 804 + 763 805 static int uio_mmap(struct file *filep, struct vm_area_struct *vma) 764 806 { 765 807 struct uio_listener *listener = filep->private_data; ··· 849 805 case UIO_MEM_LOGICAL: 850 806 case UIO_MEM_VIRTUAL: 851 807 ret = uio_mmap_logical(vma); 808 + break; 809 + case UIO_MEM_DMA_COHERENT: 810 + ret = uio_mmap_dma_coherent(vma); 852 811 break; 853 812 default: 854 813 ret = -EINVAL;
+13
include/linux/uio_driver.h
··· 28 28 * logical, virtual, or physical & phys_addr_t 29 29 * should always be large enough to handle any of 30 30 * the address types) 31 + * @dma_addr: DMA handle set by dma_alloc_coherent, used with 32 + * UIO_MEM_DMA_COHERENT only (@addr should be the 33 + * void * returned from the same dma_alloc_coherent call) 31 34 * @offs: offset of device memory within the page 32 35 * @size: size of IO (multiple of page size) 33 36 * @memtype: type of memory addr points to 34 37 * @internal_addr: ioremap-ped version of addr, for driver internal use 38 + * @dma_device: device struct that was passed to dma_alloc_coherent, 39 + * used with UIO_MEM_DMA_COHERENT only 35 40 * @map: for use by the UIO core only. 36 41 */ 37 42 struct uio_mem { 38 43 const char *name; 39 44 phys_addr_t addr; 45 + dma_addr_t dma_addr; 40 46 unsigned long offs; 41 47 resource_size_t size; 42 48 int memtype; 43 49 void __iomem *internal_addr; 50 + struct device *dma_device; 44 51 struct uio_map *map; 45 52 }; 46 53 ··· 165 158 #define UIO_MEM_LOGICAL 2 166 159 #define UIO_MEM_VIRTUAL 3 167 160 #define UIO_MEM_IOVA 4 161 + /* 162 + * UIO_MEM_DMA_COHERENT exists for legacy drivers that had been getting by with 163 + * improperly mapping DMA coherent allocations through the other modes. 164 + * Do not use in new drivers. 165 + */ 166 + #define UIO_MEM_DMA_COHERENT 5 168 167 169 168 /* defines for uio_port->porttype */ 170 169 #define UIO_PORT_NONE 0