History

Merge branch 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux into drm-next

Most notable addition this time is the support for the GPU performance counters by Christian. This has been in the making for some time and it has matured a lot. Since this is adding UAPI, the corresponding WIP userspace can be found at [1] mesa/libdrm repos. I expect that Christian sends out the final userspace patches for this once you have pulled the kernel bits. Philipp optimized the probe path, so etnaviv gets out of the way for systems that want to boot real quick. I've done mostly cleanups, disentangling etnaviv from the IOMMU API, with some MMUv1 optimizations on the way. * 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux: (36 commits) drm/etnaviv: remove unnecessary clock stabilization delay drm/etnaviv: reduce reset delay drm/etnaviv: remove unused function etnaviv_gem_new drm/etnaviv: remove stale comment drm/etnaviv: submit supports performance monitor requests drm/etnaviv: enable debug registers on demand drm/etnaviv: need to disable clock gating when doing profiling drm/etnaviv: add MC perf domain drm/etnaviv: add TX perf domain drm/etnaviv: add RA perf domain drm/etnaviv: add SE perf domain drm/etnaviv: add PA perf domain drm/etnaviv: add SH perf domain drm/etnaviv: add PE perf domain drm/etnaviv: add HI perf domain drm/etnaviv: use 'sync points' for performance monitor requests drm/etnaviv: clear alloced event drm/etnaviv: add 'sync point' support drm/etnaviv: add performance monitor request processing drm/etnaviv: copy pmrs from userspace ...

Dave Airlie committed 9 years ago

Commit 787e1b72 parents 972805c 827217019 files · +1148 −330Browse files

Unified · Split

19 files
  1. drivers/gpu/drm/etnaviv/Kconfig +0 −2
  2. drivers/gpu/drm/etnaviv/Makefile +2 −1
  3. drivers/gpu/drm/etnaviv/etnaviv_buffer.c +36 −0
  4. drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c +14 −1
  5. drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h +5 −1
  6. drivers/gpu/drm/etnaviv/etnaviv_drv.c +38 −1
  7. drivers/gpu/drm/etnaviv/etnaviv_drv.h +1 −5
  8. drivers/gpu/drm/etnaviv/etnaviv_gem.c +0 −19
  9. drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +67 −2
  10. drivers/gpu/drm/etnaviv/etnaviv_gpu.c +167 −50
  11. drivers/gpu/drm/etnaviv/etnaviv_gpu.h +11 −2
  12. drivers/gpu/drm/etnaviv/etnaviv_iommu.c +73 −124
  13. drivers/gpu/drm/etnaviv/etnaviv_iommu.h +5 −2
  14. drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +52 −68
  15. drivers/gpu/drm/etnaviv/etnaviv_mmu.c +68 −38
  16. drivers/gpu/drm/etnaviv/etnaviv_mmu.h +23 −13
  17. drivers/gpu/drm/etnaviv/etnaviv_perfmon.c +495 −0
  18. drivers/gpu/drm/etnaviv/etnaviv_perfmon.h +49 −0
  19. include/uapi/drm/etnaviv_drm.h +42 −1
drivers/gpu/drm/etnaviv/Kconfig+0−2
@@ -7,8 +7,6 @@ config DRM_ETNAVIV · 6 unmodified lines
77 select SHMEM
88 select SYNC_FILE
99 select TMPFS
10− select IOMMU_API
11− select IOMMU_SUPPORT
1210 select WANT_DEV_COREDUMP
1311 select CMA if HAVE_DMA_CONTIGUOUS
1412 select DMA_CMA if HAVE_DMA_CONTIGUOUS
drivers/gpu/drm/etnaviv/Makefile+2−1
@@ -10,6 +10,7 @@ etnaviv-y := \ · 9 unmodified lines
1010 etnaviv_gpu.o \
1111 etnaviv_iommu_v2.o \
1212 etnaviv_iommu.o \
13− etnaviv_mmu.o
13+ etnaviv_mmu.o \
14+ etnaviv_perfmon.o
1415
1516 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
drivers/gpu/drm/etnaviv/etnaviv_buffer.c+36−0
@@ -250,6 +250,42 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu) · 249 unmodified lines
250250 }
251251 }
252252
253+/* Append a 'sync point' to the ring buffer. */
254+void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event)
255+{
256+ struct etnaviv_cmdbuf *buffer = gpu->buffer;
257+ unsigned int waitlink_offset = buffer->user_size - 16;
258+ u32 dwords, target;
259+
260+ /*
261+ * We need at most 3 dwords in the return target:
262+ * 1 event + 1 end + 1 wait + 1 link.
263+ */
264+ dwords = 4;
265+ target = etnaviv_buffer_reserve(gpu, buffer, dwords);
266+
267+ /* Signal sync point event */
268+ CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
269+ VIVS_GL_EVENT_FROM_PE);
270+
271+ /* Stop the FE to 'pause' the GPU */
272+ CMD_END(buffer);
273+
274+ /* Append waitlink */
275+ CMD_WAIT(buffer);
276+ CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
277+ buffer->user_size - 4);
278+
279+ /*
280+ * Kick off the 'sync point' command by replacing the previous
281+ * WAIT with a link to the address in the ring buffer.
282+ */
283+ etnaviv_buffer_replace_wait(buffer, waitlink_offset,
284+ VIV_FE_LINK_HEADER_OP_LINK |
285+ VIV_FE_LINK_HEADER_PREFETCH(dwords),
286+ target);
287+}
288+
253289 /* Append a command buffer to the ring buffer. */
254290 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
255291 struct etnaviv_cmdbuf *cmdbuf)
drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c+14−1
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919 #include "etnaviv_cmdbuf.h"
2020 #include "etnaviv_gpu.h"
2121 #include "etnaviv_mmu.h"
22+#include "etnaviv_perfmon.h"
2223
2324 #define SUBALLOC_SIZE SZ_256K
2425 #define SUBALLOC_GRANULE SZ_4K
@@ -87,9 +88,10 @@ void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc) · 62 unmodified lines
8788
8889 struct etnaviv_cmdbuf *
8990 etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
90− size_t nr_bos)
91+ size_t nr_bos, size_t nr_pmrs)
9192 {
9293 struct etnaviv_cmdbuf *cmdbuf;
94+ struct etnaviv_perfmon_request *pmrs;
9395 size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
9496 sizeof(*cmdbuf));
9597 int granule_offs, order, ret;
@@ -98,6 +100,12 @@ etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size, · 2 unmodified lines
98100 if (!cmdbuf)
99101 return NULL;
100102
103+ sz = sizeof(*pmrs) * nr_pmrs;
104+ pmrs = kzalloc(sz, GFP_KERNEL);
105+ if (!pmrs)
106+ goto out_free_cmdbuf;
107+
108+ cmdbuf->pmrs = pmrs;
101109 cmdbuf->suballoc = suballoc;
102110 cmdbuf->size = size;
103111
@@ -124,6 +132,10 @@ retry: · 20 unmodified lines
124132 cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;
125133
126134 return cmdbuf;
135+
136+out_free_cmdbuf:
137+ kfree(cmdbuf);
138+ return NULL;
127139 }
128140
129141 void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
@@ -139,6 +151,7 @@ void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf) · 9 unmodified lines
139151 suballoc->free_space = 1;
140152 mutex_unlock(&suballoc->lock);
141153 wake_up_all(&suballoc->free_event);
154+ kfree(cmdbuf->pmrs);
142155 kfree(cmdbuf);
143156 }
144157
drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h+5−1
@@ -21,6 +21,7 @@ · 20 unmodified lines
2121
2222 struct etnaviv_gpu;
2323 struct etnaviv_cmdbuf_suballoc;
24+struct etnaviv_perfmon_request;
2425
2526 struct etnaviv_cmdbuf {
2627 /* suballocator this cmdbuf is allocated from */
@@ -38,6 +39,9 @@ struct etnaviv_cmdbuf { · 11 unmodified lines
3839 u32 exec_state;
3940 /* per GPU in-flight list */
4041 struct list_head node;
42+ /* perfmon requests */
43+ unsigned int nr_pmrs;
44+ struct etnaviv_perfmon_request *pmrs;
4145 /* BOs attached to this command buffer */
4246 unsigned int nr_bos;
4347 struct etnaviv_vram_mapping *bo_map[0];
@@ -49,7 +53,7 @@ void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc); · 5 unmodified lines
4953
5054 struct etnaviv_cmdbuf *
5155 etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
52− size_t nr_bos);
56+ size_t nr_bos, size_t nr_pmrs);
5357 void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
5458
5559 u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf);
drivers/gpu/drm/etnaviv/etnaviv_drv.c+38−1
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 #include "etnaviv_gpu.h"
2424 #include "etnaviv_gem.h"
2525 #include "etnaviv_mmu.h"
26+#include "etnaviv_perfmon.h"
2627
2728 #ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
2829 static bool reglog;
@@ -451,6 +452,40 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, · 422 unmodified lines
451452 return ret;
452453 }
453454
455+static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
456+ struct drm_file *file)
457+{
458+ struct etnaviv_drm_private *priv = dev->dev_private;
459+ struct drm_etnaviv_pm_domain *args = data;
460+ struct etnaviv_gpu *gpu;
461+
462+ if (args->pipe >= ETNA_MAX_PIPES)
463+ return -EINVAL;
464+
465+ gpu = priv->gpu[args->pipe];
466+ if (!gpu)
467+ return -ENXIO;
468+
469+ return etnaviv_pm_query_dom(gpu, args);
470+}
471+
472+static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data,
473+ struct drm_file *file)
474+{
475+ struct etnaviv_drm_private *priv = dev->dev_private;
476+ struct drm_etnaviv_pm_signal *args = data;
477+ struct etnaviv_gpu *gpu;
478+
479+ if (args->pipe >= ETNA_MAX_PIPES)
480+ return -EINVAL;
481+
482+ gpu = priv->gpu[args->pipe];
483+ if (!gpu)
484+ return -ENXIO;
485+
486+ return etnaviv_pm_query_sig(gpu, args);
487+}
488+
454489 static const struct drm_ioctl_desc etnaviv_ioctls[] = {
455490 #define ETNA_IOCTL(n, func, flags) \
456491 DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
@@ -463,6 +498,8 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = { · 6 unmodified lines
463498 ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_AUTH|DRM_RENDER_ALLOW),
464499 ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_AUTH|DRM_RENDER_ALLOW),
465500 ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_AUTH|DRM_RENDER_ALLOW),
501+ ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_AUTH|DRM_RENDER_ALLOW),
502+ ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_AUTH|DRM_RENDER_ALLOW),
466503 };
467504
468505 static const struct vm_operations_struct vm_ops = {
@@ -513,7 +550,7 @@ static struct drm_driver etnaviv_drm_driver = { · 44 unmodified lines
513550 .desc = "etnaviv DRM",
514551 .date = "20151214",
515552 .major = 1,
516− .minor = 1,
553+ .minor = 2,
517554 };
518555
519556 /*
drivers/gpu/drm/etnaviv/etnaviv_drv.h+1−5
@@ -26,7 +26,6 @@ · 25 unmodified lines
2626 #include <linux/pm_runtime.h>
2727 #include <linux/slab.h>
2828 #include <linux/list.h>
29−#include <linux/iommu.h>
3029 #include <linux/types.h>
3130 #include <linux/sizes.h>
3231
@@ -92,15 +91,12 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj); · 59 unmodified lines
9291 void etnaviv_gem_free_object(struct drm_gem_object *obj);
9392 int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
9493 u32 size, u32 flags, u32 *handle);
95−struct drm_gem_object *etnaviv_gem_new_locked(struct drm_device *dev,
96− u32 size, u32 flags);
97−struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
98− u32 size, u32 flags);
9994 int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
10095 uintptr_t ptr, u32 size, u32 flags, u32 *handle);
10196 u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
10297 u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr);
10398 void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
99+void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event);
104100 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
105101 struct etnaviv_cmdbuf *cmdbuf);
106102 void etnaviv_validate_init(void);
drivers/gpu/drm/etnaviv/etnaviv_gem.c+0−19
@@ -704,25 +704,6 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file, · 703 unmodified lines
704704 return ret;
705705 }
706706
707−struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
708− u32 size, u32 flags)
709−{
710− struct drm_gem_object *obj;
711− int ret;
712−
713− obj = __etnaviv_gem_new(dev, size, flags);
714− if (IS_ERR(obj))
715− return obj;
716−
717− ret = etnaviv_gem_obj_add(dev, obj);
718− if (ret < 0) {
719− drm_gem_object_put_unlocked(obj);
720− return ERR_PTR(ret);
721− }
722−
723− return obj;
724−}
725−
726707 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
727708 struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
728709 struct etnaviv_gem_object **res)
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c+67−2
@@ -21,6 +21,7 @@ · 20 unmodified lines
2121 #include "etnaviv_drv.h"
2222 #include "etnaviv_gpu.h"
2323 #include "etnaviv_gem.h"
24+#include "etnaviv_perfmon.h"
2425
2526 /*
2627 * Cmdstream submission:
@@ -283,6 +284,54 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, · 256 unmodified lines
283284 return 0;
284285 }
285286
287+static int submit_perfmon_validate(struct etnaviv_gem_submit *submit,
288+ struct etnaviv_cmdbuf *cmdbuf,
289+ const struct drm_etnaviv_gem_submit_pmr *pmrs,
290+ u32 nr_pms)
291+{
292+ u32 i;
293+
294+ for (i = 0; i < nr_pms; i++) {
295+ const struct drm_etnaviv_gem_submit_pmr *r = pmrs + i;
296+ struct etnaviv_gem_submit_bo *bo;
297+ int ret;
298+
299+ ret = submit_bo(submit, r->read_idx, &bo);
300+ if (ret)
301+ return ret;
302+
303+ /* at offset 0 a sequence number gets stored used for userspace sync */
304+ if (r->read_offset == 0) {
305+ DRM_ERROR("perfmon request: offset is 0");
306+ return -EINVAL;
307+ }
308+
309+ if (r->read_offset >= bo->obj->base.size - sizeof(u32)) {
310+ DRM_ERROR("perfmon request: offset %u outside object", i);
311+ return -EINVAL;
312+ }
313+
314+ if (r->flags & ~(ETNA_PM_PROCESS_PRE | ETNA_PM_PROCESS_POST)) {
315+ DRM_ERROR("perfmon request: flags are not valid");
316+ return -EINVAL;
317+ }
318+
319+ if (etnaviv_pm_req_validate(r, cmdbuf->exec_state)) {
320+ DRM_ERROR("perfmon request: domain or signal not valid");
321+ return -EINVAL;
322+ }
323+
324+ cmdbuf->pmrs[i].flags = r->flags;
325+ cmdbuf->pmrs[i].domain = r->domain;
326+ cmdbuf->pmrs[i].signal = r->signal;
327+ cmdbuf->pmrs[i].sequence = r->sequence;
328+ cmdbuf->pmrs[i].offset = r->read_offset;
329+ cmdbuf->pmrs[i].bo_vma = etnaviv_gem_vmap(&bo->obj->base);
330+ }
331+
332+ return 0;
333+}
334+
286335 static void submit_cleanup(struct etnaviv_gem_submit *submit)
287336 {
288337 unsigned i;
@@ -306,6 +355,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 17 unmodified lines
306355 struct etnaviv_drm_private *priv = dev->dev_private;
307356 struct drm_etnaviv_gem_submit *args = data;
308357 struct drm_etnaviv_gem_submit_reloc *relocs;
358+ struct drm_etnaviv_gem_submit_pmr *pmrs;
309359 struct drm_etnaviv_gem_submit_bo *bos;
310360 struct etnaviv_gem_submit *submit;
311361 struct etnaviv_cmdbuf *cmdbuf;
@@ -347,11 +397,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 35 unmodified lines
347397 */
348398 bos = kvmalloc_array(args->nr_bos, sizeof(*bos), GFP_KERNEL);
349399 relocs = kvmalloc_array(args->nr_relocs, sizeof(*relocs), GFP_KERNEL);
400+ pmrs = kvmalloc_array(args->nr_pmrs, sizeof(*pmrs), GFP_KERNEL);
350401 stream = kvmalloc_array(1, args->stream_size, GFP_KERNEL);
351402 cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc,
352403 ALIGN(args->stream_size, 8) + 8,
353− args->nr_bos);
354− if (!bos || !relocs || !stream || !cmdbuf) {
404+ args->nr_bos, args->nr_pmrs);
405+ if (!bos || !relocs || !pmrs || !stream || !cmdbuf) {
355406 ret = -ENOMEM;
356407 goto err_submit_cmds;
357408 }
@@ -373,6 +424,14 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 15 unmodified lines
373424 goto err_submit_cmds;
374425 }
375426
427+ ret = copy_from_user(pmrs, u64_to_user_ptr(args->pmrs),
428+ args->nr_pmrs * sizeof(*pmrs));
429+ if (ret) {
430+ ret = -EFAULT;
431+ goto err_submit_cmds;
432+ }
433+ cmdbuf->nr_pmrs = args->nr_pmrs;
434+
376435 ret = copy_from_user(stream, u64_to_user_ptr(args->stream),
377436 args->stream_size);
378437 if (ret) {
@@ -441,6 +500,10 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 62 unmodified lines
441500 if (ret)
442501 goto out;
443502
503+ ret = submit_perfmon_validate(submit, cmdbuf, pmrs, args->nr_pmrs);
504+ if (ret)
505+ goto out;
506+
444507 memcpy(cmdbuf->vaddr, stream, args->stream_size);
445508 cmdbuf->user_size = ALIGN(args->stream_size, 8);
446509
@@ -496,6 +559,8 @@ err_submit_cmds: · 49 unmodified lines
496559 kvfree(bos);
497560 if (relocs)
498561 kvfree(relocs);
562+ if (pmrs)
563+ kvfree(pmrs);
499564
500565 return ret;
501566 }
drivers/gpu/drm/etnaviv/etnaviv_gpu.c+167−50
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525 #include "etnaviv_gpu.h"
2626 #include "etnaviv_gem.h"
2727 #include "etnaviv_mmu.h"
28+#include "etnaviv_perfmon.h"
2829 #include "common.xml.h"
2930 #include "state.xml.h"
3031 #include "state_hi.xml.h"
@@ -420,9 +421,10 @@ static void etnaviv_gpu_update_clock(struct etnaviv_gpu *gpu) · 389 unmodified lines
420421 gpu->base_rate_shader >> gpu->freq_scale);
421422 } else {
422423 unsigned int fscale = 1 << (6 - gpu->freq_scale);
423− u32 clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
424− VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale);
424+ u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
425425
426+ clock &= ~VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK;
427+ clock |= VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale);
426428 etnaviv_gpu_load_clock(gpu, clock);
427429 }
428430 }
@@ -433,24 +435,14 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) · 4 unmodified lines
433435 unsigned long timeout;
434436 bool failed = true;
435437
436− /* TODO
437− *
438− * - clock gating
439− * - puls eater
440− * - what about VG?
441− */
442−
443438 /* We hope that the GPU resets in under one second */
444439 timeout = jiffies + msecs_to_jiffies(1000);
445440
446441 while (time_is_after_jiffies(timeout)) {
447442 /* enable clock */
448− etnaviv_gpu_update_clock(gpu);
449−
450− control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
451−
452− /* Wait for stable clock. Vivante's code waited for 1ms */
453− usleep_range(1000, 10000);
443+ unsigned int fscale = 1 << (6 - gpu->freq_scale);
444+ control = VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale);
445+ etnaviv_gpu_load_clock(gpu, control);
454446
455447 /* isolate the GPU. */
456448 control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
@@ -461,7 +453,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) · 4 unmodified lines
461453 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
462454
463455 /* wait for reset. */
464− msleep(1);
456+ usleep_range(10, 20);
465457
466458 /* reset soft reset bit. */
467459 control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
@@ -490,6 +482,10 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) · 22 unmodified lines
490482 continue;
491483 }
492484
485+ /* disable debug registers, as they are not normally needed */
486+ control |= VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS;
487+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
488+
493489 failed = false;
494490 break;
495491 }
@@ -721,7 +717,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) · 225 unmodified lines
721717 }
722718
723719 /* Create buffer: */
724− gpu->buffer = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, PAGE_SIZE, 0);
720+ gpu->buffer = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, PAGE_SIZE, 0, 0);
725721 if (!gpu->buffer) {
726722 ret = -ENOMEM;
727723 dev_err(gpu->dev, "could not create command buffer\n");
@@ -739,10 +735,9 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) · 11 unmodified lines
739735 /* Setup event management */
740736 spin_lock_init(&gpu->event_spinlock);
741737 init_completion(&gpu->event_free);
742− for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
743− gpu->event[i].used = false;
738+ bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS);
739+ for (i = 0; i < ARRAY_SIZE(gpu->event); i++)
744740 complete(&gpu->event_free);
745− }
746741
747742 /* Now program the hardware */
748743 mutex_lock(&gpu->lock);
@@ -926,7 +921,7 @@ static void recover_worker(struct work_struct *work) · 177 unmodified lines
926921 struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
927922 recover_work);
928923 unsigned long flags;
929− unsigned int i;
924+ unsigned int i = 0;
930925
931926 dev_err(gpu->dev, "hangcheck recover!\n");
932927
@@ -945,14 +940,12 @@ static void recover_worker(struct work_struct *work) · 12 unmodified lines
945940
946941 /* complete all events, the GPU won't do it after the reset */
947942 spin_lock_irqsave(&gpu->event_spinlock, flags);
948− for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
949− if (!gpu->event[i].used)
950− continue;
943+ for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) {
951944 dma_fence_signal(gpu->event[i].fence);
952945 gpu->event[i].fence = NULL;
953− gpu->event[i].used = false;
954946 complete(&gpu->event_free);
955947 }
948+ bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS);
956949 spin_unlock_irqrestore(&gpu->event_spinlock, flags);
957950 gpu->completed_fence = gpu->active_fence;
958951
@@ -1140,30 +1133,45 @@ int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, · 181 unmodified lines
11401133 * event management:
11411134 */
11421135
1143−static unsigned int event_alloc(struct etnaviv_gpu *gpu)
1136+static int event_alloc(struct etnaviv_gpu *gpu, unsigned nr_events,
1137+ unsigned int *events)
11441138 {
1145− unsigned long ret, flags;
1146− unsigned int i, event = ~0U;
1139+ unsigned long flags, timeout = msecs_to_jiffies(10 * 10000);
1140+ unsigned i, acquired = 0;
11471141
1148− ret = wait_for_completion_timeout(&gpu->event_free,
1149− msecs_to_jiffies(10 * 10000));
1150− if (!ret)
1151− dev_err(gpu->dev, "wait_for_completion_timeout failed");
1142+ for (i = 0; i < nr_events; i++) {
1143+ unsigned long ret;
11521144
1153− spin_lock_irqsave(&gpu->event_spinlock, flags);
1145+ ret = wait_for_completion_timeout(&gpu->event_free, timeout);
11541146
1155− /* find first free event */
1156− for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
1157− if (gpu->event[i].used == false) {
1158− gpu->event[i].used = true;
1159− event = i;
1160− break;
1147+ if (!ret) {
1148+ dev_err(gpu->dev, "wait_for_completion_timeout failed");
1149+ goto out;
11611150 }
1151+
1152+ acquired++;
1153+ timeout = ret;
1154+ }
1155+
1156+ spin_lock_irqsave(&gpu->event_spinlock, flags);
1157+
1158+ for (i = 0; i < nr_events; i++) {
1159+ int event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS);
1160+
1161+ events[i] = event;
1162+ memset(&gpu->event[event], 0, sizeof(struct etnaviv_event));
1163+ set_bit(event, gpu->event_bitmap);
11621164 }
11631165
11641166 spin_unlock_irqrestore(&gpu->event_spinlock, flags);
11651167
1166− return event;
1168+ return 0;
1169+
1170+out:
1171+ for (i = 0; i < acquired; i++)
1172+ complete(&gpu->event_free);
1173+
1174+ return -EBUSY;
11671175 }
11681176
11691177 static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
@@ -1172,12 +1180,12 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event) · 2 unmodified lines
11721180
11731181 spin_lock_irqsave(&gpu->event_spinlock, flags);
11741182
1175− if (gpu->event[event].used == false) {
1183+ if (!test_bit(event, gpu->event_bitmap)) {
11761184 dev_warn(gpu->dev, "event %u is already marked as free",
11771185 event);
11781186 spin_unlock_irqrestore(&gpu->event_spinlock, flags);
11791187 } else {
1180− gpu->event[event].used = false;
1188+ clear_bit(event, gpu->event_bitmap);
11811189 spin_unlock_irqrestore(&gpu->event_spinlock, flags);
11821190
11831191 complete(&gpu->event_free);
@@ -1311,12 +1319,71 @@ void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu) · 127 unmodified lines
13111319 pm_runtime_put_autosuspend(gpu->dev);
13121320 }
13131321
1322+static void sync_point_perfmon_sample(struct etnaviv_gpu *gpu,
1323+ struct etnaviv_event *event, unsigned int flags)
1324+{
1325+ const struct etnaviv_cmdbuf *cmdbuf = event->cmdbuf;
1326+ unsigned int i;
1327+
1328+ for (i = 0; i < cmdbuf->nr_pmrs; i++) {
1329+ const struct etnaviv_perfmon_request *pmr = cmdbuf->pmrs + i;
1330+
1331+ if (pmr->flags == flags)
1332+ etnaviv_perfmon_process(gpu, pmr);
1333+ }
1334+}
1335+
1336+static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu,
1337+ struct etnaviv_event *event)
1338+{
1339+ u32 val;
1340+
1341+ /* disable clock gating */
1342+ val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS);
1343+ val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING;
1344+ gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val);
1345+
1346+ /* enable debug register */
1347+ val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
1348+ val &= ~VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS;
1349+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val);
1350+
1351+ sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_PRE);
1352+}
1353+
1354+static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu,
1355+ struct etnaviv_event *event)
1356+{
1357+ const struct etnaviv_cmdbuf *cmdbuf = event->cmdbuf;
1358+ unsigned int i;
1359+ u32 val;
1360+
1361+ sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_POST);
1362+
1363+ for (i = 0; i < cmdbuf->nr_pmrs; i++) {
1364+ const struct etnaviv_perfmon_request *pmr = cmdbuf->pmrs + i;
1365+
1366+ *pmr->bo_vma = pmr->sequence;
1367+ }
1368+
1369+ /* disable debug register */
1370+ val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
1371+ val |= VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS;
1372+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val);
1373+
1374+ /* enable clock gating */
1375+ val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS);
1376+ val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING;
1377+ gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val);
1378+}
1379+
1380+
13141381 /* add bo's to gpu's ring, and kick gpu: */
13151382 int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
13161383 struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf)
13171384 {
13181385 struct dma_fence *fence;
1319− unsigned int event, i;
1386+ unsigned int i, nr_events = 1, event[3];
13201387 int ret;
13211388
13221389 ret = etnaviv_gpu_pm_get_sync(gpu);
@@ -1332,10 +1399,19 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, · 9 unmodified lines
13321399 *
13331400 */
13341401
1335− event = event_alloc(gpu);
1336− if (unlikely(event == ~0U)) {
1337− DRM_ERROR("no free event\n");
1338− ret = -EBUSY;
1402+ /*
1403+ * if there are performance monitor requests we need to have
1404+ * - a sync point to re-configure gpu and process ETNA_PM_PROCESS_PRE
1405+ * requests.
1406+ * - a sync point to re-configure gpu, process ETNA_PM_PROCESS_POST requests
1407+ * and update the sequence number for userspace.
1408+ */
1409+ if (cmdbuf->nr_pmrs)
1410+ nr_events = 3;
1411+
1412+ ret = event_alloc(gpu, nr_events, event);
1413+ if (ret) {
1414+ DRM_ERROR("no free events\n");
13391415 goto out_pm_put;
13401416 }
13411417
@@ -1343,12 +1419,14 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, · 1 unmodified line
13431419
13441420 fence = etnaviv_gpu_fence_alloc(gpu);
13451421 if (!fence) {
1346− event_free(gpu, event);
1422+ for (i = 0; i < nr_events; i++)
1423+ event_free(gpu, event[i]);
1424+
13471425 ret = -ENOMEM;
13481426 goto out_unlock;
13491427 }
13501428
1351− gpu->event[event].fence = fence;
1429+ gpu->event[event[0]].fence = fence;
13521430 submit->fence = dma_fence_get(fence);
13531431 gpu->active_fence = submit->fence->seqno;
13541432
@@ -1358,7 +1436,19 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, · 3 unmodified lines
13581436 gpu->lastctx = cmdbuf->ctx;
13591437 }
13601438
1361− etnaviv_buffer_queue(gpu, event, cmdbuf);
1439+ if (cmdbuf->nr_pmrs) {
1440+ gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre;
1441+ gpu->event[event[1]].cmdbuf = cmdbuf;
1442+ etnaviv_sync_point_queue(gpu, event[1]);
1443+ }
1444+
1445+ etnaviv_buffer_queue(gpu, event[0], cmdbuf);
1446+
1447+ if (cmdbuf->nr_pmrs) {
1448+ gpu->event[event[2]].sync_point = &sync_point_perfmon_sample_post;
1449+ gpu->event[event[2]].cmdbuf = cmdbuf;
1450+ etnaviv_sync_point_queue(gpu, event[2]);
1451+ }
13621452
13631453 cmdbuf->fence = fence;
13641454 list_add_tail(&cmdbuf->node, &gpu->active_cmd_list);
@@ -1394,6 +1484,24 @@ out_pm_put: · 29 unmodified lines
13941484 return ret;
13951485 }
13961486
1487+static void etnaviv_process_sync_point(struct etnaviv_gpu *gpu,
1488+ struct etnaviv_event *event)
1489+{
1490+ u32 addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
1491+
1492+ event->sync_point(gpu, event);
1493+ etnaviv_gpu_start_fe(gpu, addr + 2, 2);
1494+}
1495+
1496+static void sync_point_worker(struct work_struct *work)
1497+{
1498+ struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
1499+ sync_point_work);
1500+
1501+ etnaviv_process_sync_point(gpu, &gpu->event[gpu->sync_point_event]);
1502+ event_free(gpu, gpu->sync_point_event);
1503+}
1504+
13971505 /*
13981506 * Init/Cleanup:
13991507 */
@@ -1440,7 +1548,15 @@ static irqreturn_t irq_handler(int irq, void *data) · 40 unmodified lines
14401548
14411549 dev_dbg(gpu->dev, "event %u\n", event);
14421550
1551+ if (gpu->event[event].sync_point) {
1552+ gpu->sync_point_event = event;
1553+ etnaviv_queue_work(gpu->drm, &gpu->sync_point_work);
1554+ }
1555+
14431556 fence = gpu->event[event].fence;
1557+ if (!fence)
1558+ continue;
1559+
14441560 gpu->event[event].fence = NULL;
14451561 dma_fence_signal(fence);
14461562
@@ -1645,6 +1761,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, · 198 unmodified lines
16451761
16461762 INIT_LIST_HEAD(&gpu->active_cmd_list);
16471763 INIT_WORK(&gpu->retire_work, retire_worker);
1764+ INIT_WORK(&gpu->sync_point_work, sync_point_worker);
16481765 INIT_WORK(&gpu->recover_work, recover_worker);
16491766 init_waitqueue_head(&gpu->fence_event);
16501767
drivers/gpu/drm/etnaviv/etnaviv_gpu.h+11−2
@@ -88,13 +88,17 @@ struct etnaviv_chip_identity { · 87 unmodified lines
8888 };
8989
9090 struct etnaviv_event {
91− bool used;
9291 struct dma_fence *fence;
92+ struct etnaviv_cmdbuf *cmdbuf;
93+
94+ void (*sync_point)(struct etnaviv_gpu *gpu, struct etnaviv_event *event);
9395 };
9496
9597 struct etnaviv_cmdbuf_suballoc;
9698 struct etnaviv_cmdbuf;
9799
100+#define ETNA_NR_EVENTS 30
101+
98102 struct etnaviv_gpu {
99103 struct drm_device *drm;
100104 struct thermal_cooling_device *cooling;
@@ -112,7 +116,8 @@ struct etnaviv_gpu { · 11 unmodified lines
112116 u32 memory_base;
113117
114118 /* event management: */
115− struct etnaviv_event event[30];
119+ DECLARE_BITMAP(event_bitmap, ETNA_NR_EVENTS);
120+ struct etnaviv_event event[ETNA_NR_EVENTS];
116121 struct completion event_free;
117122 spinlock_t event_spinlock;
118123
@@ -133,6 +138,10 @@ struct etnaviv_gpu { · 14 unmodified lines
133138 /* worker for handling active-list retiring: */
134139 struct work_struct retire_work;
135140
141+ /* worker for handling 'sync' points: */
142+ struct work_struct sync_point_work;
143+ int sync_point_event;
144+
136145 void __iomem *mmio;
137146 int irq;
138147
drivers/gpu/drm/etnaviv/etnaviv_iommu.c+73−124
@@ -14,7 +14,6 @@ · 13 unmodified lines
1414 * this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#include <linux/iommu.h>
1817 #include <linux/platform_device.h>
1918 #include <linux/sizes.h>
2019 #include <linux/slab.h>
@@ -31,174 +30,115 @@ · 10 unmodified lines
3130
3231 #define GPU_MEM_START 0x80000000
3332
34−struct etnaviv_iommu_domain_pgtable {
35− u32 *pgtable;
36− dma_addr_t paddr;
33+struct etnaviv_iommuv1_domain {
34+ struct etnaviv_iommu_domain base;
35+ u32 *pgtable_cpu;
36+ dma_addr_t pgtable_dma;
3737 };
3838
39−struct etnaviv_iommu_domain {
40− struct iommu_domain domain;
41− struct device *dev;
42− void *bad_page_cpu;
43− dma_addr_t bad_page_dma;
44− struct etnaviv_iommu_domain_pgtable pgtable;
45− spinlock_t map_lock;
46−};
47−
48−static struct etnaviv_iommu_domain *to_etnaviv_domain(struct iommu_domain *domain)
49−{
50− return container_of(domain, struct etnaviv_iommu_domain, domain);
51−}
52−
53−static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable,
54− size_t size)
55−{
56− pgtable->pgtable = dma_alloc_coherent(NULL, size, &pgtable->paddr, GFP_KERNEL);
57− if (!pgtable->pgtable)
58− return -ENOMEM;
59−
60− return 0;
61−}
62−
63−static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable,
64− size_t size)
39+static struct etnaviv_iommuv1_domain *
40+to_etnaviv_domain(struct etnaviv_iommu_domain *domain)
6541 {
66− dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr);
67−}
68−
69−static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
70− unsigned long iova)
71−{
72− /* calcuate index into page table */
73− unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
74− phys_addr_t paddr;
75−
76− paddr = pgtable->pgtable[index];
77−
78− return paddr;
42+ return container_of(domain, struct etnaviv_iommuv1_domain, base);
7943 }
8044
81−static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
82− unsigned long iova, phys_addr_t paddr)
83−{
84− /* calcuate index into page table */
85− unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
86−
87− pgtable->pgtable[index] = paddr;
88−}
89−
90−static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
45+static int __etnaviv_iommu_init(struct etnaviv_iommuv1_domain *etnaviv_domain)
9146 {
9247 u32 *p;
93− int ret, i;
94−
95− etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
96− SZ_4K,
97− &etnaviv_domain->bad_page_dma,
98− GFP_KERNEL);
99− if (!etnaviv_domain->bad_page_cpu)
48+ int i;
49+
50+ etnaviv_domain->base.bad_page_cpu = dma_alloc_coherent(
51+ etnaviv_domain->base.dev,
52+ SZ_4K,
53+ &etnaviv_domain->base.bad_page_dma,
54+ GFP_KERNEL);
55+ if (!etnaviv_domain->base.bad_page_cpu)
10056 return -ENOMEM;
10157
102− p = etnaviv_domain->bad_page_cpu;
58+ p = etnaviv_domain->base.bad_page_cpu;
10359 for (i = 0; i < SZ_4K / 4; i++)
10460 *p++ = 0xdead55aa;
10561
106− ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE);
107− if (ret < 0) {
108− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
109− etnaviv_domain->bad_page_cpu,
110− etnaviv_domain->bad_page_dma);
111− return ret;
62+ etnaviv_domain->pgtable_cpu =
63+ dma_alloc_coherent(etnaviv_domain->base.dev, PT_SIZE,
64+ &etnaviv_domain->pgtable_dma,
65+ GFP_KERNEL);
66+ if (!etnaviv_domain->pgtable_cpu) {
67+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
68+ etnaviv_domain->base.bad_page_cpu,
69+ etnaviv_domain->base.bad_page_dma);
70+ return -ENOMEM;
11271 }
11372
11473 for (i = 0; i < PT_ENTRIES; i++)
115− etnaviv_domain->pgtable.pgtable[i] =
116− etnaviv_domain->bad_page_dma;
117−
118− spin_lock_init(&etnaviv_domain->map_lock);
74+ etnaviv_domain->pgtable_cpu[i] =
75+ etnaviv_domain->base.bad_page_dma;
11976
12077 return 0;
12178 }
12279
123−static void etnaviv_domain_free(struct iommu_domain *domain)
80+static void etnaviv_iommuv1_domain_free(struct etnaviv_iommu_domain *domain)
12481 {
125− struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
82+ struct etnaviv_iommuv1_domain *etnaviv_domain =
83+ to_etnaviv_domain(domain);
12684
127− pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
85+ dma_free_coherent(etnaviv_domain->base.dev, PT_SIZE,
86+ etnaviv_domain->pgtable_cpu,
87+ etnaviv_domain->pgtable_dma);
12888
129− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
130− etnaviv_domain->bad_page_cpu,
131− etnaviv_domain->bad_page_dma);
89+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
90+ etnaviv_domain->base.bad_page_cpu,
91+ etnaviv_domain->base.bad_page_dma);
13292
13393 kfree(etnaviv_domain);
13494 }
13595
136−static int etnaviv_iommuv1_map(struct iommu_domain *domain, unsigned long iova,
137− phys_addr_t paddr, size_t size, int prot)
96+static int etnaviv_iommuv1_map(struct etnaviv_iommu_domain *domain,
97+ unsigned long iova, phys_addr_t paddr,
98+ size_t size, int prot)
13899 {
139− struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
100+ struct etnaviv_iommuv1_domain *etnaviv_domain = to_etnaviv_domain(domain);
101+ unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
140102
141103 if (size != SZ_4K)
142104 return -EINVAL;
143105
144− spin_lock(&etnaviv_domain->map_lock);
145− pgtable_write(&etnaviv_domain->pgtable, iova, paddr);
146− spin_unlock(&etnaviv_domain->map_lock);
106+ etnaviv_domain->pgtable_cpu[index] = paddr;
147107
148108 return 0;
149109 }
150110
151−static size_t etnaviv_iommuv1_unmap(struct iommu_domain *domain,
111+static size_t etnaviv_iommuv1_unmap(struct etnaviv_iommu_domain *domain,
152112 unsigned long iova, size_t size)
153113 {
154− struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
114+ struct etnaviv_iommuv1_domain *etnaviv_domain =
115+ to_etnaviv_domain(domain);
116+ unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
155117
156118 if (size != SZ_4K)
157119 return -EINVAL;
158120
159− spin_lock(&etnaviv_domain->map_lock);
160− pgtable_write(&etnaviv_domain->pgtable, iova,
161− etnaviv_domain->bad_page_dma);
162− spin_unlock(&etnaviv_domain->map_lock);
121+ etnaviv_domain->pgtable_cpu[index] = etnaviv_domain->base.bad_page_dma;
163122
164123 return SZ_4K;
165124 }
166125
167−static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
168− dma_addr_t iova)
169−{
170− struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
171−
172− return pgtable_read(&etnaviv_domain->pgtable, iova);
173−}
174−
175−static size_t etnaviv_iommuv1_dump_size(struct iommu_domain *domain)
126+static size_t etnaviv_iommuv1_dump_size(struct etnaviv_iommu_domain *domain)
176127 {
177128 return PT_SIZE;
178129 }
179130
180−static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
131+static void etnaviv_iommuv1_dump(struct etnaviv_iommu_domain *domain, void *buf)
181132 {
182− struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
133+ struct etnaviv_iommuv1_domain *etnaviv_domain =
134+ to_etnaviv_domain(domain);
183135
184− memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
136+ memcpy(buf, etnaviv_domain->pgtable_cpu, PT_SIZE);
185137 }
186138
187−static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
188− .ops = {
189− .domain_free = etnaviv_domain_free,
190− .map = etnaviv_iommuv1_map,
191− .unmap = etnaviv_iommuv1_unmap,
192− .iova_to_phys = etnaviv_iommu_iova_to_phys,
193− .pgsize_bitmap = SZ_4K,
194− },
195− .dump_size = etnaviv_iommuv1_dump_size,
196− .dump = etnaviv_iommuv1_dump,
197−};
198−
199139 void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu)
200140 {
201− struct etnaviv_iommu_domain *etnaviv_domain =
141+ struct etnaviv_iommuv1_domain *etnaviv_domain =
202142 to_etnaviv_domain(gpu->mmu->domain);
203143 u32 pgtable;
204144
@@ -210,7 +150,7 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) · 5 unmodified lines
210150 gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
211151
212152 /* set page table address in MC */
213− pgtable = (u32)etnaviv_domain->pgtable.paddr;
153+ pgtable = (u32)etnaviv_domain->pgtable_dma;
214154
215155 gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
216156 gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);
@@ -219,28 +159,37 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) · 2 unmodified lines
219159 gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
220160 }
221161
222−struct iommu_domain *etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu)
162+const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = {
163+ .free = etnaviv_iommuv1_domain_free,
164+ .map = etnaviv_iommuv1_map,
165+ .unmap = etnaviv_iommuv1_unmap,
166+ .dump_size = etnaviv_iommuv1_dump_size,
167+ .dump = etnaviv_iommuv1_dump,
168+};
169+
170+struct etnaviv_iommu_domain *
171+etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu)
223172 {
224− struct etnaviv_iommu_domain *etnaviv_domain;
173+ struct etnaviv_iommuv1_domain *etnaviv_domain;
174+ struct etnaviv_iommu_domain *domain;
225175 int ret;
226176
227177 etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL);
228178 if (!etnaviv_domain)
229179 return NULL;
230180
231− etnaviv_domain->dev = gpu->dev;
181+ domain = &etnaviv_domain->base;
232182
233− etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
234− etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
235− etnaviv_domain->domain.pgsize_bitmap = SZ_4K;
236− etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
237− etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
183+ domain->dev = gpu->dev;
184+ domain->base = GPU_MEM_START;
185+ domain->size = PT_ENTRIES * SZ_4K;
186+ domain->ops = &etnaviv_iommuv1_ops;
238187
239188 ret = __etnaviv_iommu_init(etnaviv_domain);
240189 if (ret)
241190 goto out_free;
242191
243− return &etnaviv_domain->domain;
192+ return &etnaviv_domain->base;
244193
245194 out_free:
246195 kfree(etnaviv_domain);
drivers/gpu/drm/etnaviv/etnaviv_iommu.h+5−2
@@ -18,11 +18,14 @@ · 17 unmodified lines
1818 #define __ETNAVIV_IOMMU_H__
1919
2020 struct etnaviv_gpu;
21+struct etnaviv_iommu_domain;
2122
22−struct iommu_domain *etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu);
23+struct etnaviv_iommu_domain *
24+etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu);
2325 void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu);
2426
25−struct iommu_domain *etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu);
27+struct etnaviv_iommu_domain *
28+etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu);
2629 void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu);
2730
2831 #endif /* __ETNAVIV_IOMMU_H__ */
drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c+52−68
@@ -14,7 +14,6 @@ · 13 unmodified lines
1414 * this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#include <linux/iommu.h>
1817 #include <linux/platform_device.h>
1918 #include <linux/sizes.h>
2019 #include <linux/slab.h>
@@ -40,10 +39,7 @@ · 19 unmodified lines
4039 #define MMUv2_MAX_STLB_ENTRIES 1024
4140
4241 struct etnaviv_iommuv2_domain {
43− struct iommu_domain domain;
44− struct device *dev;
45− void *bad_page_cpu;
46− dma_addr_t bad_page_dma;
42+ struct etnaviv_iommu_domain base;
4743 /* M(aster) TLB aka first level pagetable */
4844 u32 *mtlb_cpu;
4945 dma_addr_t mtlb_dma;
@@ -52,13 +48,15 @@ struct etnaviv_iommuv2_domain { · 2 unmodified lines
5248 dma_addr_t stlb_dma[1024];
5349 };
5450
55−static struct etnaviv_iommuv2_domain *to_etnaviv_domain(struct iommu_domain *domain)
51+static struct etnaviv_iommuv2_domain *
52+to_etnaviv_domain(struct etnaviv_iommu_domain *domain)
5653 {
57− return container_of(domain, struct etnaviv_iommuv2_domain, domain);
54+ return container_of(domain, struct etnaviv_iommuv2_domain, base);
5855 }
5956
60−static int etnaviv_iommuv2_map(struct iommu_domain *domain, unsigned long iova,
61− phys_addr_t paddr, size_t size, int prot)
57+static int etnaviv_iommuv2_map(struct etnaviv_iommu_domain *domain,
58+ unsigned long iova, phys_addr_t paddr,
59+ size_t size, int prot)
6260 {
6361 struct etnaviv_iommuv2_domain *etnaviv_domain =
6462 to_etnaviv_domain(domain);
@@ -68,7 +66,7 @@ static int etnaviv_iommuv2_map(struct iommu_domain *domain, unsigned long iova, · 3 unmodified lines
6866 if (size != SZ_4K)
6967 return -EINVAL;
7068
71− if (prot & IOMMU_WRITE)
69+ if (prot & ETNAVIV_PROT_WRITE)
7270 entry |= MMUv2_PTE_WRITEABLE;
7371
7472 mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT;
@@ -79,8 +77,8 @@ static int etnaviv_iommuv2_map(struct iommu_domain *domain, unsigned long iova, · 4 unmodified lines
7977 return 0;
8078 }
8179
82−static size_t etnaviv_iommuv2_unmap(struct iommu_domain *domain,
83− unsigned long iova, size_t size)
80+static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_domain *domain,
81+ unsigned long iova, size_t size)
8482 {
8583 struct etnaviv_iommuv2_domain *etnaviv_domain =
8684 to_etnaviv_domain(domain);
@@ -97,38 +95,26 @@ static size_t etnaviv_iommuv2_unmap(struct iommu_domain *domain, · 10 unmodified lines
9795 return SZ_4K;
9896 }
9997
100−static phys_addr_t etnaviv_iommuv2_iova_to_phys(struct iommu_domain *domain,
101− dma_addr_t iova)
102−{
103− struct etnaviv_iommuv2_domain *etnaviv_domain =
104− to_etnaviv_domain(domain);
105− int mtlb_entry, stlb_entry;
106−
107− mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT;
108− stlb_entry = (iova & MMUv2_STLB_MASK) >> MMUv2_STLB_SHIFT;
109−
110− return etnaviv_domain->stlb_cpu[mtlb_entry][stlb_entry] & ~(SZ_4K - 1);
111−}
112−
11398 static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain)
11499 {
115100 u32 *p;
116101 int ret, i, j;
117102
118103 /* allocate scratch page */
119− etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
120− SZ_4K,
121− &etnaviv_domain->bad_page_dma,
122− GFP_KERNEL);
123− if (!etnaviv_domain->bad_page_cpu) {
104+ etnaviv_domain->base.bad_page_cpu = dma_alloc_coherent(
105+ etnaviv_domain->base.dev,
106+ SZ_4K,
107+ &etnaviv_domain->base.bad_page_dma,
108+ GFP_KERNEL);
109+ if (!etnaviv_domain->base.bad_page_cpu) {
124110 ret = -ENOMEM;
125111 goto fail_mem;
126112 }
127− p = etnaviv_domain->bad_page_cpu;
113+ p = etnaviv_domain->base.bad_page_cpu;
128114 for (i = 0; i < SZ_4K / 4; i++)
129115 *p++ = 0xdead55aa;
130116
131− etnaviv_domain->mtlb_cpu = dma_alloc_coherent(etnaviv_domain->dev,
117+ etnaviv_domain->mtlb_cpu = dma_alloc_coherent(etnaviv_domain->base.dev,
132118 SZ_4K,
133119 &etnaviv_domain->mtlb_dma,
134120 GFP_KERNEL);
@@ -140,7 +126,7 @@ static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) · 5 unmodified lines
140126 /* pre-populate STLB pages (may want to switch to on-demand later) */
141127 for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
142128 etnaviv_domain->stlb_cpu[i] =
143− dma_alloc_coherent(etnaviv_domain->dev,
129+ dma_alloc_coherent(etnaviv_domain->base.dev,
144130 SZ_4K,
145131 &etnaviv_domain->stlb_dma[i],
146132 GFP_KERNEL);
@@ -159,19 +145,19 @@ static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) · 12 unmodified lines
159145 return 0;
160146
161147 fail_mem:
162− if (etnaviv_domain->bad_page_cpu)
163− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
164− etnaviv_domain->bad_page_cpu,
165− etnaviv_domain->bad_page_dma);
148+ if (etnaviv_domain->base.bad_page_cpu)
149+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
150+ etnaviv_domain->base.bad_page_cpu,
151+ etnaviv_domain->base.bad_page_dma);
166152
167153 if (etnaviv_domain->mtlb_cpu)
168− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
154+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
169155 etnaviv_domain->mtlb_cpu,
170156 etnaviv_domain->mtlb_dma);
171157
172158 for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
173159 if (etnaviv_domain->stlb_cpu[i])
174− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
160+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
175161 etnaviv_domain->stlb_cpu[i],
176162 etnaviv_domain->stlb_dma[i]);
177163 }
@@ -179,23 +165,23 @@ fail_mem: · 1 unmodified line
179165 return ret;
180166 }
181167
182−static void etnaviv_iommuv2_domain_free(struct iommu_domain *domain)
168+static void etnaviv_iommuv2_domain_free(struct etnaviv_iommu_domain *domain)
183169 {
184170 struct etnaviv_iommuv2_domain *etnaviv_domain =
185171 to_etnaviv_domain(domain);
186172 int i;
187173
188− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
189− etnaviv_domain->bad_page_cpu,
190− etnaviv_domain->bad_page_dma);
174+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
175+ etnaviv_domain->base.bad_page_cpu,
176+ etnaviv_domain->base.bad_page_dma);
191177
192− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
178+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
193179 etnaviv_domain->mtlb_cpu,
194180 etnaviv_domain->mtlb_dma);
195181
196182 for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
197183 if (etnaviv_domain->stlb_cpu[i])
198− dma_free_coherent(etnaviv_domain->dev, SZ_4K,
184+ dma_free_coherent(etnaviv_domain->base.dev, SZ_4K,
199185 etnaviv_domain->stlb_cpu[i],
200186 etnaviv_domain->stlb_dma[i]);
201187 }
@@ -203,7 +189,7 @@ static void etnaviv_iommuv2_domain_free(struct iommu_domain *domain) · 1 unmodified line
203189 vfree(etnaviv_domain);
204190 }
205191
206−static size_t etnaviv_iommuv2_dump_size(struct iommu_domain *domain)
192+static size_t etnaviv_iommuv2_dump_size(struct etnaviv_iommu_domain *domain)
207193 {
208194 struct etnaviv_iommuv2_domain *etnaviv_domain =
209195 to_etnaviv_domain(domain);
@@ -217,7 +203,7 @@ static size_t etnaviv_iommuv2_dump_size(struct iommu_domain *domain) · 7 unmodified lines
217203 return dump_size;
218204 }
219205
220−static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf)
206+static void etnaviv_iommuv2_dump(struct etnaviv_iommu_domain *domain, void *buf)
221207 {
222208 struct etnaviv_iommuv2_domain *etnaviv_domain =
223209 to_etnaviv_domain(domain);
@@ -230,18 +216,6 @@ static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf) · 6 unmodified lines
230216 memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K);
231217 }
232218
233−static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
234− .ops = {
235− .domain_free = etnaviv_iommuv2_domain_free,
236− .map = etnaviv_iommuv2_map,
237− .unmap = etnaviv_iommuv2_unmap,
238− .iova_to_phys = etnaviv_iommuv2_iova_to_phys,
239− .pgsize_bitmap = SZ_4K,
240− },
241− .dump_size = etnaviv_iommuv2_dump_size,
242− .dump = etnaviv_iommuv2_dump,
243−};
244−
245219 void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu)
246220 {
247221 struct etnaviv_iommuv2_domain *etnaviv_domain =
@@ -254,35 +228,45 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) · 6 unmodified lines
254228
255229 prefetch = etnaviv_buffer_config_mmuv2(gpu,
256230 (u32)etnaviv_domain->mtlb_dma,
257− (u32)etnaviv_domain->bad_page_dma);
231+ (u32)etnaviv_domain->base.bad_page_dma);
258232 etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(gpu->buffer),
259233 prefetch);
260234 etnaviv_gpu_wait_idle(gpu, 100);
261235
262236 gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE);
263237 }
264−struct iommu_domain *etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu)
238+
239+const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = {
240+ .free = etnaviv_iommuv2_domain_free,
241+ .map = etnaviv_iommuv2_map,
242+ .unmap = etnaviv_iommuv2_unmap,
243+ .dump_size = etnaviv_iommuv2_dump_size,
244+ .dump = etnaviv_iommuv2_dump,
245+};
246+
247+struct etnaviv_iommu_domain *
248+etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu)
265249 {
266250 struct etnaviv_iommuv2_domain *etnaviv_domain;
251+ struct etnaviv_iommu_domain *domain;
267252 int ret;
268253
269254 etnaviv_domain = vzalloc(sizeof(*etnaviv_domain));
270255 if (!etnaviv_domain)
271256 return NULL;
272257
273− etnaviv_domain->dev = gpu->dev;
258+ domain = &etnaviv_domain->base;
274259
275− etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
276− etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
277− etnaviv_domain->domain.pgsize_bitmap = SZ_4K;
278− etnaviv_domain->domain.geometry.aperture_start = 0;
279− etnaviv_domain->domain.geometry.aperture_end = ~0UL & ~(SZ_4K - 1);
260+ domain->dev = gpu->dev;
261+ domain->base = 0;
262+ domain->size = (u64)SZ_1G * 4;
263+ domain->ops = &etnaviv_iommuv2_ops;
280264
281265 ret = etnaviv_iommuv2_init(etnaviv_domain);
282266 if (ret)
283267 goto out_free;
284268
285− return &etnaviv_domain->domain;
269+ return &etnaviv_domain->base;
286270
287271 out_free:
288272 vfree(etnaviv_domain);
drivers/gpu/drm/etnaviv/etnaviv_mmu.c+68−38
@@ -22,17 +22,64 @@ · 21 unmodified lines
2222 #include "etnaviv_iommu.h"
2323 #include "etnaviv_mmu.h"
2424
25−static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
26− unsigned long iova, int flags, void *arg)
25+static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain,
26+ unsigned long iova, size_t size)
2727 {
28− DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
29− return 0;
28+ size_t unmapped_page, unmapped = 0;
29+ size_t pgsize = SZ_4K;
30+
31+ if (!IS_ALIGNED(iova | size, pgsize)) {
32+ pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
33+ iova, size, pgsize);
34+ return;
35+ }
36+
37+ while (unmapped < size) {
38+ unmapped_page = domain->ops->unmap(domain, iova, pgsize);
39+ if (!unmapped_page)
40+ break;
41+
42+ iova += unmapped_page;
43+ unmapped += unmapped_page;
44+ }
3045 }
3146
32−int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
33− struct sg_table *sgt, unsigned len, int prot)
47+static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain,
48+ unsigned long iova, phys_addr_t paddr,
49+ size_t size, int prot)
3450 {
35− struct iommu_domain *domain = iommu->domain;
51+ unsigned long orig_iova = iova;
52+ size_t pgsize = SZ_4K;
53+ size_t orig_size = size;
54+ int ret = 0;
55+
56+ if (!IS_ALIGNED(iova | paddr | size, pgsize)) {
57+ pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n",
58+ iova, &paddr, size, pgsize);
59+ return -EINVAL;
60+ }
61+
62+ while (size) {
63+ ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
64+ if (ret)
65+ break;
66+
67+ iova += pgsize;
68+ paddr += pgsize;
69+ size -= pgsize;
70+ }
71+
72+ /* unroll mapping in case something went wrong */
73+ if (ret)
74+ etnaviv_domain_unmap(domain, orig_iova, orig_size - size);
75+
76+ return ret;
77+}
78+
79+static int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
80+ struct sg_table *sgt, unsigned len, int prot)
81+{
82+ struct etnaviv_iommu_domain *domain = iommu->domain;
3683 struct scatterlist *sg;
3784 unsigned int da = iova;
3885 unsigned int i, j;
@@ -47,7 +94,7 @@ int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, · 8 unmodified lines
4794
4895 VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
4996
50− ret = iommu_map(domain, da, pa, bytes, prot);
97+ ret = etnaviv_domain_map(domain, da, pa, bytes, prot);
5198 if (ret)
5299 goto fail;
53100
@@ -62,27 +109,24 @@ fail: · 8 unmodified lines
62109 for_each_sg(sgt->sgl, sg, i, j) {
63110 size_t bytes = sg_dma_len(sg) + sg->offset;
64111
65− iommu_unmap(domain, da, bytes);
112+ etnaviv_domain_unmap(domain, da, bytes);
66113 da += bytes;
67114 }
68115 return ret;
69116 }
70117
71−int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
72− struct sg_table *sgt, unsigned len)
118+static void etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
119+ struct sg_table *sgt, unsigned len)
73120 {
74− struct iommu_domain *domain = iommu->domain;
121+ struct etnaviv_iommu_domain *domain = iommu->domain;
75122 struct scatterlist *sg;
76123 unsigned int da = iova;
77124 int i;
78125
79126 for_each_sg(sgt->sgl, sg, sgt->nents, i) {
80127 size_t bytes = sg_dma_len(sg) + sg->offset;
81− size_t unmapped;
82128
83− unmapped = iommu_unmap(domain, da, bytes);
84− if (unmapped < bytes)
85− return unmapped;
129+ etnaviv_domain_unmap(domain, da, bytes);
86130
87131 VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
88132
@@ -90,8 +134,6 @@ int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, · 1 unmodified line
90134
91135 da += bytes;
92136 }
93−
94− return 0;
95137 }
96138
97139 static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu,
@@ -237,7 +279,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, · 139 unmodified lines
237279 mmu->last_iova = node->start + etnaviv_obj->base.size;
238280 mapping->iova = node->start;
239281 ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
240− IOMMU_READ | IOMMU_WRITE);
282+ ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE);
241283
242284 if (ret < 0) {
243285 drm_mm_remove_node(node);
@@ -271,7 +313,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, · 27 unmodified lines
271313 void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
272314 {
273315 drm_mm_takedown(&mmu->mm);
274− iommu_domain_free(mmu->domain);
316+ mmu->domain->ops->free(mmu->domain);
275317 kfree(mmu);
276318 }
277319
@@ -303,11 +345,7 @@ struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu) · 25 unmodified lines
303345 mutex_init(&mmu->lock);
304346 INIT_LIST_HEAD(&mmu->mappings);
305347
306− drm_mm_init(&mmu->mm, mmu->domain->geometry.aperture_start,
307− mmu->domain->geometry.aperture_end -
308− mmu->domain->geometry.aperture_start + 1);
309−
310− iommu_set_fault_handler(mmu->domain, etnaviv_fault_handler, gpu->dev);
348+ drm_mm_init(&mmu->mm, mmu->domain->base, mmu->domain->size);
311349
312350 return mmu;
313351 }
@@ -338,8 +376,8 @@ int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr, · 24 unmodified lines
338376 mutex_unlock(&mmu->lock);
339377 return ret;
340378 }
341− ret = iommu_map(mmu->domain, vram_node->start, paddr, size,
342− IOMMU_READ);
379+ ret = etnaviv_domain_map(mmu->domain, vram_node->start, paddr,
380+ size, ETNAVIV_PROT_READ);
343381 if (ret < 0) {
344382 drm_mm_remove_node(vram_node);
345383 mutex_unlock(&mmu->lock);
@@ -362,25 +400,17 @@ void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu, · 16 unmodified lines
362400
363401 if (mmu->version == ETNAVIV_IOMMU_V2) {
364402 mutex_lock(&mmu->lock);
365− iommu_unmap(mmu->domain,iova, size);
403+ etnaviv_domain_unmap(mmu->domain, iova, size);
366404 drm_mm_remove_node(vram_node);
367405 mutex_unlock(&mmu->lock);
368406 }
369407 }
370408 size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
371409 {
372− struct etnaviv_iommu_ops *ops;
373−
374− ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
375−
376− return ops->dump_size(iommu->domain);
410+ return iommu->domain->ops->dump_size(iommu->domain);
377411 }
378412
379413 void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf)
380414 {
381− struct etnaviv_iommu_ops *ops;
382−
383− ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
384−
385− ops->dump(iommu->domain, buf);
415+ iommu->domain->ops->dump(iommu->domain, buf);
386416 }
drivers/gpu/drm/etnaviv/etnaviv_mmu.h+23−13
@@ -17,7 +17,8 @@ · 16 unmodified lines
1717 #ifndef __ETNAVIV_MMU_H__
1818 #define __ETNAVIV_MMU_H__
1919
20−#include <linux/iommu.h>
20+#define ETNAVIV_PROT_READ (1 << 0)
21+#define ETNAVIV_PROT_WRITE (1 << 1)
2122
2223 enum etnaviv_iommu_version {
2324 ETNAVIV_IOMMU_V1 = 0,
@@ -26,16 +27,31 @@ enum etnaviv_iommu_version { · 2 unmodified lines
2627
2728 struct etnaviv_gpu;
2829 struct etnaviv_vram_mapping;
30+struct etnaviv_iommu_domain;
2931
30−struct etnaviv_iommu_ops {
31− struct iommu_ops ops;
32− size_t (*dump_size)(struct iommu_domain *);
33− void (*dump)(struct iommu_domain *, void *);
32+struct etnaviv_iommu_domain_ops {
33+ void (*free)(struct etnaviv_iommu_domain *);
34+ int (*map)(struct etnaviv_iommu_domain *domain, unsigned long iova,
35+ phys_addr_t paddr, size_t size, int prot);
36+ size_t (*unmap)(struct etnaviv_iommu_domain *domain, unsigned long iova,
37+ size_t size);
38+ size_t (*dump_size)(struct etnaviv_iommu_domain *);
39+ void (*dump)(struct etnaviv_iommu_domain *, void *);
40+};
41+
42+struct etnaviv_iommu_domain {
43+ struct device *dev;
44+ void *bad_page_cpu;
45+ dma_addr_t bad_page_dma;
46+ u64 base;
47+ u64 size;
48+
49+ const struct etnaviv_iommu_domain_ops *ops;
3450 };
3551
3652 struct etnaviv_iommu {
3753 struct etnaviv_gpu *gpu;
38− struct iommu_domain *domain;
54+ struct etnaviv_iommu_domain *domain;
3955
4056 enum etnaviv_iommu_version version;
4157
@@ -49,18 +65,11 @@ struct etnaviv_iommu { · 7 unmodified lines
4965
5066 struct etnaviv_gem_object;
5167
52−int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
53− int cnt);
54−int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
55− struct sg_table *sgt, unsigned len, int prot);
56−int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
57− struct sg_table *sgt, unsigned len);
5868 int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
5969 struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
6070 struct etnaviv_vram_mapping *mapping);
6171 void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
6272 struct etnaviv_vram_mapping *mapping);
63−void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
6473
6574 int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
6675 struct drm_mm_node *vram_node, size_t size,
@@ -73,6 +82,7 @@ size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); · 6 unmodified lines
7382 void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);
7483
7584 struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu);
85+void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
7686 void etnaviv_iommu_restore(struct etnaviv_gpu *gpu);
7787
7888 #endif /* __ETNAVIV_MMU_H__ */
drivers/gpu/drm/etnaviv/etnaviv_perfmon.c+495−0
@@ -0,0 +1,495 @@
1+/*
2+ * Copyright (C) 2017 Etnaviv Project
3+ * Copyright (C) 2017 Zodiac Inflight Innovations
4+ *
5+ * This program is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 as published by
7+ * the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful, but WITHOUT
10+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12+ * more details.
13+ *
14+ * You should have received a copy of the GNU General Public License along with
15+ * this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#include "etnaviv_gpu.h"
19+#include "etnaviv_perfmon.h"
20+#include "state_hi.xml.h"
21+
22+struct etnaviv_pm_domain;
23+
24+struct etnaviv_pm_signal {
25+ char name[64];
26+ u32 data;
27+
28+ u32 (*sample)(struct etnaviv_gpu *gpu,
29+ const struct etnaviv_pm_domain *domain,
30+ const struct etnaviv_pm_signal *signal);
31+};
32+
33+struct etnaviv_pm_domain {
34+ char name[64];
35+
36+ /* profile register */
37+ u32 profile_read;
38+ u32 profile_config;
39+
40+ u8 nr_signals;
41+ const struct etnaviv_pm_signal *signal;
42+};
43+
44+struct etnaviv_pm_domain_meta {
45+ const struct etnaviv_pm_domain *domains;
46+ u32 nr_domains;
47+};
48+
49+static u32 simple_reg_read(struct etnaviv_gpu *gpu,
50+ const struct etnaviv_pm_domain *domain,
51+ const struct etnaviv_pm_signal *signal)
52+{
53+ return gpu_read(gpu, signal->data);
54+}
55+
56+static u32 perf_reg_read(struct etnaviv_gpu *gpu,
57+ const struct etnaviv_pm_domain *domain,
58+ const struct etnaviv_pm_signal *signal)
59+{
60+ gpu_write(gpu, domain->profile_config, signal->data);
61+
62+ return gpu_read(gpu, domain->profile_read);
63+}
64+
65+static u32 pipe_reg_read(struct etnaviv_gpu *gpu,
66+ const struct etnaviv_pm_domain *domain,
67+ const struct etnaviv_pm_signal *signal)
68+{
69+ u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
70+ u32 value = 0;
71+ unsigned i;
72+
73+ for (i = 0; i < gpu->identity.pixel_pipes; i++) {
74+ clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
75+ clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(i);
76+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
77+ gpu_write(gpu, domain->profile_config, signal->data);
78+ value += gpu_read(gpu, domain->profile_read);
79+ }
80+
81+ /* switch back to pixel pipe 0 to prevent GPU hang */
82+ clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
83+ clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(0);
84+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
85+
86+ return value;
87+}
88+
89+static const struct etnaviv_pm_domain doms_3d[] = {
90+ {
91+ .name = "HI",
92+ .profile_read = VIVS_MC_PROFILE_HI_READ,
93+ .profile_config = VIVS_MC_PROFILE_CONFIG2,
94+ .nr_signals = 5,
95+ .signal = (const struct etnaviv_pm_signal[]) {
96+ {
97+ "TOTAL_CYCLES",
98+ VIVS_HI_PROFILE_TOTAL_CYCLES,
99+ &simple_reg_read
100+ },
101+ {
102+ "IDLE_CYCLES",
103+ VIVS_HI_PROFILE_IDLE_CYCLES,
104+ &simple_reg_read
105+ },
106+ {
107+ "AXI_CYCLES_READ_REQUEST_STALLED",
108+ VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED,
109+ &perf_reg_read
110+ },
111+ {
112+ "AXI_CYCLES_WRITE_REQUEST_STALLED",
113+ VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED,
114+ &perf_reg_read
115+ },
116+ {
117+ "AXI_CYCLES_WRITE_DATA_STALLED",
118+ VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED,
119+ &perf_reg_read
120+ }
121+ }
122+ },
123+ {
124+ .name = "PE",
125+ .profile_read = VIVS_MC_PROFILE_PE_READ,
126+ .profile_config = VIVS_MC_PROFILE_CONFIG0,
127+ .nr_signals = 5,
128+ .signal = (const struct etnaviv_pm_signal[]) {
129+ {
130+ "PIXEL_COUNT_KILLED_BY_COLOR_PIPE",
131+ VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE,
132+ &pipe_reg_read
133+ },
134+ {
135+ "PIXEL_COUNT_KILLED_BY_DEPTH_PIPE",
136+ VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE,
137+ &pipe_reg_read
138+ },
139+ {
140+ "PIXEL_COUNT_DRAWN_BY_COLOR_PIPE",
141+ VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE,
142+ &pipe_reg_read
143+ },
144+ {
145+ "PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE",
146+ VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE,
147+ &pipe_reg_read
148+ }
149+ }
150+ },
151+ {
152+ .name = "SH",
153+ .profile_read = VIVS_MC_PROFILE_SH_READ,
154+ .profile_config = VIVS_MC_PROFILE_CONFIG0,
155+ .nr_signals = 9,
156+ .signal = (const struct etnaviv_pm_signal[]) {
157+ {
158+ "SHADER_CYCLES",
159+ VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES,
160+ &perf_reg_read
161+ },
162+ {
163+ "PS_INST_COUNTER",
164+ VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER,
165+ &perf_reg_read
166+ },
167+ {
168+ "RENDERED_PIXEL_COUNTER",
169+ VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER,
170+ &perf_reg_read
171+ },
172+ {
173+ "VS_INST_COUNTER",
174+ VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER,
175+ &pipe_reg_read
176+ },
177+ {
178+ "RENDERED_VERTICE_COUNTER",
179+ VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER,
180+ &pipe_reg_read
181+ },
182+ {
183+ "VTX_BRANCH_INST_COUNTER",
184+ VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER,
185+ &pipe_reg_read
186+ },
187+ {
188+ "VTX_TEXLD_INST_COUNTER",
189+ VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER,
190+ &pipe_reg_read
191+ },
192+ {
193+ "PXL_BRANCH_INST_COUNTER",
194+ VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER,
195+ &pipe_reg_read
196+ },
197+ {
198+ "PXL_TEXLD_INST_COUNTER",
199+ VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER,
200+ &pipe_reg_read
201+ }
202+ }
203+ },
204+ {
205+ .name = "PA",
206+ .profile_read = VIVS_MC_PROFILE_PA_READ,
207+ .profile_config = VIVS_MC_PROFILE_CONFIG1,
208+ .nr_signals = 6,
209+ .signal = (const struct etnaviv_pm_signal[]) {
210+ {
211+ "INPUT_VTX_COUNTER",
212+ VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER,
213+ &perf_reg_read
214+ },
215+ {
216+ "INPUT_PRIM_COUNTER",
217+ VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER,
218+ &perf_reg_read
219+ },
220+ {
221+ "OUTPUT_PRIM_COUNTER",
222+ VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER,
223+ &perf_reg_read
224+ },
225+ {
226+ "DEPTH_CLIPPED_COUNTER",
227+ VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER,
228+ &pipe_reg_read
229+ },
230+ {
231+ "TRIVIAL_REJECTED_COUNTER",
232+ VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER,
233+ &pipe_reg_read
234+ },
235+ {
236+ "CULLED_COUNTER",
237+ VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER,
238+ &pipe_reg_read
239+ }
240+ }
241+ },
242+ {
243+ .name = "SE",
244+ .profile_read = VIVS_MC_PROFILE_SE_READ,
245+ .profile_config = VIVS_MC_PROFILE_CONFIG1,
246+ .nr_signals = 2,
247+ .signal = (const struct etnaviv_pm_signal[]) {
248+ {
249+ "CULLED_TRIANGLE_COUNT",
250+ VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT,
251+ &perf_reg_read
252+ },
253+ {
254+ "CULLED_LINES_COUNT",
255+ VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT,
256+ &perf_reg_read
257+ }
258+ }
259+ },
260+ {
261+ .name = "RA",
262+ .profile_read = VIVS_MC_PROFILE_RA_READ,
263+ .profile_config = VIVS_MC_PROFILE_CONFIG1,
264+ .nr_signals = 7,
265+ .signal = (const struct etnaviv_pm_signal[]) {
266+ {
267+ "VALID_PIXEL_COUNT",
268+ VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT,
269+ &perf_reg_read
270+ },
271+ {
272+ "TOTAL_QUAD_COUNT",
273+ VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT,
274+ &perf_reg_read
275+ },
276+ {
277+ "VALID_QUAD_COUNT_AFTER_EARLY_Z",
278+ VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z,
279+ &perf_reg_read
280+ },
281+ {
282+ "TOTAL_PRIMITIVE_COUNT",
283+ VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT,
284+ &perf_reg_read
285+ },
286+ {
287+ "PIPE_CACHE_MISS_COUNTER",
288+ VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER,
289+ &perf_reg_read
290+ },
291+ {
292+ "PREFETCH_CACHE_MISS_COUNTER",
293+ VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER,
294+ &perf_reg_read
295+ },
296+ {
297+ "CULLED_QUAD_COUNT",
298+ VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT,
299+ &perf_reg_read
300+ }
301+ }
302+ },
303+ {
304+ .name = "TX",
305+ .profile_read = VIVS_MC_PROFILE_TX_READ,
306+ .profile_config = VIVS_MC_PROFILE_CONFIG1,
307+ .nr_signals = 9,
308+ .signal = (const struct etnaviv_pm_signal[]) {
309+ {
310+ "TOTAL_BILINEAR_REQUESTS",
311+ VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS,
312+ &perf_reg_read
313+ },
314+ {
315+ "TOTAL_TRILINEAR_REQUESTS",
316+ VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS,
317+ &perf_reg_read
318+ },
319+ {
320+ "TOTAL_DISCARDED_TEXTURE_REQUESTS",
321+ VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS,
322+ &perf_reg_read
323+ },
324+ {
325+ "TOTAL_TEXTURE_REQUESTS",
326+ VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS,
327+ &perf_reg_read
328+ },
329+ {
330+ "MEM_READ_COUNT",
331+ VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT,
332+ &perf_reg_read
333+ },
334+ {
335+ "MEM_READ_IN_8B_COUNT",
336+ VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT,
337+ &perf_reg_read
338+ },
339+ {
340+ "CACHE_MISS_COUNT",
341+ VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT,
342+ &perf_reg_read
343+ },
344+ {
345+ "CACHE_HIT_TEXEL_COUNT",
346+ VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT,
347+ &perf_reg_read
348+ },
349+ {
350+ "CACHE_MISS_TEXEL_COUNT",
351+ VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT,
352+ &perf_reg_read
353+ }
354+ }
355+ },
356+ {
357+ .name = "MC",
358+ .profile_read = VIVS_MC_PROFILE_MC_READ,
359+ .profile_config = VIVS_MC_PROFILE_CONFIG2,
360+ .nr_signals = 3,
361+ .signal = (const struct etnaviv_pm_signal[]) {
362+ {
363+ "TOTAL_READ_REQ_8B_FROM_PIPELINE",
364+ VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE,
365+ &perf_reg_read
366+ },
367+ {
368+ "TOTAL_READ_REQ_8B_FROM_IP",
369+ VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP,
370+ &perf_reg_read
371+ },
372+ {
373+ "TOTAL_WRITE_REQ_8B_FROM_PIPELINE",
374+ VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE,
375+ &perf_reg_read
376+ }
377+ }
378+ }
379+};
380+
381+static const struct etnaviv_pm_domain doms_2d[] = {
382+ {
383+ .name = "PE",
384+ .profile_read = VIVS_MC_PROFILE_PE_READ,
385+ .profile_config = VIVS_MC_PROFILE_CONFIG0,
386+ .nr_signals = 1,
387+ .signal = (const struct etnaviv_pm_signal[]) {
388+ {
389+ "PIXELS_RENDERED_2D",
390+ VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D,
391+ &pipe_reg_read
392+ }
393+ }
394+ }
395+};
396+
397+static const struct etnaviv_pm_domain doms_vg[] = {
398+};
399+
400+static const struct etnaviv_pm_domain_meta doms_meta[] = {
401+ {
402+ .nr_domains = ARRAY_SIZE(doms_3d),
403+ .domains = &doms_3d[0]
404+ },
405+ {
406+ .nr_domains = ARRAY_SIZE(doms_2d),
407+ .domains = &doms_2d[0]
408+ },
409+ {
410+ .nr_domains = ARRAY_SIZE(doms_vg),
411+ .domains = &doms_vg[0]
412+ }
413+};
414+
415+int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
416+ struct drm_etnaviv_pm_domain *domain)
417+{
418+ const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe];
419+ const struct etnaviv_pm_domain *dom;
420+
421+ if (domain->iter >= meta->nr_domains)
422+ return -EINVAL;
423+
424+ dom = meta->domains + domain->iter;
425+
426+ domain->id = domain->iter;
427+ domain->nr_signals = dom->nr_signals;
428+ strncpy(domain->name, dom->name, sizeof(domain->name));
429+
430+ domain->iter++;
431+ if (domain->iter == meta->nr_domains)
432+ domain->iter = 0xff;
433+
434+ return 0;
435+}
436+
437+int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
438+ struct drm_etnaviv_pm_signal *signal)
439+{
440+ const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe];
441+ const struct etnaviv_pm_domain *dom;
442+ const struct etnaviv_pm_signal *sig;
443+
444+ if (signal->domain >= meta->nr_domains)
445+ return -EINVAL;
446+
447+ dom = meta->domains + signal->domain;
448+
449+ if (signal->iter > dom->nr_signals)
450+ return -EINVAL;
451+
452+ sig = &dom->signal[signal->iter];
453+
454+ signal->id = signal->iter;
455+ strncpy(signal->name, sig->name, sizeof(signal->name));
456+
457+ signal->iter++;
458+ if (signal->iter == dom->nr_signals)
459+ signal->iter = 0xffff;
460+
461+ return 0;
462+}
463+
464+int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r,
465+ u32 exec_state)
466+{
467+ const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state];
468+ const struct etnaviv_pm_domain *dom;
469+
470+ if (r->domain >= meta->nr_domains)
471+ return -EINVAL;
472+
473+ dom = meta->domains + r->domain;
474+
475+ if (r->signal > dom->nr_signals)
476+ return -EINVAL;
477+
478+ return 0;
479+}
480+
481+void etnaviv_perfmon_process(struct etnaviv_gpu *gpu,
482+ const struct etnaviv_perfmon_request *pmr)
483+{
484+ const struct etnaviv_pm_domain_meta *meta = &doms_meta[gpu->exec_state];
485+ const struct etnaviv_pm_domain *dom;
486+ const struct etnaviv_pm_signal *sig;
487+ u32 *bo = pmr->bo_vma;
488+ u32 val;
489+
490+ dom = meta->domains + pmr->domain;
491+ sig = &dom->signal[pmr->signal];
492+ val = sig->sample(gpu, dom, sig);
493+
494+ *(bo + pmr->offset) = val;
495+}
drivers/gpu/drm/etnaviv/etnaviv_perfmon.h+49−0
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2017 Etnaviv Project
3+ * Copyright (C) 2017 Zodiac Inflight Innovations
4+ *
5+ * This program is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 as published by
7+ * the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful, but WITHOUT
10+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12+ * more details.
13+ *
14+ * You should have received a copy of the GNU General Public License along with
15+ * this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#ifndef __ETNAVIV_PERFMON_H__
19+#define __ETNAVIV_PERFMON_H__
20+
21+struct etnaviv_gpu;
22+struct drm_etnaviv_pm_domain;
23+struct drm_etnaviv_pm_signal;
24+
25+struct etnaviv_perfmon_request
26+{
27+ u32 flags;
28+ u8 domain;
29+ u8 signal;
30+ u32 sequence;
31+
32+ /* bo to store a value */
33+ u32 *bo_vma;
34+ u32 offset;
35+};
36+
37+int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
38+ struct drm_etnaviv_pm_domain *domain);
39+
40+int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
41+ struct drm_etnaviv_pm_signal *signal);
42+
43+int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r,
44+ u32 exec_state);
45+
46+void etnaviv_perfmon_process(struct etnaviv_gpu *gpu,
47+ const struct etnaviv_perfmon_request *pmr);
48+
49+#endif /* __ETNAVIV_PERFMON_H__ */
include/uapi/drm/etnaviv_drm.h+42−1
@@ -150,6 +150,19 @@ struct drm_etnaviv_gem_submit_bo { · 149 unmodified lines
150150 __u64 presumed; /* in/out, presumed buffer address */
151151 };
152152
153+/* performance monitor request (pmr) */
154+#define ETNA_PM_PROCESS_PRE 0x0001
155+#define ETNA_PM_PROCESS_POST 0x0002
156+struct drm_etnaviv_gem_submit_pmr {
157+ __u32 flags; /* in, when to process request (ETNA_PM_PROCESS_x) */
158+ __u8 domain; /* in, pm domain */
159+ __u8 pad;
160+ __u16 signal; /* in, pm signal */
161+ __u32 sequence; /* in, sequence number */
162+ __u32 read_offset; /* in, offset from read_bo */
163+ __u32 read_idx; /* in, index of read_bo buffer */
164+};
165+
153166 /* Each cmdstream submit consists of a table of buffers involved, and
154167 * one or more cmdstream buffers. This allows for conditional execution
155168 * (context-restore), and IB buffers needed for per tile/bin draw cmds.
@@ -175,6 +188,9 @@ struct drm_etnaviv_gem_submit { · 19 unmodified lines
175188 __u64 stream; /* in, ptr to cmdstream */
176189 __u32 flags; /* in, mask of ETNA_SUBMIT_x */
177190 __s32 fence_fd; /* in/out, fence fd (see ETNA_SUBMIT_FENCE_FD_x) */
191+ __u64 pmrs; /* in, ptr to array of submit_pmr's */
192+ __u32 nr_pmrs; /* in, number of submit_pmr's */
193+ __u32 pad;
178194 };
179195
180196 /* The normal way to synchronize with the GPU is just to CPU_PREP on
@@ -210,6 +226,27 @@ struct drm_etnaviv_gem_wait { · 29 unmodified lines
210226 struct drm_etnaviv_timespec timeout; /* in */
211227 };
212228
229+/*
230+ * Performance Monitor (PM):
231+ */
232+
233+struct drm_etnaviv_pm_domain {
234+ __u32 pipe; /* in */
235+ __u8 iter; /* in/out, select pm domain at index iter */
236+ __u8 id; /* out, id of domain */
237+ __u16 nr_signals; /* out, how many signals does this domain provide */
238+ char name[64]; /* out, name of domain */
239+};
240+
241+struct drm_etnaviv_pm_signal {
242+ __u32 pipe; /* in */
243+ __u8 domain; /* in, pm domain index */
244+ __u8 pad;
245+ __u16 iter; /* in/out, select pm source at index iter */
246+ __u16 id; /* out, id of signal */
247+ char name[64]; /* out, name of domain */
248+};
249+
213250 #define DRM_ETNAVIV_GET_PARAM 0x00
214251 /* placeholder:
215252 #define DRM_ETNAVIV_SET_PARAM 0x01
@@ -222,7 +259,9 @@ struct drm_etnaviv_gem_wait { · 6 unmodified lines
222259 #define DRM_ETNAVIV_WAIT_FENCE 0x07
223260 #define DRM_ETNAVIV_GEM_USERPTR 0x08
224261 #define DRM_ETNAVIV_GEM_WAIT 0x09
225−#define DRM_ETNAVIV_NUM_IOCTLS 0x0a
262+#define DRM_ETNAVIV_PM_QUERY_DOM 0x0a
263+#define DRM_ETNAVIV_PM_QUERY_SIG 0x0b
264+#define DRM_ETNAVIV_NUM_IOCTLS 0x0c
226265
227266 #define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
228267 #define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
@@ -233,6 +272,8 @@ struct drm_etnaviv_gem_wait { · 4 unmodified lines
233272 #define DRM_IOCTL_ETNAVIV_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
234273 #define DRM_IOCTL_ETNAVIV_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
235274 #define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
275+#define DRM_IOCTL_ETNAVIV_PM_QUERY_DOM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_DOM, struct drm_etnaviv_pm_domain)
276+#define DRM_IOCTL_ETNAVIV_PM_QUERY_SIG DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_SIG, struct drm_etnaviv_pm_signal)
236277
237278 #if defined(__cplusplus)
238279 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t