Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
12static 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
27static 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
42static 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
57static 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
76static 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 }
89static 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: */
97static int
98reset_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
146DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
147
148
149int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
150{
151 struct drm_device *dev;
152 int ret;
153
154 if (!minor)
155 return 0;
156
157 dev = minor->dev;
158
159 ret = drm_debugfs_create_files(a5xx_debugfs_list,
160 ARRAY_SIZE(a5xx_debugfs_list),
161 minor->debugfs_root, minor);
162
163 if (ret) {
164 DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
165 return ret;
166 }
167
168 debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev,
169 &reset_fops);
170
171 return 0;
172}