Commit bca0fa5f12a6744a2b2e53154af65a51402b3426
1 parent
76e10d158e
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 | */ |