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