diff options
Diffstat (limited to 'drivers/staging/android/ion/ion_system_heap.c')
-rw-r--r-- | drivers/staging/android/ion/ion_system_heap.c | 134 |
1 files changed, 76 insertions, 58 deletions
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index ecae16f2109..05e9dc93980 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -26,11 +26,9 @@ #include "ion.h" #include "ion_priv.h" -static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | - __GFP_NOWARN | __GFP_NORETRY) & - ~__GFP_WAIT; -static unsigned int low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | - __GFP_NOWARN); +static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN | + __GFP_NORETRY) & ~__GFP_WAIT; +static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN); static const unsigned int orders[] = {8, 4, 0}; static const int num_orders = ARRAY_SIZE(orders); static int order_to_index(unsigned int order) @@ -74,14 +72,14 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, if (order > 4) gfp_flags = high_order_gfp_flags; - page = ion_heap_alloc_pages(buffer, gfp_flags, order); + page = alloc_pages(gfp_flags, order); if (!page) - return 0; + return NULL; ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order, DMA_BIDIRECTIONAL); } if (!page) - return 0; + return NULL; return page; } @@ -91,15 +89,10 @@ static void free_buffer_page(struct ion_system_heap *heap, unsigned int order) { bool cached = ion_buffer_cached(buffer); - bool split_pages = ion_buffer_fault_user_mappings(buffer); - int i; if (!cached) { struct ion_page_pool *pool = heap->pools[order_to_index(order)]; ion_page_pool_free(pool, page); - } else if (split_pages) { - for (i = 0; i < (1 << order); i++) - __free_page(page + i); } else { __free_pages(page, order); } @@ -150,9 +143,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap, long size_remaining = PAGE_ALIGN(size); unsigned int max_order = orders[0]; + if (align > PAGE_SIZE) + return -EINVAL; + INIT_LIST_HEAD(&pages); while (size_remaining > 0) { - info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order); + info = alloc_largest_available(sys_heap, buffer, size_remaining, + max_order); if (!info) goto err; list_add_tail(&info->list, &pages); @@ -160,8 +157,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap, max_order = info->order; i++; } - - table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) goto err; @@ -183,14 +179,14 @@ static int ion_system_heap_allocate(struct ion_heap *heap, err1: kfree(table); err: - list_for_each_entry(info, &pages, list) { + list_for_each_entry_safe(info, tmp_info, &pages, list) { free_buffer_page(sys_heap, buffer, info->page, info->order); kfree(info); } return -ENOMEM; } -void ion_system_heap_free(struct ion_buffer *buffer) +static void ion_system_heap_free(struct ion_buffer *buffer) { struct ion_heap *heap = buffer->heap; struct ion_system_heap *sys_heap = container_of(heap, @@ -214,14 +210,14 @@ void ion_system_heap_free(struct ion_buffer *buffer) kfree(table); } -struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { return buffer->priv_virt; } -void ion_system_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static void ion_system_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { return; } @@ -362,61 +358,83 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap, unsigned long align, unsigned long flags) { - buffer->priv_virt = kzalloc(len, GFP_KERNEL); - if (!buffer->priv_virt) + int order = get_order(len); + struct page *page; + struct sg_table *table; + unsigned long i; + int ret; + + if (align > (PAGE_SIZE << order)) + return -EINVAL; + + page = alloc_pages(low_order_gfp_flags, order); + if (!page) return -ENOMEM; + + split_page(page, order); + + len = PAGE_ALIGN(len); + for (i = len >> PAGE_SHIFT; i < (1 << order); i++) + __free_page(page + i); + + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) { + ret = -ENOMEM; + goto out; + } + + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto out; + + sg_set_page(table->sgl, page, len, 0); + + buffer->priv_virt = table; + + ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL); + return 0; + +out: + for (i = 0; i < len >> PAGE_SHIFT; i++) + __free_page(page + i); + kfree(table); + return ret; } -void ion_system_contig_heap_free(struct ion_buffer *buffer) +static void ion_system_contig_heap_free(struct ion_buffer *buffer) { - kfree(buffer->priv_virt); + struct sg_table *table = buffer->priv_virt; + struct page *page = sg_page(table->sgl); + unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + unsigned long i; + + for (i = 0; i < pages; i++) + __free_page(page + i); + sg_free_table(table); + kfree(table); } static int ion_system_contig_heap_phys(struct ion_heap *heap, struct ion_buffer *buffer, ion_phys_addr_t *addr, size_t *len) { - *addr = virt_to_phys(buffer->priv_virt); + struct sg_table *table = buffer->priv_virt; + struct page *page = sg_page(table->sgl); + *addr = page_to_phys(page); *len = buffer->size; return 0; } -struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, +static struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, struct ion_buffer *buffer) { - struct sg_table *table; - int ret; - - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); - if (!table) - return ERR_PTR(-ENOMEM); - ret = sg_alloc_table(table, 1, GFP_KERNEL); - if (ret) { - kfree(table); - return ERR_PTR(ret); - } - sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, - 0); - return table; -} - -void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - sg_free_table(buffer->sg_table); - kfree(buffer->sg_table); + return buffer->priv_virt; } -int ion_system_contig_heap_map_user(struct ion_heap *heap, - struct ion_buffer *buffer, - struct vm_area_struct *vma) +static void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { - unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); - return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - } static struct ion_heap_ops kmalloc_ops = { @@ -427,7 +445,7 @@ static struct ion_heap_ops kmalloc_ops = { .unmap_dma = ion_system_contig_heap_unmap_dma, .map_kernel = ion_heap_map_kernel, .unmap_kernel = ion_heap_unmap_kernel, - .map_user = ion_system_contig_heap_map_user, + .map_user = ion_heap_map_user, }; struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) |