|
@@ -360,29 +360,69 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
|
|
|
unsigned long flags)
|
|
|
{
|
|
|
int order = get_order(len);
|
|
|
+ struct page *page;
|
|
|
+ struct sg_table *table;
|
|
|
+ unsigned long i;
|
|
|
+ int ret;
|
|
|
|
|
|
if (align > (PAGE_SIZE << order))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (ion_buffer_fault_user_mappings(buffer))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- buffer->priv_virt = kzalloc(len, GFP_KERNEL);
|
|
|
- if (!buffer->priv_virt)
|
|
|
+ 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)
|
|
|
{
|
|
|
- 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;
|
|
|
}
|
|
@@ -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 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;
|
|
|
+ return buffer->priv_virt;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
static struct ion_heap_ops kmalloc_ops = {
|