1/* 2 * Copyright © 2007-2017 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 */ 24 25#include <stdbool.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <stdarg.h> 29#include <string.h> 30#include <unistd.h> 31#include <inttypes.h> 32#include <errno.h> 33#include <sys/stat.h> 34#include <sys/types.h> 35#include <sys/wait.h> 36#include <err.h> 37#include <assert.h> 38#include <getopt.h> 39#include <zlib.h> 40 41#include "common/gen_decoder.h" 42#include "util/macros.h" 43 44#define CSI "\e[" 45#define BLUE_HEADER CSI "0;44m" 46#define GREEN_HEADER CSI "1;42m" 47#define NORMAL CSI "0m" 48 49#define MIN(a, b) ((a) < (b) ? (a) : (b)) 50 51/* options */ 52 53static bool option_full_decode = true; 54static bool option_print_all_bb = false; 55static bool option_print_offsets = true; 56static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color; 57static char *xml_path = NULL; 58 59static uint32_t 60print_head(unsigned int reg) 61{ 62 printf(" head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21); 63 return reg & (0x7ffff<<2); 64} 65 66static void 67print_register(struct gen_spec *spec, const char *name, uint32_t reg) 68{ 69 struct gen_group *reg_spec = 70 name ? gen_spec_find_register_by_name(spec, name) : NULL; 71 72 if (reg_spec) { 73 gen_print_group(stdout, reg_spec, 0, ®, 0, 74 option_color == COLOR_ALWAYS); 75 } 76} 77 78struct ring_register_mapping { 79 enum drm_i915_gem_engine_class ring_class; 80 unsigned ring_instance; 81 const char *register_name; 82}; 83 84static const struct ring_register_mapping acthd_registers[] = { 85 { I915_ENGINE_CLASS_COPY, 0, "BCS_ACTHD_UDW" }, 86 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_ACTHD_UDW" }, 87 { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_ACTHD_UDW" }, 88 { I915_ENGINE_CLASS_RENDER, 0, "ACTHD_UDW" }, 89 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_ACTHD_UDW" }, 90}; 91 92static const struct ring_register_mapping ctl_registers[] = { 93 { I915_ENGINE_CLASS_COPY, 0, "BCS_RING_BUFFER_CTL" }, 94 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_RING_BUFFER_CTL" }, 95 { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_RING_BUFFER_CTL" }, 96 { I915_ENGINE_CLASS_RENDER, 0, "RCS_RING_BUFFER_CTL" }, 97 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_RING_BUFFER_CTL" }, 98}; 99 100static const struct ring_register_mapping fault_registers[] = { 101 { I915_ENGINE_CLASS_COPY, 0, "BCS_FAULT_REG" }, 102 { I915_ENGINE_CLASS_VIDEO, 0, "VCS_FAULT_REG" }, 103 { I915_ENGINE_CLASS_RENDER, 0, "RCS_FAULT_REG" }, 104 { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_FAULT_REG" }, 105}; 106 107static int ring_name_to_class(const char *ring_name, 108 enum drm_i915_gem_engine_class *class) 109{ 110 static const char *class_names[] = { 111 [I915_ENGINE_CLASS_RENDER] = "rcs", 112 [I915_ENGINE_CLASS_COPY] = "bcs", 113 [I915_ENGINE_CLASS_VIDEO] = "vcs", 114 [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "vecs", 115 }; 116 for (size_t i = 0; i < ARRAY_SIZE(class_names); i++) { 117 if (strncmp(ring_name, class_names[i], strlen(class_names[i]))) 118 continue; 119 120 *class = i; 121 return atoi(ring_name + strlen(class_names[i])); 122 } 123 124 static const struct { 125 const char *name; 126 unsigned int class; 127 int instance; 128 } legacy_names[] = { 129 { "render", I915_ENGINE_CLASS_RENDER, 0 }, 130 { "blt", I915_ENGINE_CLASS_COPY, 0 }, 131 { "bsd", I915_ENGINE_CLASS_VIDEO, 0 }, 132 { "bsd2", I915_ENGINE_CLASS_VIDEO, 1 }, 133 { "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE, 0 }, 134 }; 135 for (size_t i = 0; i < ARRAY_SIZE(legacy_names); i++) { 136 if (strcmp(ring_name, legacy_names[i].name)) 137 continue; 138 139 *class = legacy_names[i].class; 140 return legacy_names[i].instance; 141 } 142 143 return -1; 144} 145 146static const char * 147register_name_from_ring(const struct ring_register_mapping *mapping, 148 unsigned nb_mapping, 149 const char *ring_name) 150{ 151 enum drm_i915_gem_engine_class class; 152 int instance; 153 154 instance = ring_name_to_class(ring_name, &class); 155 if (instance < 0) 156 return NULL; 157 158 for (unsigned i = 0; i < nb_mapping; i++) { 159 if (mapping[i].ring_class == class && 160 mapping[i].ring_instance == instance) 161 return mapping[i].register_name; 162 } 163 return NULL; 164} 165 166static const char * 167instdone_register_for_ring(const struct gen_device_info *devinfo, 168 const char *ring_name) 169{ 170 enum drm_i915_gem_engine_class class; 171 int instance; 172 173 instance = ring_name_to_class(ring_name, &class); 174 if (instance < 0) 175 return NULL; 176 177 switch (class) { 178 case I915_ENGINE_CLASS_RENDER: 179 if (devinfo->gen == 6) 180 return "INSTDONE_2"; 181 else 182 return "INSTDONE_1"; 183 184 case I915_ENGINE_CLASS_COPY: 185 return "BCS_INSTDONE"; 186 187 case I915_ENGINE_CLASS_VIDEO: 188 switch (instance) { 189 case 0: 190 return "VCS_INSTDONE"; 191 case 1: 192 return "VCS2_INSTDONE"; 193 default: 194 return NULL; 195 } 196 197 case I915_ENGINE_CLASS_VIDEO_ENHANCE: 198 return "VECS_INSTDONE"; 199 200 default: 201 return NULL; 202 } 203 204 return NULL; 205} 206 207static void 208print_pgtbl_err(unsigned int reg, struct gen_device_info *devinfo) 209{ 210 if (reg & (1 << 26)) 211 printf(" Invalid Sampler Cache GTT entry\n"); 212 if (reg & (1 << 24)) 213 printf(" Invalid Render Cache GTT entry\n"); 214 if (reg & (1 << 23)) 215 printf(" Invalid Instruction/State Cache GTT entry\n"); 216 if (reg & (1 << 22)) 217 printf(" There is no ROC, this cannot occur!\n"); 218 if (reg & (1 << 21)) 219 printf(" Invalid GTT entry during Vertex Fetch\n"); 220 if (reg & (1 << 20)) 221 printf(" Invalid GTT entry during Command Fetch\n"); 222 if (reg & (1 << 19)) 223 printf(" Invalid GTT entry during CS\n"); 224 if (reg & (1 << 18)) 225 printf(" Invalid GTT entry during Cursor Fetch\n"); 226 if (reg & (1 << 17)) 227 printf(" Invalid GTT entry during Overlay Fetch\n"); 228 if (reg & (1 << 8)) 229 printf(" Invalid GTT entry during Display B Fetch\n"); 230 if (reg & (1 << 4)) 231 printf(" Invalid GTT entry during Display A Fetch\n"); 232 if (reg & (1 << 1)) 233 printf(" Valid PTE references illegal memory\n"); 234 if (reg & (1 << 0)) 235 printf(" Invalid GTT entry during fetch for host\n"); 236} 237 238static void 239print_snb_fence(struct gen_device_info *devinfo, uint64_t fence) 240{ 241 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", 242 fence & 1 ? "" : "in", 243 fence & (1<<1) ? 'y' : 'x', 244 (int)(((fence>>32)&0xfff)+1)*128, 245 (uint32_t)fence & 0xfffff000, 246 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); 247} 248 249static void 250print_i965_fence(struct gen_device_info *devinfo, uint64_t fence) 251{ 252 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", 253 fence & 1 ? "" : "in", 254 fence & (1<<1) ? 'y' : 'x', 255 (int)(((fence>>2)&0x1ff)+1)*128, 256 (uint32_t)fence & 0xfffff000, 257 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); 258} 259 260static void 261print_fence(struct gen_device_info *devinfo, uint64_t fence) 262{ 263 if (devinfo->gen == 6 || devinfo->gen == 7) { 264 return print_snb_fence(devinfo, fence); 265 } else if (devinfo->gen == 4 || devinfo->gen == 5) { 266 return print_i965_fence(devinfo, fence); 267 } 268} 269 270static void 271print_fault_data(struct gen_device_info *devinfo, uint32_t data1, uint32_t data0) 272{ 273 uint64_t address; 274 275 if (devinfo->gen < 8) 276 return; 277 278 address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44; 279 printf(" Address 0x%016" PRIx64 " %s\n", address, 280 data1 & (1 << 4) ? "GGTT" : "PPGTT"); 281} 282 283#define CSI "\e[" 284#define NORMAL CSI "0m" 285 286struct section { 287 uint64_t gtt_offset; 288 char *ring_name; 289 const char *buffer_name; 290 uint32_t *data; 291 int dword_count; 292}; 293 294#define MAX_SECTIONS 256 295static unsigned num_sections; 296static struct section sections[MAX_SECTIONS]; 297 298static int zlib_inflate(uint32_t **ptr, int len) 299{ 300 struct z_stream_s zstream; 301 void *out; 302 const uint32_t out_size = 128*4096; /* approximate obj size */ 303 304 memset(&zstream, 0, sizeof(zstream)); 305 306 zstream.next_in = (unsigned char *)*ptr; 307 zstream.avail_in = 4*len; 308 309 if (inflateInit(&zstream) != Z_OK) 310 return 0; 311 312 out = malloc(out_size); 313 zstream.next_out = out; 314 zstream.avail_out = out_size; 315 316 do { 317 switch (inflate(&zstream, Z_SYNC_FLUSH)) { 318 case Z_STREAM_END: 319 goto end; 320 case Z_OK: 321 break; 322 default: 323 inflateEnd(&zstream); 324 return 0; 325 } 326 327 if (zstream.avail_out) 328 break; 329 330 out = realloc(out, 2*zstream.total_out); 331 if (out == NULL) { 332 inflateEnd(&zstream); 333 return 0; 334 } 335 336 zstream.next_out = (unsigned char *)out + zstream.total_out; 337 zstream.avail_out = zstream.total_out; 338 } while (1); 339 end: 340 inflateEnd(&zstream); 341 free(*ptr); 342 *ptr = out; 343 return zstream.total_out / 4; 344} 345 346static int ascii85_decode(const char *in, uint32_t **out, bool inflate) 347{ 348 int len = 0, size = 1024; 349 350 *out = realloc(*out, sizeof(uint32_t)*size); 351 if (*out == NULL) 352 return 0; 353 354 while (*in >= '!' && *in <= 'z') { 355 uint32_t v = 0; 356 357 if (len == size) { 358 size *= 2; 359 *out = realloc(*out, sizeof(uint32_t)*size); 360 if (*out == NULL) 361 return 0; 362 } 363 364 if (*in == 'z') { 365 in++; 366 } else { 367 v += in[0] - 33; v *= 85; 368 v += in[1] - 33; v *= 85; 369 v += in[2] - 33; v *= 85; 370 v += in[3] - 33; v *= 85; 371 v += in[4] - 33; 372 in += 5; 373 } 374 (*out)[len++] = v; 375 } 376 377 if (!inflate) 378 return len; 379 380 return zlib_inflate(out, len); 381} 382 383static struct gen_batch_decode_bo 384get_gen_batch_bo(void *user_data, bool ppgtt, uint64_t address) 385{ 386 for (int s = 0; s < num_sections; s++) { 387 if (sections[s].gtt_offset <= address && 388 address < sections[s].gtt_offset + sections[s].dword_count * 4) { 389 return (struct gen_batch_decode_bo) { 390 .addr = sections[s].gtt_offset, 391 .map = sections[s].data, 392 .size = sections[s].dword_count * 4, 393 }; 394 } 395 } 396 397 return (struct gen_batch_decode_bo) { .map = NULL }; 398} 399 400static void 401read_data_file(FILE *file) 402{ 403 struct gen_spec *spec = NULL; 404 long long unsigned fence; 405 int matched; 406 char *line = NULL; 407 size_t line_size; 408 uint32_t offset, value; 409 char *ring_name = NULL; 410 struct gen_device_info devinfo; 411 412 while (getline(&line, &line_size, file) > 0) { 413 char *new_ring_name = NULL; 414 char *dashes; 415 416 if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) { 417 free(ring_name); 418 ring_name = new_ring_name; 419 } 420 421 if (line[0] == ':' || line[0] == '~') { 422 uint32_t *data = NULL; 423 int dword_count = ascii85_decode(line+1, &data, line[0] == ':'); 424 if (dword_count == 0) { 425 fprintf(stderr, "ASCII85 decode failed.\n"); 426 exit(EXIT_FAILURE); 427 } 428 assert(num_sections < MAX_SECTIONS); 429 sections[num_sections].data = data; 430 sections[num_sections].dword_count = dword_count; 431 num_sections++; 432 continue; 433 } 434 435 dashes = strstr(line, "---"); 436 if (dashes) { 437 const struct { 438 const char *match; 439 const char *name; 440 } buffers[] = { 441 { "ringbuffer", "ring buffer" }, 442 { "gtt_offset", "batch buffer" }, 443 { "hw context", "HW Context" }, 444 { "hw status", "HW status" }, 445 { "wa context", "WA context" }, 446 { "wa batchbuffer", "WA batch" }, 447 { "NULL context", "Kernel context" }, 448 { "user", "user" }, 449 { "semaphores", "semaphores", }, 450 { "guc log buffer", "GuC log", }, 451 { NULL, "unknown" }, 452 }, *b; 453 454 free(ring_name); 455 ring_name = malloc(dashes - line); 456 strncpy(ring_name, line, dashes - line); 457 ring_name[dashes - line - 1] = '\0'; 458 459 dashes += 4; 460 for (b = buffers; b->match; b++) { 461 if (strncasecmp(dashes, b->match, strlen(b->match)) == 0) 462 break; 463 } 464 465 assert(num_sections < MAX_SECTIONS); 466 sections[num_sections].buffer_name = b->name; 467 sections[num_sections].ring_name = strdup(ring_name); 468 469 uint32_t hi, lo; 470 dashes = strchr(dashes, '='); 471 if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo)) 472 sections[num_sections].gtt_offset = ((uint64_t) hi) << 32 | lo; 473 474 continue; 475 } 476 477 matched = sscanf(line, "%08x : %08x", &offset, &value); 478 if (matched != 2) { 479 uint32_t reg, reg2; 480 481 /* display reg section is after the ringbuffers, don't mix them */ 482 printf("%s", line); 483 484 matched = sscanf(line, "PCI ID: 0x%04x\n", ®); 485 if (matched == 0) 486 matched = sscanf(line, " PCI ID: 0x%04x\n", ®); 487 if (matched == 0) { 488 const char *pci_id_start = strstr(line, "PCI ID"); 489 if (pci_id_start) 490 matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", ®); 491 } 492 if (matched == 1) { 493 if (!gen_get_device_info(reg, &devinfo)) { 494 printf("Unable to identify devid=%x\n", reg); 495 exit(EXIT_FAILURE); 496 } 497 498 printf("Detected GEN%i chipset\n", devinfo.gen); 499 500 if (xml_path == NULL) 501 spec = gen_spec_load(&devinfo); 502 else 503 spec = gen_spec_load_from_path(&devinfo, xml_path); 504 } 505 506 matched = sscanf(line, " CTL: 0x%08x\n", ®); 507 if (matched == 1) { 508 print_register(spec, 509 register_name_from_ring(ctl_registers, 510 ARRAY_SIZE(ctl_registers), 511 ring_name), reg); 512 } 513 514 matched = sscanf(line, " HEAD: 0x%08x\n", ®); 515 if (matched == 1) 516 print_head(reg); 517 518 matched = sscanf(line, " ACTHD: 0x%08x\n", ®); 519 if (matched == 1) { 520 print_register(spec, 521 register_name_from_ring(acthd_registers, 522 ARRAY_SIZE(acthd_registers), 523 ring_name), reg); 524 } 525 526 matched = sscanf(line, " PGTBL_ER: 0x%08x\n", ®); 527 if (matched == 1 && reg) 528 print_pgtbl_err(reg, &devinfo); 529 530 matched = sscanf(line, " ERROR: 0x%08x\n", ®); 531 if (matched == 1 && reg) { 532 print_register(spec, "GFX_ARB_ERROR_RPT", reg); 533 } 534 535 matched = sscanf(line, " INSTDONE: 0x%08x\n", ®); 536 if (matched == 1) { 537 const char *reg_name = 538 instdone_register_for_ring(&devinfo, ring_name); 539 if (reg_name) 540 print_register(spec, reg_name, reg); 541 } 542 543 matched = sscanf(line, " SC_INSTDONE: 0x%08x\n", ®); 544 if (matched == 1) 545 print_register(spec, "SC_INSTDONE", reg); 546 547 matched = sscanf(line, " SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", ®); 548 if (matched == 1) 549 print_register(spec, "SAMPLER_INSTDONE", reg); 550 551 matched = sscanf(line, " ROW_INSTDONE[%*d][%*d]: 0x%08x\n", ®); 552 if (matched == 1) 553 print_register(spec, "ROW_INSTDONE", reg); 554 555 matched = sscanf(line, " INSTDONE1: 0x%08x\n", ®); 556 if (matched == 1) 557 print_register(spec, "INSTDONE_1", reg); 558 559 matched = sscanf(line, " fence[%i] = %Lx\n", ®, &fence); 560 if (matched == 2) 561 print_fence(&devinfo, fence); 562 563 matched = sscanf(line, " FAULT_REG: 0x%08x\n", ®); 564 if (matched == 1 && reg) { 565 const char *reg_name = 566 register_name_from_ring(fault_registers, 567 ARRAY_SIZE(fault_registers), 568 ring_name); 569 if (reg_name == NULL) 570 reg_name = "FAULT_REG"; 571 print_register(spec, reg_name, reg); 572 } 573 574 matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", ®, ®2); 575 if (matched == 2) 576 print_fault_data(&devinfo, reg, reg2); 577 578 continue; 579 } 580 } 581 582 free(line); 583 free(ring_name); 584 585 enum gen_batch_decode_flags batch_flags = 0; 586 if (option_color == COLOR_ALWAYS) 587 batch_flags |= GEN_BATCH_DECODE_IN_COLOR; 588 if (option_full_decode) 589 batch_flags |= GEN_BATCH_DECODE_FULL; 590 if (option_print_offsets) 591 batch_flags |= GEN_BATCH_DECODE_OFFSETS; 592 batch_flags |= GEN_BATCH_DECODE_FLOATS; 593 594 struct gen_batch_decode_ctx batch_ctx; 595 gen_batch_decode_ctx_init(&batch_ctx, &devinfo, stdout, batch_flags, 596 xml_path, get_gen_batch_bo, NULL, NULL); 597 598 599 for (int s = 0; s < num_sections; s++) { 600 enum drm_i915_gem_engine_class class; 601 ring_name_to_class(sections[s].ring_name, &class); 602 603 printf("--- %s (%s) at 0x%08x %08x\n", 604 sections[s].buffer_name, sections[s].ring_name, 605 (unsigned) (sections[s].gtt_offset >> 32), 606 (unsigned) sections[s].gtt_offset); 607 608 if (option_print_all_bb || 609 strcmp(sections[s].buffer_name, "batch buffer") == 0 || 610 strcmp(sections[s].buffer_name, "ring buffer") == 0 || 611 strcmp(sections[s].buffer_name, "HW Context") == 0) { 612 batch_ctx.engine = class; 613 gen_print_batch(&batch_ctx, sections[s].data, 614 sections[s].dword_count * 4, 615 sections[s].gtt_offset, false); 616 } 617 } 618 619 gen_batch_decode_ctx_finish(&batch_ctx); 620 621 for (int s = 0; s < num_sections; s++) { 622 free(sections[s].ring_name); 623 free(sections[s].data); 624 } 625} 626 627static void 628setup_pager(void) 629{ 630 int fds[2]; 631 pid_t pid; 632 633 if (!isatty(1)) 634 return; 635 636 if (pipe(fds) == -1) 637 return; 638 639 pid = fork(); 640 if (pid == -1) 641 return; 642 643 if (pid == 0) { 644 close(fds[1]); 645 dup2(fds[0], 0); 646 execlp("less", "less", "-FRSi", NULL); 647 } 648 649 close(fds[0]); 650 dup2(fds[1], 1); 651 close(fds[1]); 652} 653 654static void 655print_help(const char *progname, FILE *file) 656{ 657 fprintf(file, 658 "Usage: %s [OPTION]... [FILE]\n" 659 "Parse an Intel GPU i915_error_state.\n" 660 "With no FILE, debugfs-dri-directory is probed for in /debug and \n" 661 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n" 662 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n" 663 " --help display this help and exit\n" 664 " --headers decode only command headers\n" 665 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n" 666 " if omitted), 'always', or 'never'\n" 667 " --no-pager don't launch pager\n" 668 " --no-offsets don't print instruction offsets\n" 669 " --xml=DIR load hardware xml description from directory DIR\n" 670 " --all-bb print out all batchbuffers\n", 671 progname); 672} 673 674int 675main(int argc, char *argv[]) 676{ 677 FILE *file; 678 const char *path; 679 struct stat st; 680 int c, i, error; 681 bool help = false, pager = true; 682 const struct option aubinator_opts[] = { 683 { "help", no_argument, (int *) &help, true }, 684 { "no-pager", no_argument, (int *) &pager, false }, 685 { "no-offsets", no_argument, (int *) &option_print_offsets, false }, 686 { "headers", no_argument, (int *) &option_full_decode, false }, 687 { "color", required_argument, NULL, 'c' }, 688 { "xml", required_argument, NULL, 'x' }, 689 { "all-bb", no_argument, (int *) &option_print_all_bb, true }, 690 { NULL, 0, NULL, 0 } 691 }; 692 693 i = 0; 694 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) { 695 switch (c) { 696 case 'c': 697 if (optarg == NULL || strcmp(optarg, "always") == 0) 698 option_color = COLOR_ALWAYS; 699 else if (strcmp(optarg, "never") == 0) 700 option_color = COLOR_NEVER; 701 else if (strcmp(optarg, "auto") == 0) 702 option_color = COLOR_AUTO; 703 else { 704 fprintf(stderr, "invalid value for --color: %s", optarg); 705 exit(EXIT_FAILURE); 706 } 707 break; 708 case 'x': 709 xml_path = strdup(optarg); 710 break; 711 default: 712 break; 713 } 714 } 715 716 if (help || argc == 1) { 717 print_help(argv[0], stderr); 718 exit(EXIT_SUCCESS); 719 } 720 721 if (optind >= argc) { 722 if (isatty(0)) { 723 path = "/sys/class/drm/card0/error"; 724 error = stat(path, &st); 725 if (error != 0) { 726 path = "/debug/dri"; 727 error = stat(path, &st); 728 } 729 if (error != 0) { 730 path = "/sys/kernel/debug/dri"; 731 error = stat(path, &st); 732 } 733 if (error != 0) { 734 errx(1, 735 "Couldn't find i915 debugfs directory.\n\n" 736 "Is debugfs mounted? You might try mounting it with a command such as:\n\n" 737 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n"); 738 } 739 } else { 740 read_data_file(stdin); 741 exit(EXIT_SUCCESS); 742 } 743 } else { 744 path = argv[optind]; 745 error = stat(path, &st); 746 if (error != 0) { 747 fprintf(stderr, "Error opening %s: %s\n", 748 path, strerror(errno)); 749 exit(EXIT_FAILURE); 750 } 751 } 752 753 if (option_color == COLOR_AUTO) 754 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER; 755 756 if (isatty(1) && pager) 757 setup_pager(); 758 759 if (S_ISDIR(st.st_mode)) { 760 MAYBE_UNUSED int ret; 761 char *filename; 762 763 ret = asprintf(&filename, "%s/i915_error_state", path); 764 assert(ret > 0); 765 file = fopen(filename, "r"); 766 if (!file) { 767 int minor; 768 free(filename); 769 for (minor = 0; minor < 64; minor++) { 770 ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor); 771 assert(ret > 0); 772 773 file = fopen(filename, "r"); 774 if (file) 775 break; 776 777 free(filename); 778 } 779 } 780 if (!file) { 781 fprintf(stderr, "Failed to find i915_error_state beneath %s\n", 782 path); 783 return EXIT_FAILURE; 784 } 785 } else { 786 file = fopen(path, "r"); 787 if (!file) { 788 fprintf(stderr, "Failed to open %s: %s\n", 789 path, strerror(errno)); 790 return EXIT_FAILURE; 791 } 792 } 793 794 read_data_file(file); 795 fclose(file); 796 797 /* close the stdout which is opened to write the output */ 798 fflush(stdout); 799 close(1); 800 wait(NULL); 801 802 if (xml_path) 803 free(xml_path); 804 805 return EXIT_SUCCESS; 806} 807 808/* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/ 809