• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2021 Google, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <err.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "rnn.h"
30 #include "rnndec.h"
31 
32 #include "afuc.h"
33 #include "util.h"
34 
35 static struct rnndeccontext *ctx;
36 static struct rnndb *db;
37 static struct rnndomain *control_regs;
38 static struct rnndomain *sqe_regs;
39 static struct rnndomain *pipe_regs;
40 struct rnndomain *dom[2];
41 static struct rnnenum *pm4_packets;
42 
43 static int
find_reg(struct rnndomain * dom,const char * name)44 find_reg(struct rnndomain *dom, const char *name)
45 {
46    for (int i = 0; i < dom->subelemsnum; i++)
47       if (!strcmp(name, dom->subelems[i]->name))
48          return dom->subelems[i]->offset;
49 
50    return -1;
51 }
52 
53 static unsigned
reg(struct rnndomain * dom,const char * type,const char * name)54 reg(struct rnndomain *dom, const char *type, const char *name)
55 {
56    int val = find_reg(dom, name);
57    if (val < 0) {
58       char *endptr = NULL;
59       val = strtol(name, &endptr, 0);
60       if (endptr && *endptr) {
61          printf("invalid %s reg: %s\n", type, name);
62          exit(2);
63       }
64    }
65    return (unsigned)val;
66 }
67 
68 static char *
reg_name(struct rnndomain * dom,unsigned id)69 reg_name(struct rnndomain *dom, unsigned id)
70 {
71    if (rnndec_checkaddr(ctx, dom, id, 0)) {
72       struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, dom, id, 0);
73       char *name = info->name;
74       free(info);
75       return name;
76    } else {
77       return NULL;
78    }
79 }
80 
81 /**
82  * Map control reg name to offset.
83  */
84 unsigned
afuc_control_reg(const char * name)85 afuc_control_reg(const char *name)
86 {
87    return reg(control_regs, "control", name);
88 }
89 
90 /**
91  * Map offset to SQE reg name (or NULL), caller frees
92  */
93 char *
afuc_sqe_reg_name(unsigned id)94 afuc_sqe_reg_name(unsigned id)
95 {
96    return reg_name(sqe_regs, id);
97 }
98 
99 /**
100  * Map SQE reg name to offset.
101  */
102 unsigned
afuc_sqe_reg(const char * name)103 afuc_sqe_reg(const char *name)
104 {
105    return reg(sqe_regs, "SQE", name);
106 }
107 
108 /**
109  * Map offset to control reg name (or NULL), caller frees
110  */
111 char *
afuc_control_reg_name(unsigned id)112 afuc_control_reg_name(unsigned id)
113 {
114    return reg_name(control_regs, id);
115 }
116 
117 /**
118  * Map pipe reg name to offset.
119  */
120 unsigned
afuc_pipe_reg(const char * name)121 afuc_pipe_reg(const char *name)
122 {
123    return reg(pipe_regs, "pipe", name);
124 }
125 
126 /**
127  * "void" pipe regs don't have a value written, the $addr right is
128  * enough to trigger what they do
129  */
130 bool
afuc_pipe_reg_is_void(unsigned id)131 afuc_pipe_reg_is_void(unsigned id)
132 {
133    if (rnndec_checkaddr(ctx, pipe_regs, id, 0)) {
134       struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, pipe_regs, id, 0);
135       free(info->name);
136       bool ret = !strcmp(info->typeinfo->name, "void");
137       free(info);
138       return ret;
139    } else {
140       return false;
141    }
142 }
143 
144 /**
145  * Map offset to pipe reg name (or NULL), caller frees
146  */
147 char *
afuc_pipe_reg_name(unsigned id)148 afuc_pipe_reg_name(unsigned id)
149 {
150    return reg_name(pipe_regs, id);
151 }
152 
153 /**
154  * Map GPU reg name to offset.
155  */
156 unsigned
afuc_gpu_reg(const char * name)157 afuc_gpu_reg(const char *name)
158 {
159    int val = find_reg(dom[0], name);
160    if (val < 0)
161       val = find_reg(dom[1], name);
162    if (val < 0) {
163       char *endptr = NULL;
164       val = strtol(name, &endptr, 0);
165       if (endptr && *endptr) {
166          printf("invalid control reg: %s\n", name);
167          exit(2);
168       }
169    }
170    return (unsigned)val;
171 }
172 
173 /**
174  * Map offset to gpu reg name (or NULL), caller frees
175  */
176 char *
afuc_gpu_reg_name(unsigned id)177 afuc_gpu_reg_name(unsigned id)
178 {
179    struct rnndomain *d = NULL;
180 
181    if (rnndec_checkaddr(ctx, dom[0], id, 0)) {
182       d = dom[0];
183    } else if (rnndec_checkaddr(ctx, dom[1], id, 0)) {
184       d = dom[1];
185    }
186 
187    if (d) {
188       struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, id, 0);
189       if (info) {
190          char *name = info->name;
191          free(info);
192          return name;
193       }
194    }
195 
196    return NULL;
197 }
198 
199 unsigned
afuc_gpr_reg(const char * name)200 afuc_gpr_reg(const char *name)
201 {
202    /* If it starts with '$' just swallow it: */
203    if (name[0] == '$')
204       name++;
205 
206    /* handle aliases: */
207    if (!strcmp(name, "rem")) {
208       return REG_REM;
209    } else if (!strcmp(name, "memdata")) {
210       return REG_MEMDATA;
211    } else if (!strcmp(name, "addr")) {
212       return REG_ADDR;
213    } else if (!strcmp(name, "regdata")) {
214       return REG_REGDATA;
215    } else if (!strcmp(name, "usraddr")) {
216       return REG_USRADDR;
217    } else if (!strcmp(name, "data")) {
218       return REG_DATA;
219    } else {
220       char *endptr = NULL;
221       unsigned val = strtol(name, &endptr, 16);
222       if (endptr && *endptr) {
223          printf("invalid gpr reg: %s\n", name);
224          exit(2);
225       }
226       return val;
227    }
228 }
229 
230 static int
find_enum_val(struct rnnenum * en,const char * name)231 find_enum_val(struct rnnenum *en, const char *name)
232 {
233    int i;
234 
235    for (i = 0; i < en->valsnum; i++)
236       if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name))
237          return en->vals[i]->value;
238 
239    return -1;
240 }
241 
242 /**
243  * Map pm4 packet name to id
244  */
245 int
afuc_pm4_id(const char * name)246 afuc_pm4_id(const char *name)
247 {
248    return find_enum_val(pm4_packets, name);
249 }
250 
251 const char *
afuc_pm_id_name(unsigned id)252 afuc_pm_id_name(unsigned id)
253 {
254    return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id);
255 }
256 
257 void
afuc_printc(enum afuc_color c,const char * fmt,...)258 afuc_printc(enum afuc_color c, const char *fmt, ...)
259 {
260    va_list args;
261    if (c == AFUC_ERR) {
262       printf("%s", ctx->colors->err);
263    } else if (c == AFUC_LBL) {
264       printf("%s", ctx->colors->btarg);
265    }
266    va_start(args, fmt);
267    vprintf(fmt, args);
268    va_end(args);
269    printf("%s", ctx->colors->reset);
270 }
271 
afuc_util_init(int gpuver,bool colors)272 int afuc_util_init(int gpuver, bool colors)
273 {
274    char *name, *control_reg_name, *variant;
275    char *pipe_reg_name = NULL;
276 
277    switch (gpuver) {
278    case 7:
279       name = "A6XX";
280       variant = "A7XX";
281       control_reg_name = "A7XX_CONTROL_REG";
282       pipe_reg_name = "A7XX_PIPE_REG";
283       break;
284    case 6:
285       name = "A6XX";
286       variant = "A6XX";
287       control_reg_name = "A6XX_CONTROL_REG";
288       pipe_reg_name = "A6XX_PIPE_REG";
289       break;
290    case 5:
291       name = "A5XX";
292       variant = "A5XX";
293       control_reg_name = "A5XX_CONTROL_REG";
294       pipe_reg_name = "A5XX_PIPE_REG";
295       break;
296    default:
297       fprintf(stderr, "unknown GPU version!\n");
298       return -1;
299    }
300 
301    rnn_init();
302    db = rnn_newdb();
303 
304    ctx = rnndec_newcontext(db);
305    ctx->colors = colors ? &envy_def_colors : &envy_null_colors;
306 
307    rnn_parsefile(db, "adreno.xml");
308    rnn_prepdb(db);
309    if (db->estatus)
310       errx(db->estatus, "failed to parse register database");
311    dom[0] = rnn_finddomain(db, name);
312    dom[1] = rnn_finddomain(db, "AXXX");
313    control_regs = rnn_finddomain(db, control_reg_name);
314    sqe_regs = rnn_finddomain(db, "A6XX_SQE_REG");
315    pipe_regs = rnn_finddomain(db, pipe_reg_name);
316 
317    rnndec_varadd(ctx, "chip", variant);
318 
319    pm4_packets = rnn_findenum(ctx->db, "adreno_pm4_type3_packets");
320 
321    return 0;
322 }
323 
324