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); | ||