drm/v3d: Add gpu_gem_info node via debugfs
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / v3d / v3d_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2014-2018 Broadcom */
3
4 #include <linux/circ_buf.h>
5 #include <linux/ctype.h>
6 #include <linux/debugfs.h>
7 #include <linux/seq_file.h>
8 #include <linux/string_helpers.h>
9 #include <linux/sched/clock.h>
10
11 #include <drm/drm_debugfs.h>
12
13 #include "v3d_drv.h"
14 #include "v3d_regs.h"
15
16 #define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg }
17 struct v3d_reg_def {
18         u32 min_ver;
19         u32 max_ver;
20         u32 reg;
21         const char *name;
22 };
23
24 static const struct v3d_reg_def v3d_hub_reg_defs[] = {
25         REGDEF(33, 42, V3D_HUB_AXICFG),
26         REGDEF(33, 71, V3D_HUB_UIFCFG),
27         REGDEF(33, 71, V3D_HUB_IDENT0),
28         REGDEF(33, 71, V3D_HUB_IDENT1),
29         REGDEF(33, 71, V3D_HUB_IDENT2),
30         REGDEF(33, 71, V3D_HUB_IDENT3),
31         REGDEF(33, 71, V3D_HUB_INT_STS),
32         REGDEF(33, 71, V3D_HUB_INT_MSK_STS),
33
34         REGDEF(33, 71, V3D_MMU_CTL),
35         REGDEF(33, 71, V3D_MMU_VIO_ADDR),
36         REGDEF(33, 71, V3D_MMU_VIO_ID),
37         REGDEF(33, 71, V3D_MMU_DEBUG_INFO),
38
39         REGDEF(71, 71, V3D_V7_GMP_STATUS),
40         REGDEF(71, 71, V3D_V7_GMP_CFG),
41         REGDEF(71, 71, V3D_V7_GMP_VIO_ADDR),
42 };
43
44 static const struct v3d_reg_def v3d_gca_reg_defs[] = {
45         REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN),
46         REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK),
47 };
48
49 static const struct v3d_reg_def v3d_core_reg_defs[] = {
50         REGDEF(33, 71, V3D_CTL_IDENT0),
51         REGDEF(33, 71, V3D_CTL_IDENT1),
52         REGDEF(33, 71, V3D_CTL_IDENT2),
53         REGDEF(33, 71, V3D_CTL_MISCCFG),
54         REGDEF(33, 71, V3D_CTL_INT_STS),
55         REGDEF(33, 71, V3D_CTL_INT_MSK_STS),
56         REGDEF(33, 71, V3D_CLE_CT0CS),
57         REGDEF(33, 71, V3D_CLE_CT0CA),
58         REGDEF(33, 71, V3D_CLE_CT0EA),
59         REGDEF(33, 71, V3D_CLE_CT1CS),
60         REGDEF(33, 71, V3D_CLE_CT1CA),
61         REGDEF(33, 71, V3D_CLE_CT1EA),
62
63         REGDEF(33, 71, V3D_PTB_BPCA),
64         REGDEF(33, 71, V3D_PTB_BPCS),
65
66         REGDEF(33, 41, V3D_GMP_STATUS),
67         REGDEF(33, 41, V3D_GMP_CFG),
68         REGDEF(33, 41, V3D_GMP_VIO_ADDR),
69
70         REGDEF(33, 71, V3D_ERR_FDBGO),
71         REGDEF(33, 71, V3D_ERR_FDBGB),
72         REGDEF(33, 71, V3D_ERR_FDBGS),
73         REGDEF(33, 71, V3D_ERR_STAT),
74 };
75
76 static const struct v3d_reg_def v3d_csd_reg_defs[] = {
77         REGDEF(41, 71, V3D_CSD_STATUS),
78         REGDEF(41, 41, V3D_CSD_CURRENT_CFG0),
79         REGDEF(41, 41, V3D_CSD_CURRENT_CFG1),
80         REGDEF(41, 41, V3D_CSD_CURRENT_CFG2),
81         REGDEF(41, 41, V3D_CSD_CURRENT_CFG3),
82         REGDEF(41, 41, V3D_CSD_CURRENT_CFG4),
83         REGDEF(41, 41, V3D_CSD_CURRENT_CFG5),
84         REGDEF(41, 41, V3D_CSD_CURRENT_CFG6),
85         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG0),
86         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG1),
87         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG2),
88         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG3),
89         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG4),
90         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG5),
91         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG6),
92         REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7),
93 };
94
95 static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
96 {
97         struct drm_debugfs_entry *entry = m->private;
98         struct drm_device *dev = entry->dev;
99         struct v3d_dev *v3d = to_v3d_dev(dev);
100         int i, core;
101
102         for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) {
103                 const struct v3d_reg_def *def = &v3d_hub_reg_defs[i];
104
105                 if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
106                         seq_printf(m, "%s (0x%04x): 0x%08x\n",
107                                    def->name, def->reg, V3D_READ(def->reg));
108                 }
109         }
110
111         for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
112                 const struct v3d_reg_def *def = &v3d_gca_reg_defs[i];
113
114                 if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
115                         seq_printf(m, "%s (0x%04x): 0x%08x\n",
116                                    def->name, def->reg, V3D_GCA_READ(def->reg));
117                 }
118         }
119
120         for (core = 0; core < v3d->cores; core++) {
121                 for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) {
122                         const struct v3d_reg_def *def = &v3d_core_reg_defs[i];
123
124                         if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
125                                 seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
126                                            core, def->name, def->reg,
127                                            V3D_CORE_READ(core, def->reg));
128                         }
129                 }
130
131                 for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
132                         const struct v3d_reg_def *def = &v3d_csd_reg_defs[i];
133
134                         if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
135                                 seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
136                                            core, def->name, def->reg,
137                                            V3D_CORE_READ(core, def->reg));
138                         }
139                 }
140         }
141
142         return 0;
143 }
144
145 static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
146 {
147         struct drm_debugfs_entry *entry = m->private;
148         struct drm_device *dev = entry->dev;
149         struct v3d_dev *v3d = to_v3d_dev(dev);
150         u32 ident0, ident1, ident2, ident3, cores;
151         int core;
152
153         ident0 = V3D_READ(V3D_HUB_IDENT0);
154         ident1 = V3D_READ(V3D_HUB_IDENT1);
155         ident2 = V3D_READ(V3D_HUB_IDENT2);
156         ident3 = V3D_READ(V3D_HUB_IDENT3);
157         cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
158
159         seq_printf(m, "Revision:   %d.%d.%d.%d\n",
160                    V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER),
161                    V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV),
162                    V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV),
163                    V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPIDX));
164         seq_printf(m, "MMU:        %s\n",
165                    str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU));
166         seq_printf(m, "TFU:        %s\n",
167                    str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU));
168         if (v3d->ver <= 42) {
169                 seq_printf(m, "TSY:        %s\n",
170                            str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY));
171         }
172         seq_printf(m, "MSO:        %s\n",
173                    str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO));
174         seq_printf(m, "L3C:        %s (%dkb)\n",
175                    str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_L3C),
176                    V3D_GET_FIELD(ident2, V3D_HUB_IDENT2_L3C_NKB));
177
178         for (core = 0; core < cores; core++) {
179                 u32 misccfg;
180                 u32 nslc, ntmu, qups;
181
182                 ident0 = V3D_CORE_READ(core, V3D_CTL_IDENT0);
183                 ident1 = V3D_CORE_READ(core, V3D_CTL_IDENT1);
184                 ident2 = V3D_CORE_READ(core, V3D_CTL_IDENT2);
185                 misccfg = V3D_CORE_READ(core, V3D_CTL_MISCCFG);
186
187                 nslc = V3D_GET_FIELD(ident1, V3D_IDENT1_NSLC);
188                 ntmu = V3D_GET_FIELD(ident1, V3D_IDENT1_NTMU);
189                 qups = V3D_GET_FIELD(ident1, V3D_IDENT1_QUPS);
190
191                 seq_printf(m, "Core %d:\n", core);
192                 seq_printf(m, "  Revision:     %d.%d\n",
193                            V3D_GET_FIELD(ident0, V3D_IDENT0_VER),
194                            V3D_GET_FIELD(ident1, V3D_IDENT1_REV));
195                 seq_printf(m, "  Slices:       %d\n", nslc);
196                 seq_printf(m, "  TMUs:         %d\n", nslc * ntmu);
197                 seq_printf(m, "  QPUs:         %d\n", nslc * qups);
198                 seq_printf(m, "  Semaphores:   %d\n",
199                            V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM));
200                 if (v3d->ver <= 42) {
201                         seq_printf(m, "  BCG int:      %d\n",
202                                    (ident2 & V3D_IDENT2_BCG_INT) != 0);
203                 }
204                 if (v3d->ver < 40) {
205                         seq_printf(m, "  Override TMU: %d\n",
206                                    (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
207                 }
208         }
209
210         return 0;
211 }
212
213 static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
214 {
215         struct drm_debugfs_entry *entry = m->private;
216         struct drm_device *dev = entry->dev;
217         struct v3d_dev *v3d = to_v3d_dev(dev);
218
219         mutex_lock(&v3d->bo_lock);
220         seq_printf(m, "allocated bos:          %d\n",
221                    v3d->bo_stats.num_allocated);
222         seq_printf(m, "allocated bo size (kb): %ld\n",
223                    (long)v3d->bo_stats.pages_allocated << (PAGE_SHIFT - 10));
224         mutex_unlock(&v3d->bo_lock);
225
226         return 0;
227 }
228
229 static int v3d_debugfs_gpu_usage(struct seq_file *m, void *unused)
230 {
231         struct drm_debugfs_entry *entry = m->private;
232         struct drm_device *dev = entry->dev;
233         struct v3d_dev *v3d = to_v3d_dev(dev);
234         struct v3d_queue_stats *queue_stats;
235         enum v3d_queue queue;
236         u64 timestamp = local_clock();
237         u64 active_runtime;
238
239         seq_printf(m, "timestamp;%llu;\n", local_clock());
240         seq_printf(m, "\"QUEUE\";\"JOBS\";\"RUNTIME\";\"ACTIVE\";\n");
241         for (queue = 0; queue < V3D_MAX_QUEUES; queue++) {
242                 if (!v3d->queue[queue].sched.ready)
243                         continue;
244
245                 queue_stats = &v3d->gpu_queue_stats[queue];
246                 mutex_lock(&queue_stats->lock);
247                 v3d_sched_stats_update(queue_stats);
248                 if (queue_stats->last_pid)
249                         active_runtime = timestamp - queue_stats->last_exec_start;
250                 else
251                         active_runtime = 0;
252
253                 seq_printf(m, "%s;%d;%llu;%c;\n",
254                            v3d_queue_to_string(queue),
255                            queue_stats->jobs_sent,
256                            queue_stats->runtime + active_runtime,
257                            queue_stats->last_pid?'1':'0');
258                 mutex_unlock(&queue_stats->lock);
259         }
260
261         return 0;
262 }
263
264 static int v3d_debugfs_gpu_pid_usage(struct seq_file *m, void *unused)
265 {
266         struct drm_debugfs_entry *entry = m->private;
267         struct drm_device *dev = entry->dev;
268         struct v3d_dev *v3d = to_v3d_dev(dev);
269         struct v3d_queue_stats *queue_stats;
270         struct v3d_queue_pid_stats *cur;
271         enum v3d_queue queue;
272         u64 active_runtime;
273         u64 timestamp = local_clock();
274
275         seq_printf(m, "timestamp;%llu;\n", timestamp);
276         seq_printf(m, "\"QUEUE\";\"PID\",\"JOBS\";\"RUNTIME\";\"ACTIVE\";\n");
277         for (queue = 0; queue < V3D_MAX_QUEUES; queue++) {
278
279                 if (!v3d->queue[queue].sched.ready)
280                         continue;
281
282                 queue_stats = &v3d->gpu_queue_stats[queue];
283                 mutex_lock(&queue_stats->lock);
284                 queue_stats->gpu_pid_stats_timeout = jiffies + V3D_QUEUE_STATS_TIMEOUT;
285                 v3d_sched_stats_update(queue_stats);
286                 list_for_each_entry(cur, &queue_stats->pid_stats_list, list) {
287
288                         if (cur->pid == queue_stats->last_pid)
289                                 active_runtime = timestamp - queue_stats->last_exec_start;
290                         else
291                                 active_runtime = 0;
292
293                         seq_printf(m, "%s;%d;%d;%llu;%c;\n",
294                                    v3d_queue_to_string(queue),
295                                    cur->pid, cur->jobs_sent,
296                                    cur->runtime + active_runtime,
297                                    cur->pid == queue_stats->last_pid ? '1' : '0');
298                 }
299                 mutex_unlock(&queue_stats->lock);
300         }
301
302         return 0;
303 }
304
305 static int v3d_measure_clock(struct seq_file *m, void *unused)
306 {
307         struct drm_debugfs_entry *entry = m->private;
308         struct drm_device *dev = entry->dev;
309         struct v3d_dev *v3d = to_v3d_dev(dev);
310         uint32_t cycles;
311         int core = 0;
312         int measure_ms = 1000;
313
314         if (v3d->ver >= 40) {
315                 int cycle_count_reg = v3d->ver < 71 ?
316                         V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT;
317                 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
318                                V3D_SET_FIELD(cycle_count_reg,
319                                              V3D_PCTR_S0));
320                 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
321                 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
322         } else {
323                 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
324                                V3D_PCTR_CYCLE_COUNT);
325                 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
326                 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
327                                V3D_V3_PCTR_0_EN_ENABLE |
328                                1);
329         }
330         msleep(measure_ms);
331         cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
332
333         seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
334                    cycles,
335                    cycles / (measure_ms * 1000),
336                    (cycles / (measure_ms * 100)) % 10);
337
338         return 0;
339 }
340
341 struct v3d_gem_info_data {
342         struct drm_file *filp;
343         struct seq_file *m;
344 };
345
346 static int v3d_gem_one_info(int id, void *ptr, void *data)
347 {
348         struct drm_gem_object *obj = (struct drm_gem_object *)ptr;
349         struct v3d_gem_info_data *gem_info_data = data;
350         struct v3d_file_priv *v3d_priv = gem_info_data->filp->driver_priv;
351         struct drm_v3d_file_private *pid_priv = &v3d_priv->priv;
352
353         if (!obj) {
354                 DRM_ERROR("failed to get drm_gem_object\n");
355                 return -EFAULT;
356         }
357
358         drm_gem_object_get(obj);
359
360         seq_printf(gem_info_data->m,
361                         "%5d\t%5d\t%4d\t%4d\t\t%4d\t0x%08zx\t0x%x\t%4d\t%4d\t\t"
362                         "%4d\t\t0x%p\t%6d\n",
363                         pid_priv->pid,
364                         pid_priv->tgid,
365                         id,
366                         kref_read(&obj->refcount) - 1,
367                         obj->handle_count,
368                         obj->size,
369                         0,
370                         0,
371                         obj->dma_buf ? 1 : 0,
372                         obj->import_attach ? 1 : 0,
373                         obj,
374                         obj->name);
375
376         drm_gem_object_put(obj);
377
378         return 0;
379 }
380
381 int v3d_debugfs_gem_info(struct seq_file *m, void *data)
382 {
383         struct drm_debugfs_entry *entry = m->private;
384         struct drm_device *drm_dev = entry->dev;
385         struct v3d_gem_info_data gem_info_data;
386         struct drm_file *filp;
387
388         gem_info_data.m = m;
389
390         seq_puts(gem_info_data.m,
391                         "pid\ttgid\thandle\trefcount\thcount\tsize\t\tflags\t"
392                         "pfnmap\texport_to_fd\timport_from_fd\tobj_addr\t\t"
393                         "name\n");
394
395         mutex_lock(&drm_dev->struct_mutex);
396         list_for_each_entry(filp, &drm_dev->filelist, lhead) {
397                 gem_info_data.filp = filp;
398
399                 spin_lock(&filp->table_lock);
400                 idr_for_each(&filp->object_idr, v3d_gem_one_info,
401                                 &gem_info_data);
402                 spin_unlock(&filp->table_lock);
403         }
404         mutex_unlock(&drm_dev->struct_mutex);
405
406         return 0;
407 }
408
409 static const struct drm_debugfs_info v3d_debugfs_list[] = {
410         {"v3d_ident", v3d_v3d_debugfs_ident, 0},
411         {"v3d_regs", v3d_v3d_debugfs_regs, 0},
412         {"measure_clock", v3d_measure_clock, 0},
413         {"bo_stats", v3d_debugfs_bo_stats, 0},
414         {"gpu_usage", v3d_debugfs_gpu_usage, 0},
415         {"gpu_gem_info", v3d_debugfs_gem_info, 0},
416         {"gpu_pid_usage", v3d_debugfs_gpu_pid_usage, 0},
417 };
418
419 void
420 v3d_debugfs_init(struct drm_minor *minor)
421 {
422         drm_debugfs_add_files(minor->dev, v3d_debugfs_list, ARRAY_SIZE(v3d_debugfs_list));
423 }