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 		msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
134 		drm_gem_object_put(a5xx_gpu->pm4_bo);
135 		a5xx_gpu->pm4_bo = NULL;
136 	}
137 
138 	if (a5xx_gpu->pfp_bo) {
139 		msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
140 		drm_gem_object_put(a5xx_gpu->pfp_bo);
141 		a5xx_gpu->pfp_bo = NULL;
142 	}
143 
144 	gpu->needs_hw_init = true;
145 
146 	pm_runtime_get_sync(&gpu->pdev->dev);
147 	gpu->funcs->recover(gpu);
148 
149 	pm_runtime_put_sync(&gpu->pdev->dev);
150 	mutex_unlock(&dev->struct_mutex);
151 
152 	return 0;
153 }
154 
155 DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
156 
157 
158 int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
159 {
160 	struct drm_device *dev;
161 	struct dentry *ent;
162 	int ret;
163 
164 	if (!minor)
165 		return 0;
166 
167 	dev = minor->dev;
168 
169 	ret = drm_debugfs_create_files(a5xx_debugfs_list,
170 			ARRAY_SIZE(a5xx_debugfs_list),
171 			minor->debugfs_root, minor);
172 
173 	if (ret) {
174 		DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
175 		return ret;
176 	}
177 
178 	ent = debugfs_create_file("reset", S_IWUGO,
179 		minor->debugfs_root,
180 		dev, &reset_fops);
181 	if (!ent)
182 		return -ENOMEM;
183 
184 	return 0;
185 }
186