xref: /openbmc/linux/drivers/gpu/drm/msm/msm_debugfs.c (revision ba936421)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013-2016 Red Hat
4  * Author: Rob Clark <robdclark@gmail.com>
5  */
6 
7 #ifdef CONFIG_DEBUG_FS
8 
9 #include <linux/debugfs.h>
10 
11 #include <drm/drm_debugfs.h>
12 #include <drm/drm_file.h>
13 
14 #include "msm_drv.h"
15 #include "msm_gpu.h"
16 #include "msm_kms.h"
17 #include "msm_debugfs.h"
18 #include "disp/msm_disp_snapshot.h"
19 
20 /*
21  * GPU Snapshot:
22  */
23 
24 struct msm_gpu_show_priv {
25 	struct msm_gpu_state *state;
26 	struct drm_device *dev;
27 };
28 
29 static int msm_gpu_show(struct seq_file *m, void *arg)
30 {
31 	struct drm_printer p = drm_seq_file_printer(m);
32 	struct msm_gpu_show_priv *show_priv = m->private;
33 	struct msm_drm_private *priv = show_priv->dev->dev_private;
34 	struct msm_gpu *gpu = priv->gpu;
35 	int ret;
36 
37 	ret = mutex_lock_interruptible(&gpu->lock);
38 	if (ret)
39 		return ret;
40 
41 	drm_printf(&p, "%s Status:\n", gpu->name);
42 	gpu->funcs->show(gpu, show_priv->state, &p);
43 
44 	mutex_unlock(&gpu->lock);
45 
46 	return 0;
47 }
48 
49 static int msm_gpu_release(struct inode *inode, struct file *file)
50 {
51 	struct seq_file *m = file->private_data;
52 	struct msm_gpu_show_priv *show_priv = m->private;
53 	struct msm_drm_private *priv = show_priv->dev->dev_private;
54 	struct msm_gpu *gpu = priv->gpu;
55 
56 	mutex_lock(&gpu->lock);
57 	gpu->funcs->gpu_state_put(show_priv->state);
58 	mutex_unlock(&gpu->lock);
59 
60 	kfree(show_priv);
61 
62 	return single_release(inode, file);
63 }
64 
65 static int msm_gpu_open(struct inode *inode, struct file *file)
66 {
67 	struct drm_device *dev = inode->i_private;
68 	struct msm_drm_private *priv = dev->dev_private;
69 	struct msm_gpu *gpu = priv->gpu;
70 	struct msm_gpu_show_priv *show_priv;
71 	int ret;
72 
73 	if (!gpu || !gpu->funcs->gpu_state_get)
74 		return -ENODEV;
75 
76 	show_priv = kmalloc(sizeof(*show_priv), GFP_KERNEL);
77 	if (!show_priv)
78 		return -ENOMEM;
79 
80 	ret = mutex_lock_interruptible(&gpu->lock);
81 	if (ret)
82 		goto free_priv;
83 
84 	pm_runtime_get_sync(&gpu->pdev->dev);
85 	msm_gpu_hw_init(gpu);
86 	show_priv->state = gpu->funcs->gpu_state_get(gpu);
87 	pm_runtime_put_sync(&gpu->pdev->dev);
88 
89 	mutex_unlock(&gpu->lock);
90 
91 	if (IS_ERR(show_priv->state)) {
92 		ret = PTR_ERR(show_priv->state);
93 		goto free_priv;
94 	}
95 
96 	show_priv->dev = dev;
97 
98 	ret = single_open(file, msm_gpu_show, show_priv);
99 	if (ret)
100 		goto free_priv;
101 
102 	return 0;
103 
104 free_priv:
105 	kfree(show_priv);
106 	return ret;
107 }
108 
109 static const struct file_operations msm_gpu_fops = {
110 	.owner = THIS_MODULE,
111 	.open = msm_gpu_open,
112 	.read = seq_read,
113 	.llseek = seq_lseek,
114 	.release = msm_gpu_release,
115 };
116 
117 /*
118  * Display Snapshot:
119  */
120 
121 static int msm_kms_show(struct seq_file *m, void *arg)
122 {
123 	struct drm_printer p = drm_seq_file_printer(m);
124 	struct msm_disp_state *state = m->private;
125 
126 	msm_disp_state_print(state, &p);
127 
128 	return 0;
129 }
130 
131 static int msm_kms_release(struct inode *inode, struct file *file)
132 {
133 	struct seq_file *m = file->private_data;
134 	struct msm_disp_state *state = m->private;
135 
136 	msm_disp_state_free(state);
137 
138 	return single_release(inode, file);
139 }
140 
141 static int msm_kms_open(struct inode *inode, struct file *file)
142 {
143 	struct drm_device *dev = inode->i_private;
144 	struct msm_drm_private *priv = dev->dev_private;
145 	struct msm_disp_state *state;
146 	int ret;
147 
148 	if (!priv->kms)
149 		return -ENODEV;
150 
151 	ret = mutex_lock_interruptible(&priv->kms->dump_mutex);
152 	if (ret)
153 		return ret;
154 
155 	state = msm_disp_snapshot_state_sync(priv->kms);
156 
157 	mutex_unlock(&priv->kms->dump_mutex);
158 
159 	if (IS_ERR(state)) {
160 		return PTR_ERR(state);
161 	}
162 
163 	ret = single_open(file, msm_kms_show, state);
164 	if (ret) {
165 		msm_disp_state_free(state);
166 		return ret;
167 	}
168 
169 	return 0;
170 }
171 
172 static const struct file_operations msm_kms_fops = {
173 	.owner = THIS_MODULE,
174 	.open = msm_kms_open,
175 	.read = seq_read,
176 	.llseek = seq_lseek,
177 	.release = msm_kms_release,
178 };
179 
180 /*
181  * Other debugfs:
182  */
183 
184 static unsigned long last_shrink_freed;
185 
186 static int
187 shrink_get(void *data, u64 *val)
188 {
189 	*val = last_shrink_freed;
190 
191 	return 0;
192 }
193 
194 static int
195 shrink_set(void *data, u64 val)
196 {
197 	struct drm_device *dev = data;
198 
199 	last_shrink_freed = msm_gem_shrinker_shrink(dev, val);
200 
201 	return 0;
202 }
203 
204 DEFINE_DEBUGFS_ATTRIBUTE(shrink_fops,
205 			 shrink_get, shrink_set,
206 			 "0x%08llx\n");
207 
208 
209 static int msm_gem_show(struct seq_file *m, void *arg)
210 {
211 	struct drm_info_node *node = (struct drm_info_node *) m->private;
212 	struct drm_device *dev = node->minor->dev;
213 	struct msm_drm_private *priv = dev->dev_private;
214 	int ret;
215 
216 	ret = mutex_lock_interruptible(&priv->obj_lock);
217 	if (ret)
218 		return ret;
219 
220 	msm_gem_describe_objects(&priv->objects, m);
221 
222 	mutex_unlock(&priv->obj_lock);
223 
224 	return 0;
225 }
226 
227 static int msm_mm_show(struct seq_file *m, void *arg)
228 {
229 	struct drm_info_node *node = (struct drm_info_node *) m->private;
230 	struct drm_device *dev = node->minor->dev;
231 	struct drm_printer p = drm_seq_file_printer(m);
232 
233 	drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
234 
235 	return 0;
236 }
237 
238 static int msm_fb_show(struct seq_file *m, void *arg)
239 {
240 	struct drm_info_node *node = (struct drm_info_node *) m->private;
241 	struct drm_device *dev = node->minor->dev;
242 	struct msm_drm_private *priv = dev->dev_private;
243 	struct drm_framebuffer *fb, *fbdev_fb = NULL;
244 
245 	if (priv->fbdev) {
246 		seq_printf(m, "fbcon ");
247 		fbdev_fb = priv->fbdev->fb;
248 		msm_framebuffer_describe(fbdev_fb, m);
249 	}
250 
251 	mutex_lock(&dev->mode_config.fb_lock);
252 	list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
253 		if (fb == fbdev_fb)
254 			continue;
255 
256 		seq_printf(m, "user ");
257 		msm_framebuffer_describe(fb, m);
258 	}
259 	mutex_unlock(&dev->mode_config.fb_lock);
260 
261 	return 0;
262 }
263 
264 static struct drm_info_list msm_debugfs_list[] = {
265 		{"gem", msm_gem_show},
266 		{ "mm", msm_mm_show },
267 		{ "fb", msm_fb_show },
268 };
269 
270 static int late_init_minor(struct drm_minor *minor)
271 {
272 	int ret;
273 
274 	if (!minor)
275 		return 0;
276 
277 	ret = msm_rd_debugfs_init(minor);
278 	if (ret) {
279 		DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n");
280 		return ret;
281 	}
282 
283 	ret = msm_perf_debugfs_init(minor);
284 	if (ret) {
285 		DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n");
286 		return ret;
287 	}
288 
289 	return 0;
290 }
291 
292 int msm_debugfs_late_init(struct drm_device *dev)
293 {
294 	int ret;
295 	ret = late_init_minor(dev->primary);
296 	if (ret)
297 		return ret;
298 	ret = late_init_minor(dev->render);
299 	return ret;
300 }
301 
302 void msm_debugfs_init(struct drm_minor *minor)
303 {
304 	struct drm_device *dev = minor->dev;
305 	struct msm_drm_private *priv = dev->dev_private;
306 
307 	drm_debugfs_create_files(msm_debugfs_list,
308 				 ARRAY_SIZE(msm_debugfs_list),
309 				 minor->debugfs_root, minor);
310 
311 	debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
312 		dev, &msm_gpu_fops);
313 
314 	debugfs_create_file("kms", S_IRUSR, minor->debugfs_root,
315 		dev, &msm_kms_fops);
316 
317 	debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root,
318 		&priv->hangcheck_period);
319 
320 	debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root,
321 		&priv->disable_err_irq);
322 
323 	debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root,
324 		dev, &shrink_fops);
325 
326 	if (priv->kms && priv->kms->funcs->debugfs_init)
327 		priv->kms->funcs->debugfs_init(priv->kms, minor);
328 }
329 #endif
330 
331