1 /*
2 * Copyright © 2012 Rob Clark <robdclark@gmail.com>
3 * SPDX-License-Identifier: MIT
4 */
5
6 #ifndef __CFFDEC_H__
7 #define __CFFDEC_H__
8
9 #include <stdbool.h>
10
11 #include "freedreno_pm4.h"
12 #include "freedreno_dev_info.h"
13
14 enum query_mode {
15 /* default mode, dump all queried regs on each draw: */
16 QUERY_ALL = 0,
17
18 /* only dump if any of the queried regs were written
19 * since last draw:
20 */
21 QUERY_WRITTEN,
22
23 /* only dump if any of the queried regs changed since
24 * last draw:
25 */
26 QUERY_DELTA,
27 };
28
29 struct cffdec_options {
30 struct fd_dev_id dev_id;
31 const struct fd_dev_info *info;
32 int draw_filter;
33 int color;
34 int dump_shaders;
35 int summary;
36 int allregs;
37 int dump_textures;
38 int dump_bindless;
39 int decode_markers;
40 char *script;
41
42 int query_compare; /* binning vs SYSMEM/GMEM compare mode */
43 int query_mode; /* enum query_mode */
44 char **querystrs;
45 int nquery;
46
47 /* In "once" mode, only decode a cmdstream buffer once (per draw
48 * mode, in the case of a6xx+ where a single cmdstream buffer can
49 * be used for both binning and draw pass), rather than each time
50 * encountered (ie. once per tile/bin in GMEM draw passes)
51 */
52 int once;
53
54 /* In unit_test mode, suppress pathnames in output so that we can have references
55 * independent of the build dir.
56 */
57 int unit_test;
58
59 /* for crashdec, where we know CP_IBx_REM_SIZE, we can use this
60 * to highlight the cmdstream not parsed yet, to make it easier
61 * to see how far along the CP is.
62 */
63 struct {
64 uint64_t base;
65 uint32_t rem;
66 bool crash_found : 1;
67 } ibs[4];
68 };
69
70 /**
71 * A helper to deal with 64b registers by accumulating the lo/hi 32b
72 * dwords. Example usage:
73 *
74 * struct regacc r = regacc(rnn);
75 *
76 * for (dword in dwords) {
77 * if (regacc_push(&r, regbase, dword)) {
78 * printf("\t%08x"PRIx64", r.value);
79 * dump_register_val(r.regbase, r.value, 0);
80 * }
81 * regbase++;
82 * }
83 *
84 * It is expected that 64b regs will come in pairs of <lo, hi>.
85 */
86 struct regacc {
87 uint32_t regbase;
88 uint64_t value;
89
90 /* private: */
91 struct rnn *rnn;
92 bool has_dword_lo;
93 };
94 struct regacc regacc(struct rnn *rnn);
95 bool regacc_push(struct regacc *regacc, uint32_t regbase, uint32_t dword);
96
97 void printl(int lvl, const char *fmt, ...);
98 const char *pktname(unsigned opc);
99 uint32_t regbase(const char *name);
100 const char *regname(uint32_t regbase, int color);
101 bool reg_written(uint32_t regbase);
102 uint32_t reg_lastval(uint32_t regbase);
103 uint32_t reg_val(uint32_t regbase);
104 void reg_set(uint32_t regbase, uint32_t val);
105 uint32_t * parse_cp_indirect(uint32_t *dwords, uint32_t sizedwords,
106 uint64_t *ibaddr, uint32_t *ibsize);
107 void reset_regs(void);
108 void cffdec_init(const struct cffdec_options *options);
109 void dump_register_val(struct regacc *r, int level);
110 void dump_commands(uint32_t *dwords, uint32_t sizedwords, int level);
111
112 /*
113 * Packets (mostly) fall into two categories, "write one or more registers"
114 * (type0 or type4 depending on generation) or "packet with opcode and
115 * opcode specific payload" (type3 or type7). These helpers deal with
116 * the type0+type3 vs type4+type7 differences (a2xx-a4xx vs a5xx+).
117 */
118
119 static inline bool
pkt_is_regwrite(uint32_t dword,uint32_t * offset,uint32_t * size)120 pkt_is_regwrite(uint32_t dword, uint32_t *offset, uint32_t *size)
121 {
122 if (pkt_is_type0(dword)) {
123 *size = type0_pkt_size(dword) + 1;
124 *offset = type0_pkt_offset(dword);
125 return true;
126 } if (pkt_is_type4(dword)) {
127 *size = type4_pkt_size(dword) + 1;
128 *offset = type4_pkt_offset(dword);
129 return true;
130 }
131 return false;
132 }
133
134 static inline bool
pkt_is_opcode(uint32_t dword,uint32_t * opcode,uint32_t * size)135 pkt_is_opcode(uint32_t dword, uint32_t *opcode, uint32_t *size)
136 {
137 if (pkt_is_type3(dword)) {
138 *size = type3_pkt_size(dword) + 1;
139 *opcode = cp_type3_opcode(dword);
140 return true;
141 } else if (pkt_is_type7(dword)) {
142 *size = type7_pkt_size(dword) + 1;
143 *opcode = cp_type7_opcode(dword);
144 return true;
145 }
146 return false;
147 }
148
149 /**
150 * For a5xx+ we can detect valid packet headers vs random other noise, and
151 * can use this to "re-sync" to the start of the next valid packet. So that
152 * the same cmdstream corruption that confused the GPU doesn't confuse us!
153 */
154 static inline uint32_t
find_next_packet(uint32_t * dwords,uint32_t sizedwords)155 find_next_packet(uint32_t *dwords, uint32_t sizedwords)
156 {
157 for (uint32_t c = 0; c < sizedwords; c++) {
158 if (pkt_is_type7(dwords[c]) || pkt_is_type4(dwords[c]))
159 return c;
160 }
161 return sizedwords;
162 }
163
164
165 #endif /* __CFFDEC_H__ */
166