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