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