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(>->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