iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] iommu/tegra: Rename -i hw{grp,group} to sw{grp,group}
@ 2013-01-15  8:17 Hiroshi Doyu
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA

Use correct name/prefix from TRM to avoid confusion.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |  160 ++++++++++++++++++++++----------------------
 1 file changed, 80 insertions(+), 80 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..224c0a0 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -39,45 +39,45 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
-enum smmu_hwgrp {
-	HWGRP_AFI,
-	HWGRP_AVPC,
-	HWGRP_DC,
-	HWGRP_DCB,
-	HWGRP_EPP,
-	HWGRP_G2,
-	HWGRP_HC,
-	HWGRP_HDA,
-	HWGRP_ISP,
-	HWGRP_MPE,
-	HWGRP_NV,
-	HWGRP_NV2,
-	HWGRP_PPCS,
-	HWGRP_SATA,
-	HWGRP_VDE,
-	HWGRP_VI,
-
-	HWGRP_COUNT,
-
-	HWGRP_END = ~0,
+enum smmu_swgrp {
+	SWGRP_AFI,
+	SWGRP_AVPC,
+	SWGRP_DC,
+	SWGRP_DCB,
+	SWGRP_EPP,
+	SWGRP_G2,
+	SWGRP_HC,
+	SWGRP_HDA,
+	SWGRP_ISP,
+	SWGRP_MPE,
+	SWGRP_NV,
+	SWGRP_NV2,
+	SWGRP_PPCS,
+	SWGRP_SATA,
+	SWGRP_VDE,
+	SWGRP_VI,
+
+	SWGRP_COUNT,
+
+	SWGRP_END = ~0,
 };
 
-#define HWG_AFI		(1 << HWGRP_AFI)
-#define HWG_AVPC	(1 << HWGRP_AVPC)
-#define HWG_DC		(1 << HWGRP_DC)
-#define HWG_DCB		(1 << HWGRP_DCB)
-#define HWG_EPP		(1 << HWGRP_EPP)
-#define HWG_G2		(1 << HWGRP_G2)
-#define HWG_HC		(1 << HWGRP_HC)
-#define HWG_HDA		(1 << HWGRP_HDA)
-#define HWG_ISP		(1 << HWGRP_ISP)
-#define HWG_MPE		(1 << HWGRP_MPE)
-#define HWG_NV		(1 << HWGRP_NV)
-#define HWG_NV2		(1 << HWGRP_NV2)
-#define HWG_PPCS	(1 << HWGRP_PPCS)
-#define HWG_SATA	(1 << HWGRP_SATA)
-#define HWG_VDE		(1 << HWGRP_VDE)
-#define HWG_VI		(1 << HWGRP_VI)
+#define SWG_AFI		(1 << SWGRP_AFI)
+#define SWG_AVPC	(1 << SWGRP_AVPC)
+#define SWG_DC		(1 << SWGRP_DC)
+#define SWG_DCB		(1 << SWGRP_DCB)
+#define SWG_EPP		(1 << SWGRP_EPP)
+#define SWG_G2		(1 << SWGRP_G2)
+#define SWG_HC		(1 << SWGRP_HC)
+#define SWG_HDA		(1 << SWGRP_HDA)
+#define SWG_ISP		(1 << SWGRP_ISP)
+#define SWG_MPE		(1 << SWGRP_MPE)
+#define SWG_NV		(1 << SWGRP_NV)
+#define SWG_NV2		(1 << SWGRP_NV2)
+#define SWG_PPCS	(1 << SWGRP_PPCS)
+#define SWG_SATA	(1 << SWGRP_SATA)
+#define SWG_VDE		(1 << SWGRP_VDE)
+#define SWG_VI		(1 << SWGRP_VI)
 
 /* bitmap of the page sizes currently supported */
 #define SMMU_IOMMU_PGSIZES	(SZ_4K)
@@ -229,32 +229,32 @@ enum {
 
 #define NUM_SMMU_REG_BANKS	3
 
-#define smmu_client_enable_hwgrp(c, m)	smmu_client_set_hwgrp(c, m, 1)
-#define smmu_client_disable_hwgrp(c)	smmu_client_set_hwgrp(c, 0, 0)
-#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
-#define __smmu_client_disable_hwgrp(c)	__smmu_client_set_hwgrp(c, 0, 0)
-
-#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_hwgrp_asid_reg[] = {
-	HWGRP_INIT(AFI),
-	HWGRP_INIT(AVPC),
-	HWGRP_INIT(DC),
-	HWGRP_INIT(DCB),
-	HWGRP_INIT(EPP),
-	HWGRP_INIT(G2),
-	HWGRP_INIT(HC),
-	HWGRP_INIT(HDA),
-	HWGRP_INIT(ISP),
-	HWGRP_INIT(MPE),
-	HWGRP_INIT(NV),
-	HWGRP_INIT(NV2),
-	HWGRP_INIT(PPCS),
-	HWGRP_INIT(SATA),
-	HWGRP_INIT(VDE),
-	HWGRP_INIT(VI),
+#define smmu_client_enable_swgrp(c, m)	smmu_client_set_swgrp(c, m, 1)
+#define smmu_client_disable_swgrp(c)	smmu_client_set_swgrp(c, 0, 0)
+#define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
+#define __smmu_client_disable_swgrp(c)	__smmu_client_set_swgrp(c, 0, 0)
+
+#define SWGRP_INIT(client) [SWGRP_##client] = SMMU_##client##_ASID
+
+static const u32 smmu_swgrp_asid_reg[] = {
+	SWGRP_INIT(AFI),
+	SWGRP_INIT(AVPC),
+	SWGRP_INIT(DC),
+	SWGRP_INIT(DCB),
+	SWGRP_INIT(EPP),
+	SWGRP_INIT(G2),
+	SWGRP_INIT(HC),
+	SWGRP_INIT(HDA),
+	SWGRP_INIT(ISP),
+	SWGRP_INIT(MPE),
+	SWGRP_INIT(NV),
+	SWGRP_INIT(NV2),
+	SWGRP_INIT(PPCS),
+	SWGRP_INIT(SATA),
+	SWGRP_INIT(VDE),
+	SWGRP_INIT(VI),
 };
-#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
+#define SWGRP_ASID_REG(x) (smmu_swgrp_asid_reg[x])
 
 /*
  * Per client for address space
@@ -263,7 +263,7 @@ struct smmu_client {
 	struct device		*dev;
 	struct list_head	list;
 	struct smmu_as		*as;
-	u32			hwgrp;
+	u32			swgrp;
 };
 
 /*
@@ -375,9 +375,9 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
  */
 #define FLUSH_SMMU_REGS(smmu)	smmu_read(smmu, SMMU_CONFIG)
 
-#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
+#define smmu_client_swgrp(c) (u32)((c)->dev->platform_data)
 
-static int __smmu_client_set_hwgrp(struct smmu_client *c,
+static int __smmu_client_set_swgrp(struct smmu_client *c,
 				   unsigned long map, int on)
 {
 	int i;
@@ -389,10 +389,10 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
 	if (on && !map)
 		return -EINVAL;
 	if (!on)
-		map = smmu_client_hwgrp(c);
+		map = smmu_client_swgrp(c);
 
-	for_each_set_bit(i, &map, HWGRP_COUNT) {
-		offs = HWGRP_ASID_REG(i);
+	for_each_set_bit(i, &map, SWGRP_COUNT) {
+		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		if (on) {
 			if (WARN_ON(val & mask))
@@ -405,12 +405,12 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
 		smmu_write(smmu, val, offs);
 	}
 	FLUSH_SMMU_REGS(smmu);
-	c->hwgrp = map;
+	c->swgrp = map;
 	return 0;
 
 err_hw_busy:
-	for_each_set_bit(i, &map, HWGRP_COUNT) {
-		offs = HWGRP_ASID_REG(i);
+	for_each_set_bit(i, &map, SWGRP_COUNT) {
+		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		val &= ~mask;
 		smmu_write(smmu, val, offs);
@@ -418,7 +418,7 @@ err_hw_busy:
 	return -EBUSY;
 }
 
-static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
 {
 	u32 val;
 	unsigned long flags;
@@ -426,7 +426,7 @@ static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
 	struct smmu_device *smmu = as->smmu;
 
 	spin_lock_irqsave(&smmu->lock, flags);
-	val = __smmu_client_set_hwgrp(c, map, on);
+	val = __smmu_client_set_swgrp(c, map, on);
 	spin_unlock_irqrestore(&smmu->lock, flags);
 	return val;
 }
@@ -466,7 +466,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
 		smmu_write(smmu, val, SMMU_PTB_DATA);
 
 		list_for_each_entry(c, &as->client, list)
-			__smmu_client_set_hwgrp(c, c->hwgrp, 1);
+			__smmu_client_set_swgrp(c, c->swgrp, 1);
 	}
 
 	smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -798,9 +798,9 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	if (!map)
 		return -EINVAL;
 
-	err = smmu_client_enable_hwgrp(client, map);
+	err = smmu_client_enable_swgrp(client, map);
 	if (err)
-		goto err_hwgrp;
+		goto err_swgrp;
 
 	spin_lock(&as->client_lock);
 	list_for_each_entry(c, &as->client, list) {
@@ -818,7 +818,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	 * Reserve "page zero" for AVP vectors using a common dummy
 	 * page.
 	 */
-	if (map & HWG_AVPC) {
+	if (map & SWG_AVPC) {
 		struct page *page;
 
 		page = as->smmu->avp_vector_page;
@@ -831,9 +831,9 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	return 0;
 
 err_client:
-	smmu_client_disable_hwgrp(client);
+	smmu_client_disable_swgrp(client);
 	spin_unlock(&as->client_lock);
-err_hwgrp:
+err_swgrp:
 	devm_kfree(smmu->dev, client);
 	return err;
 }
@@ -849,7 +849,7 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
 
 	list_for_each_entry(c, &as->client, list) {
 		if (c->dev == dev) {
-			smmu_client_disable_hwgrp(c);
+			smmu_client_disable_swgrp(c);
 			list_del(&c->list);
 			devm_kfree(smmu->dev, c);
 			c->as = NULL;
-- 
1.7.9.5

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

* [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-15  8:17   ` Hiroshi Doyu
       [not found]     ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15  8:17   ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

Pass available H/W client component(software client group) info from
DT in bitmap. This info is specific to a certain generation of Tegra
SoC. With this, Tegra SMMU driver could be identical among Tegra
generations. This also removes the old way of passing this bit from
each device pdata, which could configure(enable/disable) each device
IOMMU'able, but it belongs to a kind of "policy", which can be done by
kernel/system later. Now DT passes just pure H/W info.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 .../bindings/iommu/nvidia,tegra30-smmu.txt         |   41 ++++++++
 drivers/iommu/tegra-smmu.c                         |   99 +++-----------------
 2 files changed, 55 insertions(+), 85 deletions(-)

diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
index 89fb543..de449d0 100644
--- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -8,6 +8,46 @@ Required properties:
 - nvidia,#asids : # of ASIDs
 - dma-window : IOVA start address and length.
 - nvidia,ahb : phandle to the ahb bus connected to SMMU.
+- nvidia,swgroups: Available H/W client component(software client
+  group) in bitmap in SoC. Those IDs are calculated as below:
+
+	  <ID> = (<OFFSET> - MC_SMMU_AFI_ASID_0) / 4;
+
+  This <ID>/<OFFSET> can grow if SWGROUP is added in the future
+  SoC. Please refer to Tegra SoC TRM to find which SWGROUPs are
+  implemented in SoC.
+
+------------------------
+ID	Offset	SWGROUP
+=======================
+0	238	AFI
+1	23c	AVP
+2	240	DC
+3	244	DCB
+------------------------
+4	248	EPP
+5	24c	G2
+6	250	HC
+7	254	HDA
+------------------------
+8	258	ISP
+9	25c	-
+10	260	-
+11	264	MPE
+------------------------
+12	268	NV
+13	26c	NV2
+14	270	PPC
+15	274	-
+------------------------
+16	278	SAT
+17	27c	VDE
+18	280	VI
+19	284	-
+------------------------
+20	288	-
+21	29c	-
+......
 
 Example:
 	smmu {
@@ -17,5 +57,6 @@ Example:
 		       0x7000f228 0x05c>;
 		nvidia,#asids = <4>;		/* # of ASIDs */
 		dma-window = <0 0x40000000>;	/* IOVA start & length */
+		nvidia,swgroups = <0x775ff>;
 		nvidia,ahb = <&ahb>;
 	};
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 224c0a0..e83797b 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -39,46 +39,6 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
-enum smmu_swgrp {
-	SWGRP_AFI,
-	SWGRP_AVPC,
-	SWGRP_DC,
-	SWGRP_DCB,
-	SWGRP_EPP,
-	SWGRP_G2,
-	SWGRP_HC,
-	SWGRP_HDA,
-	SWGRP_ISP,
-	SWGRP_MPE,
-	SWGRP_NV,
-	SWGRP_NV2,
-	SWGRP_PPCS,
-	SWGRP_SATA,
-	SWGRP_VDE,
-	SWGRP_VI,
-
-	SWGRP_COUNT,
-
-	SWGRP_END = ~0,
-};
-
-#define SWG_AFI		(1 << SWGRP_AFI)
-#define SWG_AVPC	(1 << SWGRP_AVPC)
-#define SWG_DC		(1 << SWGRP_DC)
-#define SWG_DCB		(1 << SWGRP_DCB)
-#define SWG_EPP		(1 << SWGRP_EPP)
-#define SWG_G2		(1 << SWGRP_G2)
-#define SWG_HC		(1 << SWGRP_HC)
-#define SWG_HDA		(1 << SWGRP_HDA)
-#define SWG_ISP		(1 << SWGRP_ISP)
-#define SWG_MPE		(1 << SWGRP_MPE)
-#define SWG_NV		(1 << SWGRP_NV)
-#define SWG_NV2		(1 << SWGRP_NV2)
-#define SWG_PPCS	(1 << SWGRP_PPCS)
-#define SWG_SATA	(1 << SWGRP_SATA)
-#define SWG_VDE		(1 << SWGRP_VDE)
-#define SWG_VI		(1 << SWGRP_VI)
-
 /* bitmap of the page sizes currently supported */
 #define SMMU_IOMMU_PGSIZES	(SZ_4K)
 
@@ -148,21 +108,10 @@ enum {
 #define SMMU_TRANSLATION_ENABLE_2		0x230
 
 #define SMMU_AFI_ASID	0x238   /* PCIE */
+#define SMMU_SWGRP_ASID_BASE	SMMU_AFI_ASID
+
 #define SMMU_AVPC_ASID	0x23c   /* AVP */
-#define SMMU_DC_ASID	0x240   /* Display controller */
-#define SMMU_DCB_ASID	0x244   /* Display controller B */
-#define SMMU_EPP_ASID	0x248   /* Encoder pre-processor */
-#define SMMU_G2_ASID	0x24c   /* 2D engine */
-#define SMMU_HC_ASID	0x250   /* Host1x */
-#define SMMU_HDA_ASID	0x254   /* High-def audio */
-#define SMMU_ISP_ASID	0x258   /* Image signal processor */
-#define SMMU_MPE_ASID	0x264   /* MPEG encoder */
-#define SMMU_NV_ASID	0x268   /* (3D) */
-#define SMMU_NV2_ASID	0x26c   /* (3D) */
-#define SMMU_PPCS_ASID	0x270   /* AHB */
-#define SMMU_SATA_ASID	0x278   /* SATA */
-#define SMMU_VDE_ASID	0x27c   /* Video decoder */
-#define SMMU_VI_ASID	0x280   /* Video input */
+#define SWG_AVPC	((SMMU_AVPC_ASID - SMMU_SWGRP_ASID_BASE) / 4)
 
 #define SMMU_PDE_NEXT_SHIFT		28
 
@@ -234,27 +183,7 @@ enum {
 #define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
 #define __smmu_client_disable_swgrp(c)	__smmu_client_set_swgrp(c, 0, 0)
 
-#define SWGRP_INIT(client) [SWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_swgrp_asid_reg[] = {
-	SWGRP_INIT(AFI),
-	SWGRP_INIT(AVPC),
-	SWGRP_INIT(DC),
-	SWGRP_INIT(DCB),
-	SWGRP_INIT(EPP),
-	SWGRP_INIT(G2),
-	SWGRP_INIT(HC),
-	SWGRP_INIT(HDA),
-	SWGRP_INIT(ISP),
-	SWGRP_INIT(MPE),
-	SWGRP_INIT(NV),
-	SWGRP_INIT(NV2),
-	SWGRP_INIT(PPCS),
-	SWGRP_INIT(SATA),
-	SWGRP_INIT(VDE),
-	SWGRP_INIT(VI),
-};
-#define SWGRP_ASID_REG(x) (smmu_swgrp_asid_reg[x])
+#define SWGRP_ASID_REG(id) (4 * (id) + SMMU_SWGRP_ASID_BASE)
 
 /*
  * Per client for address space
@@ -263,7 +192,6 @@ struct smmu_client {
 	struct device		*dev;
 	struct list_head	list;
 	struct smmu_as		*as;
-	u32			swgrp;
 };
 
 /*
@@ -313,6 +241,7 @@ struct smmu_device {
 	struct smmu_debugfs_info *debugfs_info;
 
 	struct device_node *ahb;
+	u32 swgrp;
 
 	int		num_as;
 	struct smmu_as	as[0];		/* Run-time allocated array */
@@ -375,8 +304,6 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
  */
 #define FLUSH_SMMU_REGS(smmu)	smmu_read(smmu, SMMU_CONFIG)
 
-#define smmu_client_swgrp(c) (u32)((c)->dev->platform_data)
-
 static int __smmu_client_set_swgrp(struct smmu_client *c,
 				   unsigned long map, int on)
 {
@@ -388,10 +315,8 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
 	WARN_ON(!on && map);
 	if (on && !map)
 		return -EINVAL;
-	if (!on)
-		map = smmu_client_swgrp(c);
 
-	for_each_set_bit(i, &map, SWGRP_COUNT) {
+	for_each_set_bit(i, &map, BITS_PER_LONG) {
 		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		if (on) {
@@ -405,11 +330,10 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
 		smmu_write(smmu, val, offs);
 	}
 	FLUSH_SMMU_REGS(smmu);
-	c->swgrp = map;
 	return 0;
 
 err_hw_busy:
-	for_each_set_bit(i, &map, SWGRP_COUNT) {
+	for_each_set_bit(i, &map, BITS_PER_LONG) {
 		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		val &= ~mask;
@@ -466,7 +390,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
 		smmu_write(smmu, val, SMMU_PTB_DATA);
 
 		list_for_each_entry(c, &as->client, list)
-			__smmu_client_set_swgrp(c, c->swgrp, 1);
+			__smmu_client_set_swgrp(c, smmu->swgrp, 1);
 	}
 
 	smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -794,7 +718,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 		return -ENOMEM;
 	client->dev = dev;
 	client->as = as;
-	map = (unsigned long)dev->platform_data;
+	map = smmu->swgrp;
 	if (!map)
 		return -EINVAL;
 
@@ -1154,12 +1078,16 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 	int i, asids, err = 0;
 	dma_addr_t uninitialized_var(base);
 	size_t bytes, uninitialized_var(size);
+	u32 swgrp;
 
 	if (smmu_handle)
 		return -EIO;
 
 	BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
 
+	if (of_property_read_u32(dev->of_node, "nvidia,swgroups", &swgrp))
+		return -ENODEV;
+
 	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
 		return -ENODEV;
 
@@ -1198,6 +1126,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 
 	smmu->dev = dev;
 	smmu->num_as = asids;
+	smmu->swgrp = swgrp;
 	smmu->iovmm_base = base;
 	smmu->page_count = size;
 
-- 
1.7.9.5

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

* [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15  8:17   ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
@ 2013-01-15  8:17   ` Hiroshi Doyu
  2013-01-15  8:17   ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

The definition of swgroups can grow in the future SoCs. This patch
allows to have longer bitmaps for that.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   67 ++++++++++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 27 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e83797b..e80312c 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -178,10 +178,10 @@ enum {
 
 #define NUM_SMMU_REG_BANKS	3
 
-#define smmu_client_enable_swgrp(c, m)	smmu_client_set_swgrp(c, m, 1)
-#define smmu_client_disable_swgrp(c)	smmu_client_set_swgrp(c, 0, 0)
-#define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
-#define __smmu_client_disable_swgrp(c)	__smmu_client_set_swgrp(c, 0, 0)
+#define smmu_client_enable_swgrp(c)	smmu_client_set_swgrp(c, 1)
+#define smmu_client_disable_swgrp(c)	smmu_client_set_swgrp(c, 0)
+#define __smmu_client_enable_swgrp(c) __smmu_client_set_swgrp(c, 1)
+#define __smmu_client_disable_swgrp(c)	__smmu_client_set_swgrp(c, 0)
 
 #define SWGRP_ASID_REG(id) (4 * (id) + SMMU_SWGRP_ASID_BASE)
 
@@ -241,7 +241,9 @@ struct smmu_device {
 	struct smmu_debugfs_info *debugfs_info;
 
 	struct device_node *ahb;
-	u32 swgrp;
+
+	unsigned long *swgrp;		/* software client group bitmap */
+	size_t swgrp_bits;		/* size of bitmap in bits */
 
 	int		num_as;
 	struct smmu_as	as[0];		/* Run-time allocated array */
@@ -304,19 +306,14 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
  */
 #define FLUSH_SMMU_REGS(smmu)	smmu_read(smmu, SMMU_CONFIG)
 
-static int __smmu_client_set_swgrp(struct smmu_client *c,
-				   unsigned long map, int on)
+static int __smmu_client_set_swgrp(struct smmu_client *c, int on)
 {
 	int i;
 	struct smmu_as *as = c->as;
 	u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
 	struct smmu_device *smmu = as->smmu;
 
-	WARN_ON(!on && map);
-	if (on && !map)
-		return -EINVAL;
-
-	for_each_set_bit(i, &map, BITS_PER_LONG) {
+	for_each_set_bit(i, smmu->swgrp, smmu->swgrp_bits) {
 		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		if (on) {
@@ -333,7 +330,7 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
 	return 0;
 
 err_hw_busy:
-	for_each_set_bit(i, &map, BITS_PER_LONG) {
+	for_each_set_bit(i, smmu->swgrp, smmu->swgrp_bits) {
 		offs = SWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		val &= ~mask;
@@ -342,7 +339,7 @@ err_hw_busy:
 	return -EBUSY;
 }
 
-static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
+static int smmu_client_set_swgrp(struct smmu_client *c, int on)
 {
 	u32 val;
 	unsigned long flags;
@@ -350,7 +347,7 @@ static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
 	struct smmu_device *smmu = as->smmu;
 
 	spin_lock_irqsave(&smmu->lock, flags);
-	val = __smmu_client_set_swgrp(c, map, on);
+	val = __smmu_client_set_swgrp(c, on);
 	spin_unlock_irqrestore(&smmu->lock, flags);
 	return val;
 }
@@ -390,7 +387,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
 		smmu_write(smmu, val, SMMU_PTB_DATA);
 
 		list_for_each_entry(c, &as->client, list)
-			__smmu_client_set_swgrp(c, smmu->swgrp, 1);
+			__smmu_client_set_swgrp(c, 1);
 	}
 
 	smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -710,7 +707,6 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	struct smmu_as *as = domain->priv;
 	struct smmu_device *smmu = as->smmu;
 	struct smmu_client *client, *c;
-	u32 map;
 	int err;
 
 	client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
@@ -718,11 +714,8 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 		return -ENOMEM;
 	client->dev = dev;
 	client->as = as;
-	map = smmu->swgrp;
-	if (!map)
-		return -EINVAL;
 
-	err = smmu_client_enable_swgrp(client, map);
+	err = smmu_client_enable_swgrp(client);
 	if (err)
 		goto err_swgrp;
 
@@ -742,7 +735,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	 * Reserve "page zero" for AVP vectors using a common dummy
 	 * page.
 	 */
-	if (map & SWG_AVPC) {
+	if (test_bit(SWG_AVPC, smmu->swgrp)) {
 		struct page *page;
 
 		page = as->smmu->avp_vector_page;
@@ -1071,6 +1064,27 @@ static int tegra_smmu_resume(struct device *dev)
 	return err;
 }
 
+static int tegra_smmu_of_get_swgrp(struct smmu_device *smmu)
+{
+	size_t bytes, num;
+	const char *propname = "nvidia,swgroups";
+	const __be32 *prop;
+
+	prop = of_get_property(smmu->dev->of_node, propname, &bytes);
+	if (!prop || !bytes)
+		return -EINVAL;
+
+	num = BITS_TO_LONGS(bytes * BITS_PER_BYTE);
+	bytes =  num * sizeof(unsigned long);
+	smmu->swgrp_bits = bytes * BITS_PER_BYTE;
+	smmu->swgrp = devm_kzalloc(smmu->dev, bytes, GFP_KERNEL);
+	if (!smmu->swgrp)
+		return -ENOMEM;
+
+	return of_property_read_u32_array(smmu->dev->of_node, propname,
+					  (u32 *)smmu->swgrp, num);
+}
+
 static int tegra_smmu_probe(struct platform_device *pdev)
 {
 	struct smmu_device *smmu;
@@ -1078,16 +1092,12 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 	int i, asids, err = 0;
 	dma_addr_t uninitialized_var(base);
 	size_t bytes, uninitialized_var(size);
-	u32 swgrp;
 
 	if (smmu_handle)
 		return -EIO;
 
 	BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
 
-	if (of_property_read_u32(dev->of_node, "nvidia,swgroups", &swgrp))
-		return -ENODEV;
-
 	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
 		return -ENODEV;
 
@@ -1126,7 +1136,6 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 
 	smmu->dev = dev;
 	smmu->num_as = asids;
-	smmu->swgrp = swgrp;
 	smmu->iovmm_base = base;
 	smmu->page_count = size;
 
@@ -1135,6 +1144,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 	smmu->translation_enable_2 = ~0;
 	smmu->asid_security = 0;
 
+	err = tegra_smmu_of_get_swgrp(smmu);
+	if (!err)
+		return -ENODEV;
+
 	for (i = 0; i < smmu->num_as; i++) {
 		struct smmu_as *as = &smmu->as[i];
 
-- 
1.7.9.5

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

* [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15  8:17   ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
  2013-01-15  8:17   ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
@ 2013-01-15  8:17   ` Hiroshi Doyu
       [not found]     ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15  8:17   ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA

There are 3 SMMU MMIO register blocks. They may get bigger as new
Tegra SoC comes. This patch enables to support variable size of those
register blocks.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e80312c..4f3a2a5 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -222,6 +222,7 @@ struct smmu_debugfs_info {
  */
 struct smmu_device {
 	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	resource_size_t	regsz[NUM_SMMU_REG_BANKS];
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -257,13 +258,13 @@ static struct smmu_device *smmu_handle; /* unique for a system */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
 	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
+	if (offs < 0x10 + smmu->regsz[0])
 		return readl(smmu->regs[0] + offs - 0x10);
 	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
+	if (offs < 0x1f0 + smmu->regsz[1])
 		return readl(smmu->regs[1] + offs - 0x1f0);
 	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
+	if (offs < 0x228 + smmu->regsz[2])
 		return readl(smmu->regs[2] + offs - 0x228);
 	BUG();
 }
@@ -271,17 +272,17 @@ static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
 	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
+	if (offs < 0x10 + smmu->regsz[0]) {
 		writel(val, smmu->regs[0] + offs - 0x10);
 		return;
 	}
 	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
+	if (offs < 0x1f0 + smmu->regsz[1]) {
 		writel(val, smmu->regs[1] + offs - 0x1f0);
 		return;
 	}
 	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
+	if (offs < 0x228 + smmu->regsz[2]) {
 		writel(val, smmu->regs[2] + offs - 0x228);
 		return;
 	}
@@ -1117,6 +1118,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->regsz[i] = resource_size(res);
 	}
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
-- 
1.7.9.5

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

* [PATCH 5/6] ARM: dt: tegra114: Add AHB entry
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
                     ` (2 preceding siblings ...)
  2013-01-15  8:17   ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
@ 2013-01-15  8:17   ` Hiroshi Doyu
       [not found]     ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15  8:17   ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
  2013-01-15 13:22   ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
  5 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

Add AHB entry.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/tegra114.dtsi |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 175cbc3..fd2fd0e 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -26,6 +26,11 @@
 			      0 122 0x04>;
 	};
 
+	ahb: ahb {
+		compatible = "nvidia,tegra114-ahb", "nvidia,tegra30-ahb";
+		reg = <0x6000c004 0x14c>;
+	};
+
 	serial@70006000 {
 		compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
 		reg = <0x70006000 0x40>;
-- 
1.7.9.5

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

* [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
                     ` (3 preceding siblings ...)
  2013-01-15  8:17   ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
@ 2013-01-15  8:17   ` Hiroshi Doyu
       [not found]     ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-15 13:22   ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
  5 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15  8:17 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

Add SMMU entry.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/tegra114.dtsi |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index fd2fd0e..c3a602c 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -82,6 +82,17 @@
 		reg = <0x7000e400 0x400>;
 	};
 
+	smmu {
+		compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
+		reg = <0x7000f010 0x02c
+		       0x7000f1f0 0x010
+		       0x7000f228 0x074>;
+		nvidia,#asids = <4>;
+		dma-window = <0 0x40000000>;
+		nvidia,swgroups = <0x18659fe>;
+		nvidia,ahb = <&ahb>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-- 
1.7.9.5

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

* [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC
       [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
                     ` (4 preceding siblings ...)
  2013-01-15  8:17   ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
@ 2013-01-15 13:22   ` Hiroshi Doyu
       [not found]     ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  5 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 13:22 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

TEGRA_IOMMU_SMMU depends on ARCH_TEGRA_114_SOC too.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index e39f9db..90cc484 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -158,7 +158,7 @@ config TEGRA_IOMMU_GART
 
 config TEGRA_IOMMU_SMMU
 	bool "Tegra SMMU IOMMU Support"
-	depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
+	depends on (ARCH_TEGRA_114_SOC || ARCH_TEGRA_3x_SOC) && TEGRA_AHB
 	select IOMMU_API
 	help
 	  Enables support for remapping discontiguous physical memory
-- 
1.7.9.5

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

* Re: [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT
       [not found]     ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:07       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-16 21:07 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA

On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Pass available H/W client component(software client group) info from
> DT in bitmap. This info is specific to a certain generation of Tegra
> SoC. With this, Tegra SMMU driver could be identical among Tegra
> generations. This also removes the old way of passing this bit from
> each device pdata, which could configure(enable/disable) each device
> IOMMU'able, but it belongs to a kind of "policy", which can be done by
> kernel/system later. Now DT passes just pure H/W info.

> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> index 89fb543..de449d0 100644
> --- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> @@ -8,6 +8,46 @@ Required properties:
>  - nvidia,#asids : # of ASIDs
>  - dma-window : IOVA start address and length.
>  - nvidia,ahb : phandle to the ahb bus connected to SMMU.
> +- nvidia,swgroups: Available H/W client component(software client
> +  group) in bitmap in SoC. Those IDs are calculated as below:
> +
> +	  <ID> = (<OFFSET> - MC_SMMU_AFI_ASID_0) / 4;

OK, so I understand the addition to the DT defines which clients exist,
and hence which ASID-selection registers exist. This addition makes
sense to me.

> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c

>  /*
>   * Per client for address space
> @@ -263,7 +192,6 @@ struct smmu_client {
>  	struct device		*dev;
>  	struct list_head	list;
>  	struct smmu_as		*as;
> -	u32			swgrp;
>  };

What I don't quite understand is that change, but perhaps that's because
I'm not sure what that field meant before, and/or where the
client<->ASID mapping comes from.

Before this patch, did each client use that removed "u32 swgrp" to tell
the SMMU driver which ASID-selection register was used to configure it,
and then the SMMU took the union of all clients to know which
ASID-selection registers existed? If so, then perhaps this change makes
more sense than I thought... But, how does the SMMU driver know which of
the bits in the new nvidia,swgroups property is related to each struct
smmu_client?

Or, did the removed "u32 swgrp" indicate which of the SMMU's ASIDs
should be assigned to the client?

I guess what I'm missing is: How does the SMMU know which ASID to assign
to each client, either before or after this change? Or, does the driver
just assign every client to ASID 0 right now, and there's no provision
for separate ASIDs?

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

* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found]     ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:12       ` Stephen Warren
       [not found]         ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Stephen Warren @ 2013-01-16 21:12 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA

On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> There are 3 SMMU MMIO register blocks. They may get bigger as new
> Tegra SoC comes. This patch enables to support variable size of those
> register blocks.

Why would the register blocks move around? In the HW, there's one single
chunk of memory containing all the SMMU registers, and we simply carve
out a few holes since some unrelated registers are stuck in the middle,
thus leaving us with 3 register ranges. If the size of those carved out
chunks changes, then doesn't that mean all the registers moved around
within the single chunk, and hence all the register offsets in the
driver become invalid?

It may help if you provide an explicit example of what the register
layout change is...

> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c

>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
>  {
>  	BUG_ON(offs < 0x10);
> -	if (offs < 0x3c)
> +	if (offs < 0x10 + smmu->regsz[0])
>  		return readl(smmu->regs[0] + offs - 0x10);
>  	BUG_ON(offs < 0x1f0);
> -	if (offs < 0x200)
> +	if (offs < 0x1f0 + smmu->regsz[1])

Wouldn't you need to adjust that BUG_ON() in a similar way to how the if
condition was adjusted?

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

* Re: [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry
       [not found]     ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:17       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-16 21:17 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Add SMMU entry.

> diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi

> +	smmu {
> +		compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
> +		reg = <0x7000f010 0x02c
> +		       0x7000f1f0 0x010
> +		       0x7000f228 0x074>;

Oh, so the only change here relative to Tegra30 is that the final memory
range is larger; the others don't move around at all. Is that all that
patch 4/6 is trying to cope with? If so, I'd suggest simplifying that
patch a bunch; perhaps just remove the final if() check in each function
and make all accesses with (offs > 0x200) go to smmu->regs[2]?

You can always add checks to probe() that memory range 0 and 1 have the
expected size such that the code in smmu_{read,write} will work as expected.

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

* Re: [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC
       [not found]     ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:18       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-16 21:18 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA

On 01/15/2013 06:22 AM, Hiroshi Doyu wrote:
> TEGRA_IOMMU_SMMU depends on ARCH_TEGRA_114_SOC too.

> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig

>  config TEGRA_IOMMU_SMMU
>  	bool "Tegra SMMU IOMMU Support"
> -	depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
> +	depends on (ARCH_TEGRA_114_SOC || ARCH_TEGRA_3x_SOC) && TEGRA_AHB

I think instead of listing out each SoC version individually, just
depend on ARCH_TEGRA. This will mean the SMMU driver can be enabled in a
Tegra20-only kernel, but that's not a big deal, and it means we won't
have to keep editing this Kconfig entry every time we add a new chip.

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

* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found]         ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-18  9:05           ` Hiroshi Doyu
       [not found]             ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-18  9:05 UTC (permalink / raw)
  To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Wed, 16 Jan 2013 22:12:24 +0100:

> On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> > There are 3 SMMU MMIO register blocks. They may get bigger as new
> > Tegra SoC comes. This patch enables to support variable size of those
> > register blocks.
>
> Why would the register blocks move around? In the HW, there's one single
> chunk of memory containing all the SMMU registers, and we simply carve
> out a few holes since some unrelated registers are stuck in the middle,
> thus leaving us with 3 register ranges. If the size of those carved out
> chunks changes, then doesn't that mean all the registers moved around
> within the single chunk, and hence all the register offsets in the
> driver become invalid?

Presently there are 3 register blocks. In the future chips over some
generations, some of register block "size" can be extended to the end
and also more new register blocks will be added, which is expected at
most a few blocks. Usually the starting address of each block won't
change. Ideally SMMU register blocks should be in one block, but it
was a bit too late to change this design(or H/W). Considering this
situation, in this driver, number of register blocks should be
allocated dynamically, based on the info from DT. Its range checks
should be done in the accessors as below(*1) if necessary. This way
may sacrifice some perf because a new accessor prevents compiler
optimization of register offset calculation, but I think that SMMU
register accesses are not so frequent and it's acceptable in order to
unify "tegra-smmu" over Tegra SoCs.

*1:

 /*
  *	SMMU register accessors
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
 	void __iommu *addr = smmu->regbase + offs;
 #ifdef DEBUG
 	int i;

 	for (i = 0; i < smmu->num_regblks; i++) {
 		BUG_ON(addr < smmu->reg[i].start);
 		if (addr <= smmu->reg[i].end)
 			break;
 	}
 #endfi
 	return readl(addr);
 }

Even the checks if "offs" is in some of register blocks could be
ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
as below. I don't think that we don't need to access "mc" DT entry to
get this address. since "smmu"'s 1st reg block always starts at 0x10.

  /* same as "mc"'s 1st reg block */
  smmu->regbase = smmu->reg[0] & PAGE_MASK;

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

* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found]             ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-18 16:44               ` Stephen Warren
       [not found]                 ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Stephen Warren @ 2013-01-18 16:44 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On 01/18/2013 02:05 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Wed, 16 Jan 2013 22:12:24 +0100:
> 
>> On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
>>> There are 3 SMMU MMIO register blocks. They may get bigger as new
>>> Tegra SoC comes. This patch enables to support variable size of those
>>> register blocks.
>>
>> Why would the register blocks move around? In the HW, there's one single
>> chunk of memory containing all the SMMU registers, and we simply carve
>> out a few holes since some unrelated registers are stuck in the middle,
>> thus leaving us with 3 register ranges. If the size of those carved out
>> chunks changes, then doesn't that mean all the registers moved around
>> within the single chunk, and hence all the register offsets in the
>> driver become invalid?
> 
> Presently there are 3 register blocks. In the future chips over some
> generations, some of register block "size" can be extended to the end
> and also more new register blocks will be added, which is expected at
> most a few blocks.

> Usually the starting address of each block won't change.

I would hope that was guaranteed; the only reason to move one of the
ranges would be a HW design change, and if there is a HW design change,
HW should take that opportunity to fix the interleaved register mess
instead of making it worse, and hence we could just have a single
register range after that point.

> Ideally SMMU register blocks should be in one block, but it
> was a bit too late to change this design(or H/W). Considering this
> situation, in this driver, number of register blocks should be
> allocated dynamically, based on the info from DT. Its range checks
> should be done in the accessors as below(*1) if necessary. This way
> may sacrifice some perf because a new accessor prevents compiler
> optimization of register offset calculation, but I think that SMMU
> register accesses are not so frequent and it's acceptable in order to
> unify "tegra-smmu" over Tegra SoCs.
> 
> *1:
> 
>  /*
>   *	SMMU register accessors
>   */
>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
>  {
>  	void __iommu *addr = smmu->regbase + offs;
>  #ifdef DEBUG
>  	int i;
> 
>  	for (i = 0; i < smmu->num_regblks; i++) {
>  		BUG_ON(addr < smmu->reg[i].start);
>  		if (addr <= smmu->reg[i].end)
>  			break;
>  	}
>  #endfi
>  	return readl(addr);
>  }

Yes, that kind of checking looks much better if this is all going to be
dynamic.

I would suggest enabling the checking all the time rather than hiding it
inside an ifdef; how many people build that file with DEBUG enabled?

Or perhaps you could check each register in probe() somehow.

> Even the checks if "offs" is in some of register blocks could be
> ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
> as below. I don't think that we don't need to access "mc" DT entry to
> get this address. since "smmu"'s 1st reg block always starts at 0x10.
> 
>   /* same as "mc"'s 1st reg block */
>   smmu->regbase = smmu->reg[0] & PAGE_MASK;

I don't see regbase in the existing driver or your patch. Are you
proposing to simply make readl/writel add the offset onto a base address
that's calculated like that? That may not work in general; if the SMMU
register ranges cross a page boundary, and the various separate ranges
end up getting mapped to non-contiguous virtual addresses, using a
single base address won't work.

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

* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found]                 ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-21  7:36                   ` Hiroshi Doyu
       [not found]                     ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-21  7:36 UTC (permalink / raw)
  To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org

Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Fri, 18 Jan 2013 17:44:13 +0100:

> > Even the checks if "offs" is in some of register blocks could be
> > ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
> > as below. I don't think that we don't need to access "mc" DT entry to
> > get this address. since "smmu"'s 1st reg block always starts at 0x10.
> > 
> >   /* same as "mc"'s 1st reg block */
> >   smmu->regbase = smmu->reg[0] & PAGE_MASK;
> 
> I don't see regbase in the existing driver or your patch. Are you

I attached the update one below just for "regbase".

> proposing to simply make readl/writel add the offset onto a base address
> that's calculated like that? That may not work in general; if the SMMU
> register ranges cross a page boundary, and the various separate ranges
> end up getting mapped to non-contiguous virtual addresses, using a
> single base address won't work.

That's not in general, but I think that this works because the 1st
SMMU register block offset is fixed(0x10) against MC base. If this is
not acceptable, then, I think that SMMU driver needs to access to MC
node to get the its base. What do you think?

>From 71de7ddfed8b3341f18e97b92bdf76c193e5127a Mon Sep 17 00:00:00 2001
From: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Date: Wed, 9 Jan 2013 12:38:47 +0200
Subject: [PATCH 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks

Presently there are 3 register blocks. In the future chips over some
generations, some of register block "size" can be extended to the end
and also more new register blocks will be added, which is expected at
most a few blocks. Usually the starting address of each block won't
change. Ideally SMMU register blocks should be in one block, but it
was a bit too late to change this design(or H/W). Considering this
situation, in this driver, number of register blocks should be
allocated dynamically, based on the info from DT. Its range checks
can be done in the accessors. This way may sacrifice some perf because
a new accessors prevents compiler optimization of register offset
calculation, but I think that SMMU register accesses are not so
frequent and it's acceptable, but it's ifdef'ed out. This patch is
necessary to unify "tegra-smmu.ko" over Tegra SoCs.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   62 ++++++++++++++++++++++++--------------------
 1 file changed, 34 insertions(+), 28 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e80312c..96ac4241 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -221,7 +221,11 @@ struct smmu_debugfs_info {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	void __iomem	*regbase;	/* register offset base */
+	void __iomem	**regs;		/* register block start address array */
+	void __iomem	**rege;		/* register block end address array */
+	int		nregs;		/* number of register blocks */
+
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -254,38 +258,31 @@ static struct smmu_device *smmu_handle; /* unique for a system */
 /*
  *	SMMU register accessors
  */
+#ifdef DEBUG
+static inline void smmu_check_reg_range(size_t offs)
+{
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		BUG_ON(offs < smmu->regs[i] - smmu->regbase);
+		if (offs <= smmu->rege[i] - smmu->regbase)
+			break;
+	}
+}
+#else
+static inline void smmu_check_reg_range(size_t offs) { }
+#endif
+
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
-		return readl(smmu->regs[0] + offs - 0x10);
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
-		return readl(smmu->regs[1] + offs - 0x1f0);
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
-		return readl(smmu->regs[2] + offs - 0x228);
-	BUG();
+	smmu_check_reg_range(offs);
+	return readl(smmu->regbase + offs);
 }
 
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
-		writel(val, smmu->regs[0] + offs - 0x10);
-		return;
-	}
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
-		writel(val, smmu->regs[1] + offs - 0x1f0);
-		return;
-	}
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
-		writel(val, smmu->regs[2] + offs - 0x228);
-		return;
-	}
-	BUG();
+	smmu_check_reg_range(offs);
+	writel(val, smmu->regbase + offs);
 }
 
 #define VA_PAGE_TO_PA(va, page)	\
@@ -1108,7 +1105,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+	smmu->nregs = pdev->num_resources;
+	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+				  GFP_KERNEL);
+	smmu->rege = smmu->regs + smmu->nregs;
+	if (!smmu->regs)
+		return -ENOMEM;
+	for (i = 0; i < smmu->nregs; i++) {
 		struct resource *res;
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1117,7 +1120,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->rege[i] = smmu->regs[i] + resource_size(res);
 	}
+	/* Same as "mc" 1st regiter block start address */
+	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
 	if (err)
-- 
1.7.9.5

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

* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
       [not found]                     ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-21 17:04                       ` Stephen Warren
       [not found]                         ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Stephen Warren @ 2013-01-21 17:04 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On 01/21/2013 12:36 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Fri, 18 Jan 2013 17:44:13 +0100:
> 
>>> Even the checks if "offs" is in some of register blocks could be
>>> ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
>>> as below. I don't think that we don't need to access "mc" DT entry to
>>> get this address. since "smmu"'s 1st reg block always starts at 0x10.
>>>
>>>   /* same as "mc"'s 1st reg block */
>>>   smmu->regbase = smmu->reg[0] & PAGE_MASK;
>>
>> I don't see regbase in the existing driver or your patch. Are you
> 
> I attached the update one below just for "regbase".
> 
>> proposing to simply make readl/writel add the offset onto a base address
>> that's calculated like that? That may not work in general; if the SMMU
>> register ranges cross a page boundary, and the various separate ranges
>> end up getting mapped to non-contiguous virtual addresses, using a
>> single base address won't work.
> 
> That's not in general, but I think that this works because the 1st
> SMMU register block offset is fixed(0x10) against MC base. If this is
> not acceptable, then, I think that SMMU driver needs to access to MC
> node to get the its base. What do you think?

>  drivers/iommu/tegra-smmu.c |   62 ++++++++++++++++++++++++--------------------
>  1 file changed, 34 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c

> +#ifdef DEBUG
> +static inline void smmu_check_reg_range(size_t offs)

Like I said before, when is DEBUG defined? Rarely I suspect. It'd be
best to simply enable smmu_check_reg_range() all the time. As such ...

> +{
> +	int i;
> +
> +	for (i = 0; i < smmu->nregs; i++) {
> +		BUG_ON(offs < smmu->regs[i] - smmu->regbase);
> +		if (offs <= smmu->rege[i] - smmu->regbase)
> +			break;
> +	}
> +}
> +#else
> +static inline void smmu_check_reg_range(size_t offs) { }
> +#endif
> +
>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
>  {
> -	BUG_ON(offs < 0x10);
> -	if (offs < 0x3c)
> -		return readl(smmu->regs[0] + offs - 0x10);
> -	BUG_ON(offs < 0x1f0);
> -	if (offs < 0x200)
> -		return readl(smmu->regs[1] + offs - 0x1f0);
> -	BUG_ON(offs < 0x228);
> -	if (offs < 0x284)
> -		return readl(smmu->regs[2] + offs - 0x228);
> -	BUG();
> +	smmu_check_reg_range(offs);

... here, you'd be doing the loop every access anyway, so you may as
well not calculate regbase at all, move the body of
smmu_check_reg_range() into smmu_read()/smmu_write(), and do the access
inside the if statement inside the loop, with the per-range mapping.

> +	return readl(smmu->regbase + offs);
>  }

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

* Re: [PATCH 5/6] ARM: dt: tegra114: Add AHB entry
       [not found]     ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-28 19:00       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-28 19:00 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA

On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Add AHB entry.

I've applied patches 5/6 and 6/6 to Tegra's for-3.9/soc-t114 branch.

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

* [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                         ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-29  8:34                           ` Hiroshi Doyu
       [not found]                             ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-29  8:34 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   61 ++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..e62f735 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	void __iomem	*regbase;	/* register offset base */
+	void __iomem	**regs;		/* register block start address array */
+	void __iomem	**rege;		/* register block end address array */
+	int		nregs;		/* number of register blocks */
+
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
-		return readl(smmu->regs[0] + offs - 0x10);
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
-		return readl(smmu->regs[1] + offs - 0x1f0);
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
-		return readl(smmu->regs[2] + offs - 0x228);
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i])
+			return readl(addr);
+	}
+
 	BUG();
 }
 
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
-		writel(val, smmu->regs[0] + offs - 0x10);
-		return;
-	}
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
-		writel(val, smmu->regs[1] + offs - 0x1f0);
-		return;
-	}
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
-		writel(val, smmu->regs[2] + offs - 0x228);
-		return;
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i]) {
+			writel(val, addr);
+			return;
+		}
 	}
+
 	BUG();
 }
 
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+	smmu->nregs = pdev->num_resources;
+	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+				  GFP_KERNEL);
+	smmu->rege = smmu->regs + smmu->nregs;
+	if (!smmu->regs)
+		return -ENOMEM;
+	for (i = 0; i < smmu->nregs; i++) {
 		struct resource *res;
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->rege[i] = smmu->regs[i] + resource_size(res);
 	}
+	/* Same as "mc" 1st regiter block start address */
+	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
 	if (err)
-- 
1.7.9.5

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

* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                             ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:03                               ` Stephen Warren
       [not found]                                 ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Stephen Warren @ 2013-01-29 17:03 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

On 01/29/2013 01:34 AM, Hiroshi Doyu wrote:
> Presently SMMU registers are located in discontiguous 3 blocks. They
> are interleaved by MC registers. Ideally SMMU register blocks should
> be in an independent one block, but it is too late to change this H/W
> design. In the future Tegra chips over some generations, it is
> expected that some of register block "size" can be extended towards
> the end and also more new register blocks will be added at most a few
> blocks. The starting address of each existing block won't change. This
> patch allocates multiple number of register blocks dynamically based
> on the info passed from DT. Those ranges are verified in the
> accessors{read,write}. This may sacrifice some performance because a
> new accessors prevents compiler optimization of a fixed size register
> offset calculation. Since SMMU register accesses are not so frequent,
> this would be acceptable. This patch is necessary to unify
> "tegra-smmu.ko" over some Tegra SoC generations.

> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c

>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)

> +	for (i = 0; i < smmu->nregs; i++) {
> +		void __iomem *addr = smmu->regbase + offs;

I don't really like the concept of "regbase", but I suppose it works
just fine and isn't entirely avoidable, so I won't object.

> +		BUG_ON(addr < smmu->regs[i]);
> +		if (addr <= smmu->rege[i])
> +			return readl(addr);

So here we assume that rege points at the last valid address in the range...

> @@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> -	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
> +	smmu->nregs = pdev->num_resources;
> +	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
> +				  GFP_KERNEL);
> +	smmu->rege = smmu->regs + smmu->nregs;

... but here rege is set to the first address after the range. I think
the simplest solution is to change the <= to < in smmu_{read,write}().

> +	/* Same as "mc" 1st regiter block start address */
> +	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);

I'm not sure if it's relevant how these register ranges are related to
the MC registers, given this is the SMMU driver?

s/regiter/register/ in the comment if you keep it.

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

* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                                 ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-29 17:40                                   ` Hiroshi Doyu
       [not found]                                     ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  2013-01-29 17:56                                   ` [v3 " Hiroshi Doyu
  1 sibling, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-29 17:40 UTC (permalink / raw)
  To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org

Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Tue, 29 Jan 2013 18:03:51 +0100:

> > +	/* Same as "mc" 1st regiter block start address */
> > +	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
> 
> I'm not sure if it's relevant how these register ranges are related to
> the MC registers, given this is the SMMU driver?

All SMMU register offsets are against MC[0]'s start address and SMMU
register blocks are interleaved as below. The 1st SMMU register block
SMMU[0]'s offset is always 0x10.

Address Register block
-----------------------
000-010	MC[0]
010-03c	SMMU[0]
03c-1f0	MC[1]
1f0-200	SMMU[1]
200-228	MC[2]
228-284	SMMU[2]
284-...	MC[3]

If the above assumption is not acceptable, alternatively we need to
access MC's node to get the 1st MC register block start address, for
example, via embedded in MC's phandle in smmu entry.

	Modified arch/arm/boot/dts/tegra30.dtsi
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index c5db29d..e9fb9ef 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -397,7 +397,7 @@
 		reg = <0x7000e400 0x400>;
 	};
 
-	memory-controller {
+	mc: memory-controller {
 		compatible = "nvidia,tegra30-mc";
 		reg = <0x7000f000 0x010
 		       0x7000f03c 0x1b4
@@ -414,6 +414,7 @@
 		nvidia,#asids = <4>;		/* # of ASIDs */
 		dma-window = <0 0x40000000>;	/* IOVA start & length */
 		nvidia,ahb = <&ahb>;
+		nvidia.mc = <&mc>;
 	};
 
 	ahub {

I may think that above may be a bit too much since we know that the
1st SMMU offset(0x10) and also that the MC register is aligned with
page boundary, and the following works actually.

	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);

I don't think that the existing SMMU/MC register offsets will change so easily.

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

* [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                                 ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  2013-01-29 17:40                                   ` Hiroshi Doyu
@ 2013-01-29 17:56                                   ` Hiroshi Doyu
       [not found]                                     ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  1 sibling, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-29 17:56 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A, swarren-3lzwWm7+Weoh9ZMKESR00Q
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
v3:
Fixed overlapped register validation. (Stephen Warren)
Fixed typo s/regiter/register/. (Stephen Warren)
---
 drivers/iommu/tegra-smmu.c |   61 ++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..d1448f9 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	void __iomem	*regbase;	/* register offset base */
+	void __iomem	**regs;		/* register block start address array */
+	void __iomem	**rege;		/* register block end address array */
+	int		nregs;		/* number of register blocks */
+
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
-		return readl(smmu->regs[0] + offs - 0x10);
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
-		return readl(smmu->regs[1] + offs - 0x1f0);
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
-		return readl(smmu->regs[2] + offs - 0x228);
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr < smmu->rege[i])
+			return readl(addr);
+	}
+
 	BUG();
 }
 
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
-		writel(val, smmu->regs[0] + offs - 0x10);
-		return;
-	}
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
-		writel(val, smmu->regs[1] + offs - 0x1f0);
-		return;
-	}
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
-		writel(val, smmu->regs[2] + offs - 0x228);
-		return;
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr < smmu->rege[i]) {
+			writel(val, addr);
+			return;
+		}
 	}
+
 	BUG();
 }
 
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+	smmu->nregs = pdev->num_resources;
+	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+				  GFP_KERNEL);
+	smmu->rege = smmu->regs + smmu->nregs;
+	if (!smmu->regs)
+		return -ENOMEM;
+	for (i = 0; i < smmu->nregs; i++) {
 		struct resource *res;
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->rege[i] = smmu->regs[i] + resource_size(res);
 	}
+	/* Same as "mc" 1st register block start address */
+	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
 	if (err)
-- 
1.7.9.5

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

* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                                     ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:57                                       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-29 17:57 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On 01/29/2013 10:40 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Tue, 29 Jan 2013 18:03:51 +0100:
> 
>>> +	/* Same as "mc" 1st regiter block start address */
>>> +	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
>>
>> I'm not sure if it's relevant how these register ranges are related to
>> the MC registers, given this is the SMMU driver?
> 
> All SMMU register offsets are against MC[0]'s start address and SMMU
> register blocks are interleaved as below. The 1st SMMU register block
> SMMU[0]'s offset is always 0x10.
> 
> Address Register block
> -----------------------
> 000-010	MC[0]
> 010-03c	SMMU[0]
> 03c-1f0	MC[1]
> 1f0-200	SMMU[1]
> 200-228	MC[2]
> 228-284	SMMU[2]
> 284-...	MC[3]

I know that's true, but it's still not really relevant to the SMMU
driver. What is relevant is that the SMMU has a bunch of chunks of
address space containing SMMU registers, and there are gaps, and all the
register offsets in the SMMU driver are relative to the page-aligned
base of the first chunk. The fact the gaps contain MC registers is what
isn't relevant.

> If the above assumption is not acceptable, alternatively we need to
> access MC's node to get the 1st MC register block start address, for
> example, via embedded in MC's phandle in smmu entry.

Like I said, the code is fine so I'm not really objecting to it.

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                                     ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:58                                       ` Stephen Warren
  0 siblings, 0 replies; 29+ messages in thread
From: Stephen Warren @ 2013-01-29 17:58 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

On 01/29/2013 10:56 AM, Hiroshi Doyu wrote:
> Presently SMMU registers are located in discontiguous 3 blocks. They
> are interleaved by MC registers. Ideally SMMU register blocks should
> be in an independent one block, but it is too late to change this H/W
> design. In the future Tegra chips over some generations, it is
> expected that some of register block "size" can be extended towards
> the end and also more new register blocks will be added at most a few
> blocks. The starting address of each existing block won't change. This
> patch allocates multiple number of register blocks dynamically based
> on the info passed from DT. Those ranges are verified in the
> accessors{read,write}. This may sacrifice some performance because a
> new accessors prevents compiler optimization of a fixed size register
> offset calculation. Since SMMU register accesses are not so frequent,
> this would be acceptable. This patch is necessary to unify
> "tegra-smmu.ko" over some Tegra SoC generations.

Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

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

* [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
@ 2013-01-31  8:14 Hiroshi Doyu
       [not found] ` <1359620050-28727-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-01-31  8:14 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu

Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.

Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   61 ++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 25c1210..024a7e1 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	void __iomem	*regbase;	/* register offset base */
+	void __iomem	**regs;		/* register block start address array */
+	void __iomem	**rege;		/* register block end address array */
+	int		nregs;		/* number of register blocks */
+
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
-		return readl(smmu->regs[0] + offs - 0x10);
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
-		return readl(smmu->regs[1] + offs - 0x1f0);
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
-		return readl(smmu->regs[2] + offs - 0x228);
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i])
+			return readl(addr);
+	}
+
 	BUG();
 }
 
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
-		writel(val, smmu->regs[0] + offs - 0x10);
-		return;
-	}
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
-		writel(val, smmu->regs[1] + offs - 0x1f0);
-		return;
-	}
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
-		writel(val, smmu->regs[2] + offs - 0x228);
-		return;
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i]) {
+			writel(val, addr);
+			return;
+		}
 	}
+
 	BUG();
 }
 
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+	smmu->nregs = pdev->num_resources;
+	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+				  GFP_KERNEL);
+	smmu->rege = smmu->regs + smmu->nregs;
+	if (!smmu->regs)
+		return -ENOMEM;
+	for (i = 0; i < smmu->nregs; i++) {
 		struct resource *res;
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->rege[i] = smmu->regs[i] + resource_size(res);
 	}
+	/* Same as "mc" 1st regiter block start address */
+	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
 	if (err)
-- 
1.7.9.5

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found] ` <1359620050-28727-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-02-04 19:53   ` Joerg Roedel
       [not found]     ` <20130204195232.GA15278-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Joerg Roedel @ 2013-02-04 19:53 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA

On Thu, Jan 31, 2013 at 10:14:10AM +0200, Hiroshi Doyu wrote:
>  drivers/iommu/tegra-smmu.c |   61 ++++++++++++++++++++++++++------------------
>  1 file changed, 36 insertions(+), 25 deletions(-)

Okay, applied this patch to arm/tegra, but

>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
>  {
> -	BUG_ON(offs < 0x10);
> -	if (offs < 0x3c)
> -		return readl(smmu->regs[0] + offs - 0x10);
> -	BUG_ON(offs < 0x1f0);
> -	if (offs < 0x200)
> -		return readl(smmu->regs[1] + offs - 0x1f0);
> -	BUG_ON(offs < 0x228);
> -	if (offs < 0x284)
> -		return readl(smmu->regs[2] + offs - 0x228);
> +	int i;
> +
> +	for (i = 0; i < smmu->nregs; i++) {
> +		void __iomem *addr = smmu->regbase + offs;
> +
> +		BUG_ON(addr < smmu->regs[i]);
> +		if (addr <= smmu->rege[i])
> +			return readl(addr);
> +	}

This loop is purely for checking offset to be valid. And this loop is
repeated in the smmu_write() function. I queued a patch on-top to make
this more clear. Please double-check:

>From 08c4ae0b8955bd818bdfd438a684bd5f8db7fb67 Mon Sep 17 00:00:00 2001
From: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
Date: Mon, 4 Feb 2013 20:40:58 +0100
Subject: [PATCH 1/1] iommu/tegra: smmu: Use helper function to check for
 valid register offset

Do not repeat the checking loop in the read and write
functions. Use a single helper function for that check and
call it in both accessors.

Signed-off-by: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
 drivers/iommu/tegra-smmu.c |   35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 3e07e8b..5ea8d66 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -327,36 +327,37 @@ static struct smmu_device *smmu_handle; /* unique for a system */
 /*
  *	SMMU register accessors
  */
-static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
+static bool inline smmu_valid_reg(struct smmu_device *smmu,
+				  void __iomem *addr)
 {
 	int i;
 
 	for (i = 0; i < smmu->nregs; i++) {
-		void __iomem *addr = smmu->regbase + offs;
-
-		BUG_ON(addr < smmu->regs[i]);
+		if (addr < smmu->regs[i])
+			break;
 		if (addr <= smmu->rege[i])
-			return readl(addr);
+			return true;
 	}
 
-	BUG();
+	return false;
 }
 
-static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
+static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	int i;
+	void __iomem *addr = smmu->regbase + offs;
 
-	for (i = 0; i < smmu->nregs; i++) {
-		void __iomem *addr = smmu->regbase + offs;
+	BUG_ON(!smmu_valid_reg(smmu, addr));
 
-		BUG_ON(addr < smmu->regs[i]);
-		if (addr <= smmu->rege[i]) {
-			writel(val, addr);
-			return;
-		}
-	}
+	return readl(addr);
+}
+
+static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
+{
+	void __iomem *addr = smmu->regbase + offs;
+
+	BUG_ON(!smmu_valid_reg(smmu, addr));
 
-	BUG();
+	writel(val, addr);
 }
 
 #define VA_PAGE_TO_PA(va, page)	\
-- 
1.7.9.5

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]     ` <20130204195232.GA15278-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
@ 2013-02-04 20:31       ` Hiroshi Doyu
       [not found]         ` <20130204.223114.121259250064618894.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-02-04 20:31 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org, Stephen Warren
  Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Hi Joerg,

Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org> wrote @ Mon, 4 Feb 2013 20:53:32 +0100:

> >  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
> >  {
> > -	BUG_ON(offs < 0x10);
> > -	if (offs < 0x3c)
> > -		return readl(smmu->regs[0] + offs - 0x10);
> > -	BUG_ON(offs < 0x1f0);
> > -	if (offs < 0x200)
> > -		return readl(smmu->regs[1] + offs - 0x1f0);
> > -	BUG_ON(offs < 0x228);
> > -	if (offs < 0x284)
> > -		return readl(smmu->regs[2] + offs - 0x228);
> > +	int i;
> > +
> > +	for (i = 0; i < smmu->nregs; i++) {
> > +		void __iomem *addr = smmu->regbase + offs;
> > +
> > +		BUG_ON(addr < smmu->regs[i]);
> > +		if (addr <= smmu->rege[i])
> > +			return readl(addr);
> > +	}
> 
> This loop is purely for checking offset to be valid. And this loop is
> repeated in the smmu_write() function. I queued a patch on-top to make
> this more clear. Please double-check:

Actually I did the similar thing in the first version of this patch(*1)

+static inline void smmu_check_reg_range(size_t offs)
+{
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+	    BUG_ON(offs < smmu->regs[i] - smmu->regbase);
+	    		if (offs <= smmu->rege[i] - smmu->regbase)
+			   	 break;
+	 }
+}

*1:
http://lists.linuxfoundation.org/pipermail/iommu/2013-January/005072.html

Then, Stehpen pointed out about this check function(*2).

"... here, you'd be doing the loop every access anyway, so you may as
well not calculate regbase at all, move the body of
smmu_check_reg_range() into smmu_read()/smmu_write(), and do the access
inside the if statement inside the loop, with the per-range mapping."

*2:
http://lists.linuxfoundation.org/pipermail/iommu/2013-January/005074.html

I might not get Stehpen's point in the latest patch(?), though....

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]         ` <20130204.223114.121259250064618894.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-02-04 20:35           ` Stephen Warren
       [not found]             ` <51101BA1.5090208-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Stephen Warren @ 2013-02-04 20:35 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org, Stephen Warren,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On 02/04/2013 01:31 PM, Hiroshi Doyu wrote:
> Hi Joerg,
> 
> Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org> wrote @ Mon, 4 Feb 2013 20:53:32 +0100:
> 
>>>  static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
>>>  {
>>> -	BUG_ON(offs < 0x10);
>>> -	if (offs < 0x3c)
>>> -		return readl(smmu->regs[0] + offs - 0x10);
>>> -	BUG_ON(offs < 0x1f0);
>>> -	if (offs < 0x200)
>>> -		return readl(smmu->regs[1] + offs - 0x1f0);
>>> -	BUG_ON(offs < 0x228);
>>> -	if (offs < 0x284)
>>> -		return readl(smmu->regs[2] + offs - 0x228);
>>> +	int i;
>>> +
>>> +	for (i = 0; i < smmu->nregs; i++) {
>>> +		void __iomem *addr = smmu->regbase + offs;
>>> +
>>> +		BUG_ON(addr < smmu->regs[i]);
>>> +		if (addr <= smmu->rege[i])
>>> +			return readl(addr);
>>> +	}
>>
>> This loop is purely for checking offset to be valid. And this loop is
>> repeated in the smmu_write() function. I queued a patch on-top to make
>> this more clear. Please double-check:
> 
> Actually I did the similar thing in the first version of this patch(*1)
> 
> +static inline void smmu_check_reg_range(size_t offs)
> +{
> +	int i;
> +
> +	for (i = 0; i < smmu->nregs; i++) {
> +	    BUG_ON(offs < smmu->regs[i] - smmu->regbase);
> +	    		if (offs <= smmu->rege[i] - smmu->regbase)
> +			   	 break;
> +	 }
> +}
> 
> *1:
> http://lists.linuxfoundation.org/pipermail/iommu/2013-January/005072.html
> 
> Then, Stehpen pointed out about this check function(*2).
> 
> "... here, you'd be doing the loop every access anyway, so you may as
> well not calculate regbase at all, move the body of
> smmu_check_reg_range() into smmu_read()/smmu_write(), and do the access
> inside the if statement inside the loop, with the per-range mapping."

Upon reflection, that comment probably isn't correct, since the only way
to know where each register range begins, relative to the register
numbers that the driver uses, is to calculate reg_base. So, I think you
do need reg_base, and Joerg's latest patch seems reasonable.

> *2:
> http://lists.linuxfoundation.org/pipermail/iommu/2013-January/005074.html
> 
> I might not get Stehpen's point in the latest patch(?), though....

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]             ` <51101BA1.5090208-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-02-04 20:39               ` Hiroshi Doyu
       [not found]                 ` <20130204.223921.2367725583637314.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-02-04 20:39 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
	swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
  Cc: Stephen Warren,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Mon, 4 Feb 2013 21:35:45 +0100:

> >> This loop is purely for checking offset to be valid. And this loop is
> >> repeated in the smmu_write() function. I queued a patch on-top to make
> >> this more clear. Please double-check:
> > 
> > Actually I did the similar thing in the first version of this patch(*1)
> > 
> > +static inline void smmu_check_reg_range(size_t offs)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < smmu->nregs; i++) {
> > +	    BUG_ON(offs < smmu->regs[i] - smmu->regbase);
> > +	    		if (offs <= smmu->rege[i] - smmu->regbase)
> > +			   	 break;
> > +	 }
> > +}
> > 
> > *1:
> > http://lists.linuxfoundation.org/pipermail/iommu/2013-January/005072.html
> > 
> > Then, Stehpen pointed out about this check function(*2).
> > 
> > "... here, you'd be doing the loop every access anyway, so you may as
> > well not calculate regbase at all, move the body of
> > smmu_check_reg_range() into smmu_read()/smmu_write(), and do the access
> > inside the if statement inside the loop, with the per-range mapping."
> 
> Upon reflection, that comment probably isn't correct, since the only way
> to know where each register range begins, relative to the register
> numbers that the driver uses, is to calculate reg_base. So, I think you
> do need reg_base, and Joerg's latest patch seems reasonable.

Ok, now it's clear. Joerg, please get yours merged on the top of this.

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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                 ` <20130204.223921.2367725583637314.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-02-04 20:54                   ` Hiroshi Doyu
       [not found]                     ` <20130204.225407.2202093543593597795.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 29+ messages in thread
From: Hiroshi Doyu @ 2013-02-04 20:54 UTC (permalink / raw)
  To: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org
  Cc: Stephen Warren,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

[-- Attachment #1: Type: text/plain, Size: 542 bytes --]

Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> wrote @ Mon, 04 Feb 2013 22:39:21 +0200 (EET):

> > Upon reflection, that comment probably isn't correct, since the only way
> > to know where each register range begins, relative to the register
> > numbers that the driver uses, is to calculate reg_base. So, I think you
> > do need reg_base, and Joerg's latest patch seems reasonable.
> 
> Ok, now it's clear. Joerg, please get yours merged on the top of this.

Joerg, could you please replace v3 with the attached v4?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-iommu-tegra-smmu-Support-variable-MMIO-ranges-blocks.patch --]
[-- Type: text/x-patch; name="0001-iommu-tegra-smmu-Support-variable-MMIO-ranges-blocks.patch", Size: 4447 bytes --]

From 2f71337453483da291c29b744ca165857c8b84e4 Mon Sep 17 00:00:00 2001
From: Hiroshi Doyu <hdoyu@nvidia.com>
Date: Wed, 9 Jan 2013 12:38:47 +0200
Subject: [v4 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks

Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
---
Update: Set rege the last valid address.
---
---
 drivers/iommu/tegra-smmu.c |   61 ++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..0d403fe 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
  * Per SMMU device - IOMMU device
  */
 struct smmu_device {
-	void __iomem	*regs[NUM_SMMU_REG_BANKS];
+	void __iomem	*regbase;	/* register offset base */
+	void __iomem	**regs;		/* register block start address array */
+	void __iomem	**rege;		/* register block end address array */
+	int		nregs;		/* number of register blocks */
+
 	unsigned long	iovmm_base;	/* remappable base address */
 	unsigned long	page_count;	/* total remappable size */
 	spinlock_t	lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
  */
 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c)
-		return readl(smmu->regs[0] + offs - 0x10);
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200)
-		return readl(smmu->regs[1] + offs - 0x1f0);
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284)
-		return readl(smmu->regs[2] + offs - 0x228);
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i])
+			return readl(addr);
+	}
+
 	BUG();
 }
 
 static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
 {
-	BUG_ON(offs < 0x10);
-	if (offs < 0x3c) {
-		writel(val, smmu->regs[0] + offs - 0x10);
-		return;
-	}
-	BUG_ON(offs < 0x1f0);
-	if (offs < 0x200) {
-		writel(val, smmu->regs[1] + offs - 0x1f0);
-		return;
-	}
-	BUG_ON(offs < 0x228);
-	if (offs < 0x284) {
-		writel(val, smmu->regs[2] + offs - 0x228);
-		return;
+	int i;
+
+	for (i = 0; i < smmu->nregs; i++) {
+		void __iomem *addr = smmu->regbase + offs;
+
+		BUG_ON(addr < smmu->regs[i]);
+		if (addr <= smmu->rege[i]) {
+			writel(val, addr);
+			return;
+		}
 	}
+
 	BUG();
 }
 
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+	smmu->nregs = pdev->num_resources;
+	smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+				  GFP_KERNEL);
+	smmu->rege = smmu->regs + smmu->nregs;
+	if (!smmu->regs)
+		return -ENOMEM;
+	for (i = 0; i < smmu->nregs; i++) {
 		struct resource *res;
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 		smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
 		if (!smmu->regs[i])
 			return -EBUSY;
+		smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1;
 	}
+	/* Same as "mc" 1st regiter block start address */
+	smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
 
 	err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
 	if (err)
-- 
1.7.9.5


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

* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
       [not found]                     ` <20130204.225407.2202093543593597795.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-02-05 13:19                       ` joro-zLv9SwRftAIdnm+yROfE0A
  0 siblings, 0 replies; 29+ messages in thread
From: joro-zLv9SwRftAIdnm+yROfE0A @ 2013-02-05 13:19 UTC (permalink / raw)
  To: Hiroshi Doyu
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	Stephen Warren

On Mon, Feb 04, 2013 at 09:54:07PM +0100, Hiroshi Doyu wrote:
> Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> wrote @ Mon, 04 Feb 2013 22:39:21 +0200 (EET):
> 
> > > Upon reflection, that comment probably isn't correct, since the only way
> > > to know where each register range begins, relative to the register
> > > numbers that the driver uses, is to calculate reg_base. So, I think you
> > > do need reg_base, and Joerg's latest patch seems reasonable.
> > 
> > Ok, now it's clear. Joerg, please get yours merged on the top of this.
> 
> Joerg, could you please replace v3 with the attached v4?

Done.

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

end of thread, other threads:[~2013-02-05 13:19 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-15  8:17 [PATCH 1/6] iommu/tegra: Rename -i hw{grp,group} to sw{grp,group} Hiroshi Doyu
     [not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15  8:17   ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
     [not found]     ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:07       ` Stephen Warren
2013-01-15  8:17   ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
2013-01-15  8:17   ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
     [not found]     ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:12       ` Stephen Warren
     [not found]         ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-18  9:05           ` Hiroshi Doyu
     [not found]             ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-18 16:44               ` Stephen Warren
     [not found]                 ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-21  7:36                   ` Hiroshi Doyu
     [not found]                     ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-21 17:04                       ` Stephen Warren
     [not found]                         ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-29  8:34                           ` [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks Hiroshi Doyu
     [not found]                             ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:03                               ` Stephen Warren
     [not found]                                 ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-29 17:40                                   ` Hiroshi Doyu
     [not found]                                     ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:57                                       ` Stephen Warren
2013-01-29 17:56                                   ` [v3 " Hiroshi Doyu
     [not found]                                     ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:58                                       ` Stephen Warren
2013-01-15  8:17   ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
     [not found]     ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-28 19:00       ` Stephen Warren
2013-01-15  8:17   ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
     [not found]     ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:17       ` Stephen Warren
2013-01-15 13:22   ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
     [not found]     ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:18       ` Stephen Warren
  -- strict thread matches above, loose matches on Subject: below --
2013-01-31  8:14 [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks Hiroshi Doyu
     [not found] ` <1359620050-28727-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-04 19:53   ` Joerg Roedel
     [not found]     ` <20130204195232.GA15278-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
2013-02-04 20:31       ` Hiroshi Doyu
     [not found]         ` <20130204.223114.121259250064618894.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-04 20:35           ` Stephen Warren
     [not found]             ` <51101BA1.5090208-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-02-04 20:39               ` Hiroshi Doyu
     [not found]                 ` <20130204.223921.2367725583637314.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-04 20:54                   ` Hiroshi Doyu
     [not found]                     ` <20130204.225407.2202093543593597795.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-05 13:19                       ` joro-zLv9SwRftAIdnm+yROfE0A

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).