linux/drivers/gpu/drm/msm/msm_debugfs.c
<<
>>
Prefs
   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        show_priv->state = gpu->funcs->gpu_state_get(gpu);
  81        pm_runtime_put_sync(&gpu->pdev->dev);
  82
  83        mutex_unlock(&dev->struct_mutex);
  84
  85        if (IS_ERR(show_priv->state)) {
  86                ret = PTR_ERR(show_priv->state);
  87                goto free_priv;
  88        }
  89
  90        show_priv->dev = dev;
  91
  92        ret = single_open(file, msm_gpu_show, show_priv);
  93        if (ret)
  94                goto free_priv;
  95
  96        return 0;
  97
  98free_priv:
  99        kfree(show_priv);
 100        return ret;
 101}
 102
 103static const struct file_operations msm_gpu_fops = {
 104        .owner = THIS_MODULE,
 105        .open = msm_gpu_open,
 106        .read = seq_read,
 107        .llseek = seq_lseek,
 108        .release = msm_gpu_release,
 109};
 110
 111static unsigned long last_shrink_freed;
 112
 113static int
 114shrink_get(void *data, u64 *val)
 115{
 116        *val = last_shrink_freed;
 117
 118        return 0;
 119}
 120
 121static int
 122shrink_set(void *data, u64 val)
 123{
 124        struct drm_device *dev = data;
 125
 126        last_shrink_freed = msm_gem_shrinker_shrink(dev, val);
 127
 128        return 0;
 129}
 130
 131DEFINE_SIMPLE_ATTRIBUTE(shrink_fops,
 132                        shrink_get, shrink_set,
 133                        "0x%08llx\n");
 134
 135
 136static int msm_gem_show(struct drm_device *dev, struct seq_file *m)
 137{
 138        struct msm_drm_private *priv = dev->dev_private;
 139        int ret;
 140
 141        ret = mutex_lock_interruptible(&priv->obj_lock);
 142        if (ret)
 143                return ret;
 144
 145        msm_gem_describe_objects(&priv->objects, m);
 146
 147        mutex_unlock(&priv->obj_lock);
 148
 149        return 0;
 150}
 151
 152static int msm_mm_show(struct drm_device *dev, struct seq_file *m)
 153{
 154        struct drm_printer p = drm_seq_file_printer(m);
 155
 156        drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
 157
 158        return 0;
 159}
 160
 161static int msm_fb_show(struct drm_device *dev, struct seq_file *m)
 162{
 163        struct msm_drm_private *priv = dev->dev_private;
 164        struct drm_framebuffer *fb, *fbdev_fb = NULL;
 165
 166        if (priv->fbdev) {
 167                seq_printf(m, "fbcon ");
 168                fbdev_fb = priv->fbdev->fb;
 169                msm_framebuffer_describe(fbdev_fb, m);
 170        }
 171
 172        mutex_lock(&dev->mode_config.fb_lock);
 173        list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
 174                if (fb == fbdev_fb)
 175                        continue;
 176
 177                seq_printf(m, "user ");
 178                msm_framebuffer_describe(fb, m);
 179        }
 180        mutex_unlock(&dev->mode_config.fb_lock);
 181
 182        return 0;
 183}
 184
 185static int show_locked(struct seq_file *m, void *arg)
 186{
 187        struct drm_info_node *node = (struct drm_info_node *) m->private;
 188        struct drm_device *dev = node->minor->dev;
 189        int (*show)(struct drm_device *dev, struct seq_file *m) =
 190                        node->info_ent->data;
 191        int ret;
 192
 193        ret = mutex_lock_interruptible(&dev->struct_mutex);
 194        if (ret)
 195                return ret;
 196
 197        ret = show(dev, m);
 198
 199        mutex_unlock(&dev->struct_mutex);
 200
 201        return ret;
 202}
 203
 204static struct drm_info_list msm_debugfs_list[] = {
 205                {"gem", show_locked, 0, msm_gem_show},
 206                { "mm", show_locked, 0, msm_mm_show },
 207                { "fb", show_locked, 0, msm_fb_show },
 208};
 209
 210static int late_init_minor(struct drm_minor *minor)
 211{
 212        int ret;
 213
 214        if (!minor)
 215                return 0;
 216
 217        ret = msm_rd_debugfs_init(minor);
 218        if (ret) {
 219                DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n");
 220                return ret;
 221        }
 222
 223        ret = msm_perf_debugfs_init(minor);
 224        if (ret) {
 225                DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n");
 226                return ret;
 227        }
 228
 229        return 0;
 230}
 231
 232int msm_debugfs_late_init(struct drm_device *dev)
 233{
 234        int ret;
 235        ret = late_init_minor(dev->primary);
 236        if (ret)
 237                return ret;
 238        ret = late_init_minor(dev->render);
 239        return ret;
 240}
 241
 242void msm_debugfs_init(struct drm_minor *minor)
 243{
 244        struct drm_device *dev = minor->dev;
 245        struct msm_drm_private *priv = dev->dev_private;
 246
 247        drm_debugfs_create_files(msm_debugfs_list,
 248                                 ARRAY_SIZE(msm_debugfs_list),
 249                                 minor->debugfs_root, minor);
 250
 251        debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
 252                dev, &msm_gpu_fops);
 253
 254        debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root,
 255                &priv->hangcheck_period);
 256
 257        debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root,
 258                dev, &shrink_fops);
 259
 260        if (priv->kms && priv->kms->funcs->debugfs_init)
 261                priv->kms->funcs->debugfs_init(priv->kms, minor);
 262}
 263#endif
 264
 265