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