forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-04 1543e317f1da31b75942316931e8f491a8920811
kernel/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
....@@ -3,15 +3,17 @@
33 * Copyright (C) 2015-2018 Etnaviv Project
44 */
55
6
+#include <linux/dma-mapping.h>
7
+#include <linux/scatterlist.h>
8
+
69 #include "common.xml.h"
710 #include "etnaviv_cmdbuf.h"
811 #include "etnaviv_drv.h"
912 #include "etnaviv_gem.h"
1013 #include "etnaviv_gpu.h"
11
-#include "etnaviv_iommu.h"
1214 #include "etnaviv_mmu.h"
1315
14
-static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain,
16
+static void etnaviv_context_unmap(struct etnaviv_iommu_context *context,
1517 unsigned long iova, size_t size)
1618 {
1719 size_t unmapped_page, unmapped = 0;
....@@ -24,7 +26,8 @@
2426 }
2527
2628 while (unmapped < size) {
27
- unmapped_page = domain->ops->unmap(domain, iova, pgsize);
29
+ unmapped_page = context->global->ops->unmap(context, iova,
30
+ pgsize);
2831 if (!unmapped_page)
2932 break;
3033
....@@ -33,7 +36,7 @@
3336 }
3437 }
3538
36
-static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain,
39
+static int etnaviv_context_map(struct etnaviv_iommu_context *context,
3740 unsigned long iova, phys_addr_t paddr,
3841 size_t size, int prot)
3942 {
....@@ -49,7 +52,8 @@
4952 }
5053
5154 while (size) {
52
- ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
55
+ ret = context->global->ops->map(context, iova, paddr, pgsize,
56
+ prot);
5357 if (ret)
5458 break;
5559
....@@ -60,30 +64,28 @@
6064
6165 /* unroll mapping in case something went wrong */
6266 if (ret)
63
- etnaviv_domain_unmap(domain, orig_iova, orig_size - size);
67
+ etnaviv_context_unmap(context, orig_iova, orig_size - size);
6468
6569 return ret;
6670 }
6771
68
-static int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
72
+static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
6973 struct sg_table *sgt, unsigned len, int prot)
70
-{
71
- struct etnaviv_iommu_domain *domain = iommu->domain;
72
- struct scatterlist *sg;
74
+{ struct scatterlist *sg;
7375 unsigned int da = iova;
74
- unsigned int i, j;
76
+ unsigned int i;
7577 int ret;
7678
77
- if (!domain || !sgt)
79
+ if (!context || !sgt)
7880 return -EINVAL;
7981
80
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
81
- u32 pa = sg_dma_address(sg) - sg->offset;
82
+ for_each_sgtable_dma_sg(sgt, sg, i) {
83
+ phys_addr_t pa = sg_dma_address(sg) - sg->offset;
8284 size_t bytes = sg_dma_len(sg) + sg->offset;
8385
84
- VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
86
+ VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes);
8587
86
- ret = etnaviv_domain_map(domain, da, pa, bytes, prot);
88
+ ret = etnaviv_context_map(context, da, pa, bytes, prot);
8789 if (ret)
8890 goto fail;
8991
....@@ -93,29 +95,21 @@
9395 return 0;
9496
9597 fail:
96
- da = iova;
97
-
98
- for_each_sg(sgt->sgl, sg, i, j) {
99
- size_t bytes = sg_dma_len(sg) + sg->offset;
100
-
101
- etnaviv_domain_unmap(domain, da, bytes);
102
- da += bytes;
103
- }
98
+ etnaviv_context_unmap(context, iova, da - iova);
10499 return ret;
105100 }
106101
107
-static void etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
102
+static void etnaviv_iommu_unmap(struct etnaviv_iommu_context *context, u32 iova,
108103 struct sg_table *sgt, unsigned len)
109104 {
110
- struct etnaviv_iommu_domain *domain = iommu->domain;
111105 struct scatterlist *sg;
112106 unsigned int da = iova;
113107 int i;
114108
115
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
109
+ for_each_sgtable_dma_sg(sgt, sg, i) {
116110 size_t bytes = sg_dma_len(sg) + sg->offset;
117111
118
- etnaviv_domain_unmap(domain, da, bytes);
112
+ etnaviv_context_unmap(context, da, bytes);
119113
120114 VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
121115
....@@ -125,24 +119,24 @@
125119 }
126120 }
127121
128
-static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu,
122
+static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu_context *context,
129123 struct etnaviv_vram_mapping *mapping)
130124 {
131125 struct etnaviv_gem_object *etnaviv_obj = mapping->object;
132126
133
- etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
127
+ etnaviv_iommu_unmap(context, mapping->vram_node.start,
134128 etnaviv_obj->sgt, etnaviv_obj->base.size);
135129 drm_mm_remove_node(&mapping->vram_node);
136130 }
137131
138
-static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
132
+static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context,
139133 struct drm_mm_node *node, size_t size)
140134 {
141135 struct etnaviv_vram_mapping *free = NULL;
142136 enum drm_mm_insert_mode mode = DRM_MM_INSERT_LOW;
143137 int ret;
144138
145
- lockdep_assert_held(&mmu->lock);
139
+ lockdep_assert_held(&context->lock);
146140
147141 while (1) {
148142 struct etnaviv_vram_mapping *m, *n;
....@@ -150,17 +144,17 @@
150144 struct list_head list;
151145 bool found;
152146
153
- ret = drm_mm_insert_node_in_range(&mmu->mm, node,
147
+ ret = drm_mm_insert_node_in_range(&context->mm, node,
154148 size, 0, 0, 0, U64_MAX, mode);
155149 if (ret != -ENOSPC)
156150 break;
157151
158152 /* Try to retire some entries */
159
- drm_mm_scan_init(&scan, &mmu->mm, size, 0, 0, mode);
153
+ drm_mm_scan_init(&scan, &context->mm, size, 0, 0, mode);
160154
161155 found = 0;
162156 INIT_LIST_HEAD(&list);
163
- list_for_each_entry(free, &mmu->mappings, mmu_node) {
157
+ list_for_each_entry(free, &context->mappings, mmu_node) {
164158 /* If this vram node has not been used, skip this. */
165159 if (!free->vram_node.mm)
166160 continue;
....@@ -202,8 +196,9 @@
202196 * this mapping.
203197 */
204198 list_for_each_entry_safe(m, n, &list, scan_node) {
205
- etnaviv_iommu_remove_mapping(mmu, m);
206
- m->mmu = NULL;
199
+ etnaviv_iommu_remove_mapping(context, m);
200
+ etnaviv_iommu_context_put(m->context);
201
+ m->context = NULL;
207202 list_del_init(&m->mmu_node);
208203 list_del_init(&m->scan_node);
209204 }
....@@ -219,9 +214,16 @@
219214 return ret;
220215 }
221216
222
-int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
217
+static int etnaviv_iommu_insert_exact(struct etnaviv_iommu_context *context,
218
+ struct drm_mm_node *node, size_t size, u64 va)
219
+{
220
+ return drm_mm_insert_node_in_range(&context->mm, node, size, 0, 0, va,
221
+ va + size, DRM_MM_INSERT_LOWEST);
222
+}
223
+
224
+int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context,
223225 struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
224
- struct etnaviv_vram_mapping *mapping)
226
+ struct etnaviv_vram_mapping *mapping, u64 va)
225227 {
226228 struct sg_table *sgt = etnaviv_obj->sgt;
227229 struct drm_mm_node *node;
....@@ -229,17 +231,17 @@
229231
230232 lockdep_assert_held(&etnaviv_obj->lock);
231233
232
- mutex_lock(&mmu->lock);
234
+ mutex_lock(&context->lock);
233235
234236 /* v1 MMU can optimize single entry (contiguous) scatterlists */
235
- if (mmu->version == ETNAVIV_IOMMU_V1 &&
237
+ if (context->global->version == ETNAVIV_IOMMU_V1 &&
236238 sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
237239 u32 iova;
238240
239241 iova = sg_dma_address(sgt->sgl) - memory_base;
240242 if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
241243 mapping->iova = iova;
242
- list_add_tail(&mapping->mmu_node, &mmu->mappings);
244
+ list_add_tail(&mapping->mmu_node, &context->mappings);
243245 ret = 0;
244246 goto unlock;
245247 }
....@@ -247,12 +249,17 @@
247249
248250 node = &mapping->vram_node;
249251
250
- ret = etnaviv_iommu_find_iova(mmu, node, etnaviv_obj->base.size);
252
+ if (va)
253
+ ret = etnaviv_iommu_insert_exact(context, node,
254
+ etnaviv_obj->base.size, va);
255
+ else
256
+ ret = etnaviv_iommu_find_iova(context, node,
257
+ etnaviv_obj->base.size);
251258 if (ret < 0)
252259 goto unlock;
253260
254261 mapping->iova = node->start;
255
- ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
262
+ ret = etnaviv_iommu_map(context, node->start, sgt, etnaviv_obj->base.size,
256263 ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE);
257264
258265 if (ret < 0) {
....@@ -260,130 +267,250 @@
260267 goto unlock;
261268 }
262269
263
- list_add_tail(&mapping->mmu_node, &mmu->mappings);
264
- mmu->flush_seq++;
270
+ list_add_tail(&mapping->mmu_node, &context->mappings);
271
+ context->flush_seq++;
265272 unlock:
266
- mutex_unlock(&mmu->lock);
273
+ mutex_unlock(&context->lock);
267274
268275 return ret;
269276 }
270277
271
-void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
278
+void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context,
272279 struct etnaviv_vram_mapping *mapping)
273280 {
274281 WARN_ON(mapping->use);
275282
276
- mutex_lock(&mmu->lock);
283
+ mutex_lock(&context->lock);
284
+
285
+ /* Bail if the mapping has been reaped by another thread */
286
+ if (!mapping->context) {
287
+ mutex_unlock(&context->lock);
288
+ return;
289
+ }
277290
278291 /* If the vram node is on the mm, unmap and remove the node */
279
- if (mapping->vram_node.mm == &mmu->mm)
280
- etnaviv_iommu_remove_mapping(mmu, mapping);
292
+ if (mapping->vram_node.mm == &context->mm)
293
+ etnaviv_iommu_remove_mapping(context, mapping);
281294
282295 list_del(&mapping->mmu_node);
283
- mmu->flush_seq++;
284
- mutex_unlock(&mmu->lock);
296
+ context->flush_seq++;
297
+ mutex_unlock(&context->lock);
285298 }
286299
287
-void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
300
+static void etnaviv_iommu_context_free(struct kref *kref)
288301 {
289
- drm_mm_takedown(&mmu->mm);
290
- mmu->domain->ops->free(mmu->domain);
291
- kfree(mmu);
302
+ struct etnaviv_iommu_context *context =
303
+ container_of(kref, struct etnaviv_iommu_context, refcount);
304
+
305
+ etnaviv_cmdbuf_suballoc_unmap(context, &context->cmdbuf_mapping);
306
+
307
+ context->global->ops->free(context);
308
+}
309
+void etnaviv_iommu_context_put(struct etnaviv_iommu_context *context)
310
+{
311
+ kref_put(&context->refcount, etnaviv_iommu_context_free);
292312 }
293313
294
-struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu)
314
+struct etnaviv_iommu_context *
315
+etnaviv_iommu_context_init(struct etnaviv_iommu_global *global,
316
+ struct etnaviv_cmdbuf_suballoc *suballoc)
295317 {
296
- enum etnaviv_iommu_version version;
297
- struct etnaviv_iommu *mmu;
318
+ struct etnaviv_iommu_context *ctx;
319
+ int ret;
298320
299
- mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
300
- if (!mmu)
301
- return ERR_PTR(-ENOMEM);
302
-
303
- if (!(gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION)) {
304
- mmu->domain = etnaviv_iommuv1_domain_alloc(gpu);
305
- version = ETNAVIV_IOMMU_V1;
306
- } else {
307
- mmu->domain = etnaviv_iommuv2_domain_alloc(gpu);
308
- version = ETNAVIV_IOMMU_V2;
309
- }
310
-
311
- if (!mmu->domain) {
312
- dev_err(gpu->dev, "Failed to allocate GPU IOMMU domain\n");
313
- kfree(mmu);
314
- return ERR_PTR(-ENOMEM);
315
- }
316
-
317
- mmu->gpu = gpu;
318
- mmu->version = version;
319
- mutex_init(&mmu->lock);
320
- INIT_LIST_HEAD(&mmu->mappings);
321
-
322
- drm_mm_init(&mmu->mm, mmu->domain->base, mmu->domain->size);
323
-
324
- return mmu;
325
-}
326
-
327
-void etnaviv_iommu_restore(struct etnaviv_gpu *gpu)
328
-{
329
- if (gpu->mmu->version == ETNAVIV_IOMMU_V1)
330
- etnaviv_iommuv1_restore(gpu);
321
+ if (global->version == ETNAVIV_IOMMU_V1)
322
+ ctx = etnaviv_iommuv1_context_alloc(global);
331323 else
332
- etnaviv_iommuv2_restore(gpu);
324
+ ctx = etnaviv_iommuv2_context_alloc(global);
325
+
326
+ if (!ctx)
327
+ return NULL;
328
+
329
+ ret = etnaviv_cmdbuf_suballoc_map(suballoc, ctx, &ctx->cmdbuf_mapping,
330
+ global->memory_base);
331
+ if (ret)
332
+ goto out_free;
333
+
334
+ if (global->version == ETNAVIV_IOMMU_V1 &&
335
+ ctx->cmdbuf_mapping.iova > 0x80000000) {
336
+ dev_err(global->dev,
337
+ "command buffer outside valid memory window\n");
338
+ goto out_unmap;
339
+ }
340
+
341
+ return ctx;
342
+
343
+out_unmap:
344
+ etnaviv_cmdbuf_suballoc_unmap(ctx, &ctx->cmdbuf_mapping);
345
+out_free:
346
+ global->ops->free(ctx);
347
+ return NULL;
333348 }
334349
335
-int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
336
- struct drm_mm_node *vram_node, size_t size,
337
- u32 *iova)
350
+void etnaviv_iommu_restore(struct etnaviv_gpu *gpu,
351
+ struct etnaviv_iommu_context *context)
338352 {
339
- struct etnaviv_iommu *mmu = gpu->mmu;
353
+ context->global->ops->restore(gpu, context);
354
+}
340355
341
- if (mmu->version == ETNAVIV_IOMMU_V1) {
342
- *iova = paddr - gpu->memory_base;
356
+int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu_context *context,
357
+ struct etnaviv_vram_mapping *mapping,
358
+ u32 memory_base, dma_addr_t paddr,
359
+ size_t size)
360
+{
361
+ mutex_lock(&context->lock);
362
+
363
+ if (mapping->use > 0) {
364
+ mapping->use++;
365
+ mutex_unlock(&context->lock);
343366 return 0;
367
+ }
368
+
369
+ /*
370
+ * For MMUv1 we don't add the suballoc region to the pagetables, as
371
+ * those GPUs can only work with cmdbufs accessed through the linear
372
+ * window. Instead we manufacture a mapping to make it look uniform
373
+ * to the upper layers.
374
+ */
375
+ if (context->global->version == ETNAVIV_IOMMU_V1) {
376
+ mapping->iova = paddr - memory_base;
344377 } else {
378
+ struct drm_mm_node *node = &mapping->vram_node;
345379 int ret;
346380
347
- mutex_lock(&mmu->lock);
348
- ret = etnaviv_iommu_find_iova(mmu, vram_node, size);
381
+ ret = etnaviv_iommu_find_iova(context, node, size);
349382 if (ret < 0) {
350
- mutex_unlock(&mmu->lock);
383
+ mutex_unlock(&context->lock);
351384 return ret;
352385 }
353
- ret = etnaviv_domain_map(mmu->domain, vram_node->start, paddr,
354
- size, ETNAVIV_PROT_READ);
355
- if (ret < 0) {
356
- drm_mm_remove_node(vram_node);
357
- mutex_unlock(&mmu->lock);
358
- return ret;
359
- }
360
- mmu->flush_seq++;
361
- mutex_unlock(&mmu->lock);
362386
363
- *iova = (u32)vram_node->start;
387
+ mapping->iova = node->start;
388
+ ret = etnaviv_context_map(context, node->start, paddr, size,
389
+ ETNAVIV_PROT_READ);
390
+ if (ret < 0) {
391
+ drm_mm_remove_node(node);
392
+ mutex_unlock(&context->lock);
393
+ return ret;
394
+ }
395
+
396
+ context->flush_seq++;
397
+ }
398
+
399
+ list_add_tail(&mapping->mmu_node, &context->mappings);
400
+ mapping->use = 1;
401
+
402
+ mutex_unlock(&context->lock);
403
+
404
+ return 0;
405
+}
406
+
407
+void etnaviv_iommu_put_suballoc_va(struct etnaviv_iommu_context *context,
408
+ struct etnaviv_vram_mapping *mapping)
409
+{
410
+ struct drm_mm_node *node = &mapping->vram_node;
411
+
412
+ mutex_lock(&context->lock);
413
+ mapping->use--;
414
+
415
+ if (mapping->use > 0 || context->global->version == ETNAVIV_IOMMU_V1) {
416
+ mutex_unlock(&context->lock);
417
+ return;
418
+ }
419
+
420
+ etnaviv_context_unmap(context, node->start, node->size);
421
+ drm_mm_remove_node(node);
422
+ mutex_unlock(&context->lock);
423
+}
424
+
425
+size_t etnaviv_iommu_dump_size(struct etnaviv_iommu_context *context)
426
+{
427
+ return context->global->ops->dump_size(context);
428
+}
429
+
430
+void etnaviv_iommu_dump(struct etnaviv_iommu_context *context, void *buf)
431
+{
432
+ context->global->ops->dump(context, buf);
433
+}
434
+
435
+int etnaviv_iommu_global_init(struct etnaviv_gpu *gpu)
436
+{
437
+ enum etnaviv_iommu_version version = ETNAVIV_IOMMU_V1;
438
+ struct etnaviv_drm_private *priv = gpu->drm->dev_private;
439
+ struct etnaviv_iommu_global *global;
440
+ struct device *dev = gpu->drm->dev;
441
+
442
+ if (gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION)
443
+ version = ETNAVIV_IOMMU_V2;
444
+
445
+ if (priv->mmu_global) {
446
+ if (priv->mmu_global->version != version) {
447
+ dev_err(gpu->dev,
448
+ "MMU version doesn't match global version\n");
449
+ return -ENXIO;
450
+ }
451
+
452
+ priv->mmu_global->use++;
364453 return 0;
365454 }
366
-}
367455
368
-void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu,
369
- struct drm_mm_node *vram_node, size_t size,
370
- u32 iova)
371
-{
372
- struct etnaviv_iommu *mmu = gpu->mmu;
456
+ global = kzalloc(sizeof(*global), GFP_KERNEL);
457
+ if (!global)
458
+ return -ENOMEM;
373459
374
- if (mmu->version == ETNAVIV_IOMMU_V2) {
375
- mutex_lock(&mmu->lock);
376
- etnaviv_domain_unmap(mmu->domain, iova, size);
377
- drm_mm_remove_node(vram_node);
378
- mutex_unlock(&mmu->lock);
460
+ global->bad_page_cpu = dma_alloc_wc(dev, SZ_4K, &global->bad_page_dma,
461
+ GFP_KERNEL);
462
+ if (!global->bad_page_cpu)
463
+ goto free_global;
464
+
465
+ memset32(global->bad_page_cpu, 0xdead55aa, SZ_4K / sizeof(u32));
466
+
467
+ if (version == ETNAVIV_IOMMU_V2) {
468
+ global->v2.pta_cpu = dma_alloc_wc(dev, ETNAVIV_PTA_SIZE,
469
+ &global->v2.pta_dma, GFP_KERNEL);
470
+ if (!global->v2.pta_cpu)
471
+ goto free_bad_page;
379472 }
380
-}
381
-size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
382
-{
383
- return iommu->domain->ops->dump_size(iommu->domain);
473
+
474
+ global->dev = dev;
475
+ global->version = version;
476
+ global->use = 1;
477
+ mutex_init(&global->lock);
478
+
479
+ if (version == ETNAVIV_IOMMU_V1)
480
+ global->ops = &etnaviv_iommuv1_ops;
481
+ else
482
+ global->ops = &etnaviv_iommuv2_ops;
483
+
484
+ priv->mmu_global = global;
485
+
486
+ return 0;
487
+
488
+free_bad_page:
489
+ dma_free_wc(dev, SZ_4K, global->bad_page_cpu, global->bad_page_dma);
490
+free_global:
491
+ kfree(global);
492
+
493
+ return -ENOMEM;
384494 }
385495
386
-void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf)
496
+void etnaviv_iommu_global_fini(struct etnaviv_gpu *gpu)
387497 {
388
- iommu->domain->ops->dump(iommu->domain, buf);
498
+ struct etnaviv_drm_private *priv = gpu->drm->dev_private;
499
+ struct etnaviv_iommu_global *global = priv->mmu_global;
500
+
501
+ if (--global->use > 0)
502
+ return;
503
+
504
+ if (global->v2.pta_cpu)
505
+ dma_free_wc(global->dev, ETNAVIV_PTA_SIZE,
506
+ global->v2.pta_cpu, global->v2.pta_dma);
507
+
508
+ if (global->bad_page_cpu)
509
+ dma_free_wc(global->dev, SZ_4K,
510
+ global->bad_page_cpu, global->bad_page_dma);
511
+
512
+ mutex_destroy(&global->lock);
513
+ kfree(global);
514
+
515
+ priv->mmu_global = NULL;
389516 }