ion: Fix DMA operations for ARM64

The ion API requires

" The implicit contract here is that memory coming from the heaps is
ready for dma, ie if it has a cached mapping that mapping has been
invalidated "

In v4.4, passsing device==NULL to any dma operation for arm64 results in
a no-op. Ensure that proper device pointers are used.

Change-Id: Id354f7cf6979aa58621408cfcfbd8ef62015fdbd
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
This commit is contained in:
Patrick Daly 2016-05-26 18:03:28 -07:00 committed by Kyle Yan
parent f668e1e3d0
commit 2d4fdc7bde
7 changed files with 49 additions and 24 deletions

View file

@ -1118,6 +1118,8 @@ void ion_pages_sync_for_device(struct device *dev, struct page *page,
{ {
struct scatterlist sg; struct scatterlist sg;
WARN_ONCE(!dev, "A device is required for dma_sync\n");
sg_init_table(&sg, 1); sg_init_table(&sg, 1);
sg_set_page(&sg, page, size, 0); sg_set_page(&sg, page, size, 0);
/* /*

View file

@ -111,13 +111,15 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer)
struct ion_heap *heap = buffer->heap; struct ion_heap *heap = buffer->heap;
struct sg_table *table = buffer->priv_virt; struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl); struct page *page = sg_page(table->sgl);
struct device *dev = heap->priv;
ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
ion_heap_buffer_zero(buffer); ion_heap_buffer_zero(buffer);
if (ion_buffer_cached(buffer)) if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents, dma_sync_sg_for_device(dev, table->sgl, table->nents,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
ion_carveout_free(heap, paddr, buffer->size); ion_carveout_free(heap, paddr, buffer->size);
sg_free_table(table); sg_free_table(table);
@ -153,11 +155,12 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
struct page *page; struct page *page;
size_t size; size_t size;
struct device *dev = heap_data->priv;
page = pfn_to_page(PFN_DOWN(heap_data->base)); page = pfn_to_page(PFN_DOWN(heap_data->base));
size = heap_data->size; size = heap_data->size;
ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL); ion_pages_sync_for_device(dev, page, size, DMA_BIDIRECTIONAL);
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret) if (ret)

View file

@ -99,14 +99,15 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
struct scatterlist *sg; struct scatterlist *sg;
int i; int i;
unsigned long allocated_size; unsigned long allocated_size;
struct device *dev = heap->priv;
allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size); allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size);
ion_heap_buffer_zero(buffer); ion_heap_buffer_zero(buffer);
if (ion_buffer_cached(buffer)) if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents, dma_sync_sg_for_device(dev, table->sgl, table->nents,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
for_each_sg(table->sgl, sg, table->nents, i) { for_each_sg(table->sgl, sg, table->nents, i) {
gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
@ -144,11 +145,12 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
int ret; int ret;
struct page *page; struct page *page;
size_t size; size_t size;
struct device *dev = heap_data->priv;
page = pfn_to_page(PFN_DOWN(heap_data->base)); page = pfn_to_page(PFN_DOWN(heap_data->base));
size = heap_data->size; size = heap_data->size;
ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL); ion_pages_sync_for_device(dev, page, size, DMA_BIDIRECTIONAL);
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret) if (ret)

View file

@ -35,7 +35,8 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
return NULL; return NULL;
if (pool->gfp_mask & __GFP_ZERO) if (pool->gfp_mask & __GFP_ZERO)
if (msm_ion_heap_high_order_page_zero(page, pool->order)) if (msm_ion_heap_high_order_page_zero(pool->dev, page,
pool->order))
goto error_free_pages; goto error_free_pages;
ion_page_pool_alloc_set_cache_policy(pool, page); ion_page_pool_alloc_set_cache_policy(pool, page);
@ -222,12 +223,14 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
return ion_page_pool_total(pool, high); return ion_page_pool_total(pool, high);
} }
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask,
unsigned int order)
{ {
struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool), struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
GFP_KERNEL); GFP_KERNEL);
if (!pool) if (!pool)
return NULL; return NULL;
pool->dev = dev;
pool->high_count = 0; pool->high_count = 0;
pool->low_count = 0; pool->low_count = 0;
pool->nr_unreserved = 0; pool->nr_unreserved = 0;

View file

@ -262,9 +262,11 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
int ion_heap_buffer_zero(struct ion_buffer *buffer); int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
int msm_ion_heap_high_order_page_zero(struct page *page, int order); int msm_ion_heap_high_order_page_zero(struct device *dev, struct page *page,
int order);
struct ion_heap *get_ion_heap(int heap_id); struct ion_heap *get_ion_heap(int heap_id);
int msm_ion_heap_sg_table_zero(struct sg_table *, size_t size); int msm_ion_heap_sg_table_zero(struct device *dev, struct sg_table *,
size_t size);
int msm_ion_heap_pages_zero(struct page **pages, int num_pages); int msm_ion_heap_pages_zero(struct page **pages, int num_pages);
int msm_ion_heap_alloc_pages_mem(struct pages_mem *pages_mem); int msm_ion_heap_alloc_pages_mem(struct pages_mem *pages_mem);
void msm_ion_heap_free_pages_mem(struct pages_mem *pages_mem); void msm_ion_heap_free_pages_mem(struct pages_mem *pages_mem);
@ -435,12 +437,14 @@ struct ion_page_pool {
struct list_head high_items; struct list_head high_items;
struct list_head low_items; struct list_head low_items;
struct mutex mutex; struct mutex mutex;
struct device *dev;
gfp_t gfp_mask; gfp_t gfp_mask;
unsigned int order; unsigned int order;
struct plist_node list; struct plist_node list;
}; };
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask,
unsigned int order);
void ion_page_pool_destroy(struct ion_page_pool *); void ion_page_pool_destroy(struct ion_page_pool *);
void *ion_page_pool_alloc(struct ion_page_pool *, bool *from_pool); void *ion_page_pool_alloc(struct ion_page_pool *, bool *from_pool);
void *ion_page_pool_alloc_pool_only(struct ion_page_pool *); void *ion_page_pool_alloc_pool_only(struct ion_page_pool *);

View file

@ -82,6 +82,7 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
struct page *page; struct page *page;
struct ion_page_pool *pool; struct ion_page_pool *pool;
int vmid = get_secure_vmid(buffer->flags); int vmid = get_secure_vmid(buffer->flags);
struct device *dev = heap->heap.priv;
if (*from_pool) { if (*from_pool) {
if (vmid > 0) if (vmid > 0)
@ -100,6 +101,8 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
if (order) if (order)
gfp_mask = high_order_gfp_flags; gfp_mask = high_order_gfp_flags;
page = alloc_pages(gfp_mask, order); page = alloc_pages(gfp_mask, order);
ion_pages_sync_for_device(dev, page, PAGE_SIZE << order,
DMA_BIDIRECTIONAL);
} }
if (!page) if (!page)
return 0; return 0;
@ -222,6 +225,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
struct pages_mem data; struct pages_mem data;
unsigned int sz; unsigned int sz;
int vmid = get_secure_vmid(buffer->flags); int vmid = get_secure_vmid(buffer->flags);
struct device *dev = heap->priv;
if (align > PAGE_SIZE) if (align > PAGE_SIZE)
return -EINVAL; return -EINVAL;
@ -311,7 +315,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
} }
if (nents_sync) { if (nents_sync) {
dma_sync_sg_for_device(NULL, table_sync.sgl, table_sync.nents, dma_sync_sg_for_device(dev, table_sync.sgl, table_sync.nents,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
if (vmid > 0) { if (vmid > 0) {
ret = ion_system_secure_heap_assign_sg(&table_sync, ret = ion_system_secure_heap_assign_sg(&table_sync,
@ -368,11 +372,12 @@ void ion_system_heap_free(struct ion_buffer *buffer)
LIST_HEAD(pages); LIST_HEAD(pages);
int i; int i;
int vmid = get_secure_vmid(buffer->flags); int vmid = get_secure_vmid(buffer->flags);
struct device *dev = heap->priv;
if (!(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) && if (!(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) &&
!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)) { !(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)) {
if (vmid < 0) if (vmid < 0)
msm_ion_heap_sg_table_zero(table, buffer->size); msm_ion_heap_sg_table_zero(dev, table, buffer->size);
} else if (vmid > 0) { } else if (vmid > 0) {
if (ion_system_secure_heap_unassign_sg(table, vmid)) if (ion_system_secure_heap_unassign_sg(table, vmid))
return; return;
@ -627,7 +632,8 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
* nothing. If it succeeds you'll eventually need to use * nothing. If it succeeds you'll eventually need to use
* ion_system_heap_destroy_pools to destroy the pools. * ion_system_heap_destroy_pools to destroy the pools.
*/ */
static int ion_system_heap_create_pools(struct ion_page_pool **pools) static int ion_system_heap_create_pools(struct device *dev,
struct ion_page_pool **pools)
{ {
int i; int i;
for (i = 0; i < num_orders; i++) { for (i = 0; i < num_orders; i++) {
@ -636,7 +642,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools)
if (orders[i]) if (orders[i])
gfp_flags = high_order_gfp_flags; gfp_flags = high_order_gfp_flags;
pool = ion_page_pool_create(gfp_flags, orders[i]); pool = ion_page_pool_create(dev, gfp_flags, orders[i]);
if (!pool) if (!pool)
goto err_create_pool; goto err_create_pool;
pools[i] = pool; pools[i] = pool;
@ -647,11 +653,12 @@ err_create_pool:
return 1; return 1;
} }
struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data)
{ {
struct ion_system_heap *heap; struct ion_system_heap *heap;
int i; int i;
int pools_size = sizeof(struct ion_page_pool *) * num_orders; int pools_size = sizeof(struct ion_page_pool *) * num_orders;
struct device *dev = data->priv;
heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL); heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
if (!heap) if (!heap)
@ -673,15 +680,16 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
heap->secure_pools[i] = kzalloc(pools_size, GFP_KERNEL); heap->secure_pools[i] = kzalloc(pools_size, GFP_KERNEL);
if (!heap->secure_pools[i]) if (!heap->secure_pools[i])
goto err_create_secure_pools; goto err_create_secure_pools;
if (ion_system_heap_create_pools(heap->secure_pools[i])) if (ion_system_heap_create_pools(
dev, heap->secure_pools[i]))
goto err_create_secure_pools; goto err_create_secure_pools;
} }
} }
if (ion_system_heap_create_pools(heap->uncached_pools)) if (ion_system_heap_create_pools(dev, heap->uncached_pools))
goto err_create_uncached_pools; goto err_create_uncached_pools;
if (ion_system_heap_create_pools(heap->cached_pools)) if (ion_system_heap_create_pools(dev, heap->cached_pools))
goto err_create_cached_pools; goto err_create_cached_pools;
heap->heap.debug_show = ion_system_heap_debug_show; heap->heap.debug_show = ion_system_heap_debug_show;
@ -738,6 +746,7 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
struct sg_table *table; struct sg_table *table;
unsigned long i; unsigned long i;
int ret; int ret;
struct device *dev = heap->priv;
if (align > (PAGE_SIZE << order)) if (align > (PAGE_SIZE << order))
return -EINVAL; return -EINVAL;
@ -766,7 +775,7 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
buffer->priv_virt = table; buffer->priv_virt = table;
ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL); ion_pages_sync_for_device(dev, page, len, DMA_BIDIRECTIONAL);
return 0; return 0;

View file

@ -859,7 +859,8 @@ void msm_ion_heap_free_pages_mem(struct pages_mem *pages_mem)
pages_mem->free_fn(pages_mem->pages); pages_mem->free_fn(pages_mem->pages);
} }
int msm_ion_heap_high_order_page_zero(struct page *page, int order) int msm_ion_heap_high_order_page_zero(struct device *dev, struct page *page,
int order)
{ {
int i, ret; int i, ret;
struct pages_mem pages_mem; struct pages_mem pages_mem;
@ -873,13 +874,14 @@ int msm_ion_heap_high_order_page_zero(struct page *page, int order)
pages_mem.pages[i] = page + i; pages_mem.pages[i] = page + i;
ret = msm_ion_heap_pages_zero(pages_mem.pages, npages); ret = msm_ion_heap_pages_zero(pages_mem.pages, npages);
dma_sync_single_for_device(NULL, page_to_phys(page), pages_mem.size, dma_sync_single_for_device(dev, page_to_phys(page), pages_mem.size,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
msm_ion_heap_free_pages_mem(&pages_mem); msm_ion_heap_free_pages_mem(&pages_mem);
return ret; return ret;
} }
int msm_ion_heap_sg_table_zero(struct sg_table *table, size_t size) int msm_ion_heap_sg_table_zero(struct device *dev, struct sg_table *table,
size_t size)
{ {
struct scatterlist *sg; struct scatterlist *sg;
int i, j, ret = 0, npages = 0; int i, j, ret = 0, npages = 0;
@ -901,7 +903,7 @@ int msm_ion_heap_sg_table_zero(struct sg_table *table, size_t size)
} }
ret = msm_ion_heap_pages_zero(pages_mem.pages, npages); ret = msm_ion_heap_pages_zero(pages_mem.pages, npages);
dma_sync_sg_for_device(NULL, table->sgl, table->nents, dma_sync_sg_for_device(dev, table->sgl, table->nents,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
msm_ion_heap_free_pages_mem(&pages_mem); msm_ion_heap_free_pages_mem(&pages_mem);
return ret; return ret;