1 /*
2 * Copyright 2024 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "aubinator_error_decode_xe.h"
7
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "aubinator_error_decode_lib.h"
13 #include "error_decode_lib.h"
14 #include "error_decode_xe_lib.h"
15 #include "intel/compiler/brw_isa_info.h"
16 #include "intel/dev/intel_device_info.h"
17
18 static struct intel_batch_decode_bo
get_bo(void * user_data,bool ppgtt,uint64_t bo_addr)19 get_bo(void *user_data, bool ppgtt, uint64_t bo_addr)
20 {
21 struct intel_batch_decode_bo ret = {};
22 const struct xe_vm_entry *vm_entry;
23 struct xe_vm *xe_vm = user_data;
24
25 if (!ppgtt)
26 return ret;
27
28 vm_entry = error_decode_xe_vm_entry_get(xe_vm, bo_addr);
29 if (!vm_entry)
30 return ret;
31
32 ret.addr = bo_addr;
33 ret.map = error_decode_xe_vm_entry_address_get_data(vm_entry, bo_addr);
34 ret.size = error_decode_xe_vm_entry_address_get_len(vm_entry, bo_addr);
35
36 return ret;
37 }
38
39 static void
print_batch(struct intel_batch_decode_ctx * batch_ctx,const uint32_t * bb_data,const uint64_t bb_addr,uint32_t bb_len,const char * buffer_name,const char * engine_name,enum intel_engine_class engine_class,enum intel_batch_decode_flags batch_flags,bool option_print_all_bb,bool ring_wraps)40 print_batch(struct intel_batch_decode_ctx *batch_ctx, const uint32_t *bb_data,
41 const uint64_t bb_addr, uint32_t bb_len, const char *buffer_name,
42 const char *engine_name, enum intel_engine_class engine_class,
43 enum intel_batch_decode_flags batch_flags,
44 bool option_print_all_bb, bool ring_wraps)
45 {
46 bool is_ring_buffer;
47
48 printf("--- %s (%s) at 0x%016"PRIx64"\n", buffer_name, engine_name, bb_addr);
49
50 /* TODO: checks around buffer_name are copied from i915, if Xe KMD
51 * starts to dump HW context or ring buffer this might become
52 * useful.
53 */
54 is_ring_buffer = strcmp(buffer_name, "ring buffer") == 0;
55 if (option_print_all_bb || is_ring_buffer ||
56 strcmp(buffer_name, "batch buffer") == 0 ||
57 strcmp(buffer_name, "HW Context") == 0) {
58 if (is_ring_buffer && ring_wraps)
59 batch_ctx->flags &= ~INTEL_BATCH_DECODE_OFFSETS;
60 batch_ctx->engine = engine_class;
61 intel_print_batch(batch_ctx, bb_data, bb_len, bb_addr, is_ring_buffer);
62 batch_ctx->flags = batch_flags;
63 printf("\n");
64 }
65 }
66
67 static void
print_register(struct intel_spec * spec,enum decode_color option_color,const char * name,uint32_t reg)68 print_register(struct intel_spec *spec, enum decode_color option_color,
69 const char *name, uint32_t reg)
70 {
71 struct intel_group *reg_spec =
72 name ? intel_spec_find_register_by_name(spec, name) : NULL;
73
74 if (reg_spec) {
75 const char *spacing_reg = "\t\t";
76 const char *spacing_dword = "\t";
77
78 intel_print_group_custom_spacing(stdout, reg_spec, 0, ®, 0,
79 option_color == DECODE_COLOR_ALWAYS,
80 spacing_reg, spacing_dword);
81 }
82 }
83
84 void
read_xe_data_file(FILE * file,enum intel_batch_decode_flags batch_flags,const char * spec_xml_path,bool option_dump_kernels,bool option_print_all_bb,enum decode_color option_color)85 read_xe_data_file(FILE *file,
86 enum intel_batch_decode_flags batch_flags,
87 const char *spec_xml_path,
88 bool option_dump_kernels,
89 bool option_print_all_bb,
90 enum decode_color option_color)
91 {
92 struct intel_batch_decode_ctx batch_ctx;
93 struct intel_device_info devinfo;
94 struct intel_spec *spec = NULL;
95 struct brw_isa_info isa;
96 struct {
97 uint64_t *addrs;
98 uint8_t len;
99 } batch_buffers = { .addrs = NULL, .len = 0 };
100 enum intel_engine_class engine_class = INTEL_ENGINE_CLASS_INVALID;
101 uint32_t *vm_entry_data = NULL;
102 uint32_t vm_entry_len = 0;
103 bool ring_wraps = false;
104 uint64_t acthd = 0;
105 struct xe_vm xe_vm;
106 char *line = NULL;
107 size_t line_size;
108 enum xe_topic xe_topic = XE_TOPIC_INVALID;
109
110 error_decode_xe_vm_init(&xe_vm);
111
112 while (getline(&line, &line_size, file) > 0) {
113 bool topic_changed = false;
114 bool print_line = true;
115
116 topic_changed = error_decode_xe_decode_topic(line, &xe_topic);
117 if (topic_changed) {
118 print_line = (xe_topic != XE_TOPIC_VM);
119 if (print_line)
120 fputs(line, stdout);
121 continue;
122 }
123
124 switch (xe_topic) {
125 case XE_TOPIC_DEVICE: {
126 uint32_t value;
127
128 if (error_decode_xe_read_hexacimal_parameter(line, "PCI ID", &value)) {
129 if (intel_get_device_info_from_pci_id(value, &devinfo)) {
130 printf("Detected GFX ver %i\n", devinfo.verx10);
131 brw_init_isa_info(&isa, &devinfo);
132
133 if (spec_xml_path == NULL)
134 spec = intel_spec_load(&devinfo);
135 else
136 spec = intel_spec_load_from_path(&devinfo, spec_xml_path);
137 } else {
138 printf("Unable to identify devid: 0x%x\n", value);
139 }
140 }
141
142 break;
143 }
144 case XE_TOPIC_HW_ENGINES: {
145 char engine_name[64];
146 uint64_t u64_reg;
147 uint32_t reg;
148
149 if (error_decode_xe_read_engine_name(line, engine_name)) {
150 ring_name_to_class(engine_name, &engine_class);
151 break;
152 }
153
154 if (error_decode_xe_read_u64_hexacimal_parameter(line, "ACTHD", &u64_reg)) {
155 acthd = u64_reg;
156 break;
157 }
158
159 if (error_decode_xe_read_hexacimal_parameter(line, "RING_INSTDONE", ®)) {
160 print_line = false;
161 fputs(line, stdout);
162 print_register(spec, option_color, "INSTDONE_1", reg);
163 break;
164 }
165
166 if (error_decode_xe_read_hexacimal_parameter(line, "SC_INSTDONE", ®)) {
167 print_line = false;
168 fputs(line, stdout);
169 print_register(spec, option_color, "SC_INSTDONE", reg);
170 break;
171 }
172
173 if (error_decode_xe_read_hexacimal_parameter(line, "SC_INSTDONE_EXTRA", ®)) {
174 print_line = false;
175 fputs(line, stdout);
176 print_register(spec, option_color, "SC_INSTDONE_EXTRA", reg);
177 break;
178 }
179
180 if (error_decode_xe_read_hexacimal_parameter(line, "SC_INSTDONE_EXTRA2", ®)) {
181 print_line = false;
182 fputs(line, stdout);
183 print_register(spec, option_color, "SC_INSTDONE_EXTRA2", reg);
184 break;
185 }
186
187 if (error_decode_xe_read_hexacimal_parameter(line, "SAMPLER_INSTDONE", ®)) {
188 print_line = false;
189 fputs(line, stdout);
190 print_register(spec, option_color, "SAMPLER_INSTDONE", reg);
191 break;
192 }
193
194 if (error_decode_xe_read_hexacimal_parameter(line, "ROW_INSTDONE", ®)) {
195 print_line = false;
196 fputs(line, stdout);
197 print_register(spec, option_color, "ROW_INSTDONE", reg);
198 break;
199 }
200
201 if (error_decode_xe_read_hexacimal_parameter(line, "INSTDONE_GEOM_SVGUNIT", ®)) {
202 print_line = false;
203 fputs(line, stdout);
204 print_register(spec, option_color, "INSTDONE_GEOM", reg);
205 break;
206 }
207
208 /* TODO: parse other engine registers */
209 break;
210 }
211 case XE_TOPIC_JOB: {
212 uint64_t u64_value;
213
214 if (error_decode_xe_read_u64_hexacimal_parameter(line, "batch_addr[", &u64_value)) {
215 batch_buffers.addrs = realloc(batch_buffers.addrs, sizeof(uint64_t) * (batch_buffers.len + 1));
216 batch_buffers.addrs[batch_buffers.len] = u64_value;
217 batch_buffers.len++;
218 }
219
220 break;
221 }
222 case XE_TOPIC_GUC_CT: {
223 enum xe_vm_topic_type type;
224 const char *value_ptr;
225 bool is_hw_ctx;
226
227 /* TODO: what to do with HWSP? */
228 type = error_decode_xe_read_hw_sp_or_ctx_line(line, &value_ptr, &is_hw_ctx);
229 if (type != XE_VM_TOPIC_TYPE_UNKNOWN) {
230 print_line = false;
231
232 if (!is_hw_ctx)
233 break;
234
235 switch (type) {
236 case XE_VM_TOPIC_TYPE_DATA:
237 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
238 printf("Failed to parse HWCTX data\n");
239 break;
240 case XE_VM_TOPIC_TYPE_LENGTH: {
241 vm_entry_len = strtoul(value_ptr, NULL, 0);
242 vm_entry_data = calloc(1, vm_entry_len);
243 if (!vm_entry_data) {
244 printf("Out of memory to allocate a buffer to store content of HWCTX\n");
245 break;
246 }
247
248 if (is_hw_ctx)
249 error_decode_xe_vm_hw_ctx_set(&xe_vm, vm_entry_len, vm_entry_data);
250 break;
251 }
252 case XE_VM_TOPIC_TYPE_ERROR:
253 printf("HWCTX not present in dump, content will be zeroed: %s\n", line);
254 break;
255 default:
256 printf("Not expected line in HWCTX: %s", line);
257 }
258 }
259
260 break;
261 }
262 case XE_TOPIC_VM: {
263 enum xe_vm_topic_type type;
264 const char *value_ptr;
265 uint64_t address;
266
267 print_line = false;
268 type = error_decode_xe_read_vm_line(line, &address, &value_ptr);
269 switch (type) {
270 case XE_VM_TOPIC_TYPE_DATA: {
271 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
272 printf("Failed to parse VMA 0x%" PRIx64 " data\n", address);
273 break;
274 }
275 case XE_VM_TOPIC_TYPE_LENGTH: {
276 vm_entry_len = strtoul(value_ptr, NULL, 0);
277 vm_entry_data = calloc(1, vm_entry_len);
278 if (!vm_entry_data) {
279 printf("Out of memory to allocate a buffer to store content of VMA 0x%" PRIx64 "\n", address);
280 break;
281 }
282 if (!error_decode_xe_vm_append(&xe_vm, address, vm_entry_len, vm_entry_data)) {
283 printf("xe_vm_append() failed for VMA 0x%" PRIx64 "\n", address);
284 break;
285 }
286 break;
287 }
288 case XE_VM_TOPIC_TYPE_ERROR:
289 printf("VMA 0x%" PRIx64 " not present in dump, content will be zeroed: %s\n", address, line);
290 break;
291 default:
292 printf("Not expected line in VM state: %s", line);
293 }
294 break;
295 }
296 default:
297 break;
298 }
299
300 if (print_line)
301 fputs(line, stdout);
302 }
303
304 printf("**** Batch buffers ****\n");
305 intel_batch_decode_ctx_init_brw(&batch_ctx, &isa, &devinfo, stdout,
306 batch_flags, spec_xml_path, get_bo,
307 NULL, &xe_vm);
308 batch_ctx.acthd = acthd;
309
310 if (option_dump_kernels)
311 batch_ctx.shader_binary = dump_shader_binary;
312
313 for (int i = 0; i < batch_buffers.len; i++) {
314 const uint64_t bb_addr = batch_buffers.addrs[i];
315 const struct xe_vm_entry *vm_entry = error_decode_xe_vm_entry_get(&xe_vm, bb_addr);
316 const char *engine_name = intel_engines_class_to_string(engine_class);
317 const char *buffer_name = "batch buffer";
318 const uint32_t *bb_data;
319 uint32_t bb_len;
320
321 if (!vm_entry)
322 continue;
323
324 bb_data = error_decode_xe_vm_entry_address_get_data(vm_entry, bb_addr);
325 bb_len = error_decode_xe_vm_entry_address_get_len(vm_entry, bb_addr);
326 print_batch(&batch_ctx, bb_data, bb_addr, bb_len, buffer_name,
327 engine_name, engine_class, batch_flags, option_print_all_bb,
328 ring_wraps);
329 }
330
331 printf("**** HW context ****\n");
332 if (xe_vm.hw_context.length) {
333 const char *engine_name = intel_engines_class_to_string(engine_class);
334 const char *buffer_name = "HW Context";
335 const uint64_t bb_addr = 0;
336 const uint32_t *bb_data;
337 uint32_t bb_len;
338
339 bb_data = xe_vm.hw_context.data;
340 bb_len = xe_vm.hw_context.length;
341 print_batch(&batch_ctx, bb_data, bb_addr, bb_len, buffer_name,
342 engine_name, engine_class, batch_flags, option_print_all_bb,
343 ring_wraps);
344 }
345
346 intel_batch_decode_ctx_finish(&batch_ctx);
347 intel_spec_destroy(spec);
348 free(batch_buffers.addrs);
349 free(line);
350 error_decode_xe_vm_fini(&xe_vm);
351 }
352