Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1430290 > unrolled thread

iommu/rockchip: Fix bugs and enable on ARM64

Started byShunqian Zheng <zhengsq@rock-chips.com>
First post2016-06-24 04:20 +0200
Last post2016-07-08 03:10 +0200
Articles 12 — 3 participants

Back to article view | Back to linux.kernel


Contents

  iommu/rockchip: Fix bugs and enable on ARM64 Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    [PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach devices Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
      Re: [PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach  devices Mark yao <mark.yao@rock-chips.com> - 2016-07-08 03:00 +0200
    [PATCH v5 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    [PATCH v5 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    [PATCH v5 3/8] iommu/rockchip: Fix allocation of bases array in driver probe Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    [PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
      Re: [PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if  attached to IOMMU domain Mark yao <mark.yao@rock-chips.com> - 2016-07-08 03:00 +0200
    [PATCH v5 5/8] iommu/rockchip: Prepare to support generic DMA mapping Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    [PATCH v5 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64 Shunqian Zheng <zhengsq@rock-chips.com> - 2016-06-24 04:20 +0200
    Re: iommu/rockchip: Fix bugs and enable on ARM64 Joerg Roedel <joro@8bytes.org> - 2016-06-27 15:00 +0200
      Re: iommu/rockchip: Fix bugs and enable on ARM64 Mark yao <mark.yao@rock-chips.com> - 2016-07-08 03:10 +0200

#1430290 — iommu/rockchip: Fix bugs and enable on ARM64

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subjectiommu/rockchip: Fix bugs and enable on ARM64
Message-ID<rNoSR-230-3@gated-at.bofh.it>
This series intends mostly to enable support for ARM64 architecture
in the rockchip-iommu driver. On the way to do so, some bugs are also
fixed.

The most important changes here are:
 - making the Rockchip IOMMU driver use DMA API for managing cache
   coherency of page tables,
 - making the Rockchip DRM driver not use DMA API on behalf of a virtual
   device (behind a virtual IOMMU) to allocate and map buffers, but
   instead proper DRM helpers and IOMMU API directly.

Changes since v4:
 - Address some coding style comments on:
    - https://chromium-review.googlesource.com/#/c/346328/38
    - https://chromium-review.googlesource.com/#/c/353591/10
Changes since v3:
 - Drop the idea of virtual IOMMU. Instead replace hacky allocation code
   in DRM driver, with proper management of IOMMU domain.
 - Add one more fix for allocation of IOMMU register base addresses.
Changes since v2:
 - Instead of registering virtual IOMMU from DTS, create it when
   attaching.
 - Fix some bugs found in internal review.

Shunqian Zheng (4):
  iommu/rockchip: Fix allocation of bases array in driver probe
  iommu/rockchip: Use DMA API to manage coherency
  iommu/rockchip: Prepare to support generic DMA mapping
  drm/rockchip: Use common IOMMU API to attach devices

Simon Xue (3):
  iommu/rockchip: Fix devm_{request,free}_irq parameter
  iommu/rockchip: Add map_sg callback for rk_iommu_ops
  iommu/rockchip: Enable Rockchip IOMMU on ARM64

Tomasz Figa (1):
  drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain

 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 100 +++++++------
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 221 ++++++++++++++++++++++++++--
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
 drivers/iommu/Kconfig                       |   2 +-
 drivers/iommu/rockchip-iommu.c              | 181 +++++++++++++++++------
 6 files changed, 413 insertions(+), 103 deletions(-)

-- 
1.9.1

[toc] | [next] | [standalone]


#1430291 — [PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach devices

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach devices
Message-ID<rNoSR-230-7@gated-at.bofh.it>
In reply to#1430290
Rockchip DRM used the arm special API, arm_iommu_*(), to attach
iommu for ARM32 SoCs. This patch convert to common iommu API
so it would support ARM64 like RK3399.

Since previous patch added support for direct IOMMU address space
management, there is no need to use DMA API anymore and this patch wires
things to use the new method.

Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 100 +++++++++++++++-------------
 1 file changed, 53 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 8b96c69..ca9624f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -14,18 +14,18 @@
  * GNU General Public License for more details.
  */
 
-#include <asm/dma-iommu.h>
-
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-iommu.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
 #include <linux/component.h>
 #include <linux/console.h>
+#include <linux/iommu.h>
 
 #include <drm/rockchip_drm.h>
 
@@ -51,28 +51,31 @@ static struct drm_driver rockchip_drm_driver;
 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
 				   struct device *dev)
 {
-	struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping;
+	struct rockchip_drm_private *private = drm_dev->dev_private;
 	int ret;
 
 	if (!is_support_iommu)
 		return 0;
 
-	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-	if (ret)
+	ret = iommu_attach_device(private->domain, dev);
+	if (ret) {
+		dev_err(dev, "Failed to attach iommu device\n");
 		return ret;
+	}
 
-	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
-
-	return arm_iommu_attach_device(dev, mapping);
+	return 0;
 }
 
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
 				    struct device *dev)
 {
+	struct rockchip_drm_private *private = drm_dev->dev_private;
+	struct iommu_domain *domain = private->domain;
+
 	if (!is_support_iommu)
 		return;
 
-	arm_iommu_detach_device(dev);
+	iommu_detach_device(domain, dev);
 }
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
@@ -137,11 +140,45 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev,
 		priv->crtc_funcs[pipe]->disable_vblank(crtc);
 }
 
+static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
+{
+	struct rockchip_drm_private *private = drm_dev->dev_private;
+	struct iommu_domain_geometry *geometry;
+	u64 start, end;
+
+	if (!is_support_iommu)
+		return 0;
+
+	private->domain = iommu_domain_alloc(&platform_bus_type);
+	if (!private->domain)
+		return -ENOMEM;
+
+	geometry = &private->domain->geometry;
+	start = geometry->aperture_start;
+	end = geometry->aperture_end;
+
+	DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n",
+		  start, end);
+	drm_mm_init(&private->mm, start, end - start + 1);
+
+	return 0;
+}
+
+static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
+{
+	struct rockchip_drm_private *private = drm_dev->dev_private;
+
+	if (!is_support_iommu)
+		return;
+
+	drm_mm_takedown(&private->mm);
+	iommu_domain_free(private->domain);
+}
+
 static int rockchip_drm_bind(struct device *dev)
 {
 	struct drm_device *drm_dev;
 	struct rockchip_drm_private *private;
-	struct dma_iommu_mapping *mapping = NULL;
 	int ret;
 
 	drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
@@ -162,38 +199,14 @@ static int rockchip_drm_bind(struct device *dev)
 
 	rockchip_drm_mode_config_init(drm_dev);
 
-	dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
-				      GFP_KERNEL);
-	if (!dev->dma_parms) {
-		ret = -ENOMEM;
+	ret = rockchip_drm_init_iommu(drm_dev);
+	if (ret)
 		goto err_config_cleanup;
-	}
-
-	if (is_support_iommu) {
-		/* TODO(djkurtz): fetch the mapping start/size from somewhere */
-		mapping = arm_iommu_create_mapping(&platform_bus_type,
-						   0x00000000,
-						   SZ_2G);
-		if (IS_ERR(mapping)) {
-			ret = PTR_ERR(mapping);
-			goto err_config_cleanup;
-		}
-
-		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
-		if (ret)
-			goto err_release_mapping;
-
-		dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
-
-		ret = arm_iommu_attach_device(dev, mapping);
-		if (ret)
-			goto err_release_mapping;
-	}
 
 	/* Try to bind all sub drivers. */
 	ret = component_bind_all(dev, drm_dev);
 	if (ret)
-		goto err_detach_device;
+		goto err_iommu_cleanup;
 
 	/* init kms poll for handling hpd */
 	drm_kms_helper_poll_init(drm_dev);
@@ -218,8 +231,6 @@ static int rockchip_drm_bind(struct device *dev)
 	if (ret)
 		goto err_fbdev_fini;
 
-	if (is_support_iommu)
-		arm_iommu_release_mapping(mapping);
 	return 0;
 err_fbdev_fini:
 	rockchip_drm_fbdev_fini(drm_dev);
@@ -228,12 +239,8 @@ err_vblank_cleanup:
 err_kms_helper_poll_fini:
 	drm_kms_helper_poll_fini(drm_dev);
 	component_unbind_all(dev, drm_dev);
-err_detach_device:
-	if (is_support_iommu)
-		arm_iommu_detach_device(dev);
-err_release_mapping:
-	if (is_support_iommu)
-		arm_iommu_release_mapping(mapping);
+err_iommu_cleanup:
+	rockchip_iommu_cleanup(drm_dev);
 err_config_cleanup:
 	drm_mode_config_cleanup(drm_dev);
 	drm_dev->dev_private = NULL;
@@ -250,8 +257,7 @@ static void rockchip_drm_unbind(struct device *dev)
 	drm_vblank_cleanup(drm_dev);
 	drm_kms_helper_poll_fini(drm_dev);
 	component_unbind_all(dev, drm_dev);
-	if (is_support_iommu)
-		arm_iommu_detach_device(dev);
+	rockchip_iommu_cleanup(drm_dev);
 	drm_mode_config_cleanup(drm_dev);
 	drm_dev->dev_private = NULL;
 	drm_dev_unregister(drm_dev);
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1439047 — Re: [PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach devices

FromMark yao <mark.yao@rock-chips.com>
Date2016-07-08 03:00 +0200
SubjectRe: [PATCH v5 7/8] drm/rockchip: Use common IOMMU API to attach devices
Message-ID<rSsj7-5Tb-3@gated-at.bofh.it>
In reply to#1430291
On 2016年06月24日 10:13, Shunqian Zheng wrote:
> Rockchip DRM used the arm special API, arm_iommu_*(), to attach
> iommu for ARM32 SoCs. This patch convert to common iommu API
> so it would support ARM64 like RK3399.
>
> Since previous patch added support for direct IOMMU address space
> management, there is no need to use DMA API anymore and this patch wires
> things to use the new method.
>
> Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>

Looks good for me, and it works on rk3399 board, so

Acked-by: Mark Yao <mark.yao@rock-chips.com>

> ---
>   drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 100 +++++++++++++++-------------
>   1 file changed, 53 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> index 8b96c69..ca9624f 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> @@ -14,18 +14,18 @@
>    * GNU General Public License for more details.
>    */
>   
> -#include <asm/dma-iommu.h>
> -
>   #include <drm/drmP.h>
>   #include <drm/drm_crtc_helper.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_gem_cma_helper.h>
>   #include <linux/dma-mapping.h>
> +#include <linux/dma-iommu.h>
>   #include <linux/pm_runtime.h>
>   #include <linux/module.h>
>   #include <linux/of_graph.h>
>   #include <linux/component.h>
>   #include <linux/console.h>
> +#include <linux/iommu.h>
>   
>   #include <drm/rockchip_drm.h>
>   
> @@ -51,28 +51,31 @@ static struct drm_driver rockchip_drm_driver;
>   int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
>   				   struct device *dev)
>   {
> -	struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping;
> +	struct rockchip_drm_private *private = drm_dev->dev_private;
>   	int ret;
>   
>   	if (!is_support_iommu)
>   		return 0;
>   
> -	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
> -	if (ret)
> +	ret = iommu_attach_device(private->domain, dev);
> +	if (ret) {
> +		dev_err(dev, "Failed to attach iommu device\n");
>   		return ret;
> +	}
>   
> -	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
> -
> -	return arm_iommu_attach_device(dev, mapping);
> +	return 0;
>   }
>   
>   void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
>   				    struct device *dev)
>   {
> +	struct rockchip_drm_private *private = drm_dev->dev_private;
> +	struct iommu_domain *domain = private->domain;
> +
>   	if (!is_support_iommu)
>   		return;
>   
> -	arm_iommu_detach_device(dev);
> +	iommu_detach_device(domain, dev);
>   }
>   
>   int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
> @@ -137,11 +140,45 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev,
>   		priv->crtc_funcs[pipe]->disable_vblank(crtc);
>   }
>   
> +static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
> +{
> +	struct rockchip_drm_private *private = drm_dev->dev_private;
> +	struct iommu_domain_geometry *geometry;
> +	u64 start, end;
> +
> +	if (!is_support_iommu)
> +		return 0;
> +
> +	private->domain = iommu_domain_alloc(&platform_bus_type);
> +	if (!private->domain)
> +		return -ENOMEM;
> +
> +	geometry = &private->domain->geometry;
> +	start = geometry->aperture_start;
> +	end = geometry->aperture_end;
> +
> +	DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n",
> +		  start, end);
> +	drm_mm_init(&private->mm, start, end - start + 1);
> +
> +	return 0;
> +}
> +
> +static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
> +{
> +	struct rockchip_drm_private *private = drm_dev->dev_private;
> +
> +	if (!is_support_iommu)
> +		return;
> +
> +	drm_mm_takedown(&private->mm);
> +	iommu_domain_free(private->domain);
> +}
> +
>   static int rockchip_drm_bind(struct device *dev)
>   {
>   	struct drm_device *drm_dev;
>   	struct rockchip_drm_private *private;
> -	struct dma_iommu_mapping *mapping = NULL;
>   	int ret;
>   
>   	drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
> @@ -162,38 +199,14 @@ static int rockchip_drm_bind(struct device *dev)
>   
>   	rockchip_drm_mode_config_init(drm_dev);
>   
> -	dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
> -				      GFP_KERNEL);
> -	if (!dev->dma_parms) {
> -		ret = -ENOMEM;
> +	ret = rockchip_drm_init_iommu(drm_dev);
> +	if (ret)
>   		goto err_config_cleanup;
> -	}
> -
> -	if (is_support_iommu) {
> -		/* TODO(djkurtz): fetch the mapping start/size from somewhere */
> -		mapping = arm_iommu_create_mapping(&platform_bus_type,
> -						   0x00000000,
> -						   SZ_2G);
> -		if (IS_ERR(mapping)) {
> -			ret = PTR_ERR(mapping);
> -			goto err_config_cleanup;
> -		}
> -
> -		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -		if (ret)
> -			goto err_release_mapping;
> -
> -		dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
> -
> -		ret = arm_iommu_attach_device(dev, mapping);
> -		if (ret)
> -			goto err_release_mapping;
> -	}
>   
>   	/* Try to bind all sub drivers. */
>   	ret = component_bind_all(dev, drm_dev);
>   	if (ret)
> -		goto err_detach_device;
> +		goto err_iommu_cleanup;
>   
>   	/* init kms poll for handling hpd */
>   	drm_kms_helper_poll_init(drm_dev);
> @@ -218,8 +231,6 @@ static int rockchip_drm_bind(struct device *dev)
>   	if (ret)
>   		goto err_fbdev_fini;
>   
> -	if (is_support_iommu)
> -		arm_iommu_release_mapping(mapping);
>   	return 0;
>   err_fbdev_fini:
>   	rockchip_drm_fbdev_fini(drm_dev);
> @@ -228,12 +239,8 @@ err_vblank_cleanup:
>   err_kms_helper_poll_fini:
>   	drm_kms_helper_poll_fini(drm_dev);
>   	component_unbind_all(dev, drm_dev);
> -err_detach_device:
> -	if (is_support_iommu)
> -		arm_iommu_detach_device(dev);
> -err_release_mapping:
> -	if (is_support_iommu)
> -		arm_iommu_release_mapping(mapping);
> +err_iommu_cleanup:
> +	rockchip_iommu_cleanup(drm_dev);
>   err_config_cleanup:
>   	drm_mode_config_cleanup(drm_dev);
>   	drm_dev->dev_private = NULL;
> @@ -250,8 +257,7 @@ static void rockchip_drm_unbind(struct device *dev)
>   	drm_vblank_cleanup(drm_dev);
>   	drm_kms_helper_poll_fini(drm_dev);
>   	component_unbind_all(dev, drm_dev);
> -	if (is_support_iommu)
> -		arm_iommu_detach_device(dev);
> +	rockchip_iommu_cleanup(drm_dev);
>   	drm_mode_config_cleanup(drm_dev);
>   	drm_dev->dev_private = NULL;
>   	drm_dev_unregister(drm_dev);


-- 
Mark Yao

[toc] | [prev] | [next] | [standalone]


#1430292 — [PATCH v5 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter
Message-ID<rNoSS-230-13@gated-at.bofh.it>
In reply to#1430290
From: Simon Xue <xxm@rock-chips.com>

Even though the IOMMU shares IRQ with its master, the struct device
passed to {request,free}_irq is supposed to represent the device that is
signalling the interrupt. This patch makes the driver use IOMMU device
instead of master's device to make things clear.

Signed-off-by: Simon Xue <xxm@rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/iommu/rockchip-iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 25b4627..5a9659a 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -807,7 +807,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 
 	iommu->domain = domain;
 
-	ret = devm_request_irq(dev, iommu->irq, rk_iommu_irq,
+	ret = devm_request_irq(iommu->dev, iommu->irq, rk_iommu_irq,
 			       IRQF_SHARED, dev_name(dev), iommu);
 	if (ret)
 		return ret;
@@ -860,7 +860,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
 	}
 	rk_iommu_disable_stall(iommu);
 
-	devm_free_irq(dev, iommu->irq, iommu);
+	devm_free_irq(iommu->dev, iommu->irq, iommu);
 
 	iommu->domain = NULL;
 
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1430294 — [PATCH v5 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops
Message-ID<rNoSS-230-15@gated-at.bofh.it>
In reply to#1430290
From: Simon Xue <xxm@rock-chips.com>

The iommu_dma_alloc() in iommu/dma-iommu.c calls iommu_map_sg()
that requires the callback iommu_ops .map_sg(). Adding the
default_iommu_map_sg() to Rockchip IOMMU accordingly.

Signed-off-by: Simon Xue <xxm@rock-chips.com>
Signed-off-by: Shunqian Zheng <xxm@rock-chips.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/iommu/rockchip-iommu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 5a9659a..53fa0d9 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1022,6 +1022,7 @@ static const struct iommu_ops rk_iommu_ops = {
 	.detach_dev = rk_iommu_detach_device,
 	.map = rk_iommu_map,
 	.unmap = rk_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
 	.add_device = rk_iommu_add_device,
 	.remove_device = rk_iommu_remove_device,
 	.iova_to_phys = rk_iommu_iova_to_phys,
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1430295 — [PATCH v5 3/8] iommu/rockchip: Fix allocation of bases array in driver probe

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 3/8] iommu/rockchip: Fix allocation of bases array in driver probe
Message-ID<rNoSS-230-17@gated-at.bofh.it>
In reply to#1430290
In .probe(), devm_kzalloc() is called with size == 0 and works only
by luck, due to internal behavior of the allocator and the fact
that the proper allocation size is small. Let's use proper value for
calculating the size.

Fixes: cd6438c5f844 ("iommu/rockchip: Reconstruct to support multi slaves")

Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
 drivers/iommu/rockchip-iommu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 53fa0d9..8a5bac7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1034,6 +1034,7 @@ static int rk_iommu_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct rk_iommu *iommu;
 	struct resource *res;
+	int num_res = pdev->num_resources;
 	int i;
 
 	iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL);
@@ -1043,12 +1044,13 @@ static int rk_iommu_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, iommu);
 	iommu->dev = dev;
 	iommu->num_mmu = 0;
-	iommu->bases = devm_kzalloc(dev, sizeof(*iommu->bases) * iommu->num_mmu,
+
+	iommu->bases = devm_kzalloc(dev, sizeof(*iommu->bases) * num_res,
 				    GFP_KERNEL);
 	if (!iommu->bases)
 		return -ENOMEM;
 
-	for (i = 0; i < pdev->num_resources; i++) {
+	for (i = 0; i < num_res; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		if (!res)
 			continue;
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1430297 — [PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain
Message-ID<rNoSS-230-19@gated-at.bofh.it>
In reply to#1430290
From: Tomasz Figa <tfiga@chromium.org>

The API is not suitable for subsystems consisting of multiple devices
and requires severe hacks to use it. To mitigate this, this patch
implements allocation and address space management locally by using
helpers provided by DRM framework, like other DRM drivers do, e.g.
Tegra.

This patch should not introduce any functional changes until the driver
is made to attach subdevices into an IOMMU domain with the generic IOMMU
API, which will happen in following patch. Based heavily on GEM
implementation of Tegra DRM driver.

Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 221 ++++++++++++++++++++++++++--
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
 3 files changed, 222 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..5ab1223 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -30,6 +30,7 @@
 
 struct drm_device;
 struct drm_connector;
+struct iommu_domain;
 
 /*
  * Rockchip drm private crtc funcs.
@@ -61,6 +62,8 @@ struct rockchip_drm_private {
 	struct drm_gem_object *fbdev_bo;
 	const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
 	struct drm_atomic_state *state;
+	struct iommu_domain *domain;
+	struct drm_mm mm;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 394f92b..e7cd93d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -19,11 +19,135 @@
 #include <drm/rockchip_drm.h>
 
 #include <linux/dma-attrs.h>
+#include <linux/iommu.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 
-static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
+static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
+{
+	struct drm_device *drm = rk_obj->base.dev;
+	struct rockchip_drm_private *private = drm->dev_private;
+	int prot = IOMMU_READ | IOMMU_WRITE;
+	ssize_t ret;
+
+	ret = drm_mm_insert_node_generic(&private->mm, &rk_obj->mm,
+					 rk_obj->base.size, PAGE_SIZE,
+					 0, 0, 0);
+	if (ret < 0) {
+		DRM_ERROR("out of I/O virtual memory: %zd\n", ret);
+		return ret;
+	}
+
+	rk_obj->dma_addr = rk_obj->mm.start;
+
+	ret = iommu_map_sg(private->domain, rk_obj->dma_addr, rk_obj->sgt->sgl,
+			   rk_obj->sgt->nents, prot);
+	if (ret < 0) {
+		DRM_ERROR("failed to map buffer: %zd\n", ret);
+		goto err_remove_node;
+	}
+
+	rk_obj->size = ret;
+
+	return 0;
+
+err_remove_node:
+	drm_mm_remove_node(&rk_obj->mm);
+
+	return ret;
+}
+
+static int rockchip_gem_iommu_unmap(struct rockchip_gem_object *rk_obj)
+{
+	struct drm_device *drm = rk_obj->base.dev;
+	struct rockchip_drm_private *private = drm->dev_private;
+
+	iommu_unmap(private->domain, rk_obj->dma_addr, rk_obj->size);
+	drm_mm_remove_node(&rk_obj->mm);
+
+	return 0;
+}
+
+static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
+{
+	struct drm_device *drm = rk_obj->base.dev;
+	int ret, i;
+	struct scatterlist *s;
+
+	rk_obj->pages = drm_gem_get_pages(&rk_obj->base);
+	if (IS_ERR(rk_obj->pages))
+		return PTR_ERR(rk_obj->pages);
+
+	rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
+
+	rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
+	if (IS_ERR(rk_obj->sgt)) {
+		ret = PTR_ERR(rk_obj->sgt);
+		goto err_put_pages;
+	}
+
+	/*
+	 * Fake up the SG table so that dma_sync_sg_for_device() can be used
+	 * to flush the pages associated with it.
+	 *
+	 * TODO: Replace this by drm_clflush_sg() once it can be implemented
+	 * without relying on symbols that are not exported.
+	 */
+	for_each_sg(rk_obj->sgt->sgl, s, rk_obj->sgt->nents, i)
+		sg_dma_address(s) = sg_phys(s);
+
+	dma_sync_sg_for_device(drm->dev, rk_obj->sgt->sgl, rk_obj->sgt->nents,
+			       DMA_TO_DEVICE);
+
+	return 0;
+
+err_put_pages:
+	drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
+	return ret;
+}
+
+static void rockchip_gem_put_pages(struct rockchip_gem_object *rk_obj)
+{
+	sg_free_table(rk_obj->sgt);
+	kfree(rk_obj->sgt);
+	drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
+}
+
+static int rockchip_gem_alloc_iommu(struct rockchip_gem_object *rk_obj,
+				    bool alloc_kmap)
+{
+	int ret;
+
+	ret = rockchip_gem_get_pages(rk_obj);
+	if (ret < 0)
+		return ret;
+
+	ret = rockchip_gem_iommu_map(rk_obj);
+	if (ret < 0)
+		goto err_free;
+
+	if (alloc_kmap) {
+		rk_obj->kvaddr = vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
+				      pgprot_writecombine(PAGE_KERNEL));
+		if (!rk_obj->kvaddr) {
+			DRM_ERROR("failed to vmap() buffer\n");
+			ret = -ENOMEM;
+			goto err_unmap;
+		}
+	}
+
+	return 0;
+
+err_unmap:
+	rockchip_gem_iommu_unmap(rk_obj);
+err_free:
+	rockchip_gem_put_pages(rk_obj);
+
+	return ret;
+}
+
+static int rockchip_gem_alloc_dma(struct rockchip_gem_object *rk_obj,
 				  bool alloc_kmap)
 {
 	struct drm_gem_object *obj = &rk_obj->base;
@@ -46,32 +170,93 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
 	return 0;
 }
 
-static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
+static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
+				  bool alloc_kmap)
 {
 	struct drm_gem_object *obj = &rk_obj->base;
 	struct drm_device *drm = obj->dev;
+	struct rockchip_drm_private *private = drm->dev_private;
 
-	dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
-		       &rk_obj->dma_attrs);
+	if (private->domain)
+		return rockchip_gem_alloc_iommu(rk_obj, alloc_kmap);
+	else
+		return rockchip_gem_alloc_dma(rk_obj, alloc_kmap);
 }
 
-static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
-					struct vm_area_struct *vma)
+static void rockchip_gem_free_iommu(struct rockchip_gem_object *rk_obj)
+{
+	vunmap(rk_obj->kvaddr);
+	rockchip_gem_iommu_unmap(rk_obj);
+	rockchip_gem_put_pages(rk_obj);
+}
 
+static void rockchip_gem_free_dma(struct rockchip_gem_object *rk_obj)
 {
+	struct drm_gem_object *obj = &rk_obj->base;
+	struct drm_device *drm = obj->dev;
+
+	dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr,
+		       rk_obj->dma_addr, &rk_obj->dma_attrs);
+}
+
+static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
+{
+	if (rk_obj->pages)
+		rockchip_gem_free_iommu(rk_obj);
+	else
+		rockchip_gem_free_dma(rk_obj);
+}
+
+static int rockchip_drm_gem_object_mmap_iommu(struct drm_gem_object *obj,
+					      struct vm_area_struct *vma)
+{
+	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
+	unsigned int i, count = obj->size >> PAGE_SHIFT;
+	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	unsigned long uaddr = vma->vm_start;
 	int ret;
+
+	if (user_count == 0 || user_count > count)
+		return -ENXIO;
+
+	for (i = 0; i < user_count; i++) {
+		ret = vm_insert_page(vma, uaddr, rk_obj->pages[i]);
+		if (ret)
+			return ret;
+		uaddr += PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+static int rockchip_drm_gem_object_mmap_dma(struct drm_gem_object *obj,
+					    struct vm_area_struct *vma)
+{
 	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 	struct drm_device *drm = obj->dev;
 
+	return dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
+			      obj->size, &rk_obj->dma_attrs);
+}
+
+static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
+					struct vm_area_struct *vma)
+{
+	int ret;
+	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
+
 	/*
-	 * dma_alloc_attrs() allocated a struct page table for rk_obj, so clear
+	 * We allocated a struct page table for rk_obj, so clear
 	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
 	 */
 	vma->vm_flags &= ~VM_PFNMAP;
 	vma->vm_pgoff = 0;
 
-	ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
-			     obj->size, &rk_obj->dma_attrs);
+	if (rk_obj->pages)
+		ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
+	else
+		ret = rockchip_drm_gem_object_mmap_dma(obj, vma);
+
 	if (ret)
 		drm_gem_vm_close(vma);
 
@@ -121,7 +306,7 @@ struct rockchip_gem_object *
 
 	obj = &rk_obj->base;
 
-	drm_gem_private_object_init(drm, obj, size);
+	drm_gem_object_init(drm, obj, size);
 
 	ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
 	if (ret)
@@ -277,6 +462,9 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
 	struct sg_table *sgt;
 	int ret;
 
+	if (rk_obj->pages)
+		return drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
+
 	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
 	if (!sgt)
 		return ERR_PTR(-ENOMEM);
@@ -297,6 +485,10 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
 	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
+	if (rk_obj->pages)
+		return vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
+			    pgprot_writecombine(PAGE_KERNEL));
+
 	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
 		return NULL;
 
@@ -305,5 +497,12 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 
 void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 {
-	/* Nothing to do */
+	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
+
+	if (rk_obj->pages) {
+		vunmap(vaddr);
+		return;
+	}
+
+	/* Nothing to do if allocated by DMA mapping API. */
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
index 3584b94..6aa61b2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
@@ -23,7 +23,16 @@ struct rockchip_gem_object {
 
 	void *kvaddr;
 	dma_addr_t dma_addr;
+
+	/* Used when IOMMU is disabled */
 	struct dma_attrs dma_attrs;
+
+	/* Used when IOMMU is enabled */
+	struct drm_mm_node mm;
+	unsigned long num_pages;
+	struct page **pages;
+	struct sg_table *sgt;
+	size_t size;
 };
 
 struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj);
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1439046 — Re: [PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain

FromMark yao <mark.yao@rock-chips.com>
Date2016-07-08 03:00 +0200
SubjectRe: [PATCH v5 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain
Message-ID<rSsj7-5Tb-5@gated-at.bofh.it>
In reply to#1430297
On 2016年06月24日 10:13, Shunqian Zheng wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> The API is not suitable for subsystems consisting of multiple devices
> and requires severe hacks to use it. To mitigate this, this patch
> implements allocation and address space management locally by using
> helpers provided by DRM framework, like other DRM drivers do, e.g.
> Tegra.
>
> This patch should not introduce any functional changes until the driver
> is made to attach subdevices into an IOMMU domain with the generic IOMMU
> API, which will happen in following patch. Based heavily on GEM
> implementation of Tegra DRM driver.

Acked-by: Mark Yao <mark.yao@rock-chips.com>
>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
>   drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 221 ++++++++++++++++++++++++++--
>   drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
>   3 files changed, 222 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index ea39329..5ab1223 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -30,6 +30,7 @@
>   
>   struct drm_device;
>   struct drm_connector;
> +struct iommu_domain;
>   
>   /*
>    * Rockchip drm private crtc funcs.
> @@ -61,6 +62,8 @@ struct rockchip_drm_private {
>   	struct drm_gem_object *fbdev_bo;
>   	const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
>   	struct drm_atomic_state *state;
> +	struct iommu_domain *domain;
> +	struct drm_mm mm;
>   };
>   
>   int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
> index 394f92b..e7cd93d 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
> @@ -19,11 +19,135 @@
>   #include <drm/rockchip_drm.h>
>   
>   #include <linux/dma-attrs.h>
> +#include <linux/iommu.h>
>   
>   #include "rockchip_drm_drv.h"
>   #include "rockchip_drm_gem.h"
>   
> -static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
> +static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
> +{
> +	struct drm_device *drm = rk_obj->base.dev;
> +	struct rockchip_drm_private *private = drm->dev_private;
> +	int prot = IOMMU_READ | IOMMU_WRITE;
> +	ssize_t ret;
> +
> +	ret = drm_mm_insert_node_generic(&private->mm, &rk_obj->mm,
> +					 rk_obj->base.size, PAGE_SIZE,
> +					 0, 0, 0);
> +	if (ret < 0) {
> +		DRM_ERROR("out of I/O virtual memory: %zd\n", ret);
> +		return ret;
> +	}
> +
> +	rk_obj->dma_addr = rk_obj->mm.start;
> +
> +	ret = iommu_map_sg(private->domain, rk_obj->dma_addr, rk_obj->sgt->sgl,
> +			   rk_obj->sgt->nents, prot);
> +	if (ret < 0) {
> +		DRM_ERROR("failed to map buffer: %zd\n", ret);
> +		goto err_remove_node;
> +	}
> +
> +	rk_obj->size = ret;
> +
> +	return 0;
> +
> +err_remove_node:
> +	drm_mm_remove_node(&rk_obj->mm);
> +
> +	return ret;
> +}
> +
> +static int rockchip_gem_iommu_unmap(struct rockchip_gem_object *rk_obj)
> +{
> +	struct drm_device *drm = rk_obj->base.dev;
> +	struct rockchip_drm_private *private = drm->dev_private;
> +
> +	iommu_unmap(private->domain, rk_obj->dma_addr, rk_obj->size);
> +	drm_mm_remove_node(&rk_obj->mm);
> +
> +	return 0;
> +}
> +
> +static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
> +{
> +	struct drm_device *drm = rk_obj->base.dev;
> +	int ret, i;
> +	struct scatterlist *s;
> +
> +	rk_obj->pages = drm_gem_get_pages(&rk_obj->base);
> +	if (IS_ERR(rk_obj->pages))
> +		return PTR_ERR(rk_obj->pages);
> +
> +	rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
> +
> +	rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
> +	if (IS_ERR(rk_obj->sgt)) {
> +		ret = PTR_ERR(rk_obj->sgt);
> +		goto err_put_pages;
> +	}
> +
> +	/*
> +	 * Fake up the SG table so that dma_sync_sg_for_device() can be used
> +	 * to flush the pages associated with it.
> +	 *
> +	 * TODO: Replace this by drm_clflush_sg() once it can be implemented
> +	 * without relying on symbols that are not exported.
> +	 */
> +	for_each_sg(rk_obj->sgt->sgl, s, rk_obj->sgt->nents, i)
> +		sg_dma_address(s) = sg_phys(s);
> +
> +	dma_sync_sg_for_device(drm->dev, rk_obj->sgt->sgl, rk_obj->sgt->nents,
> +			       DMA_TO_DEVICE);
> +
> +	return 0;
> +
> +err_put_pages:
> +	drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
> +	return ret;
> +}
> +
> +static void rockchip_gem_put_pages(struct rockchip_gem_object *rk_obj)
> +{
> +	sg_free_table(rk_obj->sgt);
> +	kfree(rk_obj->sgt);
> +	drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
> +}
> +
> +static int rockchip_gem_alloc_iommu(struct rockchip_gem_object *rk_obj,
> +				    bool alloc_kmap)
> +{
> +	int ret;
> +
> +	ret = rockchip_gem_get_pages(rk_obj);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = rockchip_gem_iommu_map(rk_obj);
> +	if (ret < 0)
> +		goto err_free;
> +
> +	if (alloc_kmap) {
> +		rk_obj->kvaddr = vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
> +				      pgprot_writecombine(PAGE_KERNEL));
> +		if (!rk_obj->kvaddr) {
> +			DRM_ERROR("failed to vmap() buffer\n");
> +			ret = -ENOMEM;
> +			goto err_unmap;
> +		}
> +	}
> +
> +	return 0;
> +
> +err_unmap:
> +	rockchip_gem_iommu_unmap(rk_obj);
> +err_free:
> +	rockchip_gem_put_pages(rk_obj);
> +
> +	return ret;
> +}
> +
> +static int rockchip_gem_alloc_dma(struct rockchip_gem_object *rk_obj,
>   				  bool alloc_kmap)
>   {
>   	struct drm_gem_object *obj = &rk_obj->base;
> @@ -46,32 +170,93 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
>   	return 0;
>   }
>   
> -static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
> +static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
> +				  bool alloc_kmap)
>   {
>   	struct drm_gem_object *obj = &rk_obj->base;
>   	struct drm_device *drm = obj->dev;
> +	struct rockchip_drm_private *private = drm->dev_private;
>   
> -	dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
> -		       &rk_obj->dma_attrs);
> +	if (private->domain)
> +		return rockchip_gem_alloc_iommu(rk_obj, alloc_kmap);
> +	else
> +		return rockchip_gem_alloc_dma(rk_obj, alloc_kmap);
>   }
>   
> -static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
> -					struct vm_area_struct *vma)
> +static void rockchip_gem_free_iommu(struct rockchip_gem_object *rk_obj)
> +{
> +	vunmap(rk_obj->kvaddr);
> +	rockchip_gem_iommu_unmap(rk_obj);
> +	rockchip_gem_put_pages(rk_obj);
> +}
>   
> +static void rockchip_gem_free_dma(struct rockchip_gem_object *rk_obj)
>   {
> +	struct drm_gem_object *obj = &rk_obj->base;
> +	struct drm_device *drm = obj->dev;
> +
> +	dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr,
> +		       rk_obj->dma_addr, &rk_obj->dma_attrs);
> +}
> +
> +static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
> +{
> +	if (rk_obj->pages)
> +		rockchip_gem_free_iommu(rk_obj);
> +	else
> +		rockchip_gem_free_dma(rk_obj);
> +}
> +
> +static int rockchip_drm_gem_object_mmap_iommu(struct drm_gem_object *obj,
> +					      struct vm_area_struct *vma)
> +{
> +	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
> +	unsigned int i, count = obj->size >> PAGE_SHIFT;
> +	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
> +	unsigned long uaddr = vma->vm_start;
>   	int ret;
> +
> +	if (user_count == 0 || user_count > count)
> +		return -ENXIO;
> +
> +	for (i = 0; i < user_count; i++) {
> +		ret = vm_insert_page(vma, uaddr, rk_obj->pages[i]);
> +		if (ret)
> +			return ret;
> +		uaddr += PAGE_SIZE;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_drm_gem_object_mmap_dma(struct drm_gem_object *obj,
> +					    struct vm_area_struct *vma)
> +{
>   	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
>   	struct drm_device *drm = obj->dev;
>   
> +	return dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
> +			      obj->size, &rk_obj->dma_attrs);
> +}
> +
> +static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
> +					struct vm_area_struct *vma)
> +{
> +	int ret;
> +	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
> +
>   	/*
> -	 * dma_alloc_attrs() allocated a struct page table for rk_obj, so clear
> +	 * We allocated a struct page table for rk_obj, so clear
>   	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
>   	 */
>   	vma->vm_flags &= ~VM_PFNMAP;
>   	vma->vm_pgoff = 0;
>   
> -	ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
> -			     obj->size, &rk_obj->dma_attrs);
> +	if (rk_obj->pages)
> +		ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
> +	else
> +		ret = rockchip_drm_gem_object_mmap_dma(obj, vma);
> +
>   	if (ret)
>   		drm_gem_vm_close(vma);
>   
> @@ -121,7 +306,7 @@ struct rockchip_gem_object *
>   
>   	obj = &rk_obj->base;
>   
> -	drm_gem_private_object_init(drm, obj, size);
> +	drm_gem_object_init(drm, obj, size);
>   
>   	ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
>   	if (ret)
> @@ -277,6 +462,9 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
>   	struct sg_table *sgt;
>   	int ret;
>   
> +	if (rk_obj->pages)
> +		return drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
> +
>   	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
>   	if (!sgt)
>   		return ERR_PTR(-ENOMEM);
> @@ -297,6 +485,10 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
>   {
>   	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
>   
> +	if (rk_obj->pages)
> +		return vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
> +			    pgprot_writecombine(PAGE_KERNEL));
> +
>   	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
>   		return NULL;
>   
> @@ -305,5 +497,12 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
>   
>   void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
>   {
> -	/* Nothing to do */
> +	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
> +
> +	if (rk_obj->pages) {
> +		vunmap(vaddr);
> +		return;
> +	}
> +
> +	/* Nothing to do if allocated by DMA mapping API. */
>   }
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
> index 3584b94..6aa61b2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
> @@ -23,7 +23,16 @@ struct rockchip_gem_object {
>   
>   	void *kvaddr;
>   	dma_addr_t dma_addr;
> +
> +	/* Used when IOMMU is disabled */
>   	struct dma_attrs dma_attrs;
> +
> +	/* Used when IOMMU is enabled */
> +	struct drm_mm_node mm;
> +	unsigned long num_pages;
> +	struct page **pages;
> +	struct sg_table *sgt;
> +	size_t size;
>   };
>   
>   struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj);


-- 
Mark Yao

[toc] | [prev] | [next] | [standalone]


#1430298 — [PATCH v5 5/8] iommu/rockchip: Prepare to support generic DMA mapping

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 5/8] iommu/rockchip: Prepare to support generic DMA mapping
Message-ID<rNoSS-230-21@gated-at.bofh.it>
In reply to#1430290
Set geometry for allocated domains and fix .domain_alloc() callback to
work with IOMMU_DOMAIN_DMA domain type, which is used for implicit
domains on ARM64.

Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/iommu/rockchip-iommu.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 712ed75..9afcbf7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -889,7 +889,7 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 	struct platform_device *pdev;
 	struct device *iommu_dev;
 
-	if (type != IOMMU_DOMAIN_UNMANAGED)
+	if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
 		return NULL;
 
 	/* Register a pdev per domain, so DMA API can base on this *dev
@@ -906,8 +906,8 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 
 	rk_domain->pdev = pdev;
 
-	/* To init the iovad which is required by iommu_dma_init_domain() */
-	if (iommu_get_dma_cookie(&rk_domain->domain))
+	if (type == IOMMU_DOMAIN_DMA &&
+	    iommu_get_dma_cookie(&rk_domain->domain))
 		goto err_unreg_pdev;
 
 	/*
@@ -933,12 +933,17 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 	spin_lock_init(&rk_domain->dt_lock);
 	INIT_LIST_HEAD(&rk_domain->iommus);
 
+	rk_domain->domain.geometry.aperture_start = 0;
+	rk_domain->domain.geometry.aperture_end   = DMA_BIT_MASK(32);
+	rk_domain->domain.geometry.force_aperture = true;
+
 	return &rk_domain->domain;
 
 err_free_dt:
 	free_page((unsigned long)rk_domain->dt);
 err_put_cookie:
-	iommu_put_dma_cookie(&rk_domain->domain);
+	if (type == IOMMU_DOMAIN_DMA)
+		iommu_put_dma_cookie(&rk_domain->domain);
 err_unreg_pdev:
 	platform_device_unregister(pdev);
 
@@ -967,7 +972,8 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
 			 SPAGE_SIZE, DMA_TO_DEVICE);
 	free_page((unsigned long)rk_domain->dt);
 
-	iommu_put_dma_cookie(&rk_domain->domain);
+	if (domain->type == IOMMU_DOMAIN_DMA)
+		iommu_put_dma_cookie(&rk_domain->domain);
 
 	platform_device_unregister(rk_domain->pdev);
 }
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1430299 — [PATCH v5 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64

FromShunqian Zheng <zhengsq@rock-chips.com>
Date2016-06-24 04:20 +0200
Subject[PATCH v5 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64
Message-ID<rNoSS-230-23@gated-at.bofh.it>
In reply to#1430290
From: Simon Xue <xxm@rock-chips.com>

This patch makes it possible to compile the rockchip-iommu driver on
ARM64, so that it can be used with 64-bit SoCs equipped with this type
of IOMMU.

Signed-off-by: Simon Xue <xxm@rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/iommu/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ad08603..5572621 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -218,7 +218,7 @@ config OMAP_IOMMU_DEBUG
 
 config ROCKCHIP_IOMMU
 	bool "Rockchip IOMMU Support"
-	depends on ARM
+	depends on ARM || ARM64
 	depends on ARCH_ROCKCHIP || COMPILE_TEST
 	select IOMMU_API
 	select ARM_DMA_USE_IOMMU
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1432004

FromJoerg Roedel <joro@8bytes.org>
Date2016-06-27 15:00 +0200
Message-ID<rOEiR-kO-19@gated-at.bofh.it>
In reply to#1430290
On Fri, Jun 24, 2016 at 10:13:25AM +0800, Shunqian Zheng wrote:
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 100 +++++++------
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
>  drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 221 ++++++++++++++++++++++++++--
>  drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
>  drivers/iommu/Kconfig                       |   2 +-
>  drivers/iommu/rockchip-iommu.c              | 181 +++++++++++++++++------
>  6 files changed, 413 insertions(+), 103 deletions(-)

Applied the IOMMU patches, thanks.


	Joerg

[toc] | [prev] | [next] | [standalone]


#1439049

FromMark yao <mark.yao@rock-chips.com>
Date2016-07-08 03:10 +0200
Message-ID<rSssN-6bs-1@gated-at.bofh.it>
In reply to#1432004
On 2016年06月27日 20:57, Joerg Roedel wrote:
> On Fri, Jun 24, 2016 at 10:13:25AM +0800, Shunqian Zheng wrote:
>>   drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 100 +++++++------
>>   drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
>>   drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 221 ++++++++++++++++++++++++++--
>>   drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
>>   drivers/iommu/Kconfig                       |   2 +-
>>   drivers/iommu/rockchip-iommu.c              | 181 +++++++++++++++++------
>>   6 files changed, 413 insertions(+), 103 deletions(-)
> Applied the IOMMU patches, thanks.
>
>
> 	Joerg
>
>
>
>

Hi Joerg

The drm rockchip patches are dependent on iommu/rockchip patches, can 
you also apply these patches together? So that can avoid compile problem.

Thanks.

-- 
Mark Yao

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web