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 /*
224 * Workaround bug in the kernel that would put the exec queue dump
225 * in the wrong place, under "GuC CT" topic.
226 */
227 case XE_TOPIC_CONTEXT: {
228 enum xe_vm_topic_type type;
229 const char *value_ptr;
230 bool is_hw_ctx;
231
232 /* TODO: what to do with HWSP? */
233 type = error_decode_xe_read_hw_sp_or_ctx_line(line, &value_ptr, &is_hw_ctx);
234 if (type != XE_VM_TOPIC_TYPE_UNKNOWN) {
235 print_line = false;
236
237 if (!is_hw_ctx)
238 break;
239
240 switch (type) {
241 case XE_VM_TOPIC_TYPE_DATA:
242 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
243 printf("Failed to parse HWCTX data\n");
244 break;
245 case XE_VM_TOPIC_TYPE_LENGTH: {
246 vm_entry_len = strtoul(value_ptr, NULL, 0);
247 vm_entry_data = calloc(1, vm_entry_len);
248 if (!vm_entry_data) {
249 printf("Out of memory to allocate a buffer to store content of HWCTX\n");
250 break;
251 }
252
253 if (is_hw_ctx)
254 error_decode_xe_vm_hw_ctx_set(&xe_vm, vm_entry_len, vm_entry_data);
255 break;
256 }
257 case XE_VM_TOPIC_TYPE_ERROR:
258 printf("HWCTX not present in dump, content will be zeroed: %s\n", line);
259 break;
260 default:
261 printf("Not expected line in HWCTX: %s", line);
262 }
263 }
264
265 break;
266 }
267 case XE_TOPIC_VM: {
268 enum xe_vm_topic_type type;
269 const char *value_ptr;
270 uint64_t address;
271
272 print_line = false;
273 type = error_decode_xe_read_vm_line(line, &address, &value_ptr);
274 switch (type) {
275 case XE_VM_TOPIC_TYPE_DATA: {
276 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
277 printf("Failed to parse VMA 0x%" PRIx64 " data\n", address);
278 break;
279 }
280 case XE_VM_TOPIC_TYPE_LENGTH: {
281 vm_entry_len = strtoul(value_ptr, NULL, 0);
282 vm_entry_data = calloc(1, vm_entry_len);
283 if (!vm_entry_data) {
284 printf("Out of memory to allocate a buffer to store content of VMA 0x%" PRIx64 "\n", address);
285 break;
286 }
287 if (!error_decode_xe_vm_append(&xe_vm, address, vm_entry_len, vm_entry_data)) {
288 printf("xe_vm_append() failed for VMA 0x%" PRIx64 "\n", address);
289 break;
290 }
291 break;
292 }
293 case XE_VM_TOPIC_TYPE_ERROR:
294 printf("VMA 0x%" PRIx64 " not present in dump, content will be zeroed: %s\n", address, line);
295 break;
296 default:
297 printf("Not expected line in VM state: %s", line);
298 }
299 break;
300 }
301 default:
302 break;
303 }
304
305 if (print_line)
306 fputs(line, stdout);
307 }
308
309 printf("**** Batch buffers ****\n");
310 intel_batch_decode_ctx_init_brw(&batch_ctx, &isa, &devinfo, stdout,
311 batch_flags, spec_xml_path, get_bo,
312 NULL, &xe_vm);
313 batch_ctx.acthd = acthd;
314
315 if (option_dump_kernels)
316 batch_ctx.shader_binary = dump_shader_binary;
317
318 for (int i = 0; i < batch_buffers.len; i++) {
319 const uint64_t bb_addr = batch_buffers.addrs[i];
320 const struct xe_vm_entry *vm_entry = error_decode_xe_vm_entry_get(&xe_vm, bb_addr);
321 const char *engine_name = intel_engines_class_to_string(engine_class);
322 const char *buffer_name = "batch buffer";
323 const uint32_t *bb_data;
324 uint32_t bb_len;
325
326 if (!vm_entry)
327 continue;
328
329 bb_data = error_decode_xe_vm_entry_address_get_data(vm_entry, bb_addr);
330 bb_len = error_decode_xe_vm_entry_address_get_len(vm_entry, bb_addr);
331 print_batch(&batch_ctx, bb_data, bb_addr, bb_len, buffer_name,
332 engine_name, engine_class, batch_flags, option_print_all_bb,
333 ring_wraps);
334 }
335
336 printf("**** HW context ****\n");
337 if (xe_vm.hw_context.length) {
338 const char *engine_name = intel_engines_class_to_string(engine_class);
339 const char *buffer_name = "HW Context";
340 const uint64_t bb_addr = 0;
341 const uint32_t *bb_data;
342 uint32_t bb_len;
343
344 bb_data = xe_vm.hw_context.data;
345 bb_len = xe_vm.hw_context.length;
346 print_batch(&batch_ctx, bb_data, bb_addr, bb_len, buffer_name,
347 engine_name, engine_class, batch_flags, option_print_all_bb,
348 ring_wraps);
349 }
350
351 intel_batch_decode_ctx_finish(&batch_ctx);
352 intel_spec_destroy(spec);
353 free(batch_buffers.addrs);
354 free(line);
355 error_decode_xe_vm_fini(&xe_vm);
356 }
357