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 #include <linux/debugfs.h> 9 #include "msm_drv.h" 10 #include "msm_gpu.h" 11 #include "msm_kms.h" 12 #include "msm_debugfs.h" 13 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 { 21 struct drm_printer p = drm_seq_file_printer(m); 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 31 drm_printf(&p, "%s Status:\n", gpu->name); 32 gpu->funcs->show(gpu, show_priv->state, &p); 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) 60 { 61 struct drm_device *dev = inode->i_private; 62 struct msm_drm_private *priv = dev->dev_private; 63 struct msm_gpu *gpu = priv->gpu; 64 struct msm_gpu_show_priv *show_priv; 65 int ret; 66 67 if (!gpu || !gpu->funcs->gpu_state_get) 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) 76 goto free_priv; 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); 86 goto free_priv; 87 } 88 89 show_priv->dev = dev; 90 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; 100 } 101 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 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 { 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; 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[] = { 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) { 193 DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n"); 194 return ret; 195 } 196 197 ret = msm_perf_debugfs_init(minor); 198 if (ret) { 199 DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n"); 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); 213 return ret; 214 } 215 216 int msm_debugfs_init(struct drm_minor *minor) 217 { 218 struct drm_device *dev = minor->dev; 219 struct msm_drm_private *priv = dev->dev_private; 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) { 227 DRM_DEV_ERROR(dev->dev, "could not install msm_debugfs_list\n"); 228 return ret; 229 } 230 231 debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, 232 dev, &msm_gpu_fops); 233 234 if (priv->kms && priv->kms->funcs->debugfs_init) { 235 ret = priv->kms->funcs->debugfs_init(priv->kms, minor); 236 if (ret) 237 return ret; 238 } 239 240 return ret; 241 } 242 #endif 243 244