diff options
author | Mark Brown <broonie@linaro.org> | 2013-12-13 18:50:12 +0000 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-12-13 18:50:12 +0000 |
commit | 679160a872dfe88bf34e50f1939e190ba59e534e (patch) | |
tree | fe342d02e224d006a23745a657148ce62b54fee4 /drivers/staging/android/ion/ion_heap.c | |
parent | eed4bafd63b5584adb832a582a931ecba41dec55 (diff) | |
parent | 8f1c42284159ebd6851e1e75507f2ad6fba87d0f (diff) |
Merge branch 'android-3.10' of https://android.googlesource.com/kernel/common into lsk-v3.10-aospv3.10/topic/aosp
Diffstat (limited to 'drivers/staging/android/ion/ion_heap.c')
-rw-r--r-- | drivers/staging/android/ion/ion_heap.c | 100 |
1 files changed, 47 insertions, 53 deletions
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index f32f4e69765..5b01e9e30a4 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -38,7 +38,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, struct page **tmp = pages; if (!pages) - return 0; + return NULL; if (buffer->flags & ION_FLAG_CACHED) pgprot = PAGE_KERNEL; @@ -49,9 +49,8 @@ void *ion_heap_map_kernel(struct ion_heap *heap, int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; struct page *page = sg_page(sg); BUG_ON(i >= npages); - for (j = 0; j < npages_this_entry; j++) { + for (j = 0; j < npages_this_entry; j++) *(tmp++) = page++; - } } vaddr = vmap(pages, npages, VM_MAP, pgprot); vfree(pages); @@ -76,6 +75,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long offset = vma->vm_pgoff * PAGE_SIZE; struct scatterlist *sg; int i; + int ret; for_each_sg(table->sgl, sg, table->nents, i) { struct page *page = sg_page(sg); @@ -91,8 +91,10 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, offset = 0; } len = min(len, remainder); - remap_pfn_range(vma, addr, page_to_pfn(page), len, + ret = remap_pfn_range(vma, addr, page_to_pfn(page), len, vma->vm_page_prot); + if (ret) + return ret; addr += len; if (addr >= vma->vm_end) return 0; @@ -100,71 +102,63 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, return 0; } -int ion_heap_buffer_zero(struct ion_buffer *buffer) +static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot) { - struct sg_table *table = buffer->sg_table; - pgprot_t pgprot; - struct scatterlist *sg; - struct vm_struct *vm_struct; - int i, j, ret = 0; - - if (buffer->flags & ION_FLAG_CACHED) - pgprot = PAGE_KERNEL; - else - pgprot = pgprot_writecombine(PAGE_KERNEL); - - vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC); - if (!vm_struct) + void *addr = vm_map_ram(pages, num, -1, pgprot); + if (!addr) return -ENOMEM; + memset(addr, 0, PAGE_SIZE * num); + vm_unmap_ram(addr, num); - for_each_sg(table->sgl, sg, table->nents, i) { - struct page *page = sg_page(sg); - unsigned long len = sg->length; + return 0; +} - for (j = 0; j < len / PAGE_SIZE; j++) { - struct page *sub_page = page + j; - struct page **pages = &sub_page; - ret = map_vm_area(vm_struct, pgprot, &pages); +static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents, + pgprot_t pgprot) +{ + int p = 0; + int ret = 0; + struct sg_page_iter piter; + struct page *pages[32]; + + for_each_sg_page(sgl, &piter, nents, 0) { + pages[p++] = sg_page_iter_page(&piter); + if (p == ARRAY_SIZE(pages)) { + ret = ion_heap_clear_pages(pages, p, pgprot); if (ret) - goto end; - memset(vm_struct->addr, 0, PAGE_SIZE); - unmap_kernel_range((unsigned long)vm_struct->addr, - PAGE_SIZE); + return ret; + p = 0; } } -end: - free_vm_area(vm_struct); + if (p) + ret = ion_heap_clear_pages(pages, p, pgprot); + return ret; } -struct page *ion_heap_alloc_pages(struct ion_buffer *buffer, gfp_t gfp_flags, - unsigned int order) +int ion_heap_buffer_zero(struct ion_buffer *buffer) { - struct page *page = alloc_pages(gfp_flags, order); - - if (!page) - return page; + struct sg_table *table = buffer->sg_table; + pgprot_t pgprot; - if (ion_buffer_fault_user_mappings(buffer)) - split_page(page, order); + if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_writecombine(PAGE_KERNEL); - return page; + return ion_heap_sglist_zero(table->sgl, table->nents, pgprot); } -void ion_heap_free_pages(struct ion_buffer *buffer, struct page *page, - unsigned int order) +int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot) { - int i; + struct scatterlist sg; - if (!ion_buffer_fault_user_mappings(buffer)) { - __free_pages(page, order); - return; - } - for (i = 0; i < (1 << order); i++) - __free_page(page + i); + sg_init_table(&sg, 1); + sg_set_page(&sg, page, size, 0); + return ion_heap_sglist_zero(&sg, 1, pgprot); } -void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer) +void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer) { rt_mutex_lock(&heap->lock); list_add(&buffer->list, &heap->free_list); @@ -200,16 +194,16 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) if (total_drained >= size) break; list_del(&buffer->list); - ion_buffer_destroy(buffer); heap->free_list_size -= buffer->size; total_drained += buffer->size; + ion_buffer_destroy(buffer); } rt_mutex_unlock(&heap->lock); return total_drained; } -int ion_heap_deferred_free(void *data) +static int ion_heap_deferred_free(void *data) { struct ion_heap *heap = data; @@ -281,7 +275,7 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) } if (IS_ERR_OR_NULL(heap)) { - pr_err("%s: error creating heap %s type %d base %lu size %u\n", + pr_err("%s: error creating heap %s type %d base %lu size %zu\n", __func__, heap_data->name, heap_data->type, heap_data->base, heap_data->size); return ERR_PTR(-EINVAL); |