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