| Submitter | Hiroshi Doyu |
|---|---|
| Date | Jan. 21, 2013, 7:36 a.m. |
| Message ID | <20130121.093603.449745485344660335.hdoyu@nvidia.com> |
| Download | mbox | patch |
| Permalink | /patch/214033/ |
| State | Not Applicable, archived |
| Headers | show |
Comments
On 01/21/2013 12:36 AM, Hiroshi Doyu wrote: > Stephen Warren <swarren@wwwdotorg.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); > } -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Patch
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)