aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/android/ion/ion_heap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/android/ion/ion_heap.c')
-rw-r--r--drivers/staging/android/ion/ion_heap.c100
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);