[PATCH 6/6] drm/exynos/iommu: merge IOMMU and DMA code

2018-10-12 Thread Andrzej Hajda
As DMA code is the only user of IOMMU code both files can be merged.
It allows to remove stub functions, after slight adjustment of
exynos_drm_register_dma. Since IOMMU functions are used locally they
can be marked static.

Signed-off-by: Andrzej Hajda 
---
 drivers/gpu/drm/exynos/Makefile   |   1 -
 drivers/gpu/drm/exynos/exynos_drm_dma.c   | 139 ++--
 drivers/gpu/drm/exynos/exynos_drm_iommu.c | 147 --
 drivers/gpu/drm/exynos/exynos_drm_iommu.h |  50 
 4 files changed, 128 insertions(+), 209 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_iommu.c
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_iommu.h

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 94433838445f..2fd2f3ee4fcf 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -7,7 +7,6 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o 
exynos_drm_fb.o \
exynos_drm_gem.o exynos_drm_plane.o exynos_drm_dma.o
 
 exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
-exynosdrm-$(CONFIG_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)+= exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON)   += exynos5433_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)  += exynos7_drm_decon.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c 
b/drivers/gpu/drm/exynos/exynos_drm_dma.c
index f01cb102956d..3432c5ee9f0c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dma.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c
@@ -1,27 +1,138 @@
 // SPDX-License-Identifier: GPL-2.0
 //
 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Inki Dae 
 // Author: Andrzej Hajda 
 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
+
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include 
+#else
+#define arm_iommu_create_mapping(...)  ({ NULL; })
+#define arm_iommu_attach_device(...)   ({ -ENODEV; })
+#define arm_iommu_release_mapping(...) ({ })
+#define arm_iommu_detach_device(...)   ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
+#if !defined(CONFIG_IOMMU_DMA)
+#define iommu_dma_init_domain(...) ({ -EINVAL; })
+#endif
+
+#define EXYNOS_DEV_ADDR_START  0x2000
+#define EXYNOS_DEV_ADDR_SIZE   0x4000
+
+static inline int configure_dma_max_seg_size(struct device *dev)
+{
+   if (!dev->dma_parms)
+   dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
+   if (!dev->dma_parms)
+   return -ENOMEM;
+
+   dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+   return 0;
+}
+
+static inline void clear_dma_max_seg_size(struct device *dev)
+{
+   kfree(dev->dma_parms);
+   dev->dma_parms = NULL;
+}
+
+/*
+ * drm_iommu_attach_device- attach device to iommu mapping
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be attach
+ *
+ * This function should be called by sub drivers to attach it to iommu
+ * mapping.
+ */
+static int drm_iommu_attach_device(struct drm_device *drm_dev,
+   struct device *subdrv_dev)
+{
+   struct exynos_drm_private *priv = drm_dev->dev_private;
+   int ret;
+
+   if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
+   DRM_ERROR("Device %s lacks support for IOMMU\n",
+ dev_name(subdrv_dev));
+   return -EINVAL;
+   }
+
+   ret = configure_dma_max_seg_size(subdrv_dev);
+   if (ret)
+   return ret;
+
+   if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+   if (to_dma_iommu_mapping(subdrv_dev))
+   arm_iommu_detach_device(subdrv_dev);
+
+   ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
+   } else if (IS_ENABLED(CONFIG_IOMMU_DMA)) {
+   ret = iommu_attach_device(priv->mapping, subdrv_dev);
+   }
+
+   if (ret)
+   clear_dma_max_seg_size(subdrv_dev);
+
+   return 0;
+}
+
+/*
+ * drm_iommu_detach_device -detach device address space mapping from device
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be detached
+ *
+ * This function should be called by sub drivers to detach it from iommu
+ * mapping
+ */
+static void drm_iommu_detach_device(struct drm_device *drm_dev,
+   struct device *subdrv_dev)
+{
+   struct exynos_drm_private *priv = drm_dev->dev_private;
+
+   if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+   arm_iommu_detach_device(subdrv_dev);
+   else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+   iommu_detach_device(priv->mapping, subdrv_dev);
+
+   clear_dma_max_seg_size(subdrv_dev);
+}
 
 int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
 {
struct exynos_drm_private *priv = drm->dev_private;
-   int ret;
 
if (!priv->dma_dev) {
priv->dma_dev = dev;
DRM_INFO("Exynos DRM: 

[PATCH 6/6] drm/exynos/iommu: merge IOMMU and DMA code

2018-09-25 Thread Andrzej Hajda
As DMA code is the only user of IOMMU code both files can be merged.
It allows to remove stub functions, after slight adjustment of
exynos_drm_register_dma. Since IOMMU functions are used locally they
can be marked static.

Signed-off-by: Andrzej Hajda 
---
 drivers/gpu/drm/exynos/Makefile   |   1 -
 drivers/gpu/drm/exynos/exynos_drm_dma.c   | 191 +-
 drivers/gpu/drm/exynos/exynos_drm_iommu.c | 185 -
 drivers/gpu/drm/exynos/exynos_drm_iommu.h |  50 --
 4 files changed, 183 insertions(+), 244 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_iommu.c
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_iommu.h

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 94433838445f..2fd2f3ee4fcf 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -7,7 +7,6 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o 
exynos_drm_fb.o \
exynos_drm_gem.o exynos_drm_plane.o exynos_drm_dma.o
 
 exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
-exynosdrm-$(CONFIG_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)+= exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON)   += exynos5433_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)  += exynos7_drm_decon.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c 
b/drivers/gpu/drm/exynos/exynos_drm_dma.c
index f01cb102956d..5a120ea90a71 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dma.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c
@@ -1,10 +1,181 @@
 // SPDX-License-Identifier: GPL-2.0
 //
 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Inki Dae 
 // Author: Andrzej Hajda 
 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
+
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include 
+#else
+#define arm_iommu_create_mapping(...)  ({ NULL; })
+#define arm_iommu_attach_device(...)   ({ -ENODEV; })
+#define arm_iommu_release_mapping(...) ({ })
+#define arm_iommu_detach_device(...)   ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
+#if !defined(CONFIG_IOMMU_DMA)
+#define iommu_dma_init_domain(...) ({ -EINVAL; })
+#endif
+
+#define EXYNOS_DEV_ADDR_START  0x2000
+#define EXYNOS_DEV_ADDR_SIZE   0x4000
+
+static void *iommu_dma_create_mapping(struct exynos_drm_private *priv,
+ unsigned long start, unsigned long size)
+{
+   struct iommu_domain *domain;
+   int ret;
+
+   domain = iommu_domain_alloc(priv->dma_dev->bus);
+   if (!domain)
+   return ERR_PTR(-ENOMEM);
+
+   ret = iommu_get_dma_cookie(domain);
+   if (ret)
+   goto free_domain;
+
+   ret = iommu_dma_init_domain(domain, start, size, NULL);
+   if (ret)
+   goto put_cookie;
+
+   return domain;
+
+put_cookie:
+   iommu_put_dma_cookie(domain);
+free_domain:
+   iommu_domain_free(domain);
+   return ERR_PTR(ret);
+}
+
+static inline void iommu_dma_release_mapping(struct iommu_domain *domain)
+{
+   iommu_put_dma_cookie(domain);
+   iommu_domain_free(domain);
+}
+
+static inline int configure_dma_max_seg_size(struct device *dev)
+{
+   if (!dev->dma_parms)
+   dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
+   if (!dev->dma_parms)
+   return -ENOMEM;
+
+   dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+   return 0;
+}
+
+static inline void clear_dma_max_seg_size(struct device *dev)
+{
+   kfree(dev->dma_parms);
+   dev->dma_parms = NULL;
+}
+
+/*
+ * drm_create_iommu_mapping - create a mapping structure
+ *
+ * @drm_dev: DRM device
+ */
+static int drm_create_iommu_mapping(struct drm_device *drm_dev)
+{
+   struct exynos_drm_private *priv = drm_dev->dev_private;
+
+   if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+   priv->mapping = arm_iommu_create_mapping(_bus_type,
+   EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE);
+   else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+   priv->mapping = iommu_dma_create_mapping(priv,
+   EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE);
+
+   return PTR_ERR_OR_ZERO(priv->mapping);
+}
+
+/*
+ * drm_release_iommu_mapping - release iommu mapping structure
+ *
+ * @drm_dev: DRM device
+ */
+static void drm_release_iommu_mapping(struct drm_device *drm_dev)
+{
+   struct exynos_drm_private *priv = drm_dev->dev_private;
+
+   if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+   arm_iommu_release_mapping(priv->mapping);
+   else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+   iommu_dma_release_mapping(priv->mapping);
+
+   priv->mapping = NULL;
+}
+
+/*
+ * drm_iommu_attach_device- attach device to iommu mapping
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be attach
+ *
+ * This function should be called by sub drivers to attach it