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