Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / msm / adreno / a5xx_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
3  */
4
5
6 #include <linux/types.h>
7 #include <linux/debugfs.h>
8 #include <drm/drm_print.h>
9
10 #include "a5xx_gpu.h"
11
12 static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
13 {
14         int i;
15
16         drm_printf(p, "PFP state:\n");
17
18         for (i = 0; i < 36; i++) {
19                 gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
20                 drm_printf(p, "  %02x: %08x\n", i,
21                         gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
22         }
23
24         return 0;
25 }
26
27 static int me_print(struct msm_gpu *gpu, struct drm_printer *p)
28 {
29         int i;
30
31         drm_printf(p, "ME state:\n");
32
33         for (i = 0; i < 29; i++) {
34                 gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
35                 drm_printf(p, "  %02x: %08x\n", i,
36                         gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
37         }
38
39         return 0;
40 }
41
42 static int meq_print(struct msm_gpu *gpu, struct drm_printer *p)
43 {
44         int i;
45
46         drm_printf(p, "MEQ state:\n");
47         gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
48
49         for (i = 0; i < 64; i++) {
50                 drm_printf(p, "  %02x: %08x\n", i,
51                         gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
52         }
53
54         return 0;
55 }
56
57 static int roq_print(struct msm_gpu *gpu, struct drm_printer *p)
58 {
59         int i;
60
61         drm_printf(p, "ROQ state:\n");
62         gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
63
64         for (i = 0; i < 512 / 4; i++) {
65                 uint32_t val[4];
66                 int j;
67                 for (j = 0; j < 4; j++)
68                         val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
69                 drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
70                         val[0], val[1], val[2], val[3]);
71         }
72
73         return 0;
74 }
75
76 static int show(struct seq_file *m, void *arg)
77 {
78         struct drm_info_node *node = (struct drm_info_node *) m->private;
79         struct drm_device *dev = node->minor->dev;
80         struct msm_drm_private *priv = dev->dev_private;
81         struct drm_printer p = drm_seq_file_printer(m);
82         int (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
83                 node->info_ent->data;
84
85         return show(priv->gpu, &p);
86 }
87
88 #define ENT(n) { .name = #n, .show = show, .data = n ##_print }
89 static struct drm_info_list a5xx_debugfs_list[] = {
90         ENT(pfp),
91         ENT(me),
92         ENT(meq),
93         ENT(roq),
94 };
95
96 /* for debugfs files that can be written to, we can't use drm helper: */
97 static int
98 reset_set(void *data, u64 val)
99 {
100         struct drm_device *dev = data;
101         struct msm_drm_private *priv = dev->dev_private;
102         struct msm_gpu *gpu = priv->gpu;
103         struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
104         struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
105
106         if (!capable(CAP_SYS_ADMIN))
107                 return -EINVAL;
108
109         /* TODO do we care about trying to make sure the GPU is idle?
110          * Since this is just a debug feature limited to CAP_SYS_ADMIN,
111          * maybe it is fine to let the user keep both pieces if they
112          * try to reset an active GPU.
113          */
114
115         mutex_lock(&dev->struct_mutex);
116
117         release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
118         adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
119
120         release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
121         adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
122
123         if (a5xx_gpu->pm4_bo) {
124                 msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
125                 drm_gem_object_put(a5xx_gpu->pm4_bo);
126                 a5xx_gpu->pm4_bo = NULL;
127         }
128
129         if (a5xx_gpu->pfp_bo) {
130                 msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
131                 drm_gem_object_put(a5xx_gpu->pfp_bo);
132                 a5xx_gpu->pfp_bo = NULL;
133         }
134
135         gpu->needs_hw_init = true;
136
137         pm_runtime_get_sync(&gpu->pdev->dev);
138         gpu->funcs->recover(gpu);
139
140         pm_runtime_put_sync(&gpu->pdev->dev);
141         mutex_unlock(&dev->struct_mutex);
142
143         return 0;
144 }
145
146 DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
147
148
149 int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
150 {
151         struct drm_device *dev;
152         int ret;
153
154         if (!minor)
155                 return 0;
156
157         dev = minor->dev;
158
159         ret = drm_debugfs_create_files(a5xx_debugfs_list,
160                         ARRAY_SIZE(a5xx_debugfs_list),
161                         minor->debugfs_root, minor);
162
163         if (ret) {
164                 DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
165                 return ret;
166         }
167
168         debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev,
169                             &reset_fops);
170
171         return 0;
172 }