android: ion: add fixups to ion exynos extension
authorCho KyongHo <pullip.cho@samsung.com>
Wed, 21 Feb 2018 12:42:47 +0000 (21:42 +0900)
committerSangwook Ju <sw.ju@samsung.com>
Mon, 14 May 2018 10:45:24 +0000 (19:45 +0900)
The purpose of the exynos extension is to attach addtional
improvements to ION. The first improvment is the elimination of
dma-mapping overhead.
dma_map_sg() and dma_unmap_sg() maps the given memory to the address
space of the given device. The mapping can be translation table update
if the device has iommu. It may allocate swiotlb buffer if the device
does not have iommu and the address space of the device is smaller
than the physical address space. dma_map_sg() and dma_unmap_sg() also
maintain CPU caches to ensure memory coherency.
The purpose of calls to dma_map_sg() and dma_unmap_sg() in
ion_map_dma_buf() and ion_unmap_dma_buf(), respectively is just
ensuring cache coherency in Exynos SoCs. We have another approach to
map the physical memory to the device address space, ion_iovmm_map().
But replacing dma_map_sg() with dma_sync_sg_for_device() does not work
because dma_sync_sg_for_device() needs dma_address fields to be
initialized by dma_map_sg().
This is the first step to replacing dma_map_sg() with
dma_sync_sg_for_device() in ion_map_dma_buf().
Buffer allocation now involves dma_map_sg() to assign dma_address
fields of ion_buffer.sg_table. dma_unmap_sg() is called by
ion_buffer_destroy().
Then we can finally use dma_sync_sg_for_device() in ion_map_dma_buf().

Change-Id: I8b439eddc0b3722a297ea395aa7e6f3ebc00b294
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
drivers/staging/android/ion/ion.c
drivers/staging/android/ion/ion_exynos.c
drivers/staging/android/ion/ion_exynos.h

index 89cf91901641fc9f97213944a82f67684897037b..2ff694890d377a8ef0514172571f5567774b2e98 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/sched/task.h>
 
 #include "ion.h"
+#include "ion_exynos.h"
 
 static struct ion_device *internal_dev;
 static int heap_id;
@@ -111,6 +112,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
        buffer->dev = dev;
        buffer->size = len;
 
+       ret = exynos_ion_alloc_fixup(dev, buffer);
+       if (ret < 0)
+               goto err1;
+
        INIT_LIST_HEAD(&buffer->iovas);
        mutex_init(&buffer->lock);
        mutex_lock(&dev->buffer_lock);
@@ -127,6 +132,7 @@ err2:
 
 void ion_buffer_destroy(struct ion_buffer *buffer)
 {
+       exynos_ion_free_fixup(buffer);
        if (WARN_ON(buffer->kmap_cnt > 0))
                buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
        buffer->heap->ops->free(buffer);
@@ -659,6 +665,7 @@ static int ion_device_create(void)
        }
 
 debugfs_done:
+       exynos_ion_fixup(idev);
        idev->buffers = RB_ROOT;
        mutex_init(&idev->buffer_lock);
        init_rwsem(&idev->lock);
index 11f18675fade63cf0c3729f77fe1e22f540ca96e..0542e04b6fdb55e27ccfb8297270c91490459649 100644 (file)
@@ -160,3 +160,50 @@ void ion_iovmm_unmap(struct dma_buf_attachment *attachment, dma_addr_t iova)
 
        WARN(1, "iova %pad found for %s\n", &iova, dev_name(attachment->dev));
 }
+
+/*
+ * exynos_ion_fixup - do something to ion_device for the Exynos extensions
+ */
+void exynos_ion_fixup(struct ion_device *idev)
+{
+       struct device *dev = idev->dev.this_device;
+
+       /*
+        * dma-mapping API only works on dma supported device. dma_map_sg() and
+        * the similarities allocates swiotlb buffers if the dma mask of the
+        * given device is not capable of full access to physical address space.
+        * This forces dma-mapping of ARM64 works as if the given device is full
+        * memory access devices.
+        * See ion_buffer_create() and ion_buffer_destroy().
+        */
+       arch_setup_dma_ops(dev, 0x0ULL, 1ULL << 36, NULL, false);
+       dev->dma_mask = &dev->coherent_dma_mask;
+       dma_set_mask(dev, DMA_BIT_MASK(36));
+}
+
+int exynos_ion_alloc_fixup(struct ion_device *idev, struct ion_buffer *buffer)
+{
+       struct sg_table *table = buffer->sg_table;
+       int nents;
+
+       /* assign dma_addresses to scatter-gather list */
+       nents = dma_map_sg_attrs(idev->dev.this_device, table->sgl,
+                                table->orig_nents, DMA_TO_DEVICE,
+                                DMA_ATTR_SKIP_CPU_SYNC);
+       if (nents < table->orig_nents) {
+               pr_err("%s: failed dma_map_sg(nents %d)=nents %d\n",
+                      __func__, table->orig_nents, nents);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void exynos_ion_free_fixup(struct ion_buffer *buffer)
+{
+       struct sg_table *table = buffer->sg_table;
+
+       dma_unmap_sg_attrs(buffer->dev->dev.this_device, table->sgl,
+                          table->orig_nents, DMA_TO_DEVICE,
+                          DMA_ATTR_SKIP_CPU_SYNC);
+}
index ba4d0bb18b6f47edd1c65358aab67e776be484db..f1abf8924109b55e631de86cf197a400b1f68bc9 100644 (file)
@@ -21,6 +21,8 @@ struct cma;
 struct dma_buf;
 struct ion_heap;
 struct ion_platform_heap;
+struct ion_device;
+struct ion_buffer;
 
 /**
  * struct ion_buffer_prot_info - buffer protection information
@@ -68,6 +70,10 @@ static inline int ion_secure_iova_pool_create(void)
 void *ion_buffer_protect_single(unsigned int protection_id, unsigned int size,
                                unsigned long phys, unsigned int protalign);
 void ion_buffer_unprotect(void *priv);
+void exynos_ion_fixup(struct ion_device *idev);
+int exynos_ion_alloc_fixup(struct ion_device *idev, struct ion_buffer *buffer);
+void exynos_ion_free_fixup(struct ion_buffer *buffer);
+
 #else
 static inline void *ion_buffer_protect_single(unsigned int protection_id,
                                              unsigned int size,
@@ -77,6 +83,14 @@ static inline void *ion_buffer_protect_single(unsigned int protection_id,
        return NULL;
 }
 #define ion_buffer_unprotect(priv) do { } while (0)
+#define exynos_ion_fixup(idev) do { } while (0)
+static inline int exynos_ion_alloc_fixup(struct ion_device *idev,
+                                        struct ion_buffer *buffer)
+{
+       return 0;
+}
+
+#define exynos_ion_free_fixup(buffer) do { } while (0)
 #endif
 
 extern const struct dma_buf_ops ion_dma_buf_ops;
@@ -84,4 +98,5 @@ extern const struct dma_buf_ops ion_dma_buf_ops;
 struct ion_heap *ion_get_heap_by_name(const char *heap_name);
 struct dma_buf *__ion_alloc(size_t len, unsigned int heap_id_mask,
                            unsigned int flags);
+
 #endif /* _ION_EXYNOS_H_ */