I am trying to realize DMA in Xilinx, using DMA Engine. FPGA guys give me an AXI DMA IP-Core with DMA support, so I need to write a driver, which will transfer data from kernel to user space buffer. Here you can find an example of the driver and app, which works so:
1) process opens /dev/device_file that represents the driver
2) it maps kernel coherent memory, allocated via dma_alloc_coherent
3) fills buffer with some data
4) calls ioctl() to start dma transfer
It works fine, but i have such question - can I transfer user space buffer to kernel space (via read function from file_operations structure), prepare it (shift by PAGE_SIZE or something else) and execute dma operation ? I don't understand how to make user space memory available in DMA operation.
You probably want to implement mmap
method of struct file_operations
. Consider:
static int
sample_drv_mem_mmap(struct file *filep, struct vm_area_struct *vma)
{
/*
* Set your "dev" pointer here (the one you used
* for dma_alloc_coherent() invocation)
*/
struct device *dev;
/*
* Set DMA address here (the one you obtained with
* dma_alloc_coherent() via its third argument)
*/
dma_addr_t dma_addr;
/* Set your DMA buffer size here */
size_t dma_size;
/* Physical page frame number to be derived from "dma_addr" */
unsigned long pfn;
/* Check the buffer size requested by the user */
if (vma->vm_end - vma->vm_start > dma_size)
return -EINVAL;
/*
* For the sake of simplicity, do not let the user specify an offset;
* you may want to take care of that in later versions of your code
*/
if (vma->vm_pgoff != 0)
return -EINVAL;
pfn = PHYS_PFN(dma_to_phys(dev, dma_addr));
return remap_pfn_range(vma, vma->vm_start, pfn,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
/* ... */
static const struct file_operations sample_drv_fops = {
/* ... */
.mmap = sample_drv_mem_mmap,
/* ... */
};
Long story short, the idea is to convert the DMA (bus) address you have to a kernel physical address and then use remap_pfn_range()
to do the actual mapping between the kernel and the userland.
In the user application, one should invoke mmap()
to request the mapping (instead of the read / write
approach) For more information on that, please refer to man 2 mmap
on your system.