|
166 | 166 | #define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2)
|
167 | 167 | #define ARM_MALI_LPAE_TTBR_SHARE_OUTER BIT(4)
|
168 | 168 |
|
| 169 | +#define ARM_MALI_LPAE_MEMATTR_IMP_DEF 0x88ULL |
| 170 | +#define ARM_MALI_LPAE_MEMATTR_WRITE_ALLOC 0x8DULL |
| 171 | + |
169 | 172 | /* IOPTE accessors */
|
170 | 173 | #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d))
|
171 | 174 |
|
@@ -1015,27 +1018,56 @@ arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
|
1015 | 1018 | static struct io_pgtable *
|
1016 | 1019 | arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
|
1017 | 1020 | {
|
1018 |
| - struct io_pgtable *iop; |
| 1021 | + struct arm_lpae_io_pgtable *data; |
1019 | 1022 |
|
1020 |
| - if (cfg->ias != 48 || cfg->oas > 40) |
| 1023 | + /* No quirks for Mali (hopefully) */ |
| 1024 | + if (cfg->quirks) |
| 1025 | + return NULL; |
| 1026 | + |
| 1027 | + if (cfg->ias > 48 || cfg->oas > 40) |
1021 | 1028 | return NULL;
|
1022 | 1029 |
|
1023 | 1030 | cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
|
1024 |
| - iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie); |
1025 |
| - if (iop) { |
1026 |
| - u64 mair, ttbr; |
1027 | 1031 |
|
1028 |
| - /* Copy values as union fields overlap */ |
1029 |
| - mair = cfg->arm_lpae_s1_cfg.mair[0]; |
1030 |
| - ttbr = cfg->arm_lpae_s1_cfg.ttbr[0]; |
| 1032 | + data = arm_lpae_alloc_pgtable(cfg); |
| 1033 | + if (!data) |
| 1034 | + return NULL; |
1031 | 1035 |
|
1032 |
| - cfg->arm_mali_lpae_cfg.memattr = mair; |
1033 |
| - cfg->arm_mali_lpae_cfg.transtab = ttbr | |
1034 |
| - ARM_MALI_LPAE_TTBR_READ_INNER | |
1035 |
| - ARM_MALI_LPAE_TTBR_ADRMODE_TABLE; |
| 1036 | + /* Mali seems to need a full 4-level table regardless of IAS */ |
| 1037 | + if (data->levels < ARM_LPAE_MAX_LEVELS) { |
| 1038 | + data->levels = ARM_LPAE_MAX_LEVELS; |
| 1039 | + data->pgd_size = sizeof(arm_lpae_iopte); |
1036 | 1040 | }
|
| 1041 | + /* |
| 1042 | + * MEMATTR: Mali has no actual notion of a non-cacheable type, so the |
| 1043 | + * best we can do is mimic the out-of-tree driver and hope that the |
| 1044 | + * "implementation-defined caching policy" is good enough. Similarly, |
| 1045 | + * we'll use it for the sake of a valid attribute for our 'device' |
| 1046 | + * index, although callers should never request that in practice. |
| 1047 | + */ |
| 1048 | + cfg->arm_mali_lpae_cfg.memattr = |
| 1049 | + (ARM_MALI_LPAE_MEMATTR_IMP_DEF |
| 1050 | + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_NC)) | |
| 1051 | + (ARM_MALI_LPAE_MEMATTR_WRITE_ALLOC |
| 1052 | + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) | |
| 1053 | + (ARM_MALI_LPAE_MEMATTR_IMP_DEF |
| 1054 | + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)); |
1037 | 1055 |
|
1038 |
| - return iop; |
| 1056 | + data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); |
| 1057 | + if (!data->pgd) |
| 1058 | + goto out_free_data; |
| 1059 | + |
| 1060 | + /* Ensure the empty pgd is visible before TRANSTAB can be written */ |
| 1061 | + wmb(); |
| 1062 | + |
| 1063 | + cfg->arm_mali_lpae_cfg.transtab = virt_to_phys(data->pgd) | |
| 1064 | + ARM_MALI_LPAE_TTBR_READ_INNER | |
| 1065 | + ARM_MALI_LPAE_TTBR_ADRMODE_TABLE; |
| 1066 | + return &data->iop; |
| 1067 | + |
| 1068 | +out_free_data: |
| 1069 | + kfree(data); |
| 1070 | + return NULL; |
1039 | 1071 | }
|
1040 | 1072 |
|
1041 | 1073 | struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = {
|
|
0 commit comments