aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2019-02-21 15:23:25 -0500
committerRob Herring <robh@kernel.org>2019-04-12 13:52:38 -0400
commitd08d42de6432d5064045159aed060e3db9fa7807 (patch)
tree2019c00522f05dfd8df93440401a2042cd085da0
parent0eb2766dd6f366d42448121c383420bb0307bcc7 (diff)
iommu: io-pgtable: Add ARM Mali midgard MMU page table format
ARM Mali midgard GPU is similar to standard 64-bit stage 1 page tables, but have a few differences. Add a new format type to represent the format. The input address size is 48-bits and the output address size is 40-bits (and possibly less?). Note that the later bifrost GPUs follow the standard 64-bit stage 1 format. The differences in the format compared to 64-bit stage 1 format are: The 3rd level page entry bits are 0x1 instead of 0x3 for page entries. The access flags are not read-only and unprivileged, but read and write. This is similar to stage 2 entries, but the memory attributes field matches stage 1 being an index. The nG bit is not set by the vendor driver. This one didn't seem to matter, but we'll keep it aligned to the vendor driver. Cc: Will Deacon <will.deacon@arm.com> Acked-by: Robin Murphy <robin.murphy@arm.com> Cc: linux-arm-kernel@lists.infradead.org Cc: iommu@lists.linux-foundation.org Acked-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Acked-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Rob Herring <robh@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190409205427.6943-2-robh@kernel.org
-rw-r--r--drivers/iommu/io-pgtable-arm.c91
-rw-r--r--drivers/iommu/io-pgtable.c1
-rw-r--r--include/linux/io-pgtable.h7
3 files changed, 77 insertions, 22 deletions
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index d3700ec15cbd..4e21efbc4459 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -172,6 +172,10 @@
172#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 172#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1
173#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 173#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2
174 174
175#define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0)
176#define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2)
177#define ARM_MALI_LPAE_TTBR_SHARE_OUTER BIT(4)
178
175/* IOPTE accessors */ 179/* IOPTE accessors */
176#define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d)) 180#define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d))
177 181
@@ -180,11 +184,6 @@
180 184
181#define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK) 185#define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK)
182 186
183#define iopte_leaf(pte,l) \
184 (l == (ARM_LPAE_MAX_LEVELS - 1) ? \
185 (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \
186 (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK))
187
188struct arm_lpae_io_pgtable { 187struct arm_lpae_io_pgtable {
189 struct io_pgtable iop; 188 struct io_pgtable iop;
190 189
@@ -198,6 +197,15 @@ struct arm_lpae_io_pgtable {
198 197
199typedef u64 arm_lpae_iopte; 198typedef u64 arm_lpae_iopte;
200 199
200static inline bool iopte_leaf(arm_lpae_iopte pte, int lvl,
201 enum io_pgtable_fmt fmt)
202{
203 if (lvl == (ARM_LPAE_MAX_LEVELS - 1) && fmt != ARM_MALI_LPAE)
204 return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_PAGE;
205
206 return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_BLOCK;
207}
208
201static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr, 209static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr,
202 struct arm_lpae_io_pgtable *data) 210 struct arm_lpae_io_pgtable *data)
203{ 211{
@@ -303,12 +311,14 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
303 if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) 311 if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS)
304 pte |= ARM_LPAE_PTE_NS; 312 pte |= ARM_LPAE_PTE_NS;
305 313
306 if (lvl == ARM_LPAE_MAX_LEVELS - 1) 314 if (data->iop.fmt != ARM_MALI_LPAE && lvl == ARM_LPAE_MAX_LEVELS - 1)
307 pte |= ARM_LPAE_PTE_TYPE_PAGE; 315 pte |= ARM_LPAE_PTE_TYPE_PAGE;
308 else 316 else
309 pte |= ARM_LPAE_PTE_TYPE_BLOCK; 317 pte |= ARM_LPAE_PTE_TYPE_BLOCK;
310 318
311 pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; 319 if (data->iop.fmt != ARM_MALI_LPAE)
320 pte |= ARM_LPAE_PTE_AF;
321 pte |= ARM_LPAE_PTE_SH_IS;
312 pte |= paddr_to_iopte(paddr, data); 322 pte |= paddr_to_iopte(paddr, data);
313 323
314 __arm_lpae_set_pte(ptep, pte, &data->iop.cfg); 324 __arm_lpae_set_pte(ptep, pte, &data->iop.cfg);
@@ -321,7 +331,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
321{ 331{
322 arm_lpae_iopte pte = *ptep; 332 arm_lpae_iopte pte = *ptep;
323 333
324 if (iopte_leaf(pte, lvl)) { 334 if (iopte_leaf(pte, lvl, data->iop.fmt)) {
325 /* We require an unmap first */ 335 /* We require an unmap first */
326 WARN_ON(!selftest_running); 336 WARN_ON(!selftest_running);
327 return -EEXIST; 337 return -EEXIST;
@@ -409,7 +419,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
409 __arm_lpae_sync_pte(ptep, cfg); 419 __arm_lpae_sync_pte(ptep, cfg);
410 } 420 }
411 421
412 if (pte && !iopte_leaf(pte, lvl)) { 422 if (pte && !iopte_leaf(pte, lvl, data->iop.fmt)) {
413 cptep = iopte_deref(pte, data); 423 cptep = iopte_deref(pte, data);
414 } else if (pte) { 424 } else if (pte) {
415 /* We require an unmap first */ 425 /* We require an unmap first */
@@ -429,31 +439,37 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
429 if (data->iop.fmt == ARM_64_LPAE_S1 || 439 if (data->iop.fmt == ARM_64_LPAE_S1 ||
430 data->iop.fmt == ARM_32_LPAE_S1) { 440 data->iop.fmt == ARM_32_LPAE_S1) {
431 pte = ARM_LPAE_PTE_nG; 441 pte = ARM_LPAE_PTE_nG;
432
433 if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) 442 if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
434 pte |= ARM_LPAE_PTE_AP_RDONLY; 443 pte |= ARM_LPAE_PTE_AP_RDONLY;
435
436 if (!(prot & IOMMU_PRIV)) 444 if (!(prot & IOMMU_PRIV))
437 pte |= ARM_LPAE_PTE_AP_UNPRIV; 445 pte |= ARM_LPAE_PTE_AP_UNPRIV;
438
439 if (prot & IOMMU_MMIO)
440 pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV
441 << ARM_LPAE_PTE_ATTRINDX_SHIFT);
442 else if (prot & IOMMU_CACHE)
443 pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
444 << ARM_LPAE_PTE_ATTRINDX_SHIFT);
445 } else { 446 } else {
446 pte = ARM_LPAE_PTE_HAP_FAULT; 447 pte = ARM_LPAE_PTE_HAP_FAULT;
447 if (prot & IOMMU_READ) 448 if (prot & IOMMU_READ)
448 pte |= ARM_LPAE_PTE_HAP_READ; 449 pte |= ARM_LPAE_PTE_HAP_READ;
449 if (prot & IOMMU_WRITE) 450 if (prot & IOMMU_WRITE)
450 pte |= ARM_LPAE_PTE_HAP_WRITE; 451 pte |= ARM_LPAE_PTE_HAP_WRITE;
452 }
453
454 /*
455 * Note that this logic is structured to accommodate Mali LPAE
456 * having stage-1-like attributes but stage-2-like permissions.
457 */
458 if (data->iop.fmt == ARM_64_LPAE_S2 ||
459 data->iop.fmt == ARM_32_LPAE_S2) {
451 if (prot & IOMMU_MMIO) 460 if (prot & IOMMU_MMIO)
452 pte |= ARM_LPAE_PTE_MEMATTR_DEV; 461 pte |= ARM_LPAE_PTE_MEMATTR_DEV;
453 else if (prot & IOMMU_CACHE) 462 else if (prot & IOMMU_CACHE)
454 pte |= ARM_LPAE_PTE_MEMATTR_OIWB; 463 pte |= ARM_LPAE_PTE_MEMATTR_OIWB;
455 else 464 else
456 pte |= ARM_LPAE_PTE_MEMATTR_NC; 465 pte |= ARM_LPAE_PTE_MEMATTR_NC;
466 } else {
467 if (prot & IOMMU_MMIO)
468 pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV
469 << ARM_LPAE_PTE_ATTRINDX_SHIFT);
470 else if (prot & IOMMU_CACHE)
471 pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
472 << ARM_LPAE_PTE_ATTRINDX_SHIFT);
457 } 473 }
458 474
459 if (prot & IOMMU_NOEXEC) 475 if (prot & IOMMU_NOEXEC)
@@ -511,7 +527,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
511 while (ptep != end) { 527 while (ptep != end) {
512 arm_lpae_iopte pte = *ptep++; 528 arm_lpae_iopte pte = *ptep++;
513 529
514 if (!pte || iopte_leaf(pte, lvl)) 530 if (!pte || iopte_leaf(pte, lvl, data->iop.fmt))
515 continue; 531 continue;
516 532
517 __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); 533 __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data));
@@ -602,7 +618,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
602 if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) { 618 if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) {
603 __arm_lpae_set_pte(ptep, 0, &iop->cfg); 619 __arm_lpae_set_pte(ptep, 0, &iop->cfg);
604 620
605 if (!iopte_leaf(pte, lvl)) { 621 if (!iopte_leaf(pte, lvl, iop->fmt)) {
606 /* Also flush any partial walks */ 622 /* Also flush any partial walks */
607 io_pgtable_tlb_add_flush(iop, iova, size, 623 io_pgtable_tlb_add_flush(iop, iova, size,
608 ARM_LPAE_GRANULE(data), false); 624 ARM_LPAE_GRANULE(data), false);
@@ -621,7 +637,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
621 } 637 }
622 638
623 return size; 639 return size;
624 } else if (iopte_leaf(pte, lvl)) { 640 } else if (iopte_leaf(pte, lvl, iop->fmt)) {
625 /* 641 /*
626 * Insert a table at the next level to map the old region, 642 * Insert a table at the next level to map the old region,
627 * minus the part we want to unmap 643 * minus the part we want to unmap
@@ -669,7 +685,7 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
669 return 0; 685 return 0;
670 686
671 /* Leaf entry? */ 687 /* Leaf entry? */
672 if (iopte_leaf(pte,lvl)) 688 if (iopte_leaf(pte, lvl, data->iop.fmt))
673 goto found_translation; 689 goto found_translation;
674 690
675 /* Take it to the next level */ 691 /* Take it to the next level */
@@ -995,6 +1011,32 @@ arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
995 return iop; 1011 return iop;
996} 1012}
997 1013
1014static struct io_pgtable *
1015arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
1016{
1017 struct io_pgtable *iop;
1018
1019 if (cfg->ias != 48 || cfg->oas > 40)
1020 return NULL;
1021
1022 cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
1023 iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie);
1024 if (iop) {
1025 u64 mair, ttbr;
1026
1027 /* Copy values as union fields overlap */
1028 mair = cfg->arm_lpae_s1_cfg.mair[0];
1029 ttbr = cfg->arm_lpae_s1_cfg.ttbr[0];
1030
1031 cfg->arm_mali_lpae_cfg.memattr = mair;
1032 cfg->arm_mali_lpae_cfg.transtab = ttbr |
1033 ARM_MALI_LPAE_TTBR_READ_INNER |
1034 ARM_MALI_LPAE_TTBR_ADRMODE_TABLE;
1035 }
1036
1037 return iop;
1038}
1039
998struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = { 1040struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = {
999 .alloc = arm_64_lpae_alloc_pgtable_s1, 1041 .alloc = arm_64_lpae_alloc_pgtable_s1,
1000 .free = arm_lpae_free_pgtable, 1042 .free = arm_lpae_free_pgtable,
@@ -1015,6 +1057,11 @@ struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = {
1015 .free = arm_lpae_free_pgtable, 1057 .free = arm_lpae_free_pgtable,
1016}; 1058};
1017 1059
1060struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = {
1061 .alloc = arm_mali_lpae_alloc_pgtable,
1062 .free = arm_lpae_free_pgtable,
1063};
1064
1018#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST 1065#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST
1019 1066
1020static struct io_pgtable_cfg *cfg_cookie; 1067static struct io_pgtable_cfg *cfg_cookie;
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
index 93f2880be6c6..5227cfdbb65b 100644
--- a/drivers/iommu/io-pgtable.c
+++ b/drivers/iommu/io-pgtable.c
@@ -30,6 +30,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = {
30 [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns, 30 [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns,
31 [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, 31 [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns,
32 [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, 32 [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns,
33 [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns,
33#endif 34#endif
34#ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S 35#ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S
35 [ARM_V7S] = &io_pgtable_arm_v7s_init_fns, 36 [ARM_V7S] = &io_pgtable_arm_v7s_init_fns,
diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index 47d5ae559329..76969a564831 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -12,6 +12,7 @@ enum io_pgtable_fmt {
12 ARM_64_LPAE_S1, 12 ARM_64_LPAE_S1,
13 ARM_64_LPAE_S2, 13 ARM_64_LPAE_S2,
14 ARM_V7S, 14 ARM_V7S,
15 ARM_MALI_LPAE,
15 IO_PGTABLE_NUM_FMTS, 16 IO_PGTABLE_NUM_FMTS,
16}; 17};
17 18
@@ -108,6 +109,11 @@ struct io_pgtable_cfg {
108 u32 nmrr; 109 u32 nmrr;
109 u32 prrr; 110 u32 prrr;
110 } arm_v7s_cfg; 111 } arm_v7s_cfg;
112
113 struct {
114 u64 transtab;
115 u64 memattr;
116 } arm_mali_lpae_cfg;
111 }; 117 };
112}; 118};
113 119
@@ -209,5 +215,6 @@ extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns;
209extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns; 215extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns;
210extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns; 216extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns;
211extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns; 217extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns;
218extern struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns;
212 219
213#endif /* __IO_PGTABLE_H */ 220#endif /* __IO_PGTABLE_H */