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 * 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 * 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 * 108 log_to_xe(struct xe_guc_log *log) 109 { 110 return gt_to_xe(log_to_gt(log)); 111 } 112 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(sizeof(*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 = kcalloc(snapshot->num_chunks, sizeof(*snapshot->copy), 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 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 */ 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