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