diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 7e9d096a6fe7..9ab64bae4d1c 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -294,6 +294,7 @@ size_t ion_heap_freelist_size(struct ion_heap *heap); * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool * @list: plist node for list of pools + * @dev: device for the pool * * Allows you to keep a pool of pre allocated pages to use from your heap. * Keeping a pool of pages that is ready for dma, ie any cached mapping have @@ -309,6 +310,7 @@ struct ion_page_pool { gfp_t gfp_mask; unsigned int order; struct plist_node list; + struct device *dev; }; struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 0ad1fb37408c..a136a8593061 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -5,7 +5,10 @@ * Copyright (C) 2011 Google, Inc. */ +#include #include +#include +#include #include #include #include @@ -70,6 +73,20 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) return page; } +static void page_sync_for_device(struct device *dev, struct page *page, + size_t size, enum dma_data_direction dir) +{ + struct scatterlist sg; + + if (!dev || !page) + return; + + sg_init_table(&sg, 1); + sg_set_page(&sg, page, size, 0); + sg_dma_address(&sg) = page_to_phys(page); + dma_sync_sg_for_device(dev, &sg, 1, dir); +} + struct page *ion_page_pool_alloc(struct ion_page_pool *pool) { struct page *page = NULL; @@ -83,8 +100,12 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool) page = ion_page_pool_remove(pool, false); mutex_unlock(&pool->mutex); - if (!page) + if (!page) { page = ion_page_pool_alloc_pages(pool); + page_sync_for_device(pool->dev, page, + PAGE_SIZE << pool->order, + DMA_BIDIRECTIONAL); + } return page; } @@ -148,9 +169,33 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, return freed; } +static const struct platform_device_info ion_dev_info = { + .name = "ion-pool", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; + +static struct platform_device *platform_device_register_dma(const char *name) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_register_full(&ion_dev_info); + if (pdev) { + ret = of_dma_configure(&pdev->dev, NULL, true); + if (ret) { + platform_device_unregister(pdev); + pdev = NULL; + } + } + + return pdev; +} + struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) { - struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL); + struct platform_device *pdev; + struct ion_page_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (!pool) return NULL; @@ -163,10 +208,20 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) mutex_init(&pool->mutex); plist_node_init(&pool->list, order); + pdev = platform_device_register_dma("ion_pool"); + if (!IS_ERR(pdev)) + pool->dev = &pdev->dev; + return pool; } void ion_page_pool_destroy(struct ion_page_pool *pool) { + if (pool->dev) { + struct platform_device *pdev = to_platform_device(pool->dev); + + of_dma_deconfigure(&pdev->dev); + platform_device_unregister(pdev); + } kfree(pool); }