diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_debugfs.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_debugfs.c | 320 |
1 files changed, 243 insertions, 77 deletions
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index fb423d309e91..97dc70876442 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -1,26 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef CONFIG_DEBUG_FS + #include <linux/debugfs.h> +#include <linux/fault-inject.h> + +#include <drm/drm_debugfs.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_framebuffer.h> + #include "msm_drv.h" #include "msm_gpu.h" #include "msm_kms.h" #include "msm_debugfs.h" +#include "disp/msm_disp_snapshot.h" + +/* + * GPU Snapshot: + */ struct msm_gpu_show_priv { struct msm_gpu_state *state; @@ -35,14 +37,14 @@ static int msm_gpu_show(struct seq_file *m, void *arg) struct msm_gpu *gpu = priv->gpu; int ret; - ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); + ret = mutex_lock_interruptible(&gpu->lock); if (ret) return ret; drm_printf(&p, "%s Status:\n", gpu->name); gpu->funcs->show(gpu, show_priv->state, &p); - mutex_unlock(&show_priv->dev->struct_mutex); + mutex_unlock(&gpu->lock); return 0; } @@ -53,14 +55,10 @@ static int msm_gpu_release(struct inode *inode, struct file *file) struct msm_gpu_show_priv *show_priv = m->private; struct msm_drm_private *priv = show_priv->dev->dev_private; struct msm_gpu *gpu = priv->gpu; - int ret; - - ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); - if (ret) - return ret; + mutex_lock(&gpu->lock); gpu->funcs->gpu_state_put(show_priv->state); - mutex_unlock(&show_priv->dev->struct_mutex); + mutex_unlock(&gpu->lock); kfree(show_priv); @@ -75,22 +73,23 @@ static int msm_gpu_open(struct inode *inode, struct file *file) struct msm_gpu_show_priv *show_priv; int ret; - if (!gpu) + if (!gpu || !gpu->funcs->gpu_state_get) return -ENODEV; show_priv = kmalloc(sizeof(*show_priv), GFP_KERNEL); if (!show_priv) return -ENOMEM; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&gpu->lock); if (ret) goto free_priv; pm_runtime_get_sync(&gpu->pdev->dev); + msm_gpu_hw_init(gpu); show_priv->state = gpu->funcs->gpu_state_get(gpu); pm_runtime_put_sync(&gpu->pdev->dev); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); if (IS_ERR(show_priv->state)) { ret = PTR_ERR(show_priv->state); @@ -118,96 +117,236 @@ static const struct file_operations msm_gpu_fops = { .release = msm_gpu_release, }; -static int msm_gem_show(struct drm_device *dev, struct seq_file *m) +#ifdef CONFIG_DRM_MSM_KMS +static int msm_fb_show(struct seq_file *m, void *arg) { - struct msm_drm_private *priv = dev->dev_private; - struct msm_gpu *gpu = priv->gpu; + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_framebuffer *fb, *fbdev_fb = NULL; - if (gpu) { - seq_printf(m, "Active Objects (%s):\n", gpu->name); - msm_gem_describe_objects(&gpu->active_list, m); + if (dev->fb_helper && dev->fb_helper->fb) { + seq_puts(m, "fbcon "); + fbdev_fb = dev->fb_helper->fb; + msm_framebuffer_describe(fbdev_fb, m); } - seq_printf(m, "Inactive Objects:\n"); - msm_gem_describe_objects(&priv->inactive_list, m); + mutex_lock(&dev->mode_config.fb_lock); + list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + if (fb == fbdev_fb) + continue; + + seq_puts(m, "user "); + msm_framebuffer_describe(fb, m); + } + mutex_unlock(&dev->mode_config.fb_lock); return 0; } -static int msm_mm_show(struct drm_device *dev, struct seq_file *m) +static struct drm_info_list msm_kms_debugfs_list[] = { + { "fb", msm_fb_show }, +}; + +/* + * Display Snapshot: + */ + +static int msm_kms_show(struct seq_file *m, void *arg) { struct drm_printer p = drm_seq_file_printer(m); + struct msm_disp_state *state = m->private; - drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); + msm_disp_state_print(state, &p); return 0; } -static int msm_fb_show(struct drm_device *dev, struct seq_file *m) +static int msm_kms_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = file->private_data; + struct msm_disp_state *state = m->private; + + msm_disp_state_free(state); + + return single_release(inode, file); +} + +static int msm_kms_open(struct inode *inode, struct file *file) { + struct drm_device *dev = inode->i_private; struct msm_drm_private *priv = dev->dev_private; - struct drm_framebuffer *fb, *fbdev_fb = NULL; + struct msm_disp_state *state; + int ret; - if (priv->fbdev) { - seq_printf(m, "fbcon "); - fbdev_fb = priv->fbdev->fb; - msm_framebuffer_describe(fbdev_fb, m); - } + if (!priv->kms) + return -ENODEV; - mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (fb == fbdev_fb) - continue; + ret = mutex_lock_interruptible(&priv->kms->dump_mutex); + if (ret) + return ret; - seq_printf(m, "user "); - msm_framebuffer_describe(fb, m); + state = msm_disp_snapshot_state_sync(priv->kms); + + mutex_unlock(&priv->kms->dump_mutex); + + if (IS_ERR(state)) { + return PTR_ERR(state); + } + + ret = single_open(file, msm_kms_show, state); + if (ret) { + msm_disp_state_free(state); + return ret; } - mutex_unlock(&dev->mode_config.fb_lock); return 0; } -static int show_locked(struct seq_file *m, void *arg) +static const struct file_operations msm_kms_fops = { + .owner = THIS_MODULE, + .open = msm_kms_open, + .read = seq_read, + .llseek = seq_lseek, + .release = msm_kms_release, +}; + +static void msm_debugfs_kms_init(struct drm_minor *minor) { - struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + + drm_debugfs_create_files(msm_kms_debugfs_list, + ARRAY_SIZE(msm_kms_debugfs_list), + minor->debugfs_root, minor); + debugfs_create_file("kms", 0400, minor->debugfs_root, + dev, &msm_kms_fops); + + if (priv->kms->funcs->debugfs_init) + priv->kms->funcs->debugfs_init(priv->kms, minor); + +} +#else /* ! CONFIG_DRM_MSM_KMS */ +static void msm_debugfs_kms_init(struct drm_minor *minor) +{ +} +#endif + +/* + * Other debugfs: + */ + +static unsigned long last_shrink_freed; + +static int +shrink_get(void *data, u64 *val) +{ + *val = last_shrink_freed; + + return 0; +} + +static int +shrink_set(void *data, u64 val) +{ + struct drm_device *dev = data; + + last_shrink_freed = msm_gem_shrinker_shrink(dev, val); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(shrink_fops, + shrink_get, shrink_set, + "0x%08llx\n"); + +/* + * Return the number of microseconds to wait until stall-on-fault is + * re-enabled. If 0 then it is already enabled or will be re-enabled on the + * next submit (unless there's a leftover devcoredump). This is useful for + * kernel tests that intentionally produce a fault and check the devcoredump to + * wait until the cooldown period is over. + */ + +static int +stall_reenable_time_get(void *data, u64 *val) +{ + struct msm_drm_private *priv = data; + unsigned long irq_flags; + + spin_lock_irqsave(&priv->fault_stall_lock, irq_flags); + + if (priv->stall_enabled) + *val = 0; + else + *val = max(ktime_us_delta(priv->stall_reenable_time, ktime_get()), 0); + + spin_unlock_irqrestore(&priv->fault_stall_lock, irq_flags); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(stall_reenable_time_fops, + stall_reenable_time_get, NULL, + "%lld\n"); + +static int msm_gem_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = m->private; struct drm_device *dev = node->minor->dev; - int (*show)(struct drm_device *dev, struct seq_file *m) = - node->info_ent->data; + struct msm_drm_private *priv = dev->dev_private; int ret; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&priv->obj_lock); if (ret) return ret; - ret = show(dev, m); + msm_gem_describe_objects(&priv->objects, m); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&priv->obj_lock); - return ret; + return 0; +} + +static int msm_mm_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + + drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); + + return 0; } static struct drm_info_list msm_debugfs_list[] = { - {"gem", show_locked, 0, msm_gem_show}, - { "mm", show_locked, 0, msm_mm_show }, - { "fb", show_locked, 0, msm_fb_show }, + {"gem", msm_gem_show}, + { "mm", msm_mm_show }, }; static int late_init_minor(struct drm_minor *minor) { + struct drm_device *dev; + struct msm_drm_private *priv; int ret; if (!minor) return 0; + dev = minor->dev; + priv = dev->dev_private; + + if (!priv->gpu_pdev) + return 0; + ret = msm_rd_debugfs_init(minor); if (ret) { - DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n"); + DRM_DEV_ERROR(dev->dev, "could not install rd debugfs\n"); return ret; } ret = msm_perf_debugfs_init(minor); if (ret) { - DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n"); + DRM_DEV_ERROR(dev->dev, "could not install perf debugfs\n"); return ret; } @@ -224,31 +363,58 @@ int msm_debugfs_late_init(struct drm_device *dev) return ret; } -int msm_debugfs_init(struct drm_minor *minor) +static void msm_debugfs_gpu_init(struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct msm_drm_private *priv = dev->dev_private; - int ret; - - ret = drm_debugfs_create_files(msm_debugfs_list, - ARRAY_SIZE(msm_debugfs_list), - minor->debugfs_root, minor); - - if (ret) { - DRM_DEV_ERROR(dev->dev, "could not install msm_debugfs_list\n"); - return ret; - } + struct dentry *gpu_devfreq; debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, dev, &msm_gpu_fops); - if (priv->kms && priv->kms->funcs->debugfs_init) { - ret = priv->kms->funcs->debugfs_init(priv->kms, minor); - if (ret) - return ret; - } + debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root, + &priv->hangcheck_period); - return ret; + debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root, + &priv->disable_err_irq); + + debugfs_create_file("stall_reenable_time_us", 0400, minor->debugfs_root, + priv, &stall_reenable_time_fops); + + gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root); + + debugfs_create_bool("idle_clamp",0600, gpu_devfreq, + &priv->gpu_clamp_to_idle); + + debugfs_create_u32("upthreshold",0600, gpu_devfreq, + &priv->gpu_devfreq_config.upthreshold); + + debugfs_create_u32("downdifferential",0600, gpu_devfreq, + &priv->gpu_devfreq_config.downdifferential); +} + +void msm_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + + drm_debugfs_create_files(msm_debugfs_list, + ARRAY_SIZE(msm_debugfs_list), + minor->debugfs_root, minor); + + if (priv->gpu_pdev) + msm_debugfs_gpu_init(minor); + + if (priv->kms) + msm_debugfs_kms_init(minor); + + debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, + dev, &shrink_fops); + + fault_create_debugfs_attr("fail_gem_alloc", minor->debugfs_root, + &fail_gem_alloc); + fault_create_debugfs_attr("fail_gem_iova", minor->debugfs_root, + &fail_gem_iova); } #endif |
