1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2016-2018 Etnaviv Project
6 #include <linux/bitops.h>
7 #include <linux/dma-mapping.h>
8 #include <linux/platform_device.h>
9 #include <linux/sizes.h>
10 #include <linux/slab.h>
11 #include <linux/vmalloc.h>
13 #include "etnaviv_cmdbuf.h"
14 #include "etnaviv_gpu.h"
15 #include "etnaviv_mmu.h"
16 #include "state.xml.h"
17 #include "state_hi.xml.h"
19 #define MMUv2_PTE_PRESENT BIT(0)
20 #define MMUv2_PTE_EXCEPTION BIT(1)
21 #define MMUv2_PTE_WRITEABLE BIT(2)
23 #define MMUv2_MTLB_MASK 0xffc00000
24 #define MMUv2_MTLB_SHIFT 22
25 #define MMUv2_STLB_MASK 0x003ff000
26 #define MMUv2_STLB_SHIFT 12
28 #define MMUv2_MAX_STLB_ENTRIES 1024
30 struct etnaviv_iommuv2_context
{
31 struct etnaviv_iommu_context base
;
33 /* M(aster) TLB aka first level pagetable */
36 /* S(lave) TLB aka second level pagetable */
37 u32
*stlb_cpu
[MMUv2_MAX_STLB_ENTRIES
];
38 dma_addr_t stlb_dma
[MMUv2_MAX_STLB_ENTRIES
];
41 static struct etnaviv_iommuv2_context
*
42 to_v2_context(struct etnaviv_iommu_context
*context
)
44 return container_of(context
, struct etnaviv_iommuv2_context
, base
);
47 static void etnaviv_iommuv2_free(struct etnaviv_iommu_context
*context
)
49 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
52 drm_mm_takedown(&context
->mm
);
54 for (i
= 0; i
< MMUv2_MAX_STLB_ENTRIES
; i
++) {
55 if (v2_context
->stlb_cpu
[i
])
56 dma_free_wc(context
->global
->dev
, SZ_4K
,
57 v2_context
->stlb_cpu
[i
],
58 v2_context
->stlb_dma
[i
]);
61 dma_free_wc(context
->global
->dev
, SZ_4K
, v2_context
->mtlb_cpu
,
62 v2_context
->mtlb_dma
);
64 clear_bit(v2_context
->id
, context
->global
->v2
.pta_alloc
);
69 etnaviv_iommuv2_ensure_stlb(struct etnaviv_iommuv2_context
*v2_context
,
72 if (v2_context
->stlb_cpu
[stlb
])
75 v2_context
->stlb_cpu
[stlb
] =
76 dma_alloc_wc(v2_context
->base
.global
->dev
, SZ_4K
,
77 &v2_context
->stlb_dma
[stlb
],
80 if (!v2_context
->stlb_cpu
[stlb
])
83 memset32(v2_context
->stlb_cpu
[stlb
], MMUv2_PTE_EXCEPTION
,
86 v2_context
->mtlb_cpu
[stlb
] =
87 v2_context
->stlb_dma
[stlb
] | MMUv2_PTE_PRESENT
;
92 static int etnaviv_iommuv2_map(struct etnaviv_iommu_context
*context
,
93 unsigned long iova
, phys_addr_t paddr
,
94 size_t size
, int prot
)
96 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
97 int mtlb_entry
, stlb_entry
, ret
;
98 u32 entry
= lower_32_bits(paddr
) | MMUv2_PTE_PRESENT
;
103 if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT
))
104 entry
|= (upper_32_bits(paddr
) & 0xff) << 4;
106 if (prot
& ETNAVIV_PROT_WRITE
)
107 entry
|= MMUv2_PTE_WRITEABLE
;
109 mtlb_entry
= (iova
& MMUv2_MTLB_MASK
) >> MMUv2_MTLB_SHIFT
;
110 stlb_entry
= (iova
& MMUv2_STLB_MASK
) >> MMUv2_STLB_SHIFT
;
112 ret
= etnaviv_iommuv2_ensure_stlb(v2_context
, mtlb_entry
);
116 v2_context
->stlb_cpu
[mtlb_entry
][stlb_entry
] = entry
;
121 static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_context
*context
,
122 unsigned long iova
, size_t size
)
124 struct etnaviv_iommuv2_context
*etnaviv_domain
= to_v2_context(context
);
125 int mtlb_entry
, stlb_entry
;
130 mtlb_entry
= (iova
& MMUv2_MTLB_MASK
) >> MMUv2_MTLB_SHIFT
;
131 stlb_entry
= (iova
& MMUv2_STLB_MASK
) >> MMUv2_STLB_SHIFT
;
133 etnaviv_domain
->stlb_cpu
[mtlb_entry
][stlb_entry
] = MMUv2_PTE_EXCEPTION
;
138 static size_t etnaviv_iommuv2_dump_size(struct etnaviv_iommu_context
*context
)
140 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
141 size_t dump_size
= SZ_4K
;
144 for (i
= 0; i
< MMUv2_MAX_STLB_ENTRIES
; i
++)
145 if (v2_context
->mtlb_cpu
[i
] & MMUv2_PTE_PRESENT
)
151 static void etnaviv_iommuv2_dump(struct etnaviv_iommu_context
*context
, void *buf
)
153 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
156 memcpy(buf
, v2_context
->mtlb_cpu
, SZ_4K
);
158 for (i
= 0; i
< MMUv2_MAX_STLB_ENTRIES
; i
++)
159 if (v2_context
->mtlb_cpu
[i
] & MMUv2_PTE_PRESENT
) {
160 memcpy(buf
, v2_context
->stlb_cpu
[i
], SZ_4K
);
165 static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu
*gpu
,
166 struct etnaviv_iommu_context
*context
)
168 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
171 /* If the MMU is already enabled the state is still there. */
172 if (gpu_read(gpu
, VIVS_MMUv2_CONTROL
) & VIVS_MMUv2_CONTROL_ENABLE
)
175 prefetch
= etnaviv_buffer_config_mmuv2(gpu
,
176 (u32
)v2_context
->mtlb_dma
,
177 (u32
)context
->global
->bad_page_dma
);
178 etnaviv_gpu_start_fe(gpu
, (u32
)etnaviv_cmdbuf_get_pa(&gpu
->buffer
),
180 etnaviv_gpu_wait_idle(gpu
, 100);
182 gpu_write(gpu
, VIVS_MMUv2_CONTROL
, VIVS_MMUv2_CONTROL_ENABLE
);
185 static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu
*gpu
,
186 struct etnaviv_iommu_context
*context
)
188 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
191 /* If the MMU is already enabled the state is still there. */
192 if (gpu_read(gpu
, VIVS_MMUv2_SEC_CONTROL
) & VIVS_MMUv2_SEC_CONTROL_ENABLE
)
195 gpu_write(gpu
, VIVS_MMUv2_PTA_ADDRESS_LOW
,
196 lower_32_bits(context
->global
->v2
.pta_dma
));
197 gpu_write(gpu
, VIVS_MMUv2_PTA_ADDRESS_HIGH
,
198 upper_32_bits(context
->global
->v2
.pta_dma
));
199 gpu_write(gpu
, VIVS_MMUv2_PTA_CONTROL
, VIVS_MMUv2_PTA_CONTROL_ENABLE
);
201 gpu_write(gpu
, VIVS_MMUv2_NONSEC_SAFE_ADDR_LOW
,
202 lower_32_bits(context
->global
->bad_page_dma
));
203 gpu_write(gpu
, VIVS_MMUv2_SEC_SAFE_ADDR_LOW
,
204 lower_32_bits(context
->global
->bad_page_dma
));
205 gpu_write(gpu
, VIVS_MMUv2_SAFE_ADDRESS_CONFIG
,
206 VIVS_MMUv2_SAFE_ADDRESS_CONFIG_NON_SEC_SAFE_ADDR_HIGH(
207 upper_32_bits(context
->global
->bad_page_dma
)) |
208 VIVS_MMUv2_SAFE_ADDRESS_CONFIG_SEC_SAFE_ADDR_HIGH(
209 upper_32_bits(context
->global
->bad_page_dma
)));
211 context
->global
->v2
.pta_cpu
[v2_context
->id
] = v2_context
->mtlb_dma
|
212 VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K
;
214 /* trigger a PTA load through the FE */
215 prefetch
= etnaviv_buffer_config_pta(gpu
, v2_context
->id
);
216 etnaviv_gpu_start_fe(gpu
, (u32
)etnaviv_cmdbuf_get_pa(&gpu
->buffer
),
218 etnaviv_gpu_wait_idle(gpu
, 100);
220 gpu_write(gpu
, VIVS_MMUv2_SEC_CONTROL
, VIVS_MMUv2_SEC_CONTROL_ENABLE
);
223 u32
etnaviv_iommuv2_get_mtlb_addr(struct etnaviv_iommu_context
*context
)
225 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
227 return v2_context
->mtlb_dma
;
230 unsigned short etnaviv_iommuv2_get_pta_id(struct etnaviv_iommu_context
*context
)
232 struct etnaviv_iommuv2_context
*v2_context
= to_v2_context(context
);
234 return v2_context
->id
;
236 static void etnaviv_iommuv2_restore(struct etnaviv_gpu
*gpu
,
237 struct etnaviv_iommu_context
*context
)
239 switch (gpu
->sec_mode
) {
241 etnaviv_iommuv2_restore_nonsec(gpu
, context
);
243 case ETNA_SEC_KERNEL
:
244 etnaviv_iommuv2_restore_sec(gpu
, context
);
247 WARN(1, "unhandled GPU security mode\n");
252 const struct etnaviv_iommu_ops etnaviv_iommuv2_ops
= {
253 .free
= etnaviv_iommuv2_free
,
254 .map
= etnaviv_iommuv2_map
,
255 .unmap
= etnaviv_iommuv2_unmap
,
256 .dump_size
= etnaviv_iommuv2_dump_size
,
257 .dump
= etnaviv_iommuv2_dump
,
258 .restore
= etnaviv_iommuv2_restore
,
261 struct etnaviv_iommu_context
*
262 etnaviv_iommuv2_context_alloc(struct etnaviv_iommu_global
*global
)
264 struct etnaviv_iommuv2_context
*v2_context
;
265 struct etnaviv_iommu_context
*context
;
267 v2_context
= vzalloc(sizeof(*v2_context
));
271 mutex_lock(&global
->lock
);
272 v2_context
->id
= find_first_zero_bit(global
->v2
.pta_alloc
,
273 ETNAVIV_PTA_ENTRIES
);
274 if (v2_context
->id
< ETNAVIV_PTA_ENTRIES
) {
275 set_bit(v2_context
->id
, global
->v2
.pta_alloc
);
277 mutex_unlock(&global
->lock
);
280 mutex_unlock(&global
->lock
);
282 v2_context
->mtlb_cpu
= dma_alloc_wc(global
->dev
, SZ_4K
,
283 &v2_context
->mtlb_dma
, GFP_KERNEL
);
284 if (!v2_context
->mtlb_cpu
)
287 memset32(v2_context
->mtlb_cpu
, MMUv2_PTE_EXCEPTION
,
288 MMUv2_MAX_STLB_ENTRIES
);
290 global
->v2
.pta_cpu
[v2_context
->id
] = v2_context
->mtlb_dma
;
292 context
= &v2_context
->base
;
293 context
->global
= global
;
294 kref_init(&context
->refcount
);
295 mutex_init(&context
->lock
);
296 INIT_LIST_HEAD(&context
->mappings
);
297 drm_mm_init(&context
->mm
, SZ_4K
, (u64
)SZ_1G
* 4 - SZ_4K
);
302 clear_bit(v2_context
->id
, global
->v2
.pta_alloc
);