[PATCH 6/6] drm/exynos/iommu: merge IOMMU and DMA code
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
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