GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / gpu / drm / msm / msm_debugfs.c
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