diff options
author | Rebecca Schultz Zavin <rebecca@android.com> | 2013-12-13 14:24:26 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-14 08:55:40 -0800 |
commit | 8898227ed555b477e2989a2a9b984fa37e7a9b42 (patch) | |
tree | 89d553aa01e504c78169f9e26046c7b27e1d40ef /drivers/staging/android/ion/ion_heap.c | |
parent | cd69488c7be3abb0767b49f313b12b8591abe5dc (diff) |
gpu: ion: Refactor common mapping functions out of system heap
The system heap contained several general purpose functions to map
buffers to the kernel and userspace. This patch refactors those
into ion_heap.c so they can be used by other heaps.
Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
[jstultz: modified patch to apply to staging directory]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/android/ion/ion_heap.c')
-rw-r--r-- | drivers/staging/android/ion/ion_heap.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 4f7caa87bca9..441e9ef0b69c 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -15,9 +15,84 @@ */ #include <linux/err.h> +#include <linux/mm.h> +#include <linux/scatterlist.h> +#include <linux/vmalloc.h> #include "ion.h" #include "ion_priv.h" +void *ion_heap_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct scatterlist *sg; + int i, j; + void *vaddr; + pgprot_t pgprot; + struct sg_table *table = buffer->sg_table; + int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + + if (!pages) + return 0; + + if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_writecombine(PAGE_KERNEL); + + for_each_sg(table->sgl, sg, table->nents, i) { + int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE; + struct page *page = sg_page(sg); + BUG_ON(i >= npages); + for (j = 0; j < npages_this_entry; j++) { + *(tmp++) = page++; + } + } + vaddr = vmap(pages, npages, VM_MAP, pgprot); + vfree(pages); + + return vaddr; +} + +void ion_heap_unmap_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + vunmap(buffer->vaddr); +} + +int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + struct sg_table *table = buffer->sg_table; + unsigned long addr = vma->vm_start; + unsigned long offset = vma->vm_pgoff * PAGE_SIZE; + struct scatterlist *sg; + int i; + + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + unsigned long remainder = vma->vm_end - addr; + unsigned long len = sg_dma_len(sg); + + if (offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len = sg_dma_len(sg) - offset; + offset = 0; + } + len = min(len, remainder); + remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + addr += len; + if (addr >= vma->vm_end) + return 0; + } + return 0; +} + struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) { struct ion_heap *heap = NULL; |