xref: /aosp_15_r20/external/mesa3d/src/freedreno/decode/cffdec.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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