Commit bca0fa5f12a6744a2b2e53154af65a51402b3426

Authored by Marek Szyprowski
1 parent 76e10d158e

common: add dma_mmap_from_coherent() function

Add a common helper for dma-mapping core for mapping a coherent buffer
to userspace.

Reported-by: Subash Patel <subashrp@gmail.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Tested-By: Subash Patel <subash.ramaswamy@linaro.org>

Showing 2 changed files with 45 additions and 1 deletions Side-by-side Diff

drivers/base/dma-coherent.c
... ... @@ -10,6 +10,7 @@
10 10 struct dma_coherent_mem {
11 11 void *virt_base;
12 12 dma_addr_t device_base;
  13 + phys_addr_t pfn_base;
13 14 int size;
14 15 int flags;
15 16 unsigned long *bitmap;
... ... @@ -44,6 +45,7 @@
44 45  
45 46 dev->dma_mem->virt_base = mem_base;
46 47 dev->dma_mem->device_base = device_addr;
  48 + dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
47 49 dev->dma_mem->size = pages;
48 50 dev->dma_mem->flags = flags;
49 51  
... ... @@ -176,4 +178,44 @@
176 178 return 0;
177 179 }
178 180 EXPORT_SYMBOL(dma_release_from_coherent);
  181 +
  182 +/**
  183 + * dma_mmap_from_coherent() - try to mmap the memory allocated from
  184 + * per-device coherent memory pool to userspace
  185 + * @dev: device from which the memory was allocated
  186 + * @vma: vm_area for the userspace memory
  187 + * @vaddr: cpu address returned by dma_alloc_from_coherent
  188 + * @size: size of the memory buffer allocated by dma_alloc_from_coherent
  189 + *
  190 + * This checks whether the memory was allocated from the per-device
  191 + * coherent memory pool and if so, maps that memory to the provided vma.
  192 + *
  193 + * Returns 1 if we correctly mapped the memory, or 0 if
  194 + * dma_release_coherent() should proceed with mapping memory from
  195 + * generic pools.
  196 + */
  197 +int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
  198 + void *vaddr, size_t size, int *ret)
  199 +{
  200 + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
  201 +
  202 + if (mem && vaddr >= mem->virt_base && vaddr + size <=
  203 + (mem->virt_base + (mem->size << PAGE_SHIFT))) {
  204 + unsigned long off = vma->vm_pgoff;
  205 + int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
  206 + int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
  207 + int count = size >> PAGE_SHIFT;
  208 +
  209 + *ret = -ENXIO;
  210 + if (off < count && user_count <= count - off) {
  211 + unsigned pfn = mem->pfn_base + start + off;
  212 + *ret = remap_pfn_range(vma, vma->vm_start, pfn,
  213 + user_count << PAGE_SHIFT,
  214 + vma->vm_page_prot);
  215 + }
  216 + return 1;
  217 + }
  218 + return 0;
  219 +}
  220 +EXPORT_SYMBOL(dma_mmap_from_coherent);
include/asm-generic/dma-coherent.h
... ... @@ -3,13 +3,15 @@
3 3  
4 4 #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
5 5 /*
6   - * These two functions are only for dma allocator.
  6 + * These three functions are only for dma allocator.
7 7 * Don't use them in device drivers.
8 8 */
9 9 int dma_alloc_from_coherent(struct device *dev, ssize_t size,
10 10 dma_addr_t *dma_handle, void **ret);
11 11 int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
12 12  
  13 +int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
  14 + void *cpu_addr, size_t size, int *ret);
13 15 /*
14 16 * Standard interface
15 17 */