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