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