xref: /aosp_15_r20/external/mesa3d/src/intel/tools/error_decode_xe_lib.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Intel Corporation
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "error_decode_xe_lib.h"
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "error_decode_lib.h"
12 #include "util/macros.h"
13 
14 static const char *
read_parameter_helper(const char * line,const char * parameter)15 read_parameter_helper(const char *line, const char *parameter)
16 {
17    if (!strstr(line, parameter))
18       return NULL;
19 
20    while (*line != ':')
21       line++;
22    /* skip ':' and ' ' */
23    line += 2;
24 
25    return line;
26 }
27 
28 /* parse lines like 'batch_addr[0]: 0x0000effeffff5000 */
29 bool
error_decode_xe_read_u64_hexacimal_parameter(const char * line,const char * parameter,uint64_t * value)30 error_decode_xe_read_u64_hexacimal_parameter(const char *line, const char *parameter, uint64_t *value)
31 {
32    line = read_parameter_helper(line, parameter);
33    if (!line)
34       return false;
35 
36    *value = (uint64_t)strtoull(line, NULL, 0);
37    return true;
38 }
39 
40 /* parse lines like 'PCI ID: 0x9a49' */
41 bool
error_decode_xe_read_hexacimal_parameter(const char * line,const char * parameter,uint32_t * value)42 error_decode_xe_read_hexacimal_parameter(const char *line, const char *parameter, uint32_t *value)
43 {
44    line = read_parameter_helper(line, parameter);
45    if (!line)
46       return false;
47 
48    *value = (int)strtoul(line, NULL, 0);
49    return true;
50 }
51 
52 /* parse lines like 'rcs0 (physical), logical instance=0' */
53 bool
error_decode_xe_read_engine_name(const char * line,char * ring_name)54 error_decode_xe_read_engine_name(const char *line, char *ring_name)
55 {
56    int i;
57 
58    if (!strstr(line, " (physical), logical instance="))
59       return false;
60 
61    i = 0;
62    for (i = 0; *line != ' '; i++, line++)
63       ring_name[i] = *line;
64 
65    ring_name[i] = 0;
66    return true;
67 }
68 
69 /*
70  * when a topic string is parsed it sets new_topic and returns true, otherwise
71  * does nothing.
72  */
73 bool
error_decode_xe_decode_topic(const char * line,enum xe_topic * new_topic)74 error_decode_xe_decode_topic(const char *line, enum xe_topic *new_topic)
75 {
76    static const char *xe_topic_strings[] = {
77       "**** Xe Device Coredump ****",
78       "**** GuC CT ****",
79       "**** Job ****",
80       "**** HW Engines ****",
81       "**** VM state ****",
82    };
83    bool topic_changed = false;
84 
85    for (int i = 0; i < ARRAY_SIZE(xe_topic_strings); i++) {
86       if (strncmp(xe_topic_strings[i], line, strlen(xe_topic_strings[i])) == 0) {
87          topic_changed = true;
88          *new_topic = i;
89          break;
90       }
91    }
92 
93    return topic_changed;
94 }
95 
96 /* return type of VM topic lines like '[200000].data: x...' and points
97  * value_ptr to first char of data of topic type
98  */
99 enum xe_vm_topic_type
error_decode_xe_read_vm_line(const char * line,uint64_t * address,const char ** value_ptr)100 error_decode_xe_read_vm_line(const char *line, uint64_t *address, const char **value_ptr)
101 {
102    enum xe_vm_topic_type type;
103    char text_addr[64];
104    int i;
105 
106    if (*line != '[')
107       return XE_VM_TOPIC_TYPE_UNKNOWN;
108 
109    for (i = 0, line++; *line != ']'; i++, line++)
110       text_addr[i] = *line;
111 
112    text_addr[i] = 0;
113    *address = (uint64_t)strtoull(text_addr, NULL, 16);
114 
115    /* at this point line points to last address digit so +3 to point to type */
116    line += 2;
117    switch (*line) {
118    case 'd':
119       type = XE_VM_TOPIC_TYPE_DATA;
120       break;
121    case 'l':
122       type = XE_VM_TOPIC_TYPE_LENGTH;
123       break;
124    case 'e':
125       type = XE_VM_TOPIC_TYPE_ERROR;
126       break;
127    default:
128       printf("type char: %c\n", *line);
129       return XE_VM_TOPIC_TYPE_UNKNOWN;
130    }
131 
132    for (; *line != ':'; line++);
133 
134    *value_ptr = line + 2;
135    return type;
136 }
137 
138 /*
139  * similar to read_xe_vm_line() but it parses '[HWCTX].data: ...'
140  */
141 enum xe_vm_topic_type
error_decode_xe_read_hw_sp_or_ctx_line(const char * line,const char ** value_ptr,bool * is_hw_ctx)142 error_decode_xe_read_hw_sp_or_ctx_line(const char *line, const char **value_ptr, bool *is_hw_ctx)
143 {
144    enum xe_vm_topic_type type;
145    char text_addr[64];
146    bool is_hw_sp;
147    int i;
148 
149    if (*line != '\t')
150       return XE_VM_TOPIC_TYPE_UNKNOWN;
151 
152    line++;
153    if (*line != '[')
154       return XE_VM_TOPIC_TYPE_UNKNOWN;
155 
156    for (i = 0, line++; *line != ']'; i++, line++)
157       text_addr[i] = *line;
158 
159    text_addr[i] = 0;
160    *is_hw_ctx = strncmp(text_addr, "HWCTX", strlen("HWCTX")) == 0;
161    is_hw_sp =  strncmp(text_addr, "HWSP", strlen("HWSP")) == 0;
162    if (*is_hw_ctx == false && is_hw_sp == false)
163          return XE_VM_TOPIC_TYPE_UNKNOWN;
164 
165    /* at this point line points to last address digit so +3 to point to type */
166    line += 2;
167    switch (*line) {
168    case 'd':
169       type = XE_VM_TOPIC_TYPE_DATA;
170       break;
171    case 'l':
172       type = XE_VM_TOPIC_TYPE_LENGTH;
173       break;
174    case 'e':
175       type = XE_VM_TOPIC_TYPE_ERROR;
176       break;
177    default:
178       printf("type char: %c\n", *line);
179       return XE_VM_TOPIC_TYPE_UNKNOWN;
180    }
181 
182    for (; *line != ':'; line++);
183 
184    *value_ptr = line + 2;
185    return type;
186 }
187 
error_decode_xe_vm_init(struct xe_vm * xe_vm)188 void error_decode_xe_vm_init(struct xe_vm *xe_vm)
189 {
190    xe_vm->entries = NULL;
191    xe_vm->entries_len = 0;
192    memset(&xe_vm->hw_context, 0, sizeof(xe_vm->hw_context));
193 }
194 
error_decode_xe_vm_fini(struct xe_vm * xe_vm)195 void error_decode_xe_vm_fini(struct xe_vm *xe_vm)
196 {
197    uint32_t i;
198 
199    for (i = 0; i < xe_vm->entries_len; i++)
200       free((uint32_t *)xe_vm->entries[i].data);
201 
202    free((uint32_t *)xe_vm->hw_context.data);
203    free(xe_vm->entries);
204 }
205 
206 static void
xe_vm_entry_set(struct xe_vm_entry * entry,const uint64_t address,const uint32_t length,const uint32_t * data)207 xe_vm_entry_set(struct xe_vm_entry *entry, const uint64_t address,
208                 const uint32_t length, const uint32_t *data)
209 {
210    entry->address = address;
211    entry->length = length;
212    entry->data = data;
213 }
214 
215 void
error_decode_xe_vm_hw_ctx_set(struct xe_vm * xe_vm,const uint32_t length,const uint32_t * data)216 error_decode_xe_vm_hw_ctx_set(struct xe_vm *xe_vm, const uint32_t length,
217                               const uint32_t *data)
218 {
219    xe_vm_entry_set(&xe_vm->hw_context, 0, length, data);
220 }
221 
222 /*
223  * error_decode_xe_vm_fini() will take care to free data
224  */
225 bool
error_decode_xe_vm_append(struct xe_vm * xe_vm,const uint64_t address,const uint32_t length,const uint32_t * data)226 error_decode_xe_vm_append(struct xe_vm *xe_vm, const uint64_t address,
227                           const uint32_t length, const uint32_t *data)
228 {
229    size_t len = sizeof(*xe_vm->entries) * (xe_vm->entries_len + 1);
230 
231    xe_vm->entries = realloc(xe_vm->entries, len);
232    if (!xe_vm->entries)
233       return false;
234 
235    xe_vm_entry_set(&xe_vm->entries[xe_vm->entries_len], address, length, data);
236    xe_vm->entries_len++;
237    return true;
238 }
239 
240 const struct xe_vm_entry *
error_decode_xe_vm_entry_get(struct xe_vm * xe_vm,const uint64_t address)241 error_decode_xe_vm_entry_get(struct xe_vm *xe_vm, const uint64_t address)
242 {
243    uint32_t i;
244 
245    for (i = 0; i < xe_vm->entries_len; i++) {
246       struct xe_vm_entry *entry = &xe_vm->entries[i];
247 
248       if (entry->address == address)
249          return entry;
250 
251       if (address > entry->address &&
252           address < (entry->address + entry->length))
253          return entry;
254    }
255 
256    return NULL;
257 }
258 
259 uint32_t *
error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry * entry,const uint64_t address)260 error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry *entry,
261                                           const uint64_t address)
262 {
263    uint32_t offset = (address - entry->address) / sizeof(uint32_t);
264    return (uint32_t *)&entry->data[offset];
265 }
266 
267 uint32_t
error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry * entry,const uint64_t address)268 error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry *entry,
269                                          const uint64_t address)
270 {
271    return entry->length - (address - entry->address);
272 }
273 
274 bool
error_decode_xe_ascii85_decode_allocated(const char * in,uint32_t * out,uint32_t vm_entry_bytes_len)275 error_decode_xe_ascii85_decode_allocated(const char *in, uint32_t *out, uint32_t vm_entry_bytes_len)
276 {
277    const uint32_t dword_len = vm_entry_bytes_len / sizeof(uint32_t);
278    uint32_t i;
279 
280    for (i = 0; (*in >= '!') && (*in <= 'z') && (i < dword_len); i++)
281       in = ascii85_decode_char(in, &out[i]);
282 
283    if (dword_len != i)
284       printf("mismatch dword_len=%u i=%u\n", dword_len, i);
285 
286    return dword_len == i && (*in < '!' || *in > 'z');
287 }
288