From 0fde671b81d406a59ae21f35f121851509c3b138 Mon Sep 17 00:00:00 2001 From: Sami Liedes Date: Mon, 4 Feb 2013 14:31:48 +0200 Subject: iommu/tegra: Add missing spinlock initialization Fix tegra_smmu_probe() to initialize client_lock spinlocks in per-address-space structures. Signed-off-by: Sami Liedes Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iommu/tegra-smmu.c') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index fc178893789..87a719f4adf 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1,7 +1,7 @@ /* * IOMMU API for SMMU in Tegra30 * - * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -1216,6 +1216,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) as->pte_attr = _PTE_ATTR; spin_lock_init(&as->lock); + spin_lock_init(&as->client_lock); INIT_LIST_HEAD(&as->client); } spin_lock_init(&smmu->lock); -- cgit v1.2.3-70-g09d2 From a6870e928d1b2a97d95e7bf1aaefd3da34b83a85 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 31 Jan 2013 10:14:10 +0200 Subject: 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 Reviewed-by: Stephen Warren Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 61 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'drivers/iommu/tegra-smmu.c') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 87a719f4adf..2fecbe7fd7f 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) -- cgit v1.2.3-70-g09d2 From fe1229b968e1bd391ce7a89bff51aed10d02b578 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 4 Feb 2013 20:40:58 +0100 Subject: 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 --- drivers/iommu/tegra-smmu.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/iommu/tegra-smmu.c') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 2fecbe7fd7f..774728313f5 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) \ -- cgit v1.2.3-70-g09d2 From a3b7256d643dac125f4162cd4f9b603868559b61 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Wed, 6 Feb 2013 19:38:15 +0200 Subject: iommu/tegra: smmu: Fix incorrect mask for regbase This fixes kernel crash because of BUG() in register address validation. Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu/tegra-smmu.c') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 774728313f5..117427e6004 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1191,7 +1191,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) 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); + 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) -- cgit v1.2.3-70-g09d2 From 573f4145024598990d7191523f86a6d5233be751 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 15:01:07 -0700 Subject: iommu/tegra: assume CONFIG_OF in SMMU driver Tegra only supports, and always enables, device tree. Remove all ifdefs for DT support from the driver. Signed-off-by: Stephen Warren Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iommu/tegra-smmu.c') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 117427e6004..8b1d9f75807 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1267,13 +1267,11 @@ const struct dev_pm_ops tegra_smmu_pm_ops = { .resume = tegra_smmu_resume, }; -#ifdef CONFIG_OF static struct of_device_id tegra_smmu_of_match[] = { { .compatible = "nvidia,tegra30-smmu", }, { }, }; MODULE_DEVICE_TABLE(of, tegra_smmu_of_match); -#endif static struct platform_driver tegra_smmu_driver = { .probe = tegra_smmu_probe, @@ -1282,7 +1280,7 @@ static struct platform_driver tegra_smmu_driver = { .owner = THIS_MODULE, .name = "tegra-smmu", .pm = &tegra_smmu_pm_ops, - .of_match_table = of_match_ptr(tegra_smmu_of_match), + .of_match_table = tegra_smmu_of_match, }, }; -- cgit v1.2.3-70-g09d2