2 * Copyright © 2007-2017 Intel Corporation
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:
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
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
34 #include <sys/types.h>
41 #include "common/gen_decoder.h"
42 #include "util/macros.h"
43 #include "gen_disasm.h"
46 #define BLUE_HEADER CSI "0;44m"
47 #define GREEN_HEADER CSI "1;42m"
48 #define NORMAL CSI "0m"
50 #define MIN(a, b) ((a) < (b) ? (a) : (b))
54 static bool option_full_decode
= true;
55 static bool option_print_offsets
= true;
56 static enum { COLOR_AUTO
, COLOR_ALWAYS
, COLOR_NEVER
} option_color
;
57 static char *xml_path
= NULL
;
60 print_head(unsigned int reg
)
62 printf(" head = 0x%08x, wraps = %d\n", reg
& (0x7ffff<<2), reg
>> 21);
63 return reg
& (0x7ffff<<2);
67 print_register(struct gen_spec
*spec
, const char *name
, uint32_t reg
)
69 struct gen_group
*reg_spec
= gen_spec_find_register_by_name(spec
, name
);
72 gen_print_group(stdout
, reg_spec
, 0, ®
, 0,
73 option_color
== COLOR_ALWAYS
);
77 struct ring_register_mapping
{
78 const char *ring_name
;
79 const char *register_name
;
82 static const struct ring_register_mapping acthd_registers
[] = {
83 { "blt", "BCS_ACTHD_UDW" },
84 { "bsd", "VCS_ACTHD_UDW" },
85 { "bsd2", "VCS2_ACTHD_UDW" },
86 { "render", "ACTHD_UDW" },
87 { "vebox", "VECS_ACTHD_UDW" },
90 static const struct ring_register_mapping ctl_registers
[] = {
91 { "blt", "BCS_RING_BUFFER_CTL" },
92 { "bsd", "VCS_RING_BUFFER_CTL" },
93 { "bsd2", "VCS2_RING_BUFFER_CTL" },
94 { "render", "RCS_RING_BUFFER_CTL" },
95 { "vebox", "VECS_RING_BUFFER_CTL" },
98 static const struct ring_register_mapping fault_registers
[] = {
99 { "blt", "BCS_FAULT_REG" },
100 { "bsd", "VCS_FAULT_REG" },
101 { "render", "RCS_FAULT_REG" },
102 { "vebox", "VECS_FAULT_REG" },
106 register_name_from_ring(const struct ring_register_mapping
*mapping
,
108 const char *ring_name
)
110 for (unsigned i
= 0; i
< nb_mapping
; i
++) {
111 if (strcmp(mapping
[i
].ring_name
, ring_name
) == 0)
112 return mapping
[i
].register_name
;
118 instdone_register_for_ring(const struct gen_device_info
*devinfo
,
119 const char *ring_name
)
121 if (strcmp(ring_name
, "blt") == 0)
122 return "BCS_INSTDONE";
123 else if (strcmp(ring_name
, "vebox") == 0)
124 return "VECS_INSTDONE";
125 else if (strcmp(ring_name
, "bsd") == 0)
126 return "VCS_INSTDONE";
127 else if (strcmp(ring_name
, "render") == 0) {
128 if (devinfo
->gen
== 6)
137 print_pgtbl_err(unsigned int reg
, struct gen_device_info
*devinfo
)
140 printf(" Invalid Sampler Cache GTT entry\n");
142 printf(" Invalid Render Cache GTT entry\n");
144 printf(" Invalid Instruction/State Cache GTT entry\n");
146 printf(" There is no ROC, this cannot occur!\n");
148 printf(" Invalid GTT entry during Vertex Fetch\n");
150 printf(" Invalid GTT entry during Command Fetch\n");
152 printf(" Invalid GTT entry during CS\n");
154 printf(" Invalid GTT entry during Cursor Fetch\n");
156 printf(" Invalid GTT entry during Overlay Fetch\n");
158 printf(" Invalid GTT entry during Display B Fetch\n");
160 printf(" Invalid GTT entry during Display A Fetch\n");
162 printf(" Valid PTE references illegal memory\n");
164 printf(" Invalid GTT entry during fetch for host\n");
168 print_snb_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
170 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
171 fence
& 1 ? "" : "in",
172 fence
& (1<<1) ? 'y' : 'x',
173 (int)(((fence
>>32)&0xfff)+1)*128,
174 (uint32_t)fence
& 0xfffff000,
175 (uint32_t)(((fence
>>32)&0xfffff000) - (fence
&0xfffff000) + 4096));
179 print_i965_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
181 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
182 fence
& 1 ? "" : "in",
183 fence
& (1<<1) ? 'y' : 'x',
184 (int)(((fence
>>2)&0x1ff)+1)*128,
185 (uint32_t)fence
& 0xfffff000,
186 (uint32_t)(((fence
>>32)&0xfffff000) - (fence
&0xfffff000) + 4096));
190 print_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
192 if (devinfo
->gen
== 6 || devinfo
->gen
== 7) {
193 return print_snb_fence(devinfo
, fence
);
194 } else if (devinfo
->gen
== 4 || devinfo
->gen
== 5) {
195 return print_i965_fence(devinfo
, fence
);
200 print_fault_data(struct gen_device_info
*devinfo
, uint32_t data1
, uint32_t data0
)
204 if (devinfo
->gen
< 8)
207 address
= ((uint64_t)(data0
) << 12) | ((uint64_t)data1
& 0xf) << 44;
208 printf(" Address 0x%016" PRIx64
" %s\n", address
,
209 data1
& (1 << 4) ? "GGTT" : "PPGTT");
213 #define NORMAL CSI "0m"
218 const char *buffer_name
;
223 #define MAX_SECTIONS 30
224 static struct section sections
[MAX_SECTIONS
];
227 disassemble_program(struct gen_disasm
*disasm
, const char *type
,
228 const struct section
*instruction_section
,
231 if (!instruction_section
)
234 printf("\nReferenced %s:\n", type
);
235 gen_disasm_disassemble(disasm
, instruction_section
->data
, ksp
, stdout
);
238 static const struct section
*
239 find_section(const char *str_base_address
)
241 uint64_t base_address
= strtol(str_base_address
, NULL
, 16);
242 for (int s
= 0; s
< MAX_SECTIONS
; s
++) {
243 if (sections
[s
].gtt_offset
== base_address
)
250 decode(struct gen_spec
*spec
, struct gen_disasm
*disasm
,
251 const struct section
*section
)
253 uint64_t gtt_offset
= section
->gtt_offset
;
254 uint32_t *data
= section
->data
;
255 uint32_t *p
, *end
= (data
+ section
->count
);
257 struct gen_group
*inst
;
258 const struct section
*current_instruction_buffer
= NULL
;
259 const struct section
*current_dynamic_state_buffer
= NULL
;
261 for (p
= data
; p
< end
; p
+= length
) {
262 const char *color
= option_full_decode
? BLUE_HEADER
: NORMAL
,
263 *reset_color
= NORMAL
;
264 uint64_t offset
= gtt_offset
+ 4 * (p
- data
);
266 inst
= gen_spec_find_instruction(spec
, p
);
267 length
= gen_group_get_length(inst
, p
);
268 assert(inst
== NULL
|| length
> 0);
269 length
= MAX2(1, length
);
271 printf("unknown instruction %08x\n", p
[0]);
274 if (option_color
== COLOR_NEVER
) {
279 printf("%s0x%08"PRIx64
": 0x%08x: %-80s%s\n",
280 color
, offset
, p
[0], gen_group_get_name(inst
), reset_color
);
282 gen_print_group(stdout
, inst
, offset
, p
, 0,
283 option_color
== COLOR_ALWAYS
);
285 if (strcmp(inst
->name
, "MI_BATCH_BUFFER_END") == 0)
288 if (strcmp(inst
->name
, "STATE_BASE_ADDRESS") == 0) {
289 struct gen_field_iterator iter
;
290 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
293 if (strcmp(iter
.name
, "Instruction Base Address") == 0) {
294 current_instruction_buffer
= find_section(iter
.value
);
295 } else if (strcmp(iter
.name
, "Dynamic State Base Address") == 0) {
296 current_dynamic_state_buffer
= find_section(iter
.value
);
298 } while (gen_field_iterator_next(&iter
));
299 } else if (strcmp(inst
->name
, "WM_STATE") == 0 ||
300 strcmp(inst
->name
, "3DSTATE_PS") == 0 ||
301 strcmp(inst
->name
, "3DSTATE_WM") == 0) {
302 struct gen_field_iterator iter
;
303 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
304 uint64_t ksp
[3] = {0, 0, 0};
305 bool enabled
[3] = {false, false, false};
308 if (strncmp(iter
.name
, "Kernel Start Pointer ",
309 strlen("Kernel Start Pointer ")) == 0) {
310 int idx
= iter
.name
[strlen("Kernel Start Pointer ")] - '0';
311 ksp
[idx
] = strtol(iter
.value
, NULL
, 16);
312 } else if (strcmp(iter
.name
, "8 Pixel Dispatch Enable") == 0) {
313 enabled
[0] = strcmp(iter
.value
, "true") == 0;
314 } else if (strcmp(iter
.name
, "16 Pixel Dispatch Enable") == 0) {
315 enabled
[1] = strcmp(iter
.value
, "true") == 0;
316 } else if (strcmp(iter
.name
, "32 Pixel Dispatch Enable") == 0) {
317 enabled
[2] = strcmp(iter
.value
, "true") == 0;
319 } while (gen_field_iterator_next(&iter
));
321 /* Reorder KSPs to be [8, 16, 32] instead of the hardware order. */
322 if (enabled
[0] + enabled
[1] + enabled
[2] == 1) {
326 } else if (enabled
[2]) {
331 uint64_t tmp
= ksp
[1];
336 /* FINISHME: Broken for multi-program WM_STATE,
337 * which Mesa does not use
340 disassemble_program(disasm
, "SIMD8 fragment shader",
341 current_instruction_buffer
, ksp
[0]);
344 disassemble_program(disasm
, "SIMD16 fragment shader",
345 current_instruction_buffer
, ksp
[1]);
348 disassemble_program(disasm
, "SIMD32 fragment shader",
349 current_instruction_buffer
, ksp
[2]);
352 } else if (strcmp(inst
->name
, "VS_STATE") == 0 ||
353 strcmp(inst
->name
, "GS_STATE") == 0 ||
354 strcmp(inst
->name
, "SF_STATE") == 0 ||
355 strcmp(inst
->name
, "CLIP_STATE") == 0 ||
356 strcmp(inst
->name
, "3DSTATE_DS") == 0 ||
357 strcmp(inst
->name
, "3DSTATE_HS") == 0 ||
358 strcmp(inst
->name
, "3DSTATE_GS") == 0 ||
359 strcmp(inst
->name
, "3DSTATE_VS") == 0) {
360 struct gen_field_iterator iter
;
361 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
363 bool is_simd8
= false; /* vertex shaders on Gen8+ only */
364 bool is_enabled
= true;
367 if (strcmp(iter
.name
, "Kernel Start Pointer") == 0) {
368 ksp
= strtol(iter
.value
, NULL
, 16);
369 } else if (strcmp(iter
.name
, "SIMD8 Dispatch Enable") == 0) {
370 is_simd8
= strcmp(iter
.value
, "true") == 0;
371 } else if (strcmp(iter
.name
, "Dispatch Enable") == 0) {
372 is_simd8
= strcmp(iter
.value
, "SIMD8") == 0;
373 } else if (strcmp(iter
.name
, "Enable") == 0) {
374 is_enabled
= strcmp(iter
.value
, "true") == 0;
376 } while (gen_field_iterator_next(&iter
));
379 strcmp(inst
->name
, "VS_STATE") == 0 ? "vertex shader" :
380 strcmp(inst
->name
, "GS_STATE") == 0 ? "geometry shader" :
381 strcmp(inst
->name
, "SF_STATE") == 0 ? "strips and fans shader" :
382 strcmp(inst
->name
, "CLIP_STATE") == 0 ? "clip shader" :
383 strcmp(inst
->name
, "3DSTATE_DS") == 0 ? "tessellation control shader" :
384 strcmp(inst
->name
, "3DSTATE_HS") == 0 ? "tessellation evaluation shader" :
385 strcmp(inst
->name
, "3DSTATE_VS") == 0 ? (is_simd8
? "SIMD8 vertex shader" : "vec4 vertex shader") :
386 strcmp(inst
->name
, "3DSTATE_GS") == 0 ? (is_simd8
? "SIMD8 geometry shader" : "vec4 geometry shader") :
390 disassemble_program(disasm
, type
, current_instruction_buffer
, ksp
);
393 } else if (strcmp(inst
->name
, "MEDIA_INTERFACE_DESCRIPTOR_LOAD") == 0) {
394 struct gen_field_iterator iter
;
395 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
396 uint64_t interface_offset
= 0;
398 if (strcmp(iter
.name
, "Interface Descriptor Data Start Address") == 0) {
399 interface_offset
= strtol(iter
.value
, NULL
, 16);
402 } while (gen_field_iterator_next(&iter
));
404 if (current_dynamic_state_buffer
&& interface_offset
!= 0) {
405 struct gen_group
*desc
=
406 gen_spec_find_struct(spec
, "INTERFACE_DESCRIPTOR_DATA");
408 ((void *)current_dynamic_state_buffer
->data
) + interface_offset
;
409 gen_field_iterator_init(&iter
, desc
, desc_p
, 0, false);
411 if (strcmp(iter
.name
, "Kernel Start Pointer") == 0) {
412 uint64_t ksp
= strtol(iter
.value
, NULL
, 16);
413 disassemble_program(disasm
, "compute shader",
414 current_instruction_buffer
, ksp
);
418 } while (gen_field_iterator_next(&iter
));
424 static int zlib_inflate(uint32_t **ptr
, int len
)
426 struct z_stream_s zstream
;
428 const uint32_t out_size
= 128*4096; /* approximate obj size */
430 memset(&zstream
, 0, sizeof(zstream
));
432 zstream
.next_in
= (unsigned char *)*ptr
;
433 zstream
.avail_in
= 4*len
;
435 if (inflateInit(&zstream
) != Z_OK
)
438 out
= malloc(out_size
);
439 zstream
.next_out
= out
;
440 zstream
.avail_out
= out_size
;
443 switch (inflate(&zstream
, Z_SYNC_FLUSH
)) {
449 inflateEnd(&zstream
);
453 if (zstream
.avail_out
)
456 out
= realloc(out
, 2*zstream
.total_out
);
458 inflateEnd(&zstream
);
462 zstream
.next_out
= (unsigned char *)out
+ zstream
.total_out
;
463 zstream
.avail_out
= zstream
.total_out
;
466 inflateEnd(&zstream
);
469 return zstream
.total_out
/ 4;
472 static int ascii85_decode(const char *in
, uint32_t **out
, bool inflate
)
474 int len
= 0, size
= 1024;
476 *out
= realloc(*out
, sizeof(uint32_t)*size
);
480 while (*in
>= '!' && *in
<= 'z') {
485 *out
= realloc(*out
, sizeof(uint32_t)*size
);
493 v
+= in
[0] - 33; v
*= 85;
494 v
+= in
[1] - 33; v
*= 85;
495 v
+= in
[2] - 33; v
*= 85;
496 v
+= in
[3] - 33; v
*= 85;
506 return zlib_inflate(out
, len
);
510 read_data_file(FILE *file
)
512 struct gen_spec
*spec
= NULL
;
513 long long unsigned fence
;
517 uint32_t offset
, value
;
518 char *ring_name
= NULL
;
519 struct gen_device_info devinfo
;
520 struct gen_disasm
*disasm
= NULL
;
523 while (getline(&line
, &line_size
, file
) > 0) {
524 char *new_ring_name
= NULL
;
527 if (sscanf(line
, "%m[^ ] command stream\n", &new_ring_name
) > 0) {
529 ring_name
= new_ring_name
;
532 if (line
[0] == ':' || line
[0] == '~') {
533 uint32_t *data
= NULL
;
534 int count
= ascii85_decode(line
+1, &data
, line
[0] == ':');
536 fprintf(stderr
, "ASCII85 decode failed.\n");
539 sections
[sect_num
].data
= data
;
540 sections
[sect_num
].count
= count
;
545 dashes
= strstr(line
, "---");
551 { "ringbuffer", "ring buffer" },
552 { "gtt_offset", "batch buffer" },
553 { "hw context", "HW Context" },
554 { "hw status", "HW status" },
555 { "wa context", "WA context" },
556 { "wa batchbuffer", "WA batch" },
558 { "semaphores", "semaphores", },
559 { "guc log buffer", "GuC log", },
564 ring_name
= malloc(dashes
- line
);
565 strncpy(ring_name
, line
, dashes
- line
);
566 ring_name
[dashes
- line
- 1] = '\0';
569 for (b
= buffers
; b
->match
; b
++) {
570 if (strncasecmp(dashes
, b
->match
, strlen(b
->match
)) == 0)
574 sections
[sect_num
].buffer_name
= b
->name
;
575 sections
[sect_num
].ring_name
= strdup(ring_name
);
578 dashes
= strchr(dashes
, '=');
579 if (dashes
&& sscanf(dashes
, "= 0x%08x %08x\n", &hi
, &lo
))
580 sections
[sect_num
].gtt_offset
= ((uint64_t) hi
) << 32 | lo
;
585 matched
= sscanf(line
, "%08x : %08x", &offset
, &value
);
589 /* display reg section is after the ringbuffers, don't mix them */
592 matched
= sscanf(line
, "PCI ID: 0x%04x\n", ®
);
594 matched
= sscanf(line
, " PCI ID: 0x%04x\n", ®
);
596 const char *pci_id_start
= strstr(line
, "PCI ID");
598 matched
= sscanf(pci_id_start
, "PCI ID: 0x%04x\n", ®
);
601 if (!gen_get_device_info(reg
, &devinfo
)) {
602 printf("Unable to identify devid=%x\n", reg
);
606 disasm
= gen_disasm_create(reg
);
608 printf("Detected GEN%i chipset\n", devinfo
.gen
);
610 if (xml_path
== NULL
)
611 spec
= gen_spec_load(&devinfo
);
613 spec
= gen_spec_load_from_path(&devinfo
, xml_path
);
616 matched
= sscanf(line
, " CTL: 0x%08x\n", ®
);
619 register_name_from_ring(ctl_registers
,
620 ARRAY_SIZE(ctl_registers
),
624 matched
= sscanf(line
, " HEAD: 0x%08x\n", ®
);
628 matched
= sscanf(line
, " ACTHD: 0x%08x\n", ®
);
631 register_name_from_ring(acthd_registers
,
632 ARRAY_SIZE(acthd_registers
),
636 matched
= sscanf(line
, " PGTBL_ER: 0x%08x\n", ®
);
637 if (matched
== 1 && reg
)
638 print_pgtbl_err(reg
, &devinfo
);
640 matched
= sscanf(line
, " ERROR: 0x%08x\n", ®
);
641 if (matched
== 1 && reg
) {
642 print_register(spec
, "GFX_ARB_ERROR_RPT", reg
);
645 matched
= sscanf(line
, " INSTDONE: 0x%08x\n", ®
);
647 const char *reg_name
=
648 instdone_register_for_ring(&devinfo
, ring_name
);
650 print_register(spec
, reg_name
, reg
);
653 matched
= sscanf(line
, " INSTDONE1: 0x%08x\n", ®
);
655 print_register(spec
, "INSTDONE_1", reg
);
657 matched
= sscanf(line
, " fence[%i] = %Lx\n", ®
, &fence
);
659 print_fence(&devinfo
, fence
);
661 matched
= sscanf(line
, " FAULT_REG: 0x%08x\n", ®
);
662 if (matched
== 1 && reg
) {
663 const char *reg_name
=
664 register_name_from_ring(fault_registers
,
665 ARRAY_SIZE(fault_registers
),
667 if (reg_name
== NULL
)
668 reg_name
= "FAULT_REG";
669 print_register(spec
, reg_name
, reg
);
672 matched
= sscanf(line
, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", ®
, ®2
);
674 print_fault_data(&devinfo
, reg
, reg2
);
683 for (int s
= 0; s
< sect_num
; s
++) {
684 printf("--- %s (%s) at 0x%08x %08x\n",
685 sections
[s
].buffer_name
, sections
[s
].ring_name
,
686 (unsigned) (sections
[s
].gtt_offset
>> 32),
687 (unsigned) sections
[s
].gtt_offset
);
689 if (strcmp(sections
[s
].buffer_name
, "batch buffer") == 0 ||
690 strcmp(sections
[s
].buffer_name
, "ring buffer") == 0 ||
691 strcmp(sections
[s
].buffer_name
, "HW Context") == 0) {
692 decode(spec
, disasm
, §ions
[s
]);
695 free(sections
[s
].ring_name
);
696 free(sections
[s
].data
);
699 gen_disasm_destroy(disasm
);
721 execlp("less", "less", "-FRSi", NULL
);
730 print_help(const char *progname
, FILE *file
)
733 "Usage: %s [OPTION]... [FILE]\n"
734 "Parse an Intel GPU i915_error_state.\n"
735 "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
736 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"
737 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
738 " --help display this help and exit\n"
739 " --headers decode only command headers\n"
740 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
741 " if omitted), 'always', or 'never'\n"
742 " --no-pager don't launch pager\n"
743 " --no-offsets don't print instruction offsets\n"
744 " --xml=DIR load hardware xml description from directory DIR\n",
749 main(int argc
, char *argv
[])
755 bool help
= false, pager
= true;
756 const struct option aubinator_opts
[] = {
757 { "help", no_argument
, (int *) &help
, true },
758 { "no-pager", no_argument
, (int *) &pager
, false },
759 { "no-offsets", no_argument
, (int *) &option_print_offsets
, false },
760 { "headers", no_argument
, (int *) &option_full_decode
, false },
761 { "color", required_argument
, NULL
, 'c' },
762 { "xml", required_argument
, NULL
, 'x' },
767 while ((c
= getopt_long(argc
, argv
, "", aubinator_opts
, &i
)) != -1) {
770 if (optarg
== NULL
|| strcmp(optarg
, "always") == 0)
771 option_color
= COLOR_ALWAYS
;
772 else if (strcmp(optarg
, "never") == 0)
773 option_color
= COLOR_NEVER
;
774 else if (strcmp(optarg
, "auto") == 0)
775 option_color
= COLOR_AUTO
;
777 fprintf(stderr
, "invalid value for --color: %s", optarg
);
782 xml_path
= strdup(optarg
);
789 if (help
|| argc
== 1) {
790 print_help(argv
[0], stderr
);
794 if (optind
>= argc
) {
796 path
= "/sys/class/drm/card0/error";
797 error
= stat(path
, &st
);
800 error
= stat(path
, &st
);
803 path
= "/sys/kernel/debug/dri";
804 error
= stat(path
, &st
);
808 "Couldn't find i915 debugfs directory.\n\n"
809 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
810 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
813 read_data_file(stdin
);
818 error
= stat(path
, &st
);
820 fprintf(stderr
, "Error opening %s: %s\n",
821 path
, strerror(errno
));
826 if (option_color
== COLOR_AUTO
)
827 option_color
= isatty(1) ? COLOR_ALWAYS
: COLOR_NEVER
;
829 if (isatty(1) && pager
)
832 if (S_ISDIR(st
.st_mode
)) {
836 ret
= asprintf(&filename
, "%s/i915_error_state", path
);
838 file
= fopen(filename
, "r");
842 for (minor
= 0; minor
< 64; minor
++) {
843 ret
= asprintf(&filename
, "%s/%d/i915_error_state", path
, minor
);
846 file
= fopen(filename
, "r");
854 fprintf(stderr
, "Failed to find i915_error_state beneath %s\n",
859 file
= fopen(path
, "r");
861 fprintf(stderr
, "Failed to open %s: %s\n",
862 path
, strerror(errno
));
867 read_data_file(file
);
870 /* close the stdout which is opened to write the output */
881 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/