iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [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; 9+ 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] 9+ messages in thread
* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
@ 2013-01-29 17:03 Stephen Warren
       [not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
  0 siblings, 1 reply; 9+ 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] 9+ messages in thread

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

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
  -- strict thread matches above, loose matches on Subject: below --
2013-01-29 17:03 [v2 " Stephen Warren
     [not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
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

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