Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
0003  */
0004 
0005 #include <linux/types.h>
0006 #include <linux/debugfs.h>
0007 
0008 #include <drm/drm_debugfs.h>
0009 #include <drm/drm_file.h>
0010 #include <drm/drm_print.h>
0011 
0012 #include "a5xx_gpu.h"
0013 
0014 static void pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
0015 {
0016     int i;
0017 
0018     drm_printf(p, "PFP state:\n");
0019 
0020     for (i = 0; i < 36; i++) {
0021         gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
0022         drm_printf(p, "  %02x: %08x\n", i,
0023             gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
0024     }
0025 }
0026 
0027 static void me_print(struct msm_gpu *gpu, struct drm_printer *p)
0028 {
0029     int i;
0030 
0031     drm_printf(p, "ME state:\n");
0032 
0033     for (i = 0; i < 29; i++) {
0034         gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
0035         drm_printf(p, "  %02x: %08x\n", i,
0036             gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
0037     }
0038 }
0039 
0040 static void meq_print(struct msm_gpu *gpu, struct drm_printer *p)
0041 {
0042     int i;
0043 
0044     drm_printf(p, "MEQ state:\n");
0045     gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
0046 
0047     for (i = 0; i < 64; i++) {
0048         drm_printf(p, "  %02x: %08x\n", i,
0049             gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
0050     }
0051 }
0052 
0053 static void roq_print(struct msm_gpu *gpu, struct drm_printer *p)
0054 {
0055     int i;
0056 
0057     drm_printf(p, "ROQ state:\n");
0058     gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
0059 
0060     for (i = 0; i < 512 / 4; i++) {
0061         uint32_t val[4];
0062         int j;
0063         for (j = 0; j < 4; j++)
0064             val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
0065         drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
0066             val[0], val[1], val[2], val[3]);
0067     }
0068 }
0069 
0070 static int show(struct seq_file *m, void *arg)
0071 {
0072     struct drm_info_node *node = (struct drm_info_node *) m->private;
0073     struct drm_device *dev = node->minor->dev;
0074     struct msm_drm_private *priv = dev->dev_private;
0075     struct drm_printer p = drm_seq_file_printer(m);
0076     void (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
0077         node->info_ent->data;
0078 
0079     show(priv->gpu, &p);
0080     return 0;
0081 }
0082 
0083 #define ENT(n) { .name = #n, .show = show, .data = n ##_print }
0084 static struct drm_info_list a5xx_debugfs_list[] = {
0085     ENT(pfp),
0086     ENT(me),
0087     ENT(meq),
0088     ENT(roq),
0089 };
0090 
0091 /* for debugfs files that can be written to, we can't use drm helper: */
0092 static int
0093 reset_set(void *data, u64 val)
0094 {
0095     struct drm_device *dev = data;
0096     struct msm_drm_private *priv = dev->dev_private;
0097     struct msm_gpu *gpu = priv->gpu;
0098     struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
0099     struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
0100 
0101     if (!capable(CAP_SYS_ADMIN))
0102         return -EINVAL;
0103 
0104     /* TODO do we care about trying to make sure the GPU is idle?
0105      * Since this is just a debug feature limited to CAP_SYS_ADMIN,
0106      * maybe it is fine to let the user keep both pieces if they
0107      * try to reset an active GPU.
0108      */
0109 
0110     mutex_lock(&gpu->lock);
0111 
0112     release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
0113     adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
0114 
0115     release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
0116     adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
0117 
0118     if (a5xx_gpu->pm4_bo) {
0119         msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
0120         drm_gem_object_put(a5xx_gpu->pm4_bo);
0121         a5xx_gpu->pm4_bo = NULL;
0122     }
0123 
0124     if (a5xx_gpu->pfp_bo) {
0125         msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
0126         drm_gem_object_put(a5xx_gpu->pfp_bo);
0127         a5xx_gpu->pfp_bo = NULL;
0128     }
0129 
0130     gpu->needs_hw_init = true;
0131 
0132     pm_runtime_get_sync(&gpu->pdev->dev);
0133     gpu->funcs->recover(gpu);
0134 
0135     pm_runtime_put_sync(&gpu->pdev->dev);
0136     mutex_unlock(&gpu->lock);
0137 
0138     return 0;
0139 }
0140 
0141 DEFINE_DEBUGFS_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
0142 
0143 
0144 void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
0145 {
0146     struct drm_device *dev;
0147 
0148     if (!minor)
0149         return;
0150 
0151     dev = minor->dev;
0152 
0153     drm_debugfs_create_files(a5xx_debugfs_list,
0154                  ARRAY_SIZE(a5xx_debugfs_list),
0155                  minor->debugfs_root, minor);
0156 
0157     debugfs_create_file_unsafe("reset", S_IWUGO, minor->debugfs_root, dev,
0158                 &reset_fops);
0159 }