On Wed, May 25, 2016 at 12:48:02PM -0700, Laura Abbott wrote:
> 
> Ion is currently using the DMA APIs in non-compliant ways for cache
> maintaince. The issue is Ion needs to do cache operations outside of
> the regular DMA model. The Ion model matches more closely with the
> DRM model which calls cache APIs directly. Add an appropriate
> abstraction layer for Ion to call cache operations outside of the
> DMA API.
> 
> Signed-off-by: Laura Abbott <labb...@redhat.com>

Hi Laura,

By no means a full review, just some comments:

> ---
>  drivers/staging/android/ion/Kconfig             | 14 ++++-
>  drivers/staging/android/ion/Makefile            |  3 +
>  drivers/staging/android/ion/ion-arm.c           | 83 
> +++++++++++++++++++++++++
>  drivers/staging/android/ion/ion-arm64.c         | 46 ++++++++++++++
>  drivers/staging/android/ion/ion-x86.c           | 34 ++++++++++
>  drivers/staging/android/ion/ion.c               | 59 ++++++------------
>  drivers/staging/android/ion/ion_carveout_heap.c |  5 +-
>  drivers/staging/android/ion/ion_chunk_heap.c    |  7 +--
>  drivers/staging/android/ion/ion_page_pool.c     |  3 +-
>  drivers/staging/android/ion/ion_priv.h          | 14 ++---
>  drivers/staging/android/ion/ion_system_heap.c   |  5 +-
>  11 files changed, 210 insertions(+), 63 deletions(-)
>  create mode 100644 drivers/staging/android/ion/ion-arm.c
>  create mode 100644 drivers/staging/android/ion/ion-arm64.c
>  create mode 100644 drivers/staging/android/ion/ion-x86.c
> 
> diff --git a/drivers/staging/android/ion/Kconfig 
> b/drivers/staging/android/ion/Kconfig
> index 19c1572..c1b1813 100644
> --- a/drivers/staging/android/ion/Kconfig
> +++ b/drivers/staging/android/ion/Kconfig
> @@ -1,6 +1,6 @@
>  menuconfig ION
>       bool "Ion Memory Manager"
> -     depends on HAVE_MEMBLOCK && HAS_DMA && MMU
> +     depends on HAVE_MEMBLOCK && HAS_DMA && MMU && (X86 || ARM || ARM64)
>       select GENERIC_ALLOCATOR
>       select DMA_SHARED_BUFFER
>       ---help---
> @@ -10,6 +10,18 @@ menuconfig ION
>         If you're not using Android its probably safe to
>         say N here.
>  
> +config ION_ARM
> +     depends on ION && ARM
> +     def_bool y
> +
> +config ION_ARM64
> +     depends on ION && ARM64
> +     def_bool y
> +
> +config ION_X86
> +     depends on ION && X86
> +     def_bool y

If you are going to make this arch specific, can I suggest that you make 
CONFIG_ION
depend on CONFIG_ARCH_ION (or any name you like) and then in each arch select 
it?
I don't particularly like the enumeration of all ION enabled arches above 
(is the list exhaustive?)

> +
>  config ION_TEST
>       tristate "Ion Test Device"
>       depends on ION
> diff --git a/drivers/staging/android/ion/Makefile 
> b/drivers/staging/android/ion/Makefile
> index 18cc2aa..1b82bb5 100644
> --- a/drivers/staging/android/ion/Makefile
> +++ b/drivers/staging/android/ion/Makefile
> @@ -1,5 +1,8 @@
>  obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
>                       ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o
> +obj-$(CONFIG_ION_X86) += ion-x86.o
> +obj-$(CONFIG_ION_ARM) += ion-arm.o
> +obj-$(CONFIG_ION_ARM64) += ion-arm64.o
>  obj-$(CONFIG_ION_TEST) += ion_test.o
>  ifdef CONFIG_COMPAT
>  obj-$(CONFIG_ION) += compat_ion.o
> diff --git a/drivers/staging/android/ion/ion-arm.c 
> b/drivers/staging/android/ion/ion-arm.c
> new file mode 100644
> index 0000000..b91287f
> --- /dev/null
> +++ b/drivers/staging/android/ion/ion-arm.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (C) 2016 Laura Abbott <la...@labbott.name>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/highmem.h>
> +
> +#include <asm/cacheflush.h>
> +
> +#include "ion_priv.h"
> +
> +
> +void ion_clean_page(struct page *page, size_t size)
> +{
> +     unsigned long pfn;
> +     size_t left = size;
> +
> +     pfn = page_to_pfn(page);
> +
> +     /*
> +      * A single sg entry may refer to multiple physically contiguous
> +      * pages.  But we still need to process highmem pages individually.
> +      * If highmem is not configured then the bulk of this loop gets
> +      * optimized out.
> +      */
> +     do {
> +             size_t len = left;
> +             void *vaddr;
> +
> +             page = pfn_to_page(pfn);
> +
> +             if (PageHighMem(page)) {
> +                     if (len > PAGE_SIZE)
> +                             len = PAGE_SIZE;
> +
> +                     if (cache_is_vipt_nonaliasing()) {
> +                             vaddr = kmap_atomic(page);
> +                             __cpuc_flush_dcache_area(vaddr, len);
> +                             kunmap_atomic(vaddr);
> +                     } else {
> +                             vaddr = kmap_high_get(page);
> +                             if (vaddr) {
> +                                     __cpuc_flush_dcache_area(vaddr, len);
> +                                     kunmap_high(page);
> +                             }
> +                     }
> +             } else {
> +                     vaddr = page_address(page);
> +                     __cpuc_flush_dcache_area(vaddr, len);
> +             }
> +             pfn++;
> +             left -= len;
> +     } while (left);
> +}
> +
> +/*
> + * ARM has highmem and a bunch of other 'fun' features. It's so much easier 
> just
> + * to do the ISA DMA and call things that way
> + */
> +
> +void ion_invalidate_buffer(struct ion_buffer *buffer)
> +{
> +     dma_unmap_sg(NULL, buffer->sg_table->sgl, buffer->sg_table->orig_nents,

arm_dma_unmap_sg?

> +                     DMA_BIDIRECTIONAL);
> +}
> +
> +void ion_clean_buffer(struct ion_buffer *buffer)
> +{
> +     dma_map_sg(NULL, buffer->sg_table->sgl, buffer->sg_table->orig_nents,

arm_dma_map_sg?

Otherwise, these two functions looks quite generic. Can they be the default 
implementation?

Best regards,
Liviu

> +                     DMA_BIDIRECTIONAL);
> +}
> diff --git a/drivers/staging/android/ion/ion-arm64.c 
> b/drivers/staging/android/ion/ion-arm64.c
> new file mode 100644
> index 0000000..afd387a
> --- /dev/null
> +++ b/drivers/staging/android/ion/ion-arm64.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright (C) 2016 Laura Abbott <la...@labbott.name>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <asm/cacheflush.h>
> +
> +#include "ion_priv.h"
> +
> +void ion_clean_page(struct page *page, size_t size)
> +{
> +     __flush_dcache_area(page_address(page), size);
> +}
> +
> +void ion_invalidate_buffer(struct ion_buffer *buffer)
> +{
> +     struct scatterlist *sg;
> +     int i;
> +
> +     for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->orig_nents, i)
> +             __dma_unmap_area(page_address(sg_page(sg)), sg->length,
> +                                     DMA_BIDIRECTIONAL);
> +}
> +
> +void ion_clean_buffer(struct ion_buffer *buffer)
> +{
> +     struct scatterlist *sg;
> +     int i;
> +
> +     for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->orig_nents, i)
> +             __dma_map_area(page_address(sg_page(sg)), sg->length,
> +                                     DMA_BIDIRECTIONAL);
> +}
> diff --git a/drivers/staging/android/ion/ion-x86.c 
> b/drivers/staging/android/ion/ion-x86.c
> new file mode 100644
> index 0000000..05fd684
> --- /dev/null
> +++ b/drivers/staging/android/ion/ion-x86.c
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright (C) 2016 Laura Abbott <la...@labbott.name>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +
> +#include "ion_priv.h"
> +
> +void ion_clean_page(struct page *page, size_t size)
> +{
> +     /* Do nothing right now */
> +}
> +
> +void ion_invalidate_buffer(struct ion_buffer *buffer)
> +{
> +     /* Do nothing right now */
> +}
> +
> +void ion_clean_buffer(struct ion_buffer *buffer)
> +{
> +     /* Do nothing right now */
> +}
> diff --git a/drivers/staging/android/ion/ion.c 
> b/drivers/staging/android/ion/ion.c
> index a2cf93b..9282d96a 100644
> --- a/drivers/staging/android/ion/ion.c
> +++ b/drivers/staging/android/ion/ion.c
> @@ -937,42 +937,6 @@ struct sg_table *ion_sg_table(struct ion_client *client,
>  }
>  EXPORT_SYMBOL(ion_sg_table);
>  
> -static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
> -                                    struct device *dev,
> -                                    enum dma_data_direction direction);
> -
> -static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment 
> *attachment,
> -                                     enum dma_data_direction direction)
> -{
> -     struct dma_buf *dmabuf = attachment->dmabuf;
> -     struct ion_buffer *buffer = dmabuf->priv;
> -
> -     ion_buffer_sync_for_device(buffer, attachment->dev, direction);
> -     return buffer->sg_table;
> -}
> -
> -static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
> -                           struct sg_table *table,
> -                           enum dma_data_direction direction)
> -{
> -}
> -
> -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 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;
> @@ -997,8 +961,7 @@ static void ion_buffer_sync_for_device(struct ion_buffer 
> *buffer,
>               struct page *page = buffer->pages[i];
>  
>               if (ion_buffer_page_is_dirty(page))
> -                     ion_pages_sync_for_device(dev, ion_buffer_page(page),
> -                                                     PAGE_SIZE, dir);
> +                     ion_clean_page(ion_buffer_page(page), PAGE_SIZE);
>  
>               ion_buffer_page_clean(buffer->pages + i);
>       }
> @@ -1011,6 +974,22 @@ static void ion_buffer_sync_for_device(struct 
> ion_buffer *buffer,
>       mutex_unlock(&buffer->lock);
>  }
>  
> +static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment 
> *attachment,
> +                                     enum dma_data_direction direction)
> +{
> +     struct dma_buf *dmabuf = attachment->dmabuf;
> +     struct ion_buffer *buffer = dmabuf->priv;
> +
> +     ion_buffer_sync_for_device(buffer, attachment->dev, direction);
> +     return buffer->sg_table;
> +}
> +
> +static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
> +                           struct sg_table *table,
> +                           enum dma_data_direction direction)
> +{
> +}
> +
>  static int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
>  {
>       struct ion_buffer *buffer = vma->vm_private_data;
> @@ -1293,8 +1272,8 @@ static int ion_sync_for_device(struct ion_client 
> *client, int fd)
>       }
>       buffer = dmabuf->priv;
>  
> -     dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
> -                            buffer->sg_table->nents, DMA_BIDIRECTIONAL);
> +     ion_clean_buffer(buffer);
> +
>       dma_buf_put(dmabuf);
>       return 0;
>  }
> diff --git a/drivers/staging/android/ion/ion_carveout_heap.c 
> b/drivers/staging/android/ion/ion_carveout_heap.c
> index 1fb0d81..d213cbf 100644
> --- a/drivers/staging/android/ion/ion_carveout_heap.c
> +++ b/drivers/staging/android/ion/ion_carveout_heap.c
> @@ -116,8 +116,7 @@ static void ion_carveout_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);
> +             ion_clean_page(page, buffer->size);
>  
>       ion_carveout_free(heap, paddr, buffer->size);
>       sg_free_table(table);
> @@ -157,7 +156,7 @@ struct ion_heap *ion_carveout_heap_create(struct 
> ion_platform_heap *heap_data)
>       page = pfn_to_page(PFN_DOWN(heap_data->base));
>       size = heap_data->size;
>  
> -     ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL);
> +     ion_clean_page(page, size);
>  
>       ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
>       if (ret)
> diff --git a/drivers/staging/android/ion/ion_chunk_heap.c 
> b/drivers/staging/android/ion/ion_chunk_heap.c
> index e0553fe..0666529 100644
> --- a/drivers/staging/android/ion/ion_chunk_heap.c
> +++ b/drivers/staging/android/ion/ion_chunk_heap.c
> @@ -104,11 +104,10 @@ 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))
> +                     ion_clean_page(sg_page(table->sgl), sg->length);
>               gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
>                             sg->length);
>       }
> @@ -148,7 +147,7 @@ struct ion_heap *ion_chunk_heap_create(struct 
> ion_platform_heap *heap_data)
>       page = pfn_to_page(PFN_DOWN(heap_data->base));
>       size = heap_data->size;
>  
> -     ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL);
> +     ion_clean_page(page, size);
>  
>       ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
>       if (ret)
> diff --git a/drivers/staging/android/ion/ion_page_pool.c 
> b/drivers/staging/android/ion/ion_page_pool.c
> index 1fe8016..b854f91 100644
> --- a/drivers/staging/android/ion/ion_page_pool.c
> +++ b/drivers/staging/android/ion/ion_page_pool.c
> @@ -30,8 +30,7 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool 
> *pool)
>  
>       if (!page)
>               return NULL;
> -     ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
> -                                             DMA_BIDIRECTIONAL);
> +     ion_clean_page(page, PAGE_SIZE << pool->order);
>       return page;
>  }
>  
> diff --git a/drivers/staging/android/ion/ion_priv.h 
> b/drivers/staging/android/ion/ion_priv.h
> index 0239883..b368338 100644
> --- a/drivers/staging/android/ion/ion_priv.h
> +++ b/drivers/staging/android/ion/ion_priv.h
> @@ -392,15 +392,9 @@ 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);
> +void ion_clean_page(struct page *page, size_t size);
> +
> +void ion_clean_buffer(struct ion_buffer *buffer);
>  
> +void ion_invalidate_buffer(struct ion_buffer *buffer);
>  #endif /* _ION_PRIV_H */
> diff --git a/drivers/staging/android/ion/ion_system_heap.c 
> b/drivers/staging/android/ion/ion_system_heap.c
> index b69dfc7..aa39660 100644
> --- a/drivers/staging/android/ion/ion_system_heap.c
> +++ b/drivers/staging/android/ion/ion_system_heap.c
> @@ -70,8 +70,7 @@ static struct page *alloc_buffer_page(struct 
> ion_system_heap *heap,
>               page = alloc_pages(gfp_flags | __GFP_COMP, order);
>               if (!page)
>                       return NULL;
> -             ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order,
> -                                             DMA_BIDIRECTIONAL);
> +             ion_clean_page(page, PAGE_SIZE << order);
>       }
>  
>       return page;
> @@ -360,7 +359,7 @@ static int ion_system_contig_heap_allocate(struct 
> ion_heap *heap,
>  
>       buffer->priv_virt = table;
>  
> -     ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL);
> +     ion_clean_page(page, len);
>  
>       return 0;
>  
> -- 
> 2.5.5
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to