xref: /openbmc/linux/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
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  
pfp_print(struct msm_gpu * gpu,struct drm_printer * p)14  static 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  
me_print(struct msm_gpu * gpu,struct drm_printer * p)27  static 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  
meq_print(struct msm_gpu * gpu,struct drm_printer * p)40  static 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  
roq_print(struct msm_gpu * gpu,struct drm_printer * p)53  static 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  
show(struct seq_file * m,void * arg)70  static int show(struct seq_file *m, void *arg)
71  {
72  	struct drm_info_node *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 }
84  static 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: */
92  static int
reset_set(void * data,u64 val)93  reset_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(&gpu->lock);
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(&gpu->lock);
137  
138  	return 0;
139  }
140  
141  DEFINE_DEBUGFS_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
142  
143  
a5xx_debugfs_init(struct msm_gpu * gpu,struct drm_minor * minor)144  void 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_unsafe("reset", S_IWUGO, minor->debugfs_root, dev,
158  				&reset_fops);
159  }
160