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 	struct dentry *ent;
153 	int ret;
154 
155 	if (!minor)
156 		return 0;
157 
158 	dev = minor->dev;
159 
160 	ret = drm_debugfs_create_files(a5xx_debugfs_list,
161 			ARRAY_SIZE(a5xx_debugfs_list),
162 			minor->debugfs_root, minor);
163 
164 	if (ret) {
165 		DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
166 		return ret;
167 	}
168 
169 	ent = debugfs_create_file("reset", S_IWUGO,
170 		minor->debugfs_root,
171 		dev, &reset_fops);
172 	if (!ent)
173 		return -ENOMEM;
174 
175 	return 0;
176 }
177