367 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013-2016 Red Hat4 * Author: Rob Clark <robdclark@gmail.com>5 */6 7#ifdef CONFIG_DEBUG_FS8 9#include <linux/debugfs.h>10#include <linux/fault-inject.h>11 12#include <drm/drm_debugfs.h>13#include <drm/drm_fb_helper.h>14#include <drm/drm_file.h>15#include <drm/drm_framebuffer.h>16 17#include "msm_drv.h"18#include "msm_gpu.h"19#include "msm_kms.h"20#include "msm_debugfs.h"21#include "disp/msm_disp_snapshot.h"22 23/*24 * GPU Snapshot:25 */26 27struct msm_gpu_show_priv {28 struct msm_gpu_state *state;29 struct drm_device *dev;30};31 32static int msm_gpu_show(struct seq_file *m, void *arg)33{34 struct drm_printer p = drm_seq_file_printer(m);35 struct msm_gpu_show_priv *show_priv = m->private;36 struct msm_drm_private *priv = show_priv->dev->dev_private;37 struct msm_gpu *gpu = priv->gpu;38 int ret;39 40 ret = mutex_lock_interruptible(&gpu->lock);41 if (ret)42 return ret;43 44 drm_printf(&p, "%s Status:\n", gpu->name);45 gpu->funcs->show(gpu, show_priv->state, &p);46 47 mutex_unlock(&gpu->lock);48 49 return 0;50}51 52static int msm_gpu_release(struct inode *inode, struct file *file)53{54 struct seq_file *m = file->private_data;55 struct msm_gpu_show_priv *show_priv = m->private;56 struct msm_drm_private *priv = show_priv->dev->dev_private;57 struct msm_gpu *gpu = priv->gpu;58 59 mutex_lock(&gpu->lock);60 gpu->funcs->gpu_state_put(show_priv->state);61 mutex_unlock(&gpu->lock);62 63 kfree(show_priv);64 65 return single_release(inode, file);66}67 68static int msm_gpu_open(struct inode *inode, struct file *file)69{70 struct drm_device *dev = inode->i_private;71 struct msm_drm_private *priv = dev->dev_private;72 struct msm_gpu *gpu = priv->gpu;73 struct msm_gpu_show_priv *show_priv;74 int ret;75 76 if (!gpu || !gpu->funcs->gpu_state_get)77 return -ENODEV;78 79 show_priv = kmalloc(sizeof(*show_priv), GFP_KERNEL);80 if (!show_priv)81 return -ENOMEM;82 83 ret = mutex_lock_interruptible(&gpu->lock);84 if (ret)85 goto free_priv;86 87 pm_runtime_get_sync(&gpu->pdev->dev);88 msm_gpu_hw_init(gpu);89 show_priv->state = gpu->funcs->gpu_state_get(gpu);90 pm_runtime_put_sync(&gpu->pdev->dev);91 92 mutex_unlock(&gpu->lock);93 94 if (IS_ERR(show_priv->state)) {95 ret = PTR_ERR(show_priv->state);96 goto free_priv;97 }98 99 show_priv->dev = dev;100 101 ret = single_open(file, msm_gpu_show, show_priv);102 if (ret)103 goto free_priv;104 105 return 0;106 107free_priv:108 kfree(show_priv);109 return ret;110}111 112static const struct file_operations msm_gpu_fops = {113 .owner = THIS_MODULE,114 .open = msm_gpu_open,115 .read = seq_read,116 .llseek = seq_lseek,117 .release = msm_gpu_release,118};119 120/*121 * Display Snapshot:122 */123 124static int msm_kms_show(struct seq_file *m, void *arg)125{126 struct drm_printer p = drm_seq_file_printer(m);127 struct msm_disp_state *state = m->private;128 129 msm_disp_state_print(state, &p);130 131 return 0;132}133 134static int msm_kms_release(struct inode *inode, struct file *file)135{136 struct seq_file *m = file->private_data;137 struct msm_disp_state *state = m->private;138 139 msm_disp_state_free(state);140 141 return single_release(inode, file);142}143 144static int msm_kms_open(struct inode *inode, struct file *file)145{146 struct drm_device *dev = inode->i_private;147 struct msm_drm_private *priv = dev->dev_private;148 struct msm_disp_state *state;149 int ret;150 151 if (!priv->kms)152 return -ENODEV;153 154 ret = mutex_lock_interruptible(&priv->kms->dump_mutex);155 if (ret)156 return ret;157 158 state = msm_disp_snapshot_state_sync(priv->kms);159 160 mutex_unlock(&priv->kms->dump_mutex);161 162 if (IS_ERR(state)) {163 return PTR_ERR(state);164 }165 166 ret = single_open(file, msm_kms_show, state);167 if (ret) {168 msm_disp_state_free(state);169 return ret;170 }171 172 return 0;173}174 175static const struct file_operations msm_kms_fops = {176 .owner = THIS_MODULE,177 .open = msm_kms_open,178 .read = seq_read,179 .llseek = seq_lseek,180 .release = msm_kms_release,181};182 183/*184 * Other debugfs:185 */186 187static unsigned long last_shrink_freed;188 189static int190shrink_get(void *data, u64 *val)191{192 *val = last_shrink_freed;193 194 return 0;195}196 197static int198shrink_set(void *data, u64 val)199{200 struct drm_device *dev = data;201 202 last_shrink_freed = msm_gem_shrinker_shrink(dev, val);203 204 return 0;205}206 207DEFINE_DEBUGFS_ATTRIBUTE(shrink_fops,208 shrink_get, shrink_set,209 "0x%08llx\n");210 211 212static int msm_gem_show(struct seq_file *m, void *arg)213{214 struct drm_info_node *node = m->private;215 struct drm_device *dev = node->minor->dev;216 struct msm_drm_private *priv = dev->dev_private;217 int ret;218 219 ret = mutex_lock_interruptible(&priv->obj_lock);220 if (ret)221 return ret;222 223 msm_gem_describe_objects(&priv->objects, m);224 225 mutex_unlock(&priv->obj_lock);226 227 return 0;228}229 230static int msm_mm_show(struct seq_file *m, void *arg)231{232 struct drm_info_node *node = m->private;233 struct drm_device *dev = node->minor->dev;234 struct drm_printer p = drm_seq_file_printer(m);235 236 drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);237 238 return 0;239}240 241static int msm_fb_show(struct seq_file *m, void *arg)242{243 struct drm_info_node *node = m->private;244 struct drm_device *dev = node->minor->dev;245 struct drm_framebuffer *fb, *fbdev_fb = NULL;246 247 if (dev->fb_helper && dev->fb_helper->fb) {248 seq_printf(m, "fbcon ");249 fbdev_fb = dev->fb_helper->fb;250 msm_framebuffer_describe(fbdev_fb, m);251 }252 253 mutex_lock(&dev->mode_config.fb_lock);254 list_for_each_entry(fb, &dev->mode_config.fb_list, head) {255 if (fb == fbdev_fb)256 continue;257 258 seq_printf(m, "user ");259 msm_framebuffer_describe(fb, m);260 }261 mutex_unlock(&dev->mode_config.fb_lock);262 263 return 0;264}265 266static struct drm_info_list msm_debugfs_list[] = {267 {"gem", msm_gem_show},268 { "mm", msm_mm_show },269};270 271static struct drm_info_list msm_kms_debugfs_list[] = {272 { "fb", msm_fb_show },273};274 275static int late_init_minor(struct drm_minor *minor)276{277 int ret;278 279 if (!minor)280 return 0;281 282 ret = msm_rd_debugfs_init(minor);283 if (ret) {284 DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n");285 return ret;286 }287 288 ret = msm_perf_debugfs_init(minor);289 if (ret) {290 DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n");291 return ret;292 }293 294 return 0;295}296 297int msm_debugfs_late_init(struct drm_device *dev)298{299 int ret;300 ret = late_init_minor(dev->primary);301 if (ret)302 return ret;303 ret = late_init_minor(dev->render);304 return ret;305}306 307static void msm_debugfs_gpu_init(struct drm_minor *minor)308{309 struct drm_device *dev = minor->dev;310 struct msm_drm_private *priv = dev->dev_private;311 struct dentry *gpu_devfreq;312 313 debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,314 dev, &msm_gpu_fops);315 316 debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root,317 &priv->hangcheck_period);318 319 debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root,320 &priv->disable_err_irq);321 322 gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root);323 324 debugfs_create_bool("idle_clamp",0600, gpu_devfreq,325 &priv->gpu_clamp_to_idle);326 327 debugfs_create_u32("upthreshold",0600, gpu_devfreq,328 &priv->gpu_devfreq_config.upthreshold);329 330 debugfs_create_u32("downdifferential",0600, gpu_devfreq,331 &priv->gpu_devfreq_config.downdifferential);332}333 334void msm_debugfs_init(struct drm_minor *minor)335{336 struct drm_device *dev = minor->dev;337 struct msm_drm_private *priv = dev->dev_private;338 339 drm_debugfs_create_files(msm_debugfs_list,340 ARRAY_SIZE(msm_debugfs_list),341 minor->debugfs_root, minor);342 343 if (priv->gpu_pdev)344 msm_debugfs_gpu_init(minor);345 346 if (priv->kms) {347 drm_debugfs_create_files(msm_kms_debugfs_list,348 ARRAY_SIZE(msm_kms_debugfs_list),349 minor->debugfs_root, minor);350 debugfs_create_file("kms", S_IRUSR, minor->debugfs_root,351 dev, &msm_kms_fops);352 }353 354 debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root,355 dev, &shrink_fops);356 357 if (priv->kms && priv->kms->funcs->debugfs_init)358 priv->kms->funcs->debugfs_init(priv->kms, minor);359 360 fault_create_debugfs_attr("fail_gem_alloc", minor->debugfs_root,361 &fail_gem_alloc);362 fault_create_debugfs_attr("fail_gem_iova", minor->debugfs_root,363 &fail_gem_iova);364}365#endif366 367