Home > Blockchain >  DMA transfer form kernel to user space
DMA transfer form kernel to user space

Time:01-15

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.

CodePudding user response:

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.

  •  Tags:  
  • Related