1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2022 Intel Corporation
4 */
5
6 #include "xe_guc_log.h"
7
8 #include <linux/fault-inject.h>
9
10 #include <linux/utsname.h>
11 #include <drm/drm_managed.h>
12
13 #include "abi/guc_lfd_abi.h"
14 #include "regs/xe_guc_regs.h"
15 #include "xe_bo.h"
16 #include "xe_devcoredump.h"
17 #include "xe_force_wake.h"
18 #include "xe_gt_printk.h"
19 #include "xe_gt_types.h"
20 #include "xe_map.h"
21 #include "xe_mmio.h"
22 #include "xe_module.h"
23
24 #define GUC_LOG_CHUNK_SIZE SZ_2M
25
26 /* Magic keys define */
27 #define GUC_LFD_DRIVER_KEY_STREAMING 0x8086AAAA474C5346
28 #define GUC_LFD_LOG_BUFFER_MARKER_2 0xDEADFEED
29 #define GUC_LFD_CRASH_DUMP_BUFFER_MARKER_2 0x8086DEAD
30 #define GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_2 0xBEEFFEED
31 #define GUC_LFD_LOG_BUFFER_MARKER_1V2 0xCABBA9E6
32 #define GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_1V2 0xCABBA9F7
33 #define GUC_LFD_DATA_HEADER_MAGIC 0x8086
34
35 /* LFD supported LIC type range */
36 #define GUC_LIC_TYPE_FIRST GUC_LIC_TYPE_GUC_SW_VERSION
37 #define GUC_LIC_TYPE_LAST GUC_LIC_TYPE_BUILD_PLATFORM_ID
38 #define GUC_LFD_TYPE_FW_RANGE_FIRST GUC_LFD_TYPE_FW_VERSION
39 #define GUC_LFD_TYPE_FW_RANGE_LAST GUC_LFD_TYPE_BUILD_PLATFORM_ID
40
41 #define GUC_LOG_BUFFER_STATE_HEADER_LENGTH 4096
42 #define GUC_LOG_BUFFER_INIT_CONFIG 3
43
44 struct guc_log_buffer_entry_list {
45 u32 offset;
46 u32 rd_ptr;
47 u32 wr_ptr;
48 u32 wrap_offset;
49 u32 buf_size;
50 };
51
52 struct guc_lic_save {
53 u32 version;
54 /*
55 * Array of init config KLV values.
56 * Range from GUC_LOG_LIC_TYPE_FIRST to GUC_LOG_LIC_TYPE_LAST
57 */
58 u32 values[GUC_LIC_TYPE_LAST - GUC_LIC_TYPE_FIRST + 1];
59 struct guc_log_buffer_entry_list entry[GUC_LOG_BUFFER_INIT_CONFIG];
60 };
61
62 static struct guc_log_buffer_entry_markers {
63 u32 key[2];
64 } const entry_markers[GUC_LOG_BUFFER_INIT_CONFIG + 1] = {
65 {{
66 GUC_LFD_LOG_BUFFER_MARKER_1V2,
67 GUC_LFD_LOG_BUFFER_MARKER_2
68 }},
69 {{
70 GUC_LFD_LOG_BUFFER_MARKER_1V2,
71 GUC_LFD_CRASH_DUMP_BUFFER_MARKER_2
72 }},
73 {{
74 GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_1V2,
75 GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_2
76 }},
77 {{
78 GUC_LIC_MAGIC,
79 (FIELD_PREP_CONST(GUC_LIC_VERSION_MASK_MAJOR, GUC_LIC_VERSION_MAJOR) |
80 FIELD_PREP_CONST(GUC_LIC_VERSION_MASK_MINOR, GUC_LIC_VERSION_MINOR))
81 }}
82 };
83
84 static struct guc_log_lic_lfd_map {
85 u32 lic;
86 u32 lfd;
87 } const lic_lfd_type_map[] = {
88 {GUC_LIC_TYPE_GUC_SW_VERSION, GUC_LFD_TYPE_FW_VERSION},
89 {GUC_LIC_TYPE_GUC_DEVICE_ID, GUC_LFD_TYPE_GUC_DEVICE_ID},
90 {GUC_LIC_TYPE_TSC_FREQUENCY, GUC_LFD_TYPE_TSC_FREQUENCY},
91 {GUC_LIC_TYPE_GMD_ID, GUC_LFD_TYPE_GMD_ID},
92 {GUC_LIC_TYPE_BUILD_PLATFORM_ID, GUC_LFD_TYPE_BUILD_PLATFORM_ID}
93 };
94
95 static struct xe_guc *
log_to_guc(struct xe_guc_log * log)96 log_to_guc(struct xe_guc_log *log)
97 {
98 return container_of(log, struct xe_guc, log);
99 }
100
101 static struct xe_gt *
log_to_gt(struct xe_guc_log * log)102 log_to_gt(struct xe_guc_log *log)
103 {
104 return container_of(log, struct xe_gt, uc.guc.log);
105 }
106
107 static struct xe_device *
log_to_xe(struct xe_guc_log * log)108 log_to_xe(struct xe_guc_log *log)
109 {
110 return gt_to_xe(log_to_gt(log));
111 }
112
xe_guc_log_snapshot_alloc(struct xe_guc_log * log,bool atomic)113 static struct xe_guc_log_snapshot *xe_guc_log_snapshot_alloc(struct xe_guc_log *log, bool atomic)
114 {
115 struct xe_guc_log_snapshot *snapshot;
116 size_t remain;
117 int i;
118
119 snapshot = kzalloc_obj(*snapshot, atomic ? GFP_ATOMIC : GFP_KERNEL);
120 if (!snapshot)
121 return NULL;
122
123 /*
124 * NB: kmalloc has a hard limit well below the maximum GuC log buffer size.
125 * Also, can't use vmalloc as might be called from atomic context. So need
126 * to break the buffer up into smaller chunks that can be allocated.
127 */
128 snapshot->size = xe_bo_size(log->bo);
129 snapshot->num_chunks = DIV_ROUND_UP(snapshot->size, GUC_LOG_CHUNK_SIZE);
130
131 snapshot->copy = kzalloc_objs(*snapshot->copy, snapshot->num_chunks,
132 atomic ? GFP_ATOMIC : GFP_KERNEL);
133 if (!snapshot->copy)
134 goto fail_snap;
135
136 remain = snapshot->size;
137 for (i = 0; i < snapshot->num_chunks; i++) {
138 size_t size = min(GUC_LOG_CHUNK_SIZE, remain);
139
140 snapshot->copy[i] = kmalloc(size, atomic ? GFP_ATOMIC : GFP_KERNEL);
141 if (!snapshot->copy[i])
142 goto fail_copy;
143 remain -= size;
144 }
145
146 return snapshot;
147
148 fail_copy:
149 for (i = 0; i < snapshot->num_chunks; i++)
150 kfree(snapshot->copy[i]);
151 kfree(snapshot->copy);
152 fail_snap:
153 kfree(snapshot);
154 return NULL;
155 }
156
157 /**
158 * xe_guc_log_snapshot_free - free a previously captured GuC log snapshot
159 * @snapshot: GuC log snapshot structure
160 *
161 * Return: pointer to a newly allocated snapshot object or null if out of memory. Caller is
162 * responsible for calling xe_guc_log_snapshot_free when done with the snapshot.
163 */
xe_guc_log_snapshot_free(struct xe_guc_log_snapshot * snapshot)164 void xe_guc_log_snapshot_free(struct xe_guc_log_snapshot *snapshot)
165 {
166 int i;
167
168 if (!snapshot)
169 return;
170
171 if (snapshot->copy) {
172 for (i = 0; i < snapshot->num_chunks; i++)
173 kfree(snapshot->copy[i]);
174 kfree(snapshot->copy);
175 }
176
177 kfree(snapshot);
178 }
179
180 /**
181 * xe_guc_log_snapshot_capture - create a new snapshot copy the GuC log for later dumping
182 * @log: GuC log structure
183 * @atomic: is the call inside an atomic section of some kind?
184 *
185 * Return: pointer to a newly allocated snapshot object or null if out of memory. Caller is
186 * responsible for calling xe_guc_log_snapshot_free when done with the snapshot.
187 */
xe_guc_log_snapshot_capture(struct xe_guc_log * log,bool atomic)188 struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, bool atomic)
189 {
190 struct xe_guc_log_snapshot *snapshot;
191 struct xe_device *xe = log_to_xe(log);
192 struct xe_guc *guc = log_to_guc(log);
193 struct xe_gt *gt = log_to_gt(log);
194 size_t remain;
195 int i;
196
197 if (!log->bo)
198 return NULL;
199
200 snapshot = xe_guc_log_snapshot_alloc(log, atomic);
201 if (!snapshot)
202 return NULL;
203
204 remain = snapshot->size;
205 for (i = 0; i < snapshot->num_chunks; i++) {
206 size_t size = min(GUC_LOG_CHUNK_SIZE, remain);
207
208 xe_map_memcpy_from(xe, snapshot->copy[i], &log->bo->vmap,
209 i * GUC_LOG_CHUNK_SIZE, size);
210 remain -= size;
211 }
212
213 CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT);
214 if (!fw_ref.domains)
215 snapshot->stamp = ~0ULL;
216 else
217 snapshot->stamp = xe_mmio_read64_2x32(>->mmio, GUC_PMTIMESTAMP_LO);
218
219 snapshot->ktime = ktime_get_boottime_ns();
220 snapshot->level = log->level;
221 snapshot->ver_found = guc->fw.versions.found[XE_UC_FW_VER_RELEASE];
222 snapshot->ver_want = guc->fw.versions.wanted;
223 snapshot->path = guc->fw.path;
224
225 return snapshot;
226 }
227
228 /**
229 * xe_guc_log_snapshot_print - dump a previously saved copy of the GuC log to some useful location
230 * @snapshot: a snapshot of the GuC log
231 * @p: the printer object to output to
232 */
xe_guc_log_snapshot_print(struct xe_guc_log_snapshot * snapshot,struct drm_printer * p)233 void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p)
234 {
235 size_t remain;
236 int i;
237
238 if (!snapshot) {
239 drm_printf(p, "GuC log snapshot not allocated!\n");
240 return;
241 }
242
243 drm_printf(p, "GuC firmware: %s\n", snapshot->path);
244 drm_printf(p, "GuC version: %u.%u.%u (wanted %u.%u.%u)\n",
245 snapshot->ver_found.major, snapshot->ver_found.minor, snapshot->ver_found.patch,
246 snapshot->ver_want.major, snapshot->ver_want.minor, snapshot->ver_want.patch);
247 drm_printf(p, "Kernel timestamp: 0x%08llX [%llu]\n", snapshot->ktime, snapshot->ktime);
248 drm_printf(p, "GuC timestamp: 0x%08llX [%llu]\n", snapshot->stamp, snapshot->stamp);
249 drm_printf(p, "Log level: %u\n", snapshot->level);
250
251 drm_printf(p, "[LOG].length: 0x%zx\n", snapshot->size);
252 remain = snapshot->size;
253 for (i = 0; i < snapshot->num_chunks; i++) {
254 size_t size = min(GUC_LOG_CHUNK_SIZE, remain);
255 const char *prefix = i ? NULL : "[LOG].data";
256 char suffix = i == snapshot->num_chunks - 1 ? '\n' : 0;
257
258 xe_print_blob_ascii85(p, prefix, suffix, snapshot->copy[i], 0, size);
259 remain -= size;
260 }
261 }
262
lfd_output_binary(struct drm_printer * p,char * buf,int buf_size)263 static inline void lfd_output_binary(struct drm_printer *p, char *buf, int buf_size)
264 {
265 seq_write(p->arg, buf, buf_size);
266 }
267
xe_guc_log_add_lfd_header(struct guc_lfd_data * lfd)268 static inline int xe_guc_log_add_lfd_header(struct guc_lfd_data *lfd)
269 {
270 lfd->header = FIELD_PREP_CONST(GUC_LFD_DATA_HEADER_MASK_MAGIC, GUC_LFD_DATA_HEADER_MAGIC);
271 return offsetof(struct guc_lfd_data, data);
272 }
273
xe_guc_log_add_typed_payload(struct drm_printer * p,u32 type,u32 data_len,void * data)274 static int xe_guc_log_add_typed_payload(struct drm_printer *p, u32 type,
275 u32 data_len, void *data)
276 {
277 struct guc_lfd_data lfd;
278 int len;
279
280 len = xe_guc_log_add_lfd_header(&lfd);
281 lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, type);
282 /* make length DW aligned */
283 lfd.data_count = DIV_ROUND_UP(data_len, sizeof(u32));
284 lfd_output_binary(p, (char *)&lfd, len);
285
286 lfd_output_binary(p, data, data_len);
287 len += lfd.data_count * sizeof(u32);
288
289 return len;
290 }
291
lic_type_to_index(u32 lic_type)292 static inline int lic_type_to_index(u32 lic_type)
293 {
294 XE_WARN_ON(lic_type < GUC_LIC_TYPE_FIRST || lic_type > GUC_LIC_TYPE_LAST);
295
296 return lic_type - GUC_LIC_TYPE_FIRST;
297 }
298
lfd_type_to_index(u32 lfd_type)299 static inline int lfd_type_to_index(u32 lfd_type)
300 {
301 int i, lic_type = 0;
302
303 XE_WARN_ON(lfd_type < GUC_LFD_TYPE_FW_RANGE_FIRST || lfd_type > GUC_LFD_TYPE_FW_RANGE_LAST);
304
305 for (i = 0; i < ARRAY_SIZE(lic_lfd_type_map); i++)
306 if (lic_lfd_type_map[i].lfd == lfd_type)
307 lic_type = lic_lfd_type_map[i].lic;
308
309 /* If not found, lic_type_to_index will warning invalid type */
310 return lic_type_to_index(lic_type);
311 }
312
xe_guc_log_add_klv(struct drm_printer * p,u32 lfd_type,struct guc_lic_save * config)313 static int xe_guc_log_add_klv(struct drm_printer *p, u32 lfd_type,
314 struct guc_lic_save *config)
315 {
316 int klv_index = lfd_type_to_index(lfd_type);
317
318 return xe_guc_log_add_typed_payload(p, lfd_type, sizeof(u32), &config->values[klv_index]);
319 }
320
xe_guc_log_add_os_id(struct drm_printer * p,u32 id)321 static int xe_guc_log_add_os_id(struct drm_printer *p, u32 id)
322 {
323 struct guc_lfd_data_os_info os_id;
324 struct guc_lfd_data lfd;
325 int len, info_len, section_len;
326 char *version;
327 u32 blank = 0;
328
329 len = xe_guc_log_add_lfd_header(&lfd);
330 lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_OS_ID);
331
332 os_id.os_id = id;
333 section_len = offsetof(struct guc_lfd_data_os_info, build_version);
334
335 version = init_utsname()->release;
336 info_len = strlen(version);
337
338 /* make length DW aligned */
339 lfd.data_count = DIV_ROUND_UP(section_len + info_len, sizeof(u32));
340 lfd_output_binary(p, (char *)&lfd, len);
341 lfd_output_binary(p, (char *)&os_id, section_len);
342 lfd_output_binary(p, version, info_len);
343
344 /* Padding with 0 */
345 section_len = lfd.data_count * sizeof(u32) - section_len - info_len;
346 if (section_len)
347 lfd_output_binary(p, (char *)&blank, section_len);
348
349 len += lfd.data_count * sizeof(u32);
350 return len;
351 }
352
xe_guc_log_loop_log_init(struct guc_lic * init,struct guc_lic_save * config)353 static void xe_guc_log_loop_log_init(struct guc_lic *init, struct guc_lic_save *config)
354 {
355 struct guc_klv_generic_dw_t *p = (void *)init->data;
356 int i;
357
358 for (i = 0; i < init->data_count;) {
359 int klv_len = FIELD_GET(GUC_KLV_0_LEN, p->kl) + 1;
360 int key = FIELD_GET(GUC_KLV_0_KEY, p->kl);
361
362 if (key < GUC_LIC_TYPE_FIRST || key > GUC_LIC_TYPE_LAST) {
363 XE_WARN_ON(key < GUC_LIC_TYPE_FIRST || key > GUC_LIC_TYPE_LAST);
364 break;
365 }
366 config->values[lic_type_to_index(key)] = p->value;
367 i += klv_len + 1; /* Whole KLV structure length in dwords */
368 p = (void *)((u32 *)p + klv_len);
369 }
370 }
371
find_marker(u32 mark0,u32 mark1)372 static int find_marker(u32 mark0, u32 mark1)
373 {
374 int i;
375
376 for (i = 0; i < ARRAY_SIZE(entry_markers); i++)
377 if (mark0 == entry_markers[i].key[0] && mark1 == entry_markers[i].key[1])
378 return i;
379
380 return ARRAY_SIZE(entry_markers);
381 }
382
xe_guc_log_load_lic(void * guc_log,struct guc_lic_save * config)383 static void xe_guc_log_load_lic(void *guc_log, struct guc_lic_save *config)
384 {
385 u32 offset = GUC_LOG_BUFFER_STATE_HEADER_LENGTH;
386 struct guc_log_buffer_state *p = guc_log;
387
388 config->version = p->version;
389 while (p->marker[0]) {
390 int index;
391
392 index = find_marker(p->marker[0], p->marker[1]);
393
394 if (index < ARRAY_SIZE(entry_markers)) {
395 if (index == GUC_LOG_BUFFER_INIT_CONFIG) {
396 /* Load log init config */
397 xe_guc_log_loop_log_init((void *)p, config);
398
399 /* LIC structure is the last */
400 return;
401 }
402 config->entry[index].offset = offset;
403 config->entry[index].rd_ptr = p->read_ptr;
404 config->entry[index].wr_ptr = p->write_ptr;
405 config->entry[index].wrap_offset = p->wrap_offset;
406 config->entry[index].buf_size = p->size;
407 }
408 offset += p->size;
409 p++;
410 }
411 }
412
413 static int
xe_guc_log_output_lfd_init(struct drm_printer * p,struct xe_guc_log_snapshot * snapshot,struct guc_lic_save * config)414 xe_guc_log_output_lfd_init(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot,
415 struct guc_lic_save *config)
416 {
417 int type, len;
418 size_t size = 0;
419
420 /* FW required types */
421 for (type = GUC_LFD_TYPE_FW_RANGE_FIRST; type <= GUC_LFD_TYPE_FW_RANGE_LAST; type++)
422 size += xe_guc_log_add_klv(p, type, config);
423
424 /* KMD required type(s) */
425 len = xe_guc_log_add_os_id(p, GUC_LFD_OS_TYPE_OSID_LIN);
426 size += len;
427
428 return size;
429 }
430
431 static void
xe_guc_log_print_chunks(struct drm_printer * p,struct xe_guc_log_snapshot * snapshot,u32 from,u32 to)432 xe_guc_log_print_chunks(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot,
433 u32 from, u32 to)
434 {
435 int chunk_from = from % GUC_LOG_CHUNK_SIZE;
436 int chunk_id = from / GUC_LOG_CHUNK_SIZE;
437 int to_chunk_id = to / GUC_LOG_CHUNK_SIZE;
438 int chunk_to = to % GUC_LOG_CHUNK_SIZE;
439 int pos = from;
440
441 do {
442 size_t size = (to_chunk_id == chunk_id ? chunk_to : GUC_LOG_CHUNK_SIZE) -
443 chunk_from;
444
445 lfd_output_binary(p, snapshot->copy[chunk_id] + chunk_from, size);
446 pos += size;
447 chunk_id++;
448 chunk_from = 0;
449 } while (pos < to);
450 }
451
452 static inline int
xe_guc_log_add_log_event(struct drm_printer * p,struct xe_guc_log_snapshot * snapshot,struct guc_lic_save * config)453 xe_guc_log_add_log_event(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot,
454 struct guc_lic_save *config)
455 {
456 size_t size;
457 u32 data_len, section_len;
458 struct guc_lfd_data lfd;
459 struct guc_log_buffer_entry_list *entry;
460 struct guc_lfd_data_log_events_buf events_buf;
461
462 entry = &config->entry[GUC_LOG_TYPE_EVENT_DATA];
463
464 /* Skip empty log */
465 if (entry->rd_ptr == entry->wr_ptr)
466 return 0;
467
468 size = xe_guc_log_add_lfd_header(&lfd);
469 lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_LOG_EVENTS_BUFFER);
470 events_buf.log_events_format_version = config->version;
471
472 /* Adjust to log_format_buf */
473 section_len = offsetof(struct guc_lfd_data_log_events_buf, log_event);
474 data_len = section_len;
475
476 /* Calculate data length */
477 data_len += entry->rd_ptr < entry->wr_ptr ? (entry->wr_ptr - entry->rd_ptr) :
478 (entry->wr_ptr + entry->wrap_offset - entry->rd_ptr);
479 /* make length u32 aligned */
480 lfd.data_count = DIV_ROUND_UP(data_len, sizeof(u32));
481
482 /* Output GUC_LFD_TYPE_LOG_EVENTS_BUFFER header */
483 lfd_output_binary(p, (char *)&lfd, size);
484 lfd_output_binary(p, (char *)&events_buf, section_len);
485
486 /* Output data from guc log chunks directly */
487 if (entry->rd_ptr < entry->wr_ptr) {
488 xe_guc_log_print_chunks(p, snapshot, entry->offset + entry->rd_ptr,
489 entry->offset + entry->wr_ptr);
490 } else {
491 /* 1st, print from rd to wrap offset */
492 xe_guc_log_print_chunks(p, snapshot, entry->offset + entry->rd_ptr,
493 entry->offset + entry->wrap_offset);
494
495 /* 2nd, print from buf start to wr */
496 xe_guc_log_print_chunks(p, snapshot, entry->offset, entry->offset + entry->wr_ptr);
497 }
498 return size;
499 }
500
501 static int
xe_guc_log_add_crash_dump(struct drm_printer * p,struct xe_guc_log_snapshot * snapshot,struct guc_lic_save * config)502 xe_guc_log_add_crash_dump(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot,
503 struct guc_lic_save *config)
504 {
505 struct guc_log_buffer_entry_list *entry;
506 int chunk_from, chunk_id;
507 int from, to, i;
508 size_t size = 0;
509 u32 *buf32;
510
511 entry = &config->entry[GUC_LOG_TYPE_CRASH_DUMP];
512
513 /* Skip zero sized crash dump */
514 if (!entry->buf_size)
515 return 0;
516
517 /* Check if crash dump section are all zero */
518 from = entry->offset;
519 to = entry->offset + entry->buf_size;
520 chunk_from = from % GUC_LOG_CHUNK_SIZE;
521 chunk_id = from / GUC_LOG_CHUNK_SIZE;
522 buf32 = snapshot->copy[chunk_id] + chunk_from;
523
524 for (i = 0; i < entry->buf_size / sizeof(u32); i++)
525 if (buf32[i])
526 break;
527
528 /* Buffer has non-zero data? */
529 if (i < entry->buf_size / sizeof(u32)) {
530 struct guc_lfd_data lfd;
531
532 size = xe_guc_log_add_lfd_header(&lfd);
533 lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_FW_CRASH_DUMP);
534 /* Calculate data length */
535 lfd.data_count = DIV_ROUND_UP(entry->buf_size, sizeof(u32));
536 /* Output GUC_LFD_TYPE_FW_CRASH_DUMP header */
537 lfd_output_binary(p, (char *)&lfd, size);
538
539 /* rd/wr ptr is not used for crash dump */
540 xe_guc_log_print_chunks(p, snapshot, from, to);
541 }
542 return size;
543 }
544
545 static void
xe_guc_log_snapshot_print_lfd(struct xe_guc_log_snapshot * snapshot,struct drm_printer * p)546 xe_guc_log_snapshot_print_lfd(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p)
547 {
548 struct guc_lfd_file_header header;
549 struct guc_lic_save config;
550 size_t size;
551
552 if (!snapshot || !snapshot->size)
553 return;
554
555 header.magic = GUC_LFD_DRIVER_KEY_STREAMING;
556 header.version = FIELD_PREP_CONST(GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR,
557 GUC_LFD_FORMAT_VERSION_MINOR) |
558 FIELD_PREP_CONST(GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR,
559 GUC_LFD_FORMAT_VERSION_MAJOR);
560
561 /* Output LFD file header */
562 lfd_output_binary(p, (char *)&header,
563 offsetof(struct guc_lfd_file_header, stream));
564
565 /* Output LFD stream */
566 xe_guc_log_load_lic(snapshot->copy[0], &config);
567 size = xe_guc_log_output_lfd_init(p, snapshot, &config);
568 if (!size)
569 return;
570
571 xe_guc_log_add_log_event(p, snapshot, &config);
572 xe_guc_log_add_crash_dump(p, snapshot, &config);
573 }
574
575 /**
576 * xe_guc_log_print_dmesg - dump a copy of the GuC log to dmesg
577 * @log: GuC log structure
578 */
xe_guc_log_print_dmesg(struct xe_guc_log * log)579 void xe_guc_log_print_dmesg(struct xe_guc_log *log)
580 {
581 struct xe_gt *gt = log_to_gt(log);
582 static int g_count;
583 struct drm_printer ip = xe_gt_info_printer(gt);
584 struct drm_printer lp = drm_line_printer(&ip, "Capture", ++g_count);
585
586 drm_printf(&lp, "Dumping GuC log for %ps...\n", __builtin_return_address(0));
587
588 xe_guc_log_print(log, &lp);
589
590 drm_printf(&lp, "Done.\n");
591 }
592
593 /**
594 * xe_guc_log_print - dump a copy of the GuC log to some useful location
595 * @log: GuC log structure
596 * @p: the printer object to output to
597 */
xe_guc_log_print(struct xe_guc_log * log,struct drm_printer * p)598 void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p)
599 {
600 struct xe_guc_log_snapshot *snapshot;
601
602 drm_printf(p, "**** GuC Log ****\n");
603
604 snapshot = xe_guc_log_snapshot_capture(log, false);
605 drm_printf(p, "CS reference clock: %u\n", log_to_gt(log)->info.reference_clock);
606 xe_guc_log_snapshot_print(snapshot, p);
607 xe_guc_log_snapshot_free(snapshot);
608 }
609
610 /**
611 * xe_guc_log_print_lfd - dump a copy of the GuC log in LFD format
612 * @log: GuC log structure
613 * @p: the printer object to output to
614 */
xe_guc_log_print_lfd(struct xe_guc_log * log,struct drm_printer * p)615 void xe_guc_log_print_lfd(struct xe_guc_log *log, struct drm_printer *p)
616 {
617 struct xe_guc_log_snapshot *snapshot;
618
619 snapshot = xe_guc_log_snapshot_capture(log, false);
620 xe_guc_log_snapshot_print_lfd(snapshot, p);
621 xe_guc_log_snapshot_free(snapshot);
622 }
623
xe_guc_log_init(struct xe_guc_log * log)624 int xe_guc_log_init(struct xe_guc_log *log)
625 {
626 struct xe_device *xe = log_to_xe(log);
627 struct xe_tile *tile = gt_to_tile(log_to_gt(log));
628 struct xe_bo *bo;
629
630 bo = xe_managed_bo_create_pin_map(xe, tile, GUC_LOG_SIZE,
631 XE_BO_FLAG_SYSTEM |
632 XE_BO_FLAG_GGTT |
633 XE_BO_FLAG_GGTT_INVALIDATE |
634 XE_BO_FLAG_PINNED_NORESTORE);
635 if (IS_ERR(bo))
636 return PTR_ERR(bo);
637
638 xe_map_memset(xe, &bo->vmap, 0, 0, xe_bo_size(bo));
639 log->bo = bo;
640 log->level = xe_modparam.guc_log_level;
641
642 return 0;
643 }
644
645 ALLOW_ERROR_INJECTION(xe_guc_log_init, ERRNO); /* See xe_pci_probe() */
646
647 /**
648 * xe_guc_check_log_buf_overflow - Check if log buffer overflowed
649 * @log: The log object.
650 * @type: The log buffer type
651 * @full_cnt: The count of buffer full
652 *
653 * This function will check count of buffer full against previous, mismatch
654 * indicate overflowed.
655 * Update the sampled_overflow counter, if the 4 bit counter overflowed, add
656 * up 16 to correct the value.
657 *
658 * Return: True if overflowed.
659 */
xe_guc_check_log_buf_overflow(struct xe_guc_log * log,enum guc_log_type type,unsigned int full_cnt)660 bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, enum guc_log_type type,
661 unsigned int full_cnt)
662 {
663 unsigned int prev_full_cnt = log->stats[type].sampled_overflow;
664 bool overflow = false;
665
666 if (full_cnt != prev_full_cnt) {
667 overflow = true;
668
669 log->stats[type].overflow = full_cnt;
670 log->stats[type].sampled_overflow += full_cnt - prev_full_cnt;
671
672 if (full_cnt < prev_full_cnt) {
673 /* buffer_full_cnt is a 4 bit counter */
674 log->stats[type].sampled_overflow += 16;
675 }
676 xe_gt_notice(log_to_gt(log), "log buffer overflow\n");
677 }
678
679 return overflow;
680 }
681