• Ian Abbott's avatar
    staging: comedi: use dma_mmap_coherent for DMA-able buffer mmap · e3647214
    Ian Abbott authored
    Comedi's acquisition buffer allocation code can allocate the buffer from
    normal kernel memory or from DMA coherent memory depending on the
    `dma_async_dir` value in the comedi subdevice.  (A value of `DMA_NONE`
    causes the buffer to be allocated from normal kernel memory.  Other
    values cause the buffer to be allocated from DMA coherent memory.)   The
    buffer currently consists of a bunch of page-sized blocks that are
    vmap'ed into a contiguous range of virtual addresses. The pages are also
    mmap'able into user address space.  For DMA'able buffers, these
    page-sized blocks are allocated by `dma_alloc_coherent()`.
    
    For DMA-able buffers, the DMA API is currently abused in various ways,
    the most serious abuse being the calling of `virt_to_page()` on the
    blocks allocated by `dma_alloc_coherent()` and passing those pages to
    `vmap()` (for mapping to the kernels vmalloc address space) and via
    `page_to_pfn()` to `remap_pfn_range()` (for mmap'ing to user space).  it
    also uses the `__GFP_COMP` flag when allocating the blocks, and marks
    the allocated pages as reserved (which is unnecessary for DMA coherent
    allocations).
    
    The code can be changed to get rid of the vmap'ed address altogether if
    necessary, since there are only a few places in the comedi code that use
    the vmap'ed address directly and we also keep a list of the kernel
    addresses for the individual pages prior to the vmap operation. This
    would add some run-time overhead to buffer accesses.  The real killer is
    the mmap operation.
    
    For mmap, the address range specified in the VMA needs to be mmap'ed to
    the individually allocated page-sized blocks.  That is not a problem
    when the pages are allocated from normal kernel memory as the individual
    pages can be remapped by `remap_pfn_range()`, but it is a problem when
    the page-sized blocks are allocated by `dma_alloc_coherent()` because
    the DMA API currently has no support for splitting a VMA across multiple
    blocks of DMA coherent memory (or rather, no support for mapping part of
    a VMA range to a single block of DMA coherent memory).
    
    In order to comply with the DMA API and allow the buffer to be mmap'ed,
    the buffer needs to be allocated as a single block by a single call to
    `dma_alloc_coherent()`, freed by a single call to `dma_free_coherent()`,
    and mmap'ed to user space by a single call to `dma_mmap_coherent()`.
    This patch changes the buffer allocation, freeing, and mmap'ing code to
    do that, with the unfortunate consequence that buffer allocation is more
    likely to fail.  It also no longer uses the `__GFP_COMP` flag when
    allocating DMA coherent memory, no longer marks the
    allocated pages of DMA coherent memory as reserved, and no longer vmap's
    the DMA coherent memory pages (since they are contiguous anyway).
    Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
    Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    e3647214
comedi_fops.c 70.7 KB