linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
@ 2016-06-21  4:34 Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter Tomasz Figa
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

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 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 | 236 ++++++++++++++++++++++++++--
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
 drivers/iommu/Kconfig                       |   2 +-
 drivers/iommu/rockchip-iommu.c              | 180 +++++++++++++++------
 6 files changed, 427 insertions(+), 103 deletions(-)

-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops Tomasz Figa
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Simon Xue, Tomasz Figa

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-on: https://chromium-review.googlesource.com/346325
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;
 
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe Tomasz Figa
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Simon Xue, Tomasz Figa

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-on: https://chromium-review.googlesource.com/346326
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,
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21 17:19   ` Doug Anderson
  2016-06-21  4:34 ` [PATCH v4 4/8] iommu/rockchip: Use DMA API to manage coherency Tomasz Figa
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

From: Shunqian Zheng <zhengsq@rock-chips.com>

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>
---
 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;
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 4/8] iommu/rockchip: Use DMA API to manage coherency
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (2 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 5/8] iommu/rockchip: Prepare to support generic DMA mapping Tomasz Figa
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

From: Shunqian Zheng <zhengsq@rock-chips.com>

Use DMA API instead of architecture internal functions like
__cpuc_flush_dcache_area() etc.

The biggest difficulty here is that dma_map and _sync calls require some
struct device, while there is no real 1:1 relation between an IOMMU
domain and some device. To overcome this, a simple platform device is
registered for each allocated IOMMU domain.

With this patch, this driver can be used on both ARM and ARM64
platforms, such as RK3288 and RK3399 respectively.

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

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 8a5bac7..0551146 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -4,11 +4,10 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/cacheflush.h>
-#include <asm/pgtable.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dma-iommu.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -77,7 +76,9 @@
 
 struct rk_iommu_domain {
 	struct list_head iommus;
+	struct platform_device *pdev;
 	u32 *dt; /* page directory table */
+	dma_addr_t dt_dma;
 	spinlock_t iommus_lock; /* lock for iommus list */
 	spinlock_t dt_lock; /* lock for modifying page directory table */
 
@@ -93,14 +94,12 @@ struct rk_iommu {
 	struct iommu_domain *domain; /* domain to which iommu is attached */
 };
 
-static inline void rk_table_flush(u32 *va, unsigned int count)
+static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
+				  unsigned int count)
 {
-	phys_addr_t pa_start = virt_to_phys(va);
-	phys_addr_t pa_end = virt_to_phys(va + count);
-	size_t size = pa_end - pa_start;
+	size_t size = count * 4; /* count of entry, 4 bytes per entry */
 
-	__cpuc_flush_dcache_area(va, size);
-	outer_flush_range(pa_start, pa_end);
+	dma_sync_single_for_device(&dom->pdev->dev, dma, size, DMA_TO_DEVICE);
 }
 
 static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
@@ -183,10 +182,9 @@ static inline bool rk_dte_is_pt_valid(u32 dte)
 	return dte & RK_DTE_PT_VALID;
 }
 
-static u32 rk_mk_dte(u32 *pt)
+static inline u32 rk_mk_dte(dma_addr_t pt_dma)
 {
-	phys_addr_t pt_phys = virt_to_phys(pt);
-	return (pt_phys & RK_DTE_PT_ADDRESS_MASK) | RK_DTE_PT_VALID;
+	return (pt_dma & RK_DTE_PT_ADDRESS_MASK) | RK_DTE_PT_VALID;
 }
 
 /*
@@ -603,13 +601,16 @@ static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain,
 static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
 				  dma_addr_t iova)
 {
+	struct device *dev = &rk_domain->pdev->dev;
 	u32 *page_table, *dte_addr;
-	u32 dte;
+	u32 dte_index, dte;
 	phys_addr_t pt_phys;
+	dma_addr_t pt_dma;
 
 	assert_spin_locked(&rk_domain->dt_lock);
 
-	dte_addr = &rk_domain->dt[rk_iova_dte_index(iova)];
+	dte_index = rk_iova_dte_index(iova);
+	dte_addr = &rk_domain->dt[dte_index];
 	dte = *dte_addr;
 	if (rk_dte_is_pt_valid(dte))
 		goto done;
@@ -618,19 +619,26 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
 	if (!page_table)
 		return ERR_PTR(-ENOMEM);
 
-	dte = rk_mk_dte(page_table);
-	*dte_addr = dte;
+	pt_dma = dma_map_single(dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, pt_dma)) {
+		dev_err(dev, "DMA mapping error while allocating page table\n");
+		free_page((unsigned long)page_table);
+		return ERR_PTR(-ENOMEM);
+	}
 
-	rk_table_flush(page_table, NUM_PT_ENTRIES);
-	rk_table_flush(dte_addr, 1);
+	dte = rk_mk_dte(pt_dma);
+	*dte_addr = dte;
 
+	rk_table_flush(rk_domain, pt_dma, NUM_PT_ENTRIES);
+	rk_table_flush(rk_domain, rk_domain->dt_dma + dte_index * 4, 1);
 done:
 	pt_phys = rk_dte_pt_address(dte);
 	return (u32 *)phys_to_virt(pt_phys);
 }
 
 static size_t rk_iommu_unmap_iova(struct rk_iommu_domain *rk_domain,
-				  u32 *pte_addr, dma_addr_t iova, size_t size)
+				  u32 *pte_addr, dma_addr_t pte_dma,
+				  size_t size)
 {
 	unsigned int pte_count;
 	unsigned int pte_total = size / SPAGE_SIZE;
@@ -645,14 +653,14 @@ static size_t rk_iommu_unmap_iova(struct rk_iommu_domain *rk_domain,
 		pte_addr[pte_count] = rk_mk_pte_invalid(pte);
 	}
 
-	rk_table_flush(pte_addr, pte_count);
+	rk_table_flush(rk_domain, pte_dma, pte_count);
 
 	return pte_count * SPAGE_SIZE;
 }
 
 static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
-			     dma_addr_t iova, phys_addr_t paddr, size_t size,
-			     int prot)
+			     dma_addr_t pte_dma, dma_addr_t iova,
+			     phys_addr_t paddr, size_t size, int prot)
 {
 	unsigned int pte_count;
 	unsigned int pte_total = size / SPAGE_SIZE;
@@ -671,7 +679,7 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
 		paddr += SPAGE_SIZE;
 	}
 
-	rk_table_flush(pte_addr, pte_count);
+	rk_table_flush(rk_domain, pte_dma, pte_total);
 
 	/*
 	 * Zap the first and last iova to evict from iotlb any previously
@@ -684,7 +692,8 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
 	return 0;
 unwind:
 	/* Unmap the range of iovas that we just mapped */
-	rk_iommu_unmap_iova(rk_domain, pte_addr, iova, pte_count * SPAGE_SIZE);
+	rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma,
+			    pte_count * SPAGE_SIZE);
 
 	iova += pte_count * SPAGE_SIZE;
 	page_phys = rk_pte_page_address(pte_addr[pte_count]);
@@ -699,8 +708,9 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
 {
 	struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
 	unsigned long flags;
-	dma_addr_t iova = (dma_addr_t)_iova;
+	dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
 	u32 *page_table, *pte_addr;
+	u32 dte_index, pte_index;
 	int ret;
 
 	spin_lock_irqsave(&rk_domain->dt_lock, flags);
@@ -718,8 +728,13 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
 		return PTR_ERR(page_table);
 	}
 
-	pte_addr = &page_table[rk_iova_pte_index(iova)];
-	ret = rk_iommu_map_iova(rk_domain, pte_addr, iova, paddr, size, prot);
+	dte_index = rk_domain->dt[rk_iova_dte_index(iova)];
+	pte_index = rk_iova_pte_index(iova);
+	pte_addr = &page_table[pte_index];
+	pte_dma = rk_dte_pt_address(dte_index) + pte_index * 4;
+	ret = rk_iommu_map_iova(rk_domain, pte_addr, pte_dma, iova,
+				paddr, size, prot);
+
 	spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
 
 	return ret;
@@ -730,7 +745,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
 {
 	struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
 	unsigned long flags;
-	dma_addr_t iova = (dma_addr_t)_iova;
+	dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
 	phys_addr_t pt_phys;
 	u32 dte;
 	u32 *pte_addr;
@@ -754,7 +769,8 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
 
 	pt_phys = rk_dte_pt_address(dte);
 	pte_addr = (u32 *)phys_to_virt(pt_phys) + rk_iova_pte_index(iova);
-	unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, iova, size);
+	pte_dma = pt_phys + rk_iova_pte_index(iova) * 4;
+	unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size);
 
 	spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
 
@@ -787,7 +803,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 	struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
 	unsigned long flags;
 	int ret, i;
-	phys_addr_t dte_addr;
 
 	/*
 	 * Allow 'virtual devices' (e.g., drm) to attach to domain.
@@ -812,9 +827,9 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 	if (ret)
 		return ret;
 
-	dte_addr = virt_to_phys(rk_domain->dt);
 	for (i = 0; i < iommu->num_mmu; i++) {
-		rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, dte_addr);
+		rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
+			       rk_domain->dt_dma);
 		rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
 		rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
 	}
@@ -870,14 +885,30 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
 static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 {
 	struct rk_iommu_domain *rk_domain;
+	struct platform_device *pdev;
+	struct device *iommu_dev;
 
 	if (type != IOMMU_DOMAIN_UNMANAGED)
 		return NULL;
 
-	rk_domain = kzalloc(sizeof(*rk_domain), GFP_KERNEL);
-	if (!rk_domain)
+	/* Register a pdev per domain, so DMA API can base on this *dev
+	 * even some virtual master doesn't have an iommu slave
+	 */
+	pdev = platform_device_register_simple("rk_iommu_domain",
+					       PLATFORM_DEVID_AUTO, NULL, 0);
+	if (IS_ERR(pdev))
 		return NULL;
 
+	rk_domain = devm_kzalloc(&pdev->dev, sizeof(*rk_domain), GFP_KERNEL);
+	if (!rk_domain)
+		goto err_unreg_pdev;
+
+	rk_domain->pdev = pdev;
+
+	/* To init the iovad which is required by iommu_dma_init_domain() */
+	if (iommu_get_dma_cookie(&rk_domain->domain))
+		goto err_unreg_pdev;
+
 	/*
 	 * rk32xx iommus use a 2 level pagetable.
 	 * Each level1 (dt) and level2 (pt) table has 1024 4-byte entries.
@@ -885,9 +916,17 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 	 */
 	rk_domain->dt = (u32 *)get_zeroed_page(GFP_KERNEL | GFP_DMA32);
 	if (!rk_domain->dt)
-		goto err_dt;
+		goto err_put_cookie;
+
+	iommu_dev = &pdev->dev;
+	rk_domain->dt_dma = dma_map_single(iommu_dev, rk_domain->dt,
+					   SPAGE_SIZE, DMA_TO_DEVICE);
+	if (dma_mapping_error(iommu_dev, rk_domain->dt_dma)) {
+		dev_err(iommu_dev, "DMA map error for DT\n");
+		goto err_free_dt;
+	}
 
-	rk_table_flush(rk_domain->dt, NUM_DT_ENTRIES);
+	rk_table_flush(rk_domain, rk_domain->dt_dma, NUM_DT_ENTRIES);
 
 	spin_lock_init(&rk_domain->iommus_lock);
 	spin_lock_init(&rk_domain->dt_lock);
@@ -895,8 +934,13 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 
 	return &rk_domain->domain;
 
-err_dt:
-	kfree(rk_domain);
+err_free_dt:
+	free_page((unsigned long)rk_domain->dt);
+err_put_cookie:
+	iommu_put_dma_cookie(&rk_domain->domain);
+err_unreg_pdev:
+	platform_device_unregister(pdev);
+
 	return NULL;
 }
 
@@ -912,12 +956,19 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
 		if (rk_dte_is_pt_valid(dte)) {
 			phys_addr_t pt_phys = rk_dte_pt_address(dte);
 			u32 *page_table = phys_to_virt(pt_phys);
+			dma_unmap_single(&rk_domain->pdev->dev, pt_phys,
+					 SPAGE_SIZE, DMA_TO_DEVICE);
 			free_page((unsigned long)page_table);
 		}
 	}
 
+	dma_unmap_single(&rk_domain->pdev->dev, rk_domain->dt_dma,
+			 SPAGE_SIZE, DMA_TO_DEVICE);
 	free_page((unsigned long)rk_domain->dt);
-	kfree(rk_domain);
+
+	iommu_put_dma_cookie(&rk_domain->domain);
+
+	platform_device_unregister(rk_domain->pdev);
 }
 
 static bool rk_iommu_is_dev_iommu_master(struct device *dev)
@@ -1029,6 +1080,30 @@ static const struct iommu_ops rk_iommu_ops = {
 	.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
 };
 
+static int rk_iommu_domain_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+	if (!dev->dma_parms)
+		return -ENOMEM;
+
+	/* Set dma_ops for dev, otherwise it would be dummy_dma_ops */
+	arch_setup_dma_ops(dev, 0, DMA_BIT_MASK(32), NULL, false);
+
+	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+	dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+
+	return 0;
+}
+
+static struct platform_driver rk_iommu_domain_driver = {
+	.probe = rk_iommu_domain_probe,
+	.driver = {
+		   .name = "rk_iommu_domain",
+	},
+};
+
 static int rk_iommu_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1106,11 +1181,19 @@ static int __init rk_iommu_init(void)
 	if (ret)
 		return ret;
 
-	return platform_driver_register(&rk_iommu_driver);
+	ret = platform_driver_register(&rk_iommu_domain_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&rk_iommu_driver);
+	if (ret)
+		platform_driver_unregister(&rk_iommu_domain_driver);
+	return ret;
 }
 static void __exit rk_iommu_exit(void)
 {
 	platform_driver_unregister(&rk_iommu_driver);
+	platform_driver_unregister(&rk_iommu_domain_driver);
 }
 
 subsys_initcall(rk_iommu_init);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 5/8] iommu/rockchip: Prepare to support generic DMA mapping
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (3 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 4/8] iommu/rockchip: Use DMA API to manage coherency Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain Tomasz Figa
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

From: Shunqian Zheng <zhengsq@rock-chips.com>

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 0551146..d5fd074 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -888,7 +888,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
@@ -905,8 +905,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;
 
 	/*
@@ -932,12 +932,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);
 
@@ -966,7 +971,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);
 }
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (4 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 5/8] iommu/rockchip: Prepare to support generic DMA mapping Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 7/8] drm/rockchip: Use common IOMMU API to attach devices Tomasz Figa
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

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>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 236 ++++++++++++++++++++++++++--
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h |   9 ++
 3 files changed, 237 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 059e902..fc0e6c1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -18,11 +18,147 @@
 #include <drm/drm_vma_manager.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_drm_private *private,
+				  struct rockchip_gem_object *rk_obj)
+{
+	int prot = IOMMU_READ | IOMMU_WRITE;
+	ssize_t ret;
+
+	if (rk_obj->mm)
+		return -EBUSY;
+
+	rk_obj->mm = kzalloc(sizeof(*rk_obj->mm), GFP_KERNEL);
+	if (!rk_obj->mm)
+		return -ENOMEM;
+
+	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);
+		goto err_free_mm;
+	}
+
+	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);
+err_free_mm:
+	kfree(rk_obj->mm);
+	return ret;
+}
+
+static int rockchip_gem_iommu_unmap(struct rockchip_drm_private *private,
+				    struct rockchip_gem_object *rk_obj)
+{
+	if (!rk_obj->mm)
+		return 0;
+
+	iommu_unmap(private->domain, rk_obj->dma_addr, rk_obj->size);
+	drm_mm_remove_node(rk_obj->mm);
+	kfree(rk_obj->mm);
+
+	return 0;
+}
+
+static int rockchip_gem_get_pages(struct drm_device *drm,
+				  struct rockchip_gem_object *rk_obj)
+{
+	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_clflash_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 drm_device *drm,
+				   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 drm_device *drm,
+				    struct rockchip_gem_object *rk_obj,
+				    bool alloc_kmap)
+{
+	struct rockchip_drm_private *private = drm->dev_private;
+	int ret;
+
+	ret = rockchip_gem_get_pages(drm, rk_obj);
+	if (ret < 0)
+		return ret;
+
+	ret = rockchip_gem_iommu_map(private, 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() framebuffer\n");
+			ret = -ENOMEM;
+			goto err_unmap;
+		}
+	}
+
+	return 0;
+
+err_unmap:
+	rockchip_gem_iommu_unmap(private, rk_obj);
+err_free:
+	rockchip_gem_put_pages(drm, 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;
@@ -45,32 +181,97 @@ 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;
+
+	if (private->domain)
+		return rockchip_gem_alloc_iommu(drm, rk_obj, alloc_kmap);
+	else
+		return rockchip_gem_alloc_dma(rk_obj, alloc_kmap);
+}
+
+static void rockchip_gem_free_iommu(struct rockchip_gem_object *rk_obj)
+{
+	struct drm_gem_object *obj = &rk_obj->base;
+	struct drm_device *drm = obj->dev;
+	struct rockchip_drm_private *private = drm->dev_private;
+
+	vunmap(rk_obj->kvaddr);
+	rockchip_gem_iommu_unmap(private, rk_obj);
+	rockchip_gem_put_pages(drm, 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);
+	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 = PAGE_ALIGN(obj->size) >> PAGE_SHIFT;
+	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	unsigned long uaddr = vma->vm_start;
+	int ret = -ENXIO;
+
+	if (user_count > count)
+		return -ENXIO;
+
+	for (i = 0; i < user_count; i++) {
+		ret = vm_insert_page(vma, uaddr, rk_obj->pages[i]);
+		if (ret)
+			break;
+		uaddr += PAGE_SIZE;
+	}
+
+	return ret;
+}
+
+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);
-	struct drm_device *drm = obj->dev;
 
 	/*
-	 * 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);
 
@@ -120,7 +321,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)
@@ -256,6 +457,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);
@@ -276,6 +480,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;
 
@@ -284,5 +492,11 @@ 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);
+
+	/* Nothing to do if allocated by DMA mapping API. */
+	if (!rk_obj->pages)
+		return;
+
+	vunmap(vaddr);
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
index ad22618..26090f8 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);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 7/8] drm/rockchip: Use common IOMMU API to attach devices
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (5 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  4:34 ` [PATCH v4 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64 Tomasz Figa
  2016-06-21  9:17 ` [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable " Joerg Roedel
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Tomasz Figa

From: Shunqian Zheng <zhengsq@rock-chips.com>

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 e2c31d3..2793ac9 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 "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
@@ -49,28 +49,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,
@@ -135,11 +138,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);
@@ -160,38 +197,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);
@@ -216,8 +229,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);
@@ -227,12 +238,8 @@ err_kms_helper_poll_fini:
 	drm_kms_helper_poll_fini(drm_dev);
 err_unbind:
 	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;
@@ -251,8 +258,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);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (6 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 7/8] drm/rockchip: Use common IOMMU API to attach devices Tomasz Figa
@ 2016-06-21  4:34 ` Tomasz Figa
  2016-06-21  9:17 ` [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable " Joerg Roedel
  8 siblings, 0 replies; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21  4:34 UTC (permalink / raw)
  To: iommu, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, linux-kernel, David Airlie,
	Heiko Stuebner, Mark Yao, Shunqian Zheng, Daniel Kurtz,
	Joerg Roedel, Marek Szyprowski, Simon Xue, Tomasz Figa

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
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
  2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
                   ` (7 preceding siblings ...)
  2016-06-21  4:34 ` [PATCH v4 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64 Tomasz Figa
@ 2016-06-21  9:17 ` Joerg Roedel
  2016-06-21 12:42   ` Tomasz Figa
  8 siblings, 1 reply; 15+ messages in thread
From: Joerg Roedel @ 2016-06-21  9:17 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: iommu, dri-devel, linux-arm-kernel, linux-rockchip, linux-kernel,
	David Airlie, Heiko Stuebner, Mark Yao, Shunqian Zheng,
	Daniel Kurtz, Marek Szyprowski

On Tue, Jun 21, 2016 at 01:34:33PM +0900, Tomasz Figa wrote:
> 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.

Are these two parts dependent on each other or can the IOMMU and the DRM
part merged independently?


	Joerg

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
  2016-06-21  9:17 ` [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable " Joerg Roedel
@ 2016-06-21 12:42   ` Tomasz Figa
  2016-06-21 12:54     ` Joerg Roedel
  0 siblings, 1 reply; 15+ messages in thread
From: Tomasz Figa @ 2016-06-21 12:42 UTC (permalink / raw)
  To: Joerg Roedel
  Cc: open list:IOMMU DRIVERS, dri-devel, linux-arm-kernel,
	open list:ARM/Rockchip SoC...,
	linux-kernel, David Airlie, Heiko Stuebner, Mark Yao,
	Shunqian Zheng, Daniel Kurtz, Marek Szyprowski

Hi Joerg,

On Tue, Jun 21, 2016 at 6:17 PM, Joerg Roedel <joro@8bytes.org> wrote:
>
> On Tue, Jun 21, 2016 at 01:34:33PM +0900, Tomasz Figa wrote:
> > 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.
>
> Are these two parts dependent on each other or can the IOMMU and the DRM
> part merged independently?

In simple words, DRM patches depend on IOMMU patches.

More precisely: The IOMMU patches alone are supposed to not break
anything. Same goes for the first DRM patch (7/8). Only second DRM
patch (8/8) depends on changes introduced by its predecessors.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
  2016-06-21 12:42   ` Tomasz Figa
@ 2016-06-21 12:54     ` Joerg Roedel
  2016-06-21 13:18       ` Heiko Stübner
  0 siblings, 1 reply; 15+ messages in thread
From: Joerg Roedel @ 2016-06-21 12:54 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: open list:IOMMU DRIVERS, dri-devel, linux-arm-kernel,
	open list:ARM/Rockchip SoC...,
	linux-kernel, David Airlie, Heiko Stuebner, Mark Yao,
	Shunqian Zheng, Daniel Kurtz, Marek Szyprowski

Hi Tomasz,

On Tue, Jun 21, 2016 at 09:42:16PM +0900, Tomasz Figa wrote:
> In simple words, DRM patches depend on IOMMU patches.
> 
> More precisely: The IOMMU patches alone are supposed to not break
> anything. Same goes for the first DRM patch (7/8). Only second DRM
> patch (8/8) depends on changes introduced by its predecessors.

The first DRM patch is 6/7, so it is 7/8 with the iommu dependency,
right? Anyway, I think the best is I take the iommu patches when Heiko
is ok with them and then the DRM tree can merge that branch in to apply
the DRM patches.

But first Heiko should have a look at the patches.


Thanks,

	Joerg

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
  2016-06-21 12:54     ` Joerg Roedel
@ 2016-06-21 13:18       ` Heiko Stübner
  2016-06-21 13:52         ` Joerg Roedel
  0 siblings, 1 reply; 15+ messages in thread
From: Heiko Stübner @ 2016-06-21 13:18 UTC (permalink / raw)
  To: Joerg Roedel
  Cc: Tomasz Figa, open list:IOMMU DRIVERS, dri-devel,
	linux-arm-kernel, open list:ARM/Rockchip SoC...,
	linux-kernel, David Airlie, Mark Yao, Shunqian Zheng,
	Daniel Kurtz, Marek Szyprowski

Am Dienstag, 21. Juni 2016, 14:54:35 schrieb Joerg Roedel:
> Hi Tomasz,
> 
> On Tue, Jun 21, 2016 at 09:42:16PM +0900, Tomasz Figa wrote:
> > In simple words, DRM patches depend on IOMMU patches.
> > 
> > More precisely: The IOMMU patches alone are supposed to not break
> > anything. Same goes for the first DRM patch (7/8). Only second DRM
> > patch (8/8) depends on changes introduced by its predecessors.
> 
> The first DRM patch is 6/7, so it is 7/8 with the iommu dependency,
> right? Anyway, I think the best is I take the iommu patches when Heiko
> is ok with them and then the DRM tree can merge that branch in to apply
> the DRM patches.
> 
> But first Heiko should have a look at the patches.

I think from all his previous work on the rockchip iommus Tomasz is a lot more 
qualified to judge them - which I guess he did when picking up the ones from 
Rockchip devs :-) .

>From a style-side, please don't carry the Reviewed-on gerrit tags over to 
mainline patches (patches 1 and 2).

Other than that, I didn't see anything jump out and it looks all pretty nice.


Heiko

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64
  2016-06-21 13:18       ` Heiko Stübner
@ 2016-06-21 13:52         ` Joerg Roedel
  0 siblings, 0 replies; 15+ messages in thread
From: Joerg Roedel @ 2016-06-21 13:52 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Tomasz Figa, open list:IOMMU DRIVERS, dri-devel,
	linux-arm-kernel, open list:ARM/Rockchip SoC...,
	linux-kernel, David Airlie, Mark Yao, Shunqian Zheng,
	Daniel Kurtz, Marek Szyprowski

On Tue, Jun 21, 2016 at 03:18:49PM +0200, Heiko Stübner wrote:
> Am Dienstag, 21. Juni 2016, 14:54:35 schrieb Joerg Roedel:
> > Hi Tomasz,
> > 
> > On Tue, Jun 21, 2016 at 09:42:16PM +0900, Tomasz Figa wrote:
> > > In simple words, DRM patches depend on IOMMU patches.
> > > 
> > > More precisely: The IOMMU patches alone are supposed to not break
> > > anything. Same goes for the first DRM patch (7/8). Only second DRM
> > > patch (8/8) depends on changes introduced by its predecessors.
> > 
> > The first DRM patch is 6/7, so it is 7/8 with the iommu dependency,
> > right? Anyway, I think the best is I take the iommu patches when Heiko
> > is ok with them and then the DRM tree can merge that branch in to apply
> > the DRM patches.
> > 
> > But first Heiko should have a look at the patches.
> 
> I think from all his previous work on the rockchip iommus Tomasz is a lot more 
> qualified to judge them - which I guess he did when picking up the ones from 
> Rockchip devs :-) .

In that case you guys should probably co-maintain that driver?
> 
> >From a style-side, please don't carry the Reviewed-on gerrit tags over to 
> mainline patches (patches 1 and 2).

Okay.



	Joerg

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe
  2016-06-21  4:34 ` [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe Tomasz Figa
@ 2016-06-21 17:19   ` Doug Anderson
  0 siblings, 0 replies; 15+ messages in thread
From: Doug Anderson @ 2016-06-21 17:19 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: iommu, dri-devel, linux-arm-kernel, open list:ARM/Rockchip SoC...,
	linux-kernel, David Airlie, Heiko Stuebner, Mark Yao,
	Shunqian Zheng, Daniel Kurtz, Joerg Roedel, Marek Szyprowski

Hi,

On Mon, Jun 20, 2016 at 9:34 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> From: Shunqian Zheng <zhengsq@rock-chips.com>
>
> 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>
> ---
>  drivers/iommu/rockchip-iommu.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Douglas Anderson <dianders@chromium.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2016-06-21 17:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-21  4:34 [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable on ARM64 Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 1/8] iommu/rockchip: Fix devm_{request,free}_irq parameter Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 2/8] iommu/rockchip: Add map_sg callback for rk_iommu_ops Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 3/8] iommu/rockchip: Fix allocation of bases array in driver probe Tomasz Figa
2016-06-21 17:19   ` Doug Anderson
2016-06-21  4:34 ` [PATCH v4 4/8] iommu/rockchip: Use DMA API to manage coherency Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 5/8] iommu/rockchip: Prepare to support generic DMA mapping Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 6/8] drm/rockchip: Do not use DMA mapping API if attached to IOMMU domain Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 7/8] drm/rockchip: Use common IOMMU API to attach devices Tomasz Figa
2016-06-21  4:34 ` [PATCH v4 8/8] iommu/rockchip: Enable Rockchip IOMMU on ARM64 Tomasz Figa
2016-06-21  9:17 ` [PATCH v4 0/8] iommu/rockchip: Fix bugs and enable " Joerg Roedel
2016-06-21 12:42   ` Tomasz Figa
2016-06-21 12:54     ` Joerg Roedel
2016-06-21 13:18       ` Heiko Stübner
2016-06-21 13:52         ` Joerg Roedel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).