ion: fix dma APIs
authorColin Cross <ccross@android.com>
Fri, 13 Dec 2013 22:25:01 +0000 (14:25 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 14 Dec 2013 16:57:18 +0000 (08:57 -0800)
__dma_page_cpu_to_dev is a private ARM api that is not available
on 3.10 and was never available on other architectures.  We can
get the same behavior by calling dma_sync_sg_for_device with a
scatterlist containing a single page.  It's still not quite a
kosher use of the dma apis, we still conflate physical addresses
with bus addresses, but it should at least compile on all
platforms, and work on any platform that doesn't have a physical
to bus address translation.

Signed-off-by: Colin Cross <ccross@android.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/android/ion/ion.c
drivers/staging/android/ion/ion_chunk_heap.c
drivers/staging/android/ion/ion_page_pool.c
drivers/staging/android/ion/ion_priv.h
drivers/staging/android/ion/ion_system_heap.c

index 2e7be70dd9c062dbb2ff0bb0c943d9881970af9d..4bdbdece3f30c450da942a76fd10a365e2668f1f 100644 (file)
@@ -840,6 +840,22 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
 {
 }
 
+void ion_pages_sync_for_device(struct device *dev, struct page *page,
+               size_t size, enum dma_data_direction dir)
+{
+       struct scatterlist sg;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, page, size, 0);
+       /*
+        * This is not correct - sg_dma_address needs a dma_addr_t that is valid
+        * for the the targeted device, but this works on the currently targeted
+        * hardware.
+        */
+       sg_dma_address(&sg) = page_to_phys(page);
+       dma_sync_sg_for_device(dev, &sg, 1, dir);
+}
+
 struct ion_vma_list {
        struct list_head list;
        struct vm_area_struct *vma;
@@ -864,7 +880,9 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
                struct page *page = buffer->pages[i];
 
                if (ion_buffer_page_is_dirty(page))
-                       __dma_page_cpu_to_dev(page, 0, PAGE_SIZE, dir);
+                       ion_pages_sync_for_device(dev, ion_buffer_page(page),
+                                                       PAGE_SIZE, dir);
+
                ion_buffer_page_clean(buffer->pages + i);
        }
        list_for_each_entry(vma_list, &buffer->vmas, list) {
index 85fefe7788454417358a75fdc43f6d4031b6d568..2fddc041ac1313039f4a8c3e3246ae7f3f9e3a4b 100644 (file)
@@ -106,11 +106,11 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
 
        ion_heap_buffer_zero(buffer);
 
+       if (ion_buffer_cached(buffer))
+               dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+                                                               DMA_BIDIRECTIONAL);
+
        for_each_sg(table->sgl, sg, table->nents, i) {
-               if (ion_buffer_cached(buffer))
-                       arm_dma_ops.sync_single_for_device(NULL,
-                               pfn_to_dma(NULL, page_to_pfn(sg_page(sg))),
-                               sg_dma_len(sg), DMA_BIDIRECTIONAL);
                gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
                              sg_dma_len(sg));
        }
@@ -148,7 +148,6 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
        pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL);
        int i, ret;
 
-
        chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL);
        if (!chunk_heap)
                return ERR_PTR(-ENOMEM);
@@ -181,9 +180,9 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
        }
        free_vm_area(vm_struct);
 
-       arm_dma_ops.sync_single_for_device(NULL,
-               pfn_to_dma(NULL, page_to_pfn(phys_to_page(heap_data->base))),
-               heap_data->size, DMA_BIDIRECTIONAL);
+       ion_pages_sync_for_device(NULL, pfn_to_page(PFN_DOWN(heap_data->base)),
+                       heap_data->size, DMA_BIDIRECTIONAL);
+
        gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1);
        chunk_heap->heap.ops = &chunk_heap_ops;
        chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
index 855f30c3967ae345fb78af2637514c4d48ec8c18..979d2e4a6b12e3063c707bbe8f76f4f6141aa67f 100644 (file)
@@ -34,13 +34,8 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
 
        if (!page)
                return NULL;
-       /* this is only being used to flush the page for dma,
-          this api is not really suitable for calling from a driver
-          but no better way to flush a page for dma exist at this time */
-       arm_dma_ops.sync_single_for_device(NULL,
-                                          pfn_to_dma(NULL, page_to_pfn(page)),
-                                          PAGE_SIZE << pool->order,
-                                          DMA_BIDIRECTIONAL);
+       ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
+                                               DMA_BIDIRECTIONAL);
        return page;
 }
 
index f2635631e9befc7ab6e4a7f9113695babdc0bfe0..d1fa7719b2402fecd151916513e63462ea99badd 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef _ION_PRIV_H
 #define _ION_PRIV_H
 
+#include <linux/dma-direction.h>
 #include <linux/kref.h>
 #include <linux/mm_types.h>
 #include <linux/mutex.h>
@@ -357,4 +358,15 @@ void ion_page_pool_free(struct ion_page_pool *, struct page *);
 int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
                          int nr_to_scan);
 
+/**
+ * ion_pages_sync_for_device - cache flush pages for use with the specified
+ *                             device
+ * @dev:               the device the pages will be used with
+ * @page:              the first page to be flushed
+ * @size:              size in bytes of region to be flushed
+ * @dir:               direction of dma transfer
+ */
+void ion_pages_sync_for_device(struct device *dev, struct page *page,
+               size_t size, enum dma_data_direction dir);
+
 #endif /* _ION_PRIV_H */
index b9b10365f450861466abd706104e37052a9546f6..792cade3e4043d0d70c13e601f1963fbe28db4ba 100644 (file)
@@ -77,9 +77,8 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
                page = ion_heap_alloc_pages(buffer, gfp_flags, order);
                if (!page)
                        return 0;
-               arm_dma_ops.sync_single_for_device(NULL,
-                       pfn_to_dma(NULL, page_to_pfn(page)),
-                       PAGE_SIZE << order, DMA_BIDIRECTIONAL);
+               ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order,
+                                               DMA_BIDIRECTIONAL);
        }
        if (!page)
                return 0;