xref: /aosp_15_r20/external/mesa3d/src/intel/tools/aubinator_error_decode_xe.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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, &reg, 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", &reg)) {
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", &reg)) {
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", &reg)) {
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", &reg)) {
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", &reg)) {
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", &reg)) {
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", &reg)) {
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