linux/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
   3 */
   4
   5#include <linux/types.h>
   6#include <linux/debugfs.h>
   7
   8#include <drm/drm_debugfs.h>
   9#include <drm/drm_file.h>
  10#include <drm/drm_print.h>
  11
  12#include "a5xx_gpu.h"
  13
  14static void pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
  15{
  16        int i;
  17
  18        drm_printf(p, "PFP state:\n");
  19
  20        for (i = 0; i < 36; i++) {
  21                gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
  22                drm_printf(p, "  %02x: %08x\n", i,
  23                        gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
  24        }
  25}
  26
  27static void me_print(struct msm_gpu *gpu, struct drm_printer *p)
  28{
  29        int i;
  30
  31        drm_printf(p, "ME state:\n");
  32
  33        for (i = 0; i < 29; i++) {
  34                gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
  35                drm_printf(p, "  %02x: %08x\n", i,
  36                        gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
  37        }
  38}
  39
  40static void meq_print(struct msm_gpu *gpu, struct drm_printer *p)
  41{
  42        int i;
  43
  44        drm_printf(p, "MEQ state:\n");
  45        gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
  46
  47        for (i = 0; i < 64; i++) {
  48                drm_printf(p, "  %02x: %08x\n", i,
  49                        gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
  50        }
  51}
  52
  53static void roq_print(struct msm_gpu *gpu, struct drm_printer *p)
  54{
  55        int i;
  56
  57        drm_printf(p, "ROQ state:\n");
  58        gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
  59
  60        for (i = 0; i < 512 / 4; i++) {
  61                uint32_t val[4];
  62                int j;
  63                for (j = 0; j < 4; j++)
  64                        val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
  65                drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
  66                        val[0], val[1], val[2], val[3]);
  67        }
  68}
  69
  70static int show(struct seq_file *m, void *arg)
  71{
  72        struct drm_info_node *node = (struct drm_info_node *) m->private;
  73        struct drm_device *dev = node->minor->dev;
  74        struct msm_drm_private *priv = dev->dev_private;
  75        struct drm_printer p = drm_seq_file_printer(m);
  76        void (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
  77                node->info_ent->data;
  78
  79        show(priv->gpu, &p);
  80        return 0;
  81}
  82
  83#define ENT(n) { .name = #n, .show = show, .data = n ##_print }
  84static struct drm_info_list a5xx_debugfs_list[] = {
  85        ENT(pfp),
  86        ENT(me),
  87        ENT(meq),
  88        ENT(roq),
  89};
  90
  91/* for debugfs files that can be written to, we can't use drm helper: */
  92static int
  93reset_set(void *data, u64 val)
  94{
  95        struct drm_device *dev = data;
  96        struct msm_drm_private *priv = dev->dev_private;
  97        struct msm_gpu *gpu = priv->gpu;
  98        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
  99        struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
 100
 101        if (!capable(CAP_SYS_ADMIN))
 102                return -EINVAL;
 103
 104        /* TODO do we care about trying to make sure the GPU is idle?
 105         * Since this is just a debug feature limited to CAP_SYS_ADMIN,
 106         * maybe it is fine to let the user keep both pieces if they
 107         * try to reset an active GPU.
 108         */
 109
 110        mutex_lock(&dev->struct_mutex);
 111
 112        release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
 113        adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
 114
 115        release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
 116        adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
 117
 118        if (a5xx_gpu->pm4_bo) {
 119                msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
 120                drm_gem_object_put(a5xx_gpu->pm4_bo);
 121                a5xx_gpu->pm4_bo = NULL;
 122        }
 123
 124        if (a5xx_gpu->pfp_bo) {
 125                msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
 126                drm_gem_object_put(a5xx_gpu->pfp_bo);
 127                a5xx_gpu->pfp_bo = NULL;
 128        }
 129
 130        gpu->needs_hw_init = true;
 131
 132        pm_runtime_get_sync(&gpu->pdev->dev);
 133        gpu->funcs->recover(gpu);
 134
 135        pm_runtime_put_sync(&gpu->pdev->dev);
 136        mutex_unlock(&dev->struct_mutex);
 137
 138        return 0;
 139}
 140
 141DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
 142
 143
 144void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
 145{
 146        struct drm_device *dev;
 147
 148        if (!minor)
 149                return;
 150
 151        dev = minor->dev;
 152
 153        drm_debugfs_create_files(a5xx_debugfs_list,
 154                                 ARRAY_SIZE(a5xx_debugfs_list),
 155                                 minor->debugfs_root, minor);
 156
 157        debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev,
 158                            &reset_fops);
 159}
 160