Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1430290 > unrolled thread
| Started by | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| First post | 2016-06-24 04:20 +0200 |
| Last post | 2016-07-08 03:10 +0200 |
| Articles | 12 — 3 participants |
Back to article view | Back to linux.kernel
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
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-06-24 04:20 +0200 |
| Subject | iommu/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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Mark yao <mark.yao@rock-chips.com> |
|---|---|
| Date | 2016-07-08 03:00 +0200 |
| Subject | Re: [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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Mark yao <mark.yao@rock-chips.com> |
|---|---|
| Date | 2016-07-08 03:00 +0200 |
| Subject | Re: [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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Shunqian Zheng <zhengsq@rock-chips.com> |
|---|---|
| Date | 2016-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]
| From | Joerg Roedel <joro@8bytes.org> |
|---|---|
| Date | 2016-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]
| From | Mark yao <mark.yao@rock-chips.com> |
|---|---|
| Date | 2016-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