]>
Commit | Line | Data |
---|---|---|
caab277b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
edcd60ce RC |
2 | /* |
3 | * Copyright (C) 2013-2016 Red Hat | |
4 | * Author: Rob Clark <robdclark@gmail.com> | |
edcd60ce RC |
5 | */ |
6 | ||
7 | #ifdef CONFIG_DEBUG_FS | |
4f776f45 | 8 | #include <linux/debugfs.h> |
edcd60ce RC |
9 | #include "msm_drv.h" |
10 | #include "msm_gpu.h" | |
bc5289ee | 11 | #include "msm_kms.h" |
c170a14e | 12 | #include "msm_debugfs.h" |
edcd60ce | 13 | |
4f776f45 JC |
14 | struct msm_gpu_show_priv { |
15 | struct msm_gpu_state *state; | |
16 | struct drm_device *dev; | |
17 | }; | |
18 | ||
19 | static int msm_gpu_show(struct seq_file *m, void *arg) | |
20 | { | |
c0fec7f5 | 21 | struct drm_printer p = drm_seq_file_printer(m); |
4f776f45 JC |
22 | struct msm_gpu_show_priv *show_priv = m->private; |
23 | struct msm_drm_private *priv = show_priv->dev->dev_private; | |
24 | struct msm_gpu *gpu = priv->gpu; | |
25 | int ret; | |
26 | ||
27 | ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); | |
28 | if (ret) | |
29 | return ret; | |
30 | ||
c0fec7f5 JC |
31 | drm_printf(&p, "%s Status:\n", gpu->name); |
32 | gpu->funcs->show(gpu, show_priv->state, &p); | |
4f776f45 JC |
33 | |
34 | mutex_unlock(&show_priv->dev->struct_mutex); | |
35 | ||
36 | return 0; | |
37 | } | |
38 | ||
39 | static int msm_gpu_release(struct inode *inode, struct file *file) | |
40 | { | |
41 | struct seq_file *m = file->private_data; | |
42 | struct msm_gpu_show_priv *show_priv = m->private; | |
43 | struct msm_drm_private *priv = show_priv->dev->dev_private; | |
44 | struct msm_gpu *gpu = priv->gpu; | |
45 | int ret; | |
46 | ||
47 | ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); | |
48 | if (ret) | |
49 | return ret; | |
50 | ||
51 | gpu->funcs->gpu_state_put(show_priv->state); | |
52 | mutex_unlock(&show_priv->dev->struct_mutex); | |
53 | ||
54 | kfree(show_priv); | |
55 | ||
56 | return single_release(inode, file); | |
57 | } | |
58 | ||
59 | static int msm_gpu_open(struct inode *inode, struct file *file) | |
edcd60ce | 60 | { |
4f776f45 | 61 | struct drm_device *dev = inode->i_private; |
edcd60ce RC |
62 | struct msm_drm_private *priv = dev->dev_private; |
63 | struct msm_gpu *gpu = priv->gpu; | |
4f776f45 JC |
64 | struct msm_gpu_show_priv *show_priv; |
65 | int ret; | |
edcd60ce | 66 | |
b02872df | 67 | if (!gpu || !gpu->funcs->gpu_state_get) |
4f776f45 JC |
68 | return -ENODEV; |
69 | ||
70 | show_priv = kmalloc(sizeof(*show_priv), GFP_KERNEL); | |
71 | if (!show_priv) | |
72 | return -ENOMEM; | |
73 | ||
74 | ret = mutex_lock_interruptible(&dev->struct_mutex); | |
75 | if (ret) | |
51270de9 | 76 | goto free_priv; |
4f776f45 JC |
77 | |
78 | pm_runtime_get_sync(&gpu->pdev->dev); | |
79 | show_priv->state = gpu->funcs->gpu_state_get(gpu); | |
80 | pm_runtime_put_sync(&gpu->pdev->dev); | |
81 | ||
82 | mutex_unlock(&dev->struct_mutex); | |
83 | ||
84 | if (IS_ERR(show_priv->state)) { | |
85 | ret = PTR_ERR(show_priv->state); | |
51270de9 | 86 | goto free_priv; |
edcd60ce RC |
87 | } |
88 | ||
4f776f45 JC |
89 | show_priv->dev = dev; |
90 | ||
51270de9 DC |
91 | ret = single_open(file, msm_gpu_show, show_priv); |
92 | if (ret) | |
93 | goto free_priv; | |
94 | ||
95 | return 0; | |
96 | ||
97 | free_priv: | |
98 | kfree(show_priv); | |
99 | return ret; | |
edcd60ce RC |
100 | } |
101 | ||
4f776f45 JC |
102 | static const struct file_operations msm_gpu_fops = { |
103 | .owner = THIS_MODULE, | |
104 | .open = msm_gpu_open, | |
105 | .read = seq_read, | |
106 | .llseek = seq_lseek, | |
107 | .release = msm_gpu_release, | |
108 | }; | |
109 | ||
edcd60ce RC |
110 | static int msm_gem_show(struct drm_device *dev, struct seq_file *m) |
111 | { | |
112 | struct msm_drm_private *priv = dev->dev_private; | |
113 | struct msm_gpu *gpu = priv->gpu; | |
114 | ||
115 | if (gpu) { | |
116 | seq_printf(m, "Active Objects (%s):\n", gpu->name); | |
117 | msm_gem_describe_objects(&gpu->active_list, m); | |
118 | } | |
119 | ||
120 | seq_printf(m, "Inactive Objects:\n"); | |
121 | msm_gem_describe_objects(&priv->inactive_list, m); | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static int msm_mm_show(struct drm_device *dev, struct seq_file *m) | |
127 | { | |
b5c3714f DV |
128 | struct drm_printer p = drm_seq_file_printer(m); |
129 | ||
130 | drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); | |
131 | ||
132 | return 0; | |
edcd60ce RC |
133 | } |
134 | ||
135 | static int msm_fb_show(struct drm_device *dev, struct seq_file *m) | |
136 | { | |
137 | struct msm_drm_private *priv = dev->dev_private; | |
138 | struct drm_framebuffer *fb, *fbdev_fb = NULL; | |
139 | ||
140 | if (priv->fbdev) { | |
141 | seq_printf(m, "fbcon "); | |
142 | fbdev_fb = priv->fbdev->fb; | |
143 | msm_framebuffer_describe(fbdev_fb, m); | |
144 | } | |
145 | ||
146 | mutex_lock(&dev->mode_config.fb_lock); | |
147 | list_for_each_entry(fb, &dev->mode_config.fb_list, head) { | |
148 | if (fb == fbdev_fb) | |
149 | continue; | |
150 | ||
151 | seq_printf(m, "user "); | |
152 | msm_framebuffer_describe(fb, m); | |
153 | } | |
154 | mutex_unlock(&dev->mode_config.fb_lock); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | static int show_locked(struct seq_file *m, void *arg) | |
160 | { | |
161 | struct drm_info_node *node = (struct drm_info_node *) m->private; | |
162 | struct drm_device *dev = node->minor->dev; | |
163 | int (*show)(struct drm_device *dev, struct seq_file *m) = | |
164 | node->info_ent->data; | |
165 | int ret; | |
166 | ||
167 | ret = mutex_lock_interruptible(&dev->struct_mutex); | |
168 | if (ret) | |
169 | return ret; | |
170 | ||
171 | ret = show(dev, m); | |
172 | ||
173 | mutex_unlock(&dev->struct_mutex); | |
174 | ||
175 | return ret; | |
176 | } | |
177 | ||
178 | static struct drm_info_list msm_debugfs_list[] = { | |
edcd60ce RC |
179 | {"gem", show_locked, 0, msm_gem_show}, |
180 | { "mm", show_locked, 0, msm_mm_show }, | |
181 | { "fb", show_locked, 0, msm_fb_show }, | |
182 | }; | |
183 | ||
184 | static int late_init_minor(struct drm_minor *minor) | |
185 | { | |
186 | int ret; | |
187 | ||
188 | if (!minor) | |
189 | return 0; | |
190 | ||
191 | ret = msm_rd_debugfs_init(minor); | |
192 | if (ret) { | |
6a41da17 | 193 | DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n"); |
edcd60ce RC |
194 | return ret; |
195 | } | |
196 | ||
197 | ret = msm_perf_debugfs_init(minor); | |
198 | if (ret) { | |
6a41da17 | 199 | DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n"); |
edcd60ce RC |
200 | return ret; |
201 | } | |
202 | ||
203 | return 0; | |
204 | } | |
205 | ||
206 | int msm_debugfs_late_init(struct drm_device *dev) | |
207 | { | |
208 | int ret; | |
209 | ret = late_init_minor(dev->primary); | |
210 | if (ret) | |
211 | return ret; | |
212 | ret = late_init_minor(dev->render); | |
edcd60ce RC |
213 | return ret; |
214 | } | |
215 | ||
216 | int msm_debugfs_init(struct drm_minor *minor) | |
217 | { | |
218 | struct drm_device *dev = minor->dev; | |
bc5289ee | 219 | struct msm_drm_private *priv = dev->dev_private; |
edcd60ce RC |
220 | int ret; |
221 | ||
222 | ret = drm_debugfs_create_files(msm_debugfs_list, | |
223 | ARRAY_SIZE(msm_debugfs_list), | |
224 | minor->debugfs_root, minor); | |
225 | ||
226 | if (ret) { | |
6a41da17 | 227 | DRM_DEV_ERROR(dev->dev, "could not install msm_debugfs_list\n"); |
edcd60ce RC |
228 | return ret; |
229 | } | |
230 | ||
4f776f45 JC |
231 | debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, |
232 | dev, &msm_gpu_fops); | |
233 | ||
e6f6d63e | 234 | if (priv->kms && priv->kms->funcs->debugfs_init) { |
bc5289ee | 235 | ret = priv->kms->funcs->debugfs_init(priv->kms, minor); |
331dc0bc RC |
236 | if (ret) |
237 | return ret; | |
238 | } | |
bc5289ee RC |
239 | |
240 | return ret; | |
edcd60ce | 241 | } |
edcd60ce RC |
242 | #endif |
243 |