diff options
Diffstat (limited to 'drivers/staging/android/ion')
-rw-r--r-- | drivers/staging/android/ion/ion.c | 14 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_carveout_heap.c | 2 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_chunk_heap.c | 2 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_heap.c | 2 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_page_pool.c | 49 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_priv.h | 3 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_system_heap.c | 68 |
7 files changed, 73 insertions, 67 deletions
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 3d5bf1472236..389b8f67a2ec 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -408,6 +408,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, while (n) { struct ion_handle *entry = rb_entry(n, struct ion_handle, node); + if (buffer < entry->buffer) n = n->rb_left; else if (buffer > entry->buffer) @@ -626,6 +627,10 @@ static void ion_handle_kmap_put(struct ion_handle *handle) { struct ion_buffer *buffer = handle->buffer; + if (!handle->kmap_cnt) { + WARN(1, "%s: Double unmap detected! bailing...\n", __func__); + return; + } handle->kmap_cnt--; if (!handle->kmap_cnt) ion_buffer_kmap_put(buffer); @@ -720,9 +725,11 @@ static int ion_get_client_serial(const struct rb_root *root, { int serial = -1; struct rb_node *node; + for (node = rb_first(root); node; node = rb_next(node)) { struct ion_client *client = rb_entry(node, struct ion_client, node); + if (strcmp(client->name, name)) continue; serial = max(serial, client->display_serial); @@ -1035,12 +1042,14 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) static void ion_dma_buf_release(struct dma_buf *dmabuf) { struct ion_buffer *buffer = dmabuf->priv; + ion_buffer_put(buffer); } static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) { struct ion_buffer *buffer = dmabuf->priv; + return buffer->vaddr + offset * PAGE_SIZE; } @@ -1292,6 +1301,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case ION_IOC_IMPORT: { struct ion_handle *handle; + handle = ion_import_dma_buf(client, data.fd.fd); if (IS_ERR(handle)) ret = PTR_ERR(handle); @@ -1393,6 +1403,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) struct ion_client *client = rb_entry(n, struct ion_client, node); size_t size = ion_debug_heap_total(client, heap->id); + if (!size) continue; if (client->task) { @@ -1516,6 +1527,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) if (!debug_file) { char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap debugfs at %s/%s\n", path, heap->name); @@ -1531,6 +1543,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) &debug_shrink_fops); if (!debug_file) { char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap shrinker debugfs at %s/%s\n", path, debug_name); @@ -1606,6 +1619,7 @@ void __init ion_reserve(struct ion_platform_data *data) if (data->heaps[i].base == 0) { phys_addr_t paddr; + paddr = memblock_alloc_base(data->heaps[i].size, data->heaps[i].align, MEMBLOCK_ALLOC_ANYWHERE); diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index 3cb05b9b0e93..dcb6f2196c87 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -81,7 +81,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, if (align > PAGE_SIZE) return -EINVAL; - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) return -ENOMEM; ret = sg_alloc_table(table, 1, GFP_KERNEL); diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index d40f5f831808..3f2c12ba4d14 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -55,7 +55,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap, if (allocated_size > chunk_heap->size - chunk_heap->allocated) return -ENOMEM; - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) return -ENOMEM; ret = sg_alloc_table(table, num_chunks, GFP_KERNEL); diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index bdc6a28ba8c9..4605e04712aa 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -48,6 +48,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, for_each_sg(table->sgl, sg, table->nents, i) { 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++) *(tmp++) = page++; @@ -105,6 +106,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot) { void *addr = vm_map_ram(pages, num, -1, pgprot); + if (!addr) return -ENOMEM; memset(addr, 0, PAGE_SIZE * num); diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index ecb5fc34ec5c..5864f3dfcbc6 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -21,13 +21,9 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/swap.h> #include "ion_priv.h" -struct ion_page_pool_item { - struct page *page; - struct list_head list; -}; - static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) { struct page *page = alloc_pages(pool->gfp_mask, pool->order); @@ -47,19 +43,12 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { - struct ion_page_pool_item *item; - - item = kmalloc(sizeof(struct ion_page_pool_item), GFP_KERNEL); - if (!item) - return -ENOMEM; - mutex_lock(&pool->mutex); - item->page = page; if (PageHighMem(page)) { - list_add_tail(&item->list, &pool->high_items); + list_add_tail(&page->lru, &pool->high_items); pool->high_count++; } else { - list_add_tail(&item->list, &pool->low_items); + list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } mutex_unlock(&pool->mutex); @@ -68,28 +57,23 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) { - struct ion_page_pool_item *item; struct page *page; if (high) { BUG_ON(!pool->high_count); - item = list_first_entry(&pool->high_items, - struct ion_page_pool_item, list); + page = list_first_entry(&pool->high_items, struct page, lru); pool->high_count--; } else { BUG_ON(!pool->low_count); - item = list_first_entry(&pool->low_items, - struct ion_page_pool_item, list); + page = list_first_entry(&pool->low_items, struct page, lru); pool->low_count--; } - list_del(&item->list); - page = item->page; - kfree(item); + list_del(&page->lru); return page; } -void *ion_page_pool_alloc(struct ion_page_pool *pool) +struct page *ion_page_pool_alloc(struct ion_page_pool *pool) { struct page *page = NULL; @@ -112,6 +96,8 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) { int ret; + BUG_ON(pool->order != compound_order(page)); + ret = ion_page_pool_add(pool, page); if (ret) ion_page_pool_free_pages(pool, page); @@ -119,12 +105,12 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) static int ion_page_pool_total(struct ion_page_pool *pool, bool high) { - int total = 0; + int count = pool->low_count; + + if (high) + count += pool->high_count; - total += high ? (pool->high_count + pool->low_count) * - (1 << pool->order) : - pool->low_count * (1 << pool->order); - return total; + return count << pool->order; } int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, @@ -133,7 +119,10 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int freed; bool high; - high = !!(gfp_mask & __GFP_HIGHMEM); + if (current_is_kswapd()) + high = 1; + else + high = !!(gfp_mask & __GFP_HIGHMEM); if (nr_to_scan == 0) return ion_page_pool_total(pool, high); @@ -167,7 +156,7 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) pool->low_count = 0; INIT_LIST_HEAD(&pool->low_items); INIT_LIST_HEAD(&pool->high_items); - pool->gfp_mask = gfp_mask; + pool->gfp_mask = gfp_mask | __GFP_COMP; pool->order = order; mutex_init(&pool->mutex); plist_node_init(&pool->list, order); diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 1eba3f2076a9..c8f01757abfa 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -178,6 +178,7 @@ struct ion_heap { spinlock_t free_lock; wait_queue_head_t waitqueue; struct task_struct *task; + int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); }; @@ -377,7 +378,7 @@ struct ion_page_pool { struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); void ion_page_pool_destroy(struct ion_page_pool *); -void *ion_page_pool_alloc(struct ion_page_pool *); +struct page *ion_page_pool_alloc(struct ion_page_pool *); void ion_page_pool_free(struct ion_page_pool *, struct page *); /** ion_page_pool_shrink - shrinks the size of the memory cached in the pool diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index c92363356ae1..cb7ae08a5e24 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -34,6 +34,7 @@ static const int num_orders = ARRAY_SIZE(orders); static int order_to_index(unsigned int order) { int i; + for (i = 0; i < num_orders; i++) if (order == orders[i]) return i; @@ -41,7 +42,7 @@ static int order_to_index(unsigned int order) return -1; } -static unsigned int order_to_size(int order) +static inline unsigned int order_to_size(int order) { return PAGE_SIZE << order; } @@ -72,14 +73,12 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, if (order > 4) gfp_flags = high_order_gfp_flags; - page = alloc_pages(gfp_flags, order); + page = alloc_pages(gfp_flags | __GFP_COMP, order); if (!page) return NULL; ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order, DMA_BIDIRECTIONAL); } - if (!page) - return NULL; return page; } @@ -92,6 +91,7 @@ static void free_buffer_page(struct ion_system_heap *heap, if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) { struct ion_page_pool *pool = heap->pools[order_to_index(order)]; + ion_page_pool_free(pool, page); } else { __free_pages(page, order); @@ -124,7 +124,6 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap, info->page = page; info->order = orders[i]; - INIT_LIST_HEAD(&info->list); return info; } kfree(info); @@ -142,7 +141,6 @@ static int ion_system_heap_allocate(struct ion_heap *heap, heap); struct sg_table *table; struct scatterlist *sg; - int ret; struct list_head pages; struct page_info *info, *tmp_info; int i = 0; @@ -160,24 +158,23 @@ static int ion_system_heap_allocate(struct ion_heap *heap, info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order); if (!info) - goto err; + goto free_pages; list_add_tail(&info->list, &pages); - size_remaining -= (1 << info->order) * PAGE_SIZE; + size_remaining -= PAGE_SIZE << info->order; max_order = info->order; i++; } - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) - goto err; + goto free_pages; - ret = sg_alloc_table(table, i, GFP_KERNEL); - if (ret) - goto err1; + if (sg_alloc_table(table, i, GFP_KERNEL)) + goto free_table; sg = table->sgl; list_for_each_entry_safe(info, tmp_info, &pages, list) { struct page *page = info->page; - sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, 0); + sg_set_page(sg, page, PAGE_SIZE << info->order, 0); sg = sg_next(sg); list_del(&info->list); kfree(info); @@ -185,9 +182,10 @@ static int ion_system_heap_allocate(struct ion_heap *heap, buffer->priv_virt = table; return 0; -err1: + +free_table: kfree(table); -err: +free_pages: list_for_each_entry_safe(info, tmp_info, &pages, list) { free_buffer_page(sys_heap, buffer, info->page, info->order); kfree(info); @@ -197,14 +195,12 @@ err: 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, + struct ion_system_heap *sys_heap = container_of(buffer->heap, struct ion_system_heap, heap); struct sg_table *table = buffer->sg_table; bool cached = ion_buffer_cached(buffer); struct scatterlist *sg; - LIST_HEAD(pages); int i; /* uncached pages come from the page pools, zero them before returning @@ -242,6 +238,7 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->pools[i]; + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); } @@ -267,14 +264,16 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, struct ion_system_heap, heap); int i; + for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->pools[i]; + seq_printf(s, "%d order %u highmem pages in pool = %lu total\n", pool->high_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->high_count); + (PAGE_SIZE << pool->order) * pool->high_count); seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n", pool->low_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->low_count); + (PAGE_SIZE << pool->order) * pool->low_count); } return 0; } @@ -293,7 +292,7 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders, GFP_KERNEL); if (!heap->pools) - goto err_alloc_pools; + goto free_heap; for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool; gfp_t gfp_flags = low_order_gfp_flags; @@ -302,18 +301,18 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) gfp_flags = high_order_gfp_flags; pool = ion_page_pool_create(gfp_flags, orders[i]); if (!pool) - goto err_create_pool; + goto destroy_pools; heap->pools[i] = pool; } heap->heap.debug_show = ion_system_heap_debug_show; return &heap->heap; -err_create_pool: - for (i = 0; i < num_orders; i++) - if (heap->pools[i]) - ion_page_pool_destroy(heap->pools[i]); + +destroy_pools: + while (i--) + ion_page_pool_destroy(heap->pools[i]); kfree(heap->pools); -err_alloc_pools: +free_heap: kfree(heap); return ERR_PTR(-ENOMEM); } @@ -356,15 +355,15 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap, for (i = len >> PAGE_SHIFT; i < (1 << order); i++) __free_page(page + i); - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) { ret = -ENOMEM; - goto out; + goto free_pages; } ret = sg_alloc_table(table, 1, GFP_KERNEL); if (ret) - goto out; + goto free_table; sg_set_page(table->sgl, page, len, 0); @@ -374,10 +373,12 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap, return 0; -out: +free_table: + kfree(table); +free_pages: for (i = 0; i < len >> PAGE_SHIFT; i++) __free_page(page + i); - kfree(table); + return ret; } @@ -443,4 +444,3 @@ void ion_system_contig_heap_destroy(struct ion_heap *heap) { kfree(heap); } - |