aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2015-10-07 06:23:24 -0400
committerJoerg Roedel <jroedel@suse.de>2015-10-07 06:23:24 -0400
commit02685b1df0461ce4c23d263b66ea0aac66450d13 (patch)
treebea4402e96bb54b6813971bfb48784bcefb875c6 /drivers/iommu
parent499f3aa4323775d5320bdf7ccc26576c54a54169 (diff)
parent1c27df1c0a82b938d8073a60243ff62eff8056b5 (diff)
Merge branch 'for-joerg/arm-smmu/fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into iommu/fixes
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/Kconfig3
-rw-r--r--drivers/iommu/arm-smmu-v3.c21
-rw-r--r--drivers/iommu/io-pgtable-arm.c24
3 files changed, 29 insertions, 19 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 4664c2a96c67..3dc1bcb0d01d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -23,8 +23,7 @@ config IOMMU_IO_PGTABLE
23config IOMMU_IO_PGTABLE_LPAE 23config IOMMU_IO_PGTABLE_LPAE
24 bool "ARMv7/v8 Long Descriptor Format" 24 bool "ARMv7/v8 Long Descriptor Format"
25 select IOMMU_IO_PGTABLE 25 select IOMMU_IO_PGTABLE
26 # SWIOTLB guarantees a dma_to_phys() implementation 26 depends on HAS_DMA && (ARM || ARM64 || COMPILE_TEST)
27 depends on ARM || ARM64 || (COMPILE_TEST && SWIOTLB)
28 help 27 help
29 Enable support for the ARM long descriptor pagetable format. 28 Enable support for the ARM long descriptor pagetable format.
30 This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page 29 This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index dafaf59dc3b8..286e890e7d64 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -56,6 +56,7 @@
56#define IDR0_TTF_SHIFT 2 56#define IDR0_TTF_SHIFT 2
57#define IDR0_TTF_MASK 0x3 57#define IDR0_TTF_MASK 0x3
58#define IDR0_TTF_AARCH64 (2 << IDR0_TTF_SHIFT) 58#define IDR0_TTF_AARCH64 (2 << IDR0_TTF_SHIFT)
59#define IDR0_TTF_AARCH32_64 (3 << IDR0_TTF_SHIFT)
59#define IDR0_S1P (1 << 1) 60#define IDR0_S1P (1 << 1)
60#define IDR0_S2P (1 << 0) 61#define IDR0_S2P (1 << 0)
61 62
@@ -342,7 +343,8 @@
342#define CMDQ_TLBI_0_VMID_SHIFT 32 343#define CMDQ_TLBI_0_VMID_SHIFT 32
343#define CMDQ_TLBI_0_ASID_SHIFT 48 344#define CMDQ_TLBI_0_ASID_SHIFT 48
344#define CMDQ_TLBI_1_LEAF (1UL << 0) 345#define CMDQ_TLBI_1_LEAF (1UL << 0)
345#define CMDQ_TLBI_1_ADDR_MASK ~0xfffUL 346#define CMDQ_TLBI_1_VA_MASK ~0xfffUL
347#define CMDQ_TLBI_1_IPA_MASK 0xfffffffff000UL
346 348
347#define CMDQ_PRI_0_SSID_SHIFT 12 349#define CMDQ_PRI_0_SSID_SHIFT 12
348#define CMDQ_PRI_0_SSID_MASK 0xfffffUL 350#define CMDQ_PRI_0_SSID_MASK 0xfffffUL
@@ -770,11 +772,13 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
770 break; 772 break;
771 case CMDQ_OP_TLBI_NH_VA: 773 case CMDQ_OP_TLBI_NH_VA:
772 cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT; 774 cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT;
773 /* Fallthrough */ 775 cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0;
776 cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
777 break;
774 case CMDQ_OP_TLBI_S2_IPA: 778 case CMDQ_OP_TLBI_S2_IPA:
775 cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT; 779 cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT;
776 cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0; 780 cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0;
777 cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_ADDR_MASK; 781 cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
778 break; 782 break;
779 case CMDQ_OP_TLBI_NH_ASID: 783 case CMDQ_OP_TLBI_NH_ASID:
780 cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT; 784 cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT;
@@ -2460,7 +2464,13 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
2460 } 2464 }
2461 2465
2462 /* We only support the AArch64 table format at present */ 2466 /* We only support the AArch64 table format at present */
2463 if ((reg & IDR0_TTF_MASK << IDR0_TTF_SHIFT) < IDR0_TTF_AARCH64) { 2467 switch (reg & IDR0_TTF_MASK << IDR0_TTF_SHIFT) {
2468 case IDR0_TTF_AARCH32_64:
2469 smmu->ias = 40;
2470 /* Fallthrough */
2471 case IDR0_TTF_AARCH64:
2472 break;
2473 default:
2464 dev_err(smmu->dev, "AArch64 table format not supported!\n"); 2474 dev_err(smmu->dev, "AArch64 table format not supported!\n");
2465 return -ENXIO; 2475 return -ENXIO;
2466 } 2476 }
@@ -2541,8 +2551,7 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
2541 dev_warn(smmu->dev, 2551 dev_warn(smmu->dev,
2542 "failed to set DMA mask for table walker\n"); 2552 "failed to set DMA mask for table walker\n");
2543 2553
2544 if (!smmu->ias) 2554 smmu->ias = max(smmu->ias, smmu->oas);
2545 smmu->ias = smmu->oas;
2546 2555
2547 dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n", 2556 dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n",
2548 smmu->ias, smmu->oas, smmu->features); 2557 smmu->ias, smmu->oas, smmu->features);
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 73c07482f487..7df97777662d 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -202,9 +202,9 @@ typedef u64 arm_lpae_iopte;
202 202
203static bool selftest_running = false; 203static bool selftest_running = false;
204 204
205static dma_addr_t __arm_lpae_dma_addr(struct device *dev, void *pages) 205static dma_addr_t __arm_lpae_dma_addr(void *pages)
206{ 206{
207 return phys_to_dma(dev, virt_to_phys(pages)); 207 return (dma_addr_t)virt_to_phys(pages);
208} 208}
209 209
210static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, 210static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
@@ -223,10 +223,10 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
223 goto out_free; 223 goto out_free;
224 /* 224 /*
225 * We depend on the IOMMU being able to work with any physical 225 * We depend on the IOMMU being able to work with any physical
226 * address directly, so if the DMA layer suggests it can't by 226 * address directly, so if the DMA layer suggests otherwise by
227 * giving us back some translation, that bodes very badly... 227 * translating or truncating them, that bodes very badly...
228 */ 228 */
229 if (dma != __arm_lpae_dma_addr(dev, pages)) 229 if (dma != virt_to_phys(pages))
230 goto out_unmap; 230 goto out_unmap;
231 } 231 }
232 232
@@ -243,10 +243,8 @@ out_free:
243static void __arm_lpae_free_pages(void *pages, size_t size, 243static void __arm_lpae_free_pages(void *pages, size_t size,
244 struct io_pgtable_cfg *cfg) 244 struct io_pgtable_cfg *cfg)
245{ 245{
246 struct device *dev = cfg->iommu_dev;
247
248 if (!selftest_running) 246 if (!selftest_running)
249 dma_unmap_single(dev, __arm_lpae_dma_addr(dev, pages), 247 dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
250 size, DMA_TO_DEVICE); 248 size, DMA_TO_DEVICE);
251 free_pages_exact(pages, size); 249 free_pages_exact(pages, size);
252} 250}
@@ -254,12 +252,11 @@ static void __arm_lpae_free_pages(void *pages, size_t size,
254static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte, 252static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte,
255 struct io_pgtable_cfg *cfg) 253 struct io_pgtable_cfg *cfg)
256{ 254{
257 struct device *dev = cfg->iommu_dev;
258
259 *ptep = pte; 255 *ptep = pte;
260 256
261 if (!selftest_running) 257 if (!selftest_running)
262 dma_sync_single_for_device(dev, __arm_lpae_dma_addr(dev, ptep), 258 dma_sync_single_for_device(cfg->iommu_dev,
259 __arm_lpae_dma_addr(ptep),
263 sizeof(pte), DMA_TO_DEVICE); 260 sizeof(pte), DMA_TO_DEVICE);
264} 261}
265 262
@@ -629,6 +626,11 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
629 if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS) 626 if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS)
630 return NULL; 627 return NULL;
631 628
629 if (!selftest_running && cfg->iommu_dev->dma_pfn_offset) {
630 dev_err(cfg->iommu_dev, "Cannot accommodate DMA offset for IOMMU page tables\n");
631 return NULL;
632 }
633
632 data = kmalloc(sizeof(*data), GFP_KERNEL); 634 data = kmalloc(sizeof(*data), GFP_KERNEL);
633 if (!data) 635 if (!data)
634 return NULL; 636 return NULL;