Commit 5c6a4705 authored by Colin Cross's avatar Colin Cross Committed by Greg Kroah-Hartman

ion: use alloc_pages in system contig heap

There is no reason to use kzalloc, just call alloc_pages directly.
Change the GFP from GFP_KERNEL to include __GFP_HIGH, to allow it
to return contiguous pages from highmem.  virt_to_* functions
aren't valid on highmem pages, so store the struct page * in an
sg_table in buffer->priv_virt like most other heaps, and replace
virt_to_* with page_to_*.
Signed-off-by: default avatarColin Cross <ccross@android.com>
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a053b6ac
...@@ -360,29 +360,69 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap, ...@@ -360,29 +360,69 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
unsigned long flags) unsigned long flags)
{ {
int order = get_order(len); int order = get_order(len);
struct page *page;
struct sg_table *table;
unsigned long i;
int ret;
if (align > (PAGE_SIZE << order)) if (align > (PAGE_SIZE << order))
return -EINVAL; return -EINVAL;
if (ion_buffer_fault_user_mappings(buffer)) page = alloc_pages(low_order_gfp_flags, order);
return -EINVAL; if (!page)
buffer->priv_virt = kzalloc(len, GFP_KERNEL);
if (!buffer->priv_virt)
return -ENOMEM; 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; 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) 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, static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len) 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; *len = buffer->size;
return 0; return 0;
} }
...@@ -390,27 +430,12 @@ static int ion_system_contig_heap_phys(struct ion_heap *heap, ...@@ -390,27 +430,12 @@ static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer) struct ion_buffer *buffer)
{ {
struct sg_table *table; return buffer->priv_virt;
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, void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer) struct ion_buffer *buffer)
{ {
sg_free_table(buffer->sg_table);
kfree(buffer->sg_table);
} }
static struct ion_heap_ops kmalloc_ops = { static struct ion_heap_ops kmalloc_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment