diff options
| author | Marek Szyprowski <m.szyprowski@samsung.com> | 2012-03-23 08:05:14 -0400 |
|---|---|---|
| committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2012-05-21 09:06:09 -0400 |
| commit | bca0fa5f12a6744a2b2e53154af65a51402b3426 (patch) | |
| tree | 3da5a3098d9a9139e7a027cdab1a8ae5386f6be0 /drivers/base | |
| parent | 76e10d158efb6d4516018846f60c2ab5501900bc (diff) | |
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>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/dma-coherent.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index bb0025c510b3..1b85949e3d2f 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | struct dma_coherent_mem { | 10 | struct dma_coherent_mem { |
| 11 | void *virt_base; | 11 | void *virt_base; |
| 12 | dma_addr_t device_base; | 12 | dma_addr_t device_base; |
| 13 | phys_addr_t pfn_base; | ||
| 13 | int size; | 14 | int size; |
| 14 | int flags; | 15 | int flags; |
| 15 | unsigned long *bitmap; | 16 | unsigned long *bitmap; |
| @@ -44,6 +45,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | |||
| 44 | 45 | ||
| 45 | dev->dma_mem->virt_base = mem_base; | 46 | dev->dma_mem->virt_base = mem_base; |
| 46 | dev->dma_mem->device_base = device_addr; | 47 | dev->dma_mem->device_base = device_addr; |
| 48 | dev->dma_mem->pfn_base = PFN_DOWN(bus_addr); | ||
| 47 | dev->dma_mem->size = pages; | 49 | dev->dma_mem->size = pages; |
| 48 | dev->dma_mem->flags = flags; | 50 | dev->dma_mem->flags = flags; |
| 49 | 51 | ||
| @@ -176,3 +178,43 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr) | |||
| 176 | return 0; | 178 | return 0; |
| 177 | } | 179 | } |
| 178 | EXPORT_SYMBOL(dma_release_from_coherent); | 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); | ||
