1 /*
2 * Copyright 2024 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "error2hangdump_xe.h"
7
8 #include <inttypes.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "error_decode_xe_lib.h"
14 #include "error2hangdump_lib.h"
15 #include "intel/dev/intel_device_info.h"
16 #include "util/macros.h"
17
18 void
read_xe_data_file(FILE * dump_file,FILE * hang_dump_file,bool verbose)19 read_xe_data_file(FILE *dump_file, FILE *hang_dump_file, bool verbose)
20 {
21 enum xe_topic xe_topic = XE_TOPIC_INVALID;
22 uint32_t *vm_entry_data = NULL;
23 uint32_t vm_entry_len = 0;
24 struct xe_vm xe_vm;
25 char *line = NULL;
26 size_t line_size;
27 struct {
28 uint64_t *addrs;
29 uint8_t len;
30 } batch_buffers = { .addrs = NULL, .len = 0 };
31 uint32_t i;
32
33 error_decode_xe_vm_init(&xe_vm);
34
35 while (getline(&line, &line_size, dump_file) > 0) {
36 if (error_decode_xe_decode_topic(line, &xe_topic))
37 continue;
38
39 switch (xe_topic) {
40 case XE_TOPIC_JOB: {
41 uint64_t u64_value;
42
43 if (error_decode_xe_read_u64_hexacimal_parameter(line, "batch_addr[", &u64_value)) {
44 batch_buffers.addrs = realloc(batch_buffers.addrs, sizeof(uint64_t) * (batch_buffers.len + 1));
45 batch_buffers.addrs[batch_buffers.len] = u64_value;
46 batch_buffers.len++;
47 }
48
49 break;
50 }
51 case XE_TOPIC_GUC_CT:
52 /*
53 * Workaround bug in the kernel that would put the exec queue dump
54 * in the wrong place, under "GuC CT" topic.
55 */
56 case XE_TOPIC_CONTEXT: {
57 enum xe_vm_topic_type type;
58 const char *value_ptr;
59 bool is_hw_ctx;
60
61 type = error_decode_xe_read_hw_sp_or_ctx_line(line, &value_ptr, &is_hw_ctx);
62 if (type == XE_VM_TOPIC_TYPE_UNKNOWN || !is_hw_ctx) {
63 break;
64 }
65
66 switch (type) {
67 case XE_VM_TOPIC_TYPE_DATA:
68 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
69 printf("Failed to parse HWCTX data\n");
70 break;
71 case XE_VM_TOPIC_TYPE_LENGTH: {
72 vm_entry_len = strtoul(value_ptr, NULL, 0);
73 vm_entry_data = calloc(1, vm_entry_len);
74 if (!vm_entry_data) {
75 printf("Out of memory to allocate a buffer to store content of HWCTX\n");
76 break;
77 }
78
79 error_decode_xe_vm_hw_ctx_set(&xe_vm, vm_entry_len, vm_entry_data);
80 break;
81 }
82 case XE_VM_TOPIC_TYPE_ERROR:
83 printf("HWCTX not present in dump, content will be zeroed: %s\n", line);
84 break;
85 default:
86 printf("Not expected line in HWCTX: %s", line);
87 }
88
89 break;
90 }
91 case XE_TOPIC_VM: {
92 enum xe_vm_topic_type type;
93 const char *value_ptr;
94 uint64_t address;
95
96 type = error_decode_xe_read_vm_line(line, &address, &value_ptr);
97 switch (type) {
98 case XE_VM_TOPIC_TYPE_DATA: {
99 if (!error_decode_xe_ascii85_decode_allocated(value_ptr, vm_entry_data, vm_entry_len))
100 printf("Failed to parse VMA 0x%" PRIx64 " data\n", address);
101 break;
102 }
103 case XE_VM_TOPIC_TYPE_LENGTH: {
104 vm_entry_len = strtoul(value_ptr, NULL, 0);
105 vm_entry_data = calloc(1, vm_entry_len);
106 if (!vm_entry_data) {
107 printf("Out of memory to allocate a buffer to store content of VMA 0x%" PRIx64 "\n", address);
108 break;
109 }
110 if (!error_decode_xe_vm_append(&xe_vm, address, vm_entry_len, vm_entry_data)) {
111 printf("xe_vm_append() failed for VMA 0x%" PRIx64 "\n", address);
112 }
113 break;
114 }
115 case XE_VM_TOPIC_TYPE_ERROR:
116 printf("VMA 0x%" PRIx64 " not present in dump, content will be zeroed: %s\n", address, line);
117 break;
118 default:
119 printf("Not expected line in VM state: %s", line);
120 }
121
122 break;
123 }
124 default:
125 break;
126 }
127 }
128
129 if (verbose) {
130 fprintf(stdout, "BOs found:\n");
131 for (i = 0; i < xe_vm.entries_len; i++) {
132 struct xe_vm_entry *entry = &xe_vm.entries[i];
133
134 fprintf(stdout, "\taddr=0x%016" PRIx64 " size=%" PRIu32 "\n", entry->address, entry->length);
135 }
136 }
137
138 fail_if(!batch_buffers.len, "Failed to find batch buffer.\n");
139 fail_if(!xe_vm.hw_context.length, "Failed to find HW image buffer.\n");
140
141 for (i = 0; i < xe_vm.entries_len; i++) {
142 struct xe_vm_entry *entry = &xe_vm.entries[i];
143 const char *name = "user";
144 uint32_t j;
145
146 for (j = 0; j < batch_buffers.len; j++) {
147 if (batch_buffers.addrs[j] == entry->address)
148 name = "batch";
149 }
150
151 write_buffer(hang_dump_file, entry->address, entry->data, entry->length, name);
152 }
153
154 fprintf(stderr, "writing image buffer size=0x%016" PRIx32 "\n", xe_vm.hw_context.length);
155 write_hw_image_buffer(hang_dump_file, xe_vm.hw_context.data, xe_vm.hw_context.length);
156
157 for (i = 0; i < batch_buffers.len; i++) {
158 write_exec(hang_dump_file, batch_buffers.addrs[i]);
159 }
160
161 free(batch_buffers.addrs);
162 free(line);
163 error_decode_xe_vm_fini(&xe_vm);
164 }
165