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