dma_mmap_coherent () is defined in dma-mapping.h as a wrapper around dma_mmap_attrs (). dma_mmap_attrs () tries to find out if the dma_mmap_ops set is installed associated with the device (struct device * dev) you are working with if it does not call dma_common_mmap (), which ultimately leads to calling remap_pfn_range () after setting the page protection as not cached ( see dma_common_mmap () in dma-mapping.c).
As for the general overview of how memory core memory works with user space, the following is my quick and easy way to mmap'ing DMA buffers from user space:
Allocate the buffer through IOCTL and assign a buffer identifier for each buffer with some flags:
static int my_ioctl_alloc(struct my_struct *info, struct alloc_info *alloc) { ... info->buf->kvaddr = dma_alloc_coherent(dev, alloc->size, info->buf->phyaddr, GFP_KERNEL); info->buf->buf_id = alloc->buf_id; ... }
Define mmap operating files:
static const struct file_operations my_fops = { .open = my_open, .close = my_close, .mmap = my_mmap, .unlocked_ioctl = my_ioctl, };
Remember to register the my_fops structure somewhere in your driver validation function.
Implement mmap operational files:
static int my_mmap(struct file *fptr, struct vm_area_struct *vma) { ... desc_id = vma->vm_pgoff; buf = find_buf_by_id(alloc, desc_id); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ret = remap_pfn_range(vma, vma->vm_start, buf->phyaddr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); if (ret) { } return 0; }
At the same time, your kernel driver should have a minimum for placing mmap buffers as well. Buffer release is an exercise for bonus points!
In the application, you open the () file and get a valid fd file descriptor, call the IOCTL allocation, and set the buffer identifier before copying to the kernel. In mmap you must specify the buffer identifier through the offset parameter:
mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buffer_id << PAGE_SHIFT);
PAGE_SHIFT is the architecture-dependent MACRO macro time fixed in the kernel. Hope this helps.
This is not checkpatch.pl compatible code, and it is not the best practice, but I know how to do it. Comments / improvements / suggestions are welcome!
See Linux Device Drivers - Chapter 15: Map and DMA Mapping for sample tutorials and good reference information for interested readers.
Rohit source share