Loading...
Note: File does not exist in v3.1.
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
21static 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
36static 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
51static 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
66static 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
85static 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 }
98static 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: */
106static int
107reset_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
157DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
158
159
160int 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}