1 #ifndef NV_PUSH_H
2 #define NV_PUSH_H
3
4 #include "nvtypes.h"
5 #include "util/macros.h"
6
7 #include <assert.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <stdio.h>
11
12 struct nv_device_info;
13
14 struct nv_push {
15 uint32_t *start;
16 uint32_t *end;
17 uint32_t *limit;
18
19 /* A pointer to the last method header */
20 uint32_t *last_hdr;
21
22 /* The value in the last method header, used to avoid read-back */
23 uint32_t last_hdr_dw;
24 };
25
26 static inline void
nv_push_init(struct nv_push * push,uint32_t * start,size_t dw_count)27 nv_push_init(struct nv_push *push, uint32_t *start, size_t dw_count)
28 {
29 push->start = start;
30 push->end = start;
31 push->limit = start + dw_count;
32 push->last_hdr = NULL;
33 push->last_hdr_dw = 0;
34 }
35
36 static inline size_t
nv_push_dw_count(struct nv_push * push)37 nv_push_dw_count(struct nv_push *push)
38 {
39 assert(push->start <= push->end);
40 assert(push->end <= push->limit);
41 return push->end - push->start;
42 }
43
44 #ifndef NDEBUG
45 void nv_push_validate(struct nv_push *push);
46 #else
nv_push_validate(struct nv_push * push)47 static inline void nv_push_validate(struct nv_push *push) { }
48 #endif
49
50 void vk_push_print(FILE *fp, const struct nv_push *push,
51 const struct nv_device_info *devinfo);
52
53 #define SUBC_NV9097 0
54 #define SUBC_NVA097 0
55 #define SUBC_NVB097 0
56 #define SUBC_NVB197 0
57 #define SUBC_NVC097 0
58 #define SUBC_NVC397 0
59 #define SUBC_NVC597 0
60
61 #define SUBC_NV90C0 1
62 #define SUBC_NVA0C0 1
63 #define SUBC_NVB0C0 1
64 #define SUBC_NVB1C0 1
65 #define SUBC_NVC0C0 1
66 #define SUBC_NVC3C0 1
67 #define SUBC_NVC6C0 1
68
69 #define SUBC_NV9039 2
70
71 #define SUBC_NV902D 3
72
73 #define SUBC_NV90B5 4
74 #define SUBC_NVC1B5 4
75
76 static inline uint32_t
NVC0_FIFO_PKHDR_SQ(int subc,int mthd,unsigned size)77 NVC0_FIFO_PKHDR_SQ(int subc, int mthd, unsigned size)
78 {
79 return 0x20000000 | (size << 16) | (subc << 13) | (mthd >> 2);
80 }
81
82 static inline void
__push_verify(struct nv_push * push)83 __push_verify(struct nv_push *push)
84 {
85 if (push->last_hdr == NULL)
86 return;
87
88 /* check for immd */
89 if (push->last_hdr_dw >> 29 == 4)
90 return;
91
92 ASSERTED uint32_t last_count = (push->last_hdr_dw & 0x1fff0000);
93 assert(last_count);
94 }
95
96 static inline void
__push_hdr(struct nv_push * push,uint32_t hdr)97 __push_hdr(struct nv_push *push, uint32_t hdr)
98 {
99 __push_verify(push);
100
101 *push->end = hdr;
102 push->last_hdr_dw = hdr;
103 push->last_hdr = push->end;
104 push->end++;
105 }
106
107 static inline void
__push_mthd_size(struct nv_push * push,int subc,uint32_t mthd,unsigned size)108 __push_mthd_size(struct nv_push *push, int subc, uint32_t mthd, unsigned size)
109 {
110 __push_hdr(push, NVC0_FIFO_PKHDR_SQ(subc, mthd, size));
111 }
112
113 static inline void
__push_mthd(struct nv_push * push,int subc,uint32_t mthd)114 __push_mthd(struct nv_push *push, int subc, uint32_t mthd)
115 {
116 __push_mthd_size(push, subc, mthd, 0);
117 }
118
119 #define P_MTHD(push, class, mthd) __push_mthd(push, SUBC_##class, class##_##mthd)
120
121 static inline uint32_t
NVC0_FIFO_PKHDR_IL(int subc,int mthd,uint16_t data)122 NVC0_FIFO_PKHDR_IL(int subc, int mthd, uint16_t data)
123 {
124 assert(!(data & ~0x1fff));
125 return 0x80000000 | (data << 16) | (subc << 13) | (mthd >> 2);
126 }
127
128 static inline void
__push_immd(struct nv_push * push,int subc,uint32_t mthd,uint32_t val)129 __push_immd(struct nv_push *push, int subc, uint32_t mthd, uint32_t val)
130 {
131 __push_hdr(push, NVC0_FIFO_PKHDR_IL(subc, mthd, val));
132 }
133
134 #define P_IMMD(push, class, mthd, args...) do { \
135 uint32_t __val; \
136 VA_##class##_##mthd(__val, args); \
137 if (__builtin_constant_p(__val & ~0x1fff) && !(__val & ~0x1fff)) { \
138 __push_immd(push, SUBC_##class, class##_##mthd, __val); \
139 } else { \
140 __push_mthd_size(push, SUBC_##class, class##_##mthd, 0); \
141 nv_push_val(push, class##_##mthd, __val); \
142 } \
143 } while(0)
144
145 static inline uint32_t
NVC0_FIFO_PKHDR_1I(int subc,int mthd,unsigned size)146 NVC0_FIFO_PKHDR_1I(int subc, int mthd, unsigned size)
147 {
148 return 0xa0000000 | (size << 16) | (subc << 13) | (mthd >> 2);
149 }
150
151 static inline void
__push_1inc(struct nv_push * push,int subc,uint32_t mthd)152 __push_1inc(struct nv_push *push, int subc, uint32_t mthd)
153 {
154 __push_hdr(push, NVC0_FIFO_PKHDR_1I(subc, mthd, 0));
155 }
156
157 #define P_1INC(push, class, mthd) __push_1inc(push, SUBC_##class, class##_##mthd)
158
159 static inline uint32_t
NVC0_FIFO_PKHDR_0I(int subc,int mthd,unsigned size)160 NVC0_FIFO_PKHDR_0I(int subc, int mthd, unsigned size)
161 {
162 return 0x60000000 | (size << 16) | (subc << 13) | (mthd >> 2);
163 }
164
165 static inline void
__push_0inc(struct nv_push * push,int subc,uint32_t mthd)166 __push_0inc(struct nv_push *push, int subc, uint32_t mthd)
167 {
168 __push_hdr(push, NVC0_FIFO_PKHDR_0I(subc, mthd, 0));
169 }
170
171 #define P_0INC(push, class, mthd) __push_0inc(push, SUBC_##class, class##_##mthd)
172
173 #define NV_PUSH_MAX_COUNT 0x1fff
174
175 static inline bool
nv_push_update_count(struct nv_push * push,uint16_t count)176 nv_push_update_count(struct nv_push *push, uint16_t count)
177 {
178 assert(push->last_hdr != NULL);
179
180 assert(count <= NV_PUSH_MAX_COUNT);
181 if (count > NV_PUSH_MAX_COUNT)
182 return false;
183
184 uint32_t hdr_dw = push->last_hdr_dw;
185
186 /* size is encoded at 28:16 */
187 uint32_t new_count = (count + (hdr_dw >> 16)) & NV_PUSH_MAX_COUNT;
188 bool overflow = new_count < count;
189 /* if we would overflow, don't change anything and just let it be */
190 assert(!overflow);
191 if (overflow)
192 return false;
193
194 hdr_dw &= ~0x1fff0000;
195 hdr_dw |= new_count << 16;
196 push->last_hdr_dw = hdr_dw;
197 *push->last_hdr = hdr_dw;
198 return true;
199 }
200
201 static inline void
P_INLINE_DATA(struct nv_push * push,uint32_t value)202 P_INLINE_DATA(struct nv_push *push, uint32_t value)
203 {
204 assert(push->end < push->limit);
205 if (nv_push_update_count(push, 1)) {
206 /* push new value */
207 *push->end = value;
208 push->end++;
209 }
210 }
211
212 static inline void
P_INLINE_FLOAT(struct nv_push * push,float value)213 P_INLINE_FLOAT(struct nv_push *push, float value)
214 {
215 assert(push->end < push->limit);
216 if (nv_push_update_count(push, 1)) {
217 /* push new value */
218 *(float *)push->end = value;
219 push->end++;
220 }
221 }
222
223 static inline void
P_INLINE_ARRAY(struct nv_push * push,const uint32_t * data,int num_dw)224 P_INLINE_ARRAY(struct nv_push *push, const uint32_t *data, int num_dw)
225 {
226 assert(push->end + num_dw <= push->limit);
227 if (nv_push_update_count(push, num_dw)) {
228 /* push new value */
229 memcpy(push->end, data, num_dw * 4);
230 push->end += num_dw;
231 }
232 }
233
234 /* internally used by generated inlines. */
235 static inline void
nv_push_val(struct nv_push * push,uint32_t idx,uint32_t val)236 nv_push_val(struct nv_push *push, uint32_t idx, uint32_t val)
237 {
238 ASSERTED uint32_t last_hdr_dw = push->last_hdr_dw;
239 ASSERTED bool is_0inc = (last_hdr_dw & 0xe0000000) == 0x60000000;
240 ASSERTED bool is_1inc = (last_hdr_dw & 0xe0000000) == 0xa0000000;
241 ASSERTED bool is_immd = (last_hdr_dw & 0xe0000000) == 0x80000000;
242 ASSERTED uint16_t last_method = (last_hdr_dw & 0x1fff) << 2;
243
244 uint16_t distance = push->end - push->last_hdr - 1;
245 if (is_0inc)
246 distance = 0;
247 else if (is_1inc)
248 distance = MIN2(1, distance);
249 last_method += distance * 4;
250
251 /* can't have empty headers ever */
252 assert(last_hdr_dw);
253 assert(!is_immd);
254 assert(last_method == idx);
255 assert(push->end < push->limit);
256
257 P_INLINE_DATA(push, val);
258 }
259
260 static inline void
nv_push_raw(struct nv_push * push,uint32_t * raw_dw,uint32_t dw_count)261 nv_push_raw(struct nv_push *push, uint32_t *raw_dw, uint32_t dw_count)
262 {
263 assert(push->end + dw_count <= push->limit);
264 memcpy(push->end, raw_dw, dw_count * 4);
265 push->end += dw_count;
266 push->last_hdr = NULL;
267 }
268
269 #endif /* NV_PUSH_H */
270