diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 14:09:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 14:09:17 -0500 |
commit | f6c0ffa8f0b0781f4954cb06f0a81d6c10c1b434 (patch) | |
tree | f99190661706d18f129497a4ef2d37822c9c34db /drivers/iommu/tegra-smmu.c | |
parent | 42a0a1b0fd343888c59afc8b243a77bcec2cc11c (diff) | |
parent | 604542b824f72fa5d7fd977af277538c1e15b5f0 (diff) |
Merge tag 'iommu-updates-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU Updates from Joerg Roedel:
"Besides some fixes and cleanups in the code there are three more
important changes to point out this time:
* New IOMMU driver for the ARM SHMOBILE platform
* An IOMMU-API extension for non-paging IOMMUs (required for
upcoming PAMU driver)
* Rework of the way the Tegra IOMMU driver accesses its
registetrs - register windows are easier to extend now.
There are also a few changes to non-iommu code, but that is acked by
the respective maintainers."
* tag 'iommu-updates-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (23 commits)
iommu/tegra: assume CONFIG_OF in SMMU driver
iommu/tegra: assume CONFIG_OF in gart driver
iommu/amd: Remove redundant NULL check before dma_ops_domain_free().
iommu/amd: Initialize device table after dma_ops
iommu/vt-d: Zero out allocated memory in dmar_enable_qi
iommu/tegra: smmu: Fix incorrect mask for regbase
iommu/exynos: Make exynos_sysmmu_disable static
ARM: mach-shmobile: r8a7740: Add IPMMU device
ARM: mach-shmobile: sh73a0: Add IPMMU device
ARM: mach-shmobile: sh7372: Add IPMMU device
iommu/shmobile: Add iommu driver for Renesas IPMMU modules
iommu: Add DOMAIN_ATTR_WINDOWS domain attribute
iommu: Add domain window handling functions
iommu: Implement DOMAIN_ATTR_PAGING attribute
iommu: Check for valid pgsize_bitmap in iommu_map/unmap
iommu: Make sure DOMAIN_ATTR_MAX is really the maximum
iommu/tegra: smmu: Change SMMU's dependency on ARCH_TEGRA
iommu/tegra: smmu: Use helper function to check for valid register offset
iommu/tegra: smmu: Support variable MMIO ranges/blocks
iommu/tegra: Add missing spinlock initialization
...
Diffstat (limited to 'drivers/iommu/tegra-smmu.c')
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 75 |
1 files changed, 43 insertions, 32 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index f08dbcd2f175..eb0109f98946 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * IOMMU API for SMMU in Tegra30 | 2 | * IOMMU API for SMMU in Tegra30 |
3 | * | 3 | * |
4 | * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. | 4 | * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
@@ -294,7 +294,11 @@ struct smmu_debugfs_info { | |||
294 | * Per SMMU device - IOMMU device | 294 | * Per SMMU device - IOMMU device |
295 | */ | 295 | */ |
296 | struct smmu_device { | 296 | struct smmu_device { |
297 | void __iomem *regs[NUM_SMMU_REG_BANKS]; | 297 | void __iomem *regbase; /* register offset base */ |
298 | void __iomem **regs; /* register block start address array */ | ||
299 | void __iomem **rege; /* register block end address array */ | ||
300 | int nregs; /* number of register blocks */ | ||
301 | |||
298 | unsigned long iovmm_base; /* remappable base address */ | 302 | unsigned long iovmm_base; /* remappable base address */ |
299 | unsigned long page_count; /* total remappable size */ | 303 | unsigned long page_count; /* total remappable size */ |
300 | spinlock_t lock; | 304 | spinlock_t lock; |
@@ -324,38 +328,37 @@ static struct smmu_device *smmu_handle; /* unique for a system */ | |||
324 | /* | 328 | /* |
325 | * SMMU register accessors | 329 | * SMMU register accessors |
326 | */ | 330 | */ |
331 | static bool inline smmu_valid_reg(struct smmu_device *smmu, | ||
332 | void __iomem *addr) | ||
333 | { | ||
334 | int i; | ||
335 | |||
336 | for (i = 0; i < smmu->nregs; i++) { | ||
337 | if (addr < smmu->regs[i]) | ||
338 | break; | ||
339 | if (addr <= smmu->rege[i]) | ||
340 | return true; | ||
341 | } | ||
342 | |||
343 | return false; | ||
344 | } | ||
345 | |||
327 | static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) | 346 | static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) |
328 | { | 347 | { |
329 | BUG_ON(offs < 0x10); | 348 | void __iomem *addr = smmu->regbase + offs; |
330 | if (offs < 0x3c) | 349 | |
331 | return readl(smmu->regs[0] + offs - 0x10); | 350 | BUG_ON(!smmu_valid_reg(smmu, addr)); |
332 | BUG_ON(offs < 0x1f0); | 351 | |
333 | if (offs < 0x200) | 352 | return readl(addr); |
334 | return readl(smmu->regs[1] + offs - 0x1f0); | ||
335 | BUG_ON(offs < 0x228); | ||
336 | if (offs < 0x284) | ||
337 | return readl(smmu->regs[2] + offs - 0x228); | ||
338 | BUG(); | ||
339 | } | 353 | } |
340 | 354 | ||
341 | static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) | 355 | static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) |
342 | { | 356 | { |
343 | BUG_ON(offs < 0x10); | 357 | void __iomem *addr = smmu->regbase + offs; |
344 | if (offs < 0x3c) { | 358 | |
345 | writel(val, smmu->regs[0] + offs - 0x10); | 359 | BUG_ON(!smmu_valid_reg(smmu, addr)); |
346 | return; | 360 | |
347 | } | 361 | writel(val, addr); |
348 | BUG_ON(offs < 0x1f0); | ||
349 | if (offs < 0x200) { | ||
350 | writel(val, smmu->regs[1] + offs - 0x1f0); | ||
351 | return; | ||
352 | } | ||
353 | BUG_ON(offs < 0x228); | ||
354 | if (offs < 0x284) { | ||
355 | writel(val, smmu->regs[2] + offs - 0x228); | ||
356 | return; | ||
357 | } | ||
358 | BUG(); | ||
359 | } | 362 | } |
360 | 363 | ||
361 | #define VA_PAGE_TO_PA(va, page) \ | 364 | #define VA_PAGE_TO_PA(va, page) \ |
@@ -1171,7 +1174,13 @@ static int tegra_smmu_probe(struct platform_device *pdev) | |||
1171 | return -ENOMEM; | 1174 | return -ENOMEM; |
1172 | } | 1175 | } |
1173 | 1176 | ||
1174 | for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) { | 1177 | smmu->nregs = pdev->num_resources; |
1178 | smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs), | ||
1179 | GFP_KERNEL); | ||
1180 | smmu->rege = smmu->regs + smmu->nregs; | ||
1181 | if (!smmu->regs) | ||
1182 | return -ENOMEM; | ||
1183 | for (i = 0; i < smmu->nregs; i++) { | ||
1175 | struct resource *res; | 1184 | struct resource *res; |
1176 | 1185 | ||
1177 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | 1186 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); |
@@ -1180,7 +1189,10 @@ static int tegra_smmu_probe(struct platform_device *pdev) | |||
1180 | smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res); | 1189 | smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res); |
1181 | if (IS_ERR(smmu->regs[i])) | 1190 | if (IS_ERR(smmu->regs[i])) |
1182 | return PTR_ERR(smmu->regs[i]); | 1191 | return PTR_ERR(smmu->regs[i]); |
1192 | smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1; | ||
1183 | } | 1193 | } |
1194 | /* Same as "mc" 1st regiter block start address */ | ||
1195 | smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & PAGE_MASK); | ||
1184 | 1196 | ||
1185 | err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); | 1197 | err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); |
1186 | if (err) | 1198 | if (err) |
@@ -1217,6 +1229,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) | |||
1217 | as->pte_attr = _PTE_ATTR; | 1229 | as->pte_attr = _PTE_ATTR; |
1218 | 1230 | ||
1219 | spin_lock_init(&as->lock); | 1231 | spin_lock_init(&as->lock); |
1232 | spin_lock_init(&as->client_lock); | ||
1220 | INIT_LIST_HEAD(&as->client); | 1233 | INIT_LIST_HEAD(&as->client); |
1221 | } | 1234 | } |
1222 | spin_lock_init(&smmu->lock); | 1235 | spin_lock_init(&smmu->lock); |
@@ -1255,13 +1268,11 @@ const struct dev_pm_ops tegra_smmu_pm_ops = { | |||
1255 | .resume = tegra_smmu_resume, | 1268 | .resume = tegra_smmu_resume, |
1256 | }; | 1269 | }; |
1257 | 1270 | ||
1258 | #ifdef CONFIG_OF | ||
1259 | static struct of_device_id tegra_smmu_of_match[] = { | 1271 | static struct of_device_id tegra_smmu_of_match[] = { |
1260 | { .compatible = "nvidia,tegra30-smmu", }, | 1272 | { .compatible = "nvidia,tegra30-smmu", }, |
1261 | { }, | 1273 | { }, |
1262 | }; | 1274 | }; |
1263 | MODULE_DEVICE_TABLE(of, tegra_smmu_of_match); | 1275 | MODULE_DEVICE_TABLE(of, tegra_smmu_of_match); |
1264 | #endif | ||
1265 | 1276 | ||
1266 | static struct platform_driver tegra_smmu_driver = { | 1277 | static struct platform_driver tegra_smmu_driver = { |
1267 | .probe = tegra_smmu_probe, | 1278 | .probe = tegra_smmu_probe, |
@@ -1270,7 +1281,7 @@ static struct platform_driver tegra_smmu_driver = { | |||
1270 | .owner = THIS_MODULE, | 1281 | .owner = THIS_MODULE, |
1271 | .name = "tegra-smmu", | 1282 | .name = "tegra-smmu", |
1272 | .pm = &tegra_smmu_pm_ops, | 1283 | .pm = &tegra_smmu_pm_ops, |
1273 | .of_match_table = of_match_ptr(tegra_smmu_of_match), | 1284 | .of_match_table = tegra_smmu_of_match, |
1274 | }, | 1285 | }, |
1275 | }; | 1286 | }; |
1276 | 1287 | ||