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 "dev/gen_debug.h"
43 #include "util/macros.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_all_bb
= false;
56 static bool option_print_offsets
= true;
57 static enum { COLOR_AUTO
, COLOR_ALWAYS
, COLOR_NEVER
} option_color
;
58 static char *xml_path
= NULL
;
61 print_head(unsigned int reg
)
63 printf(" head = 0x%08x, wraps = %d\n", reg
& (0x7ffff<<2), reg
>> 21);
64 return reg
& (0x7ffff<<2);
68 print_register(struct gen_spec
*spec
, const char *name
, uint32_t reg
)
70 struct gen_group
*reg_spec
=
71 name
? gen_spec_find_register_by_name(spec
, name
) : NULL
;
74 gen_print_group(stdout
, reg_spec
, 0, ®
, 0,
75 option_color
== COLOR_ALWAYS
);
79 struct ring_register_mapping
{
80 enum drm_i915_gem_engine_class ring_class
;
81 unsigned ring_instance
;
82 const char *register_name
;
85 static const struct ring_register_mapping acthd_registers
[] = {
86 { I915_ENGINE_CLASS_COPY
, 0, "BCS_ACTHD_UDW" },
87 { I915_ENGINE_CLASS_VIDEO
, 0, "VCS_ACTHD_UDW" },
88 { I915_ENGINE_CLASS_VIDEO
, 1, "VCS2_ACTHD_UDW" },
89 { I915_ENGINE_CLASS_RENDER
, 0, "ACTHD_UDW" },
90 { I915_ENGINE_CLASS_VIDEO_ENHANCE
, 0, "VECS_ACTHD_UDW" },
93 static const struct ring_register_mapping ctl_registers
[] = {
94 { I915_ENGINE_CLASS_COPY
, 0, "BCS_RING_BUFFER_CTL" },
95 { I915_ENGINE_CLASS_VIDEO
, 0, "VCS_RING_BUFFER_CTL" },
96 { I915_ENGINE_CLASS_VIDEO
, 1, "VCS2_RING_BUFFER_CTL" },
97 { I915_ENGINE_CLASS_RENDER
, 0, "RCS_RING_BUFFER_CTL" },
98 { I915_ENGINE_CLASS_VIDEO_ENHANCE
, 0, "VECS_RING_BUFFER_CTL" },
101 static const struct ring_register_mapping fault_registers
[] = {
102 { I915_ENGINE_CLASS_COPY
, 0, "BCS_FAULT_REG" },
103 { I915_ENGINE_CLASS_VIDEO
, 0, "VCS_FAULT_REG" },
104 { I915_ENGINE_CLASS_RENDER
, 0, "RCS_FAULT_REG" },
105 { I915_ENGINE_CLASS_VIDEO_ENHANCE
, 0, "VECS_FAULT_REG" },
108 static int ring_name_to_class(const char *ring_name
,
109 enum drm_i915_gem_engine_class
*class)
111 static const char *class_names
[] = {
112 [I915_ENGINE_CLASS_RENDER
] = "rcs",
113 [I915_ENGINE_CLASS_COPY
] = "bcs",
114 [I915_ENGINE_CLASS_VIDEO
] = "vcs",
115 [I915_ENGINE_CLASS_VIDEO_ENHANCE
] = "vecs",
117 for (size_t i
= 0; i
< ARRAY_SIZE(class_names
); i
++) {
118 if (strncmp(ring_name
, class_names
[i
], strlen(class_names
[i
])))
122 return atoi(ring_name
+ strlen(class_names
[i
]));
125 static const struct {
130 { "render", I915_ENGINE_CLASS_RENDER
, 0 },
131 { "blt", I915_ENGINE_CLASS_COPY
, 0 },
132 { "bsd", I915_ENGINE_CLASS_VIDEO
, 0 },
133 { "bsd2", I915_ENGINE_CLASS_VIDEO
, 1 },
134 { "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE
, 0 },
136 for (size_t i
= 0; i
< ARRAY_SIZE(legacy_names
); i
++) {
137 if (strcmp(ring_name
, legacy_names
[i
].name
))
140 *class = legacy_names
[i
].class;
141 return legacy_names
[i
].instance
;
148 register_name_from_ring(const struct ring_register_mapping
*mapping
,
150 const char *ring_name
)
152 enum drm_i915_gem_engine_class
class;
155 instance
= ring_name_to_class(ring_name
, &class);
159 for (unsigned i
= 0; i
< nb_mapping
; i
++) {
160 if (mapping
[i
].ring_class
== class &&
161 mapping
[i
].ring_instance
== instance
)
162 return mapping
[i
].register_name
;
168 instdone_register_for_ring(const struct gen_device_info
*devinfo
,
169 const char *ring_name
)
171 enum drm_i915_gem_engine_class
class;
174 instance
= ring_name_to_class(ring_name
, &class);
179 case I915_ENGINE_CLASS_RENDER
:
180 if (devinfo
->gen
== 6)
185 case I915_ENGINE_CLASS_COPY
:
186 return "BCS_INSTDONE";
188 case I915_ENGINE_CLASS_VIDEO
:
191 return "VCS_INSTDONE";
193 return "VCS2_INSTDONE";
198 case I915_ENGINE_CLASS_VIDEO_ENHANCE
:
199 return "VECS_INSTDONE";
209 print_pgtbl_err(unsigned int reg
, struct gen_device_info
*devinfo
)
212 printf(" Invalid Sampler Cache GTT entry\n");
214 printf(" Invalid Render Cache GTT entry\n");
216 printf(" Invalid Instruction/State Cache GTT entry\n");
218 printf(" There is no ROC, this cannot occur!\n");
220 printf(" Invalid GTT entry during Vertex Fetch\n");
222 printf(" Invalid GTT entry during Command Fetch\n");
224 printf(" Invalid GTT entry during CS\n");
226 printf(" Invalid GTT entry during Cursor Fetch\n");
228 printf(" Invalid GTT entry during Overlay Fetch\n");
230 printf(" Invalid GTT entry during Display B Fetch\n");
232 printf(" Invalid GTT entry during Display A Fetch\n");
234 printf(" Valid PTE references illegal memory\n");
236 printf(" Invalid GTT entry during fetch for host\n");
240 print_snb_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
242 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
243 fence
& 1 ? "" : "in",
244 fence
& (1<<1) ? 'y' : 'x',
245 (int)(((fence
>>32)&0xfff)+1)*128,
246 (uint32_t)fence
& 0xfffff000,
247 (uint32_t)(((fence
>>32)&0xfffff000) - (fence
&0xfffff000) + 4096));
251 print_i965_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
253 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
254 fence
& 1 ? "" : "in",
255 fence
& (1<<1) ? 'y' : 'x',
256 (int)(((fence
>>2)&0x1ff)+1)*128,
257 (uint32_t)fence
& 0xfffff000,
258 (uint32_t)(((fence
>>32)&0xfffff000) - (fence
&0xfffff000) + 4096));
262 print_fence(struct gen_device_info
*devinfo
, uint64_t fence
)
264 if (devinfo
->gen
== 6 || devinfo
->gen
== 7) {
265 return print_snb_fence(devinfo
, fence
);
266 } else if (devinfo
->gen
== 4 || devinfo
->gen
== 5) {
267 return print_i965_fence(devinfo
, fence
);
272 print_fault_data(struct gen_device_info
*devinfo
, uint32_t data1
, uint32_t data0
)
276 if (devinfo
->gen
< 8)
279 address
= ((uint64_t)(data0
) << 12) | ((uint64_t)data1
& 0xf) << 44;
280 printf(" Address 0x%016" PRIx64
" %s\n", address
,
281 data1
& (1 << 4) ? "GGTT" : "PPGTT");
285 #define NORMAL CSI "0m"
290 const char *buffer_name
;
296 #define MAX_SECTIONS 256
297 static unsigned num_sections
;
298 static struct section sections
[MAX_SECTIONS
];
300 static int zlib_inflate(uint32_t **ptr
, int len
)
302 struct z_stream_s zstream
;
304 const uint32_t out_size
= 128*4096; /* approximate obj size */
306 memset(&zstream
, 0, sizeof(zstream
));
308 zstream
.next_in
= (unsigned char *)*ptr
;
309 zstream
.avail_in
= 4*len
;
311 if (inflateInit(&zstream
) != Z_OK
)
314 out
= malloc(out_size
);
315 zstream
.next_out
= out
;
316 zstream
.avail_out
= out_size
;
319 switch (inflate(&zstream
, Z_SYNC_FLUSH
)) {
325 inflateEnd(&zstream
);
329 if (zstream
.avail_out
)
332 out
= realloc(out
, 2*zstream
.total_out
);
334 inflateEnd(&zstream
);
338 zstream
.next_out
= (unsigned char *)out
+ zstream
.total_out
;
339 zstream
.avail_out
= zstream
.total_out
;
342 inflateEnd(&zstream
);
345 return zstream
.total_out
/ 4;
348 static int ascii85_decode(const char *in
, uint32_t **out
, bool inflate
)
350 int len
= 0, size
= 1024;
352 *out
= realloc(*out
, sizeof(uint32_t)*size
);
356 while (*in
>= '!' && *in
<= 'z') {
361 *out
= realloc(*out
, sizeof(uint32_t)*size
);
369 v
+= in
[0] - 33; v
*= 85;
370 v
+= in
[1] - 33; v
*= 85;
371 v
+= in
[2] - 33; v
*= 85;
372 v
+= in
[3] - 33; v
*= 85;
382 return zlib_inflate(out
, len
);
385 static int qsort_hw_context_first(const void *a
, const void *b
)
387 const struct section
*sa
= a
, *sb
= b
;
388 if (strcmp(sa
->buffer_name
, "HW Context") == 0)
390 if (strcmp(sb
->buffer_name
, "HW Context") == 0)
396 static struct gen_batch_decode_bo
397 get_gen_batch_bo(void *user_data
, bool ppgtt
, uint64_t address
)
399 for (int s
= 0; s
< num_sections
; s
++) {
400 if (sections
[s
].gtt_offset
<= address
&&
401 address
< sections
[s
].gtt_offset
+ sections
[s
].dword_count
* 4) {
402 return (struct gen_batch_decode_bo
) {
403 .addr
= sections
[s
].gtt_offset
,
404 .map
= sections
[s
].data
,
405 .size
= sections
[s
].dword_count
* 4,
410 return (struct gen_batch_decode_bo
) { .map
= NULL
};
414 read_data_file(FILE *file
)
416 struct gen_spec
*spec
= NULL
;
417 long long unsigned fence
;
421 uint32_t offset
, value
;
422 uint32_t ring_head
= UINT32_MAX
, ring_tail
= UINT32_MAX
;
423 bool ring_wraps
= false;
424 char *ring_name
= NULL
;
425 struct gen_device_info devinfo
;
427 while (getline(&line
, &line_size
, file
) > 0) {
428 char *new_ring_name
= NULL
;
431 if (sscanf(line
, "%m[^ ] command stream\n", &new_ring_name
) > 0) {
433 ring_name
= new_ring_name
;
436 if (line
[0] == ':' || line
[0] == '~') {
437 uint32_t *data
= NULL
;
438 int dword_count
= ascii85_decode(line
+1, &data
, line
[0] == ':');
439 if (dword_count
== 0) {
440 fprintf(stderr
, "ASCII85 decode failed.\n");
443 assert(num_sections
< MAX_SECTIONS
);
444 sections
[num_sections
].data
= data
;
445 sections
[num_sections
].dword_count
= dword_count
;
450 dashes
= strstr(line
, "---");
456 { "ringbuffer", "ring buffer" },
457 { "ring", "ring buffer" },
458 { "gtt_offset", "batch buffer" },
459 { "batch", "batch buffer" },
460 { "hw context", "HW Context" },
461 { "hw status", "HW status" },
462 { "wa context", "WA context" },
463 { "wa batchbuffer", "WA batch" },
464 { "NULL context", "Kernel context" },
466 { "semaphores", "semaphores", },
467 { "guc log buffer", "GuC log", },
472 ring_name
= malloc(dashes
- line
);
473 strncpy(ring_name
, line
, dashes
- line
);
474 ring_name
[dashes
- line
- 1] = '\0';
477 for (b
= buffers
; b
->match
; b
++) {
478 if (strncasecmp(dashes
, b
->match
, strlen(b
->match
)) == 0)
482 assert(num_sections
< MAX_SECTIONS
);
483 sections
[num_sections
].buffer_name
= b
->name
;
484 sections
[num_sections
].ring_name
= strdup(ring_name
);
487 dashes
= strchr(dashes
, '=');
488 if (dashes
&& sscanf(dashes
, "= 0x%08x %08x\n", &hi
, &lo
))
489 sections
[num_sections
].gtt_offset
= ((uint64_t) hi
) << 32 | lo
;
494 matched
= sscanf(line
, "%08x : %08x", &offset
, &value
);
498 /* display reg section is after the ringbuffers, don't mix them */
501 matched
= sscanf(line
, "PCI ID: 0x%04x\n", ®
);
503 matched
= sscanf(line
, " PCI ID: 0x%04x\n", ®
);
505 const char *pci_id_start
= strstr(line
, "PCI ID");
507 matched
= sscanf(pci_id_start
, "PCI ID: 0x%04x\n", ®
);
510 if (!gen_get_device_info_from_pci_id(reg
, &devinfo
)) {
511 printf("Unable to identify devid=%x\n", reg
);
515 printf("Detected GEN%i chipset\n", devinfo
.gen
);
517 if (xml_path
== NULL
)
518 spec
= gen_spec_load(&devinfo
);
520 spec
= gen_spec_load_from_path(&devinfo
, xml_path
);
523 matched
= sscanf(line
, " CTL: 0x%08x\n", ®
);
526 register_name_from_ring(ctl_registers
,
527 ARRAY_SIZE(ctl_registers
),
531 matched
= sscanf(line
, " HEAD: 0x%08x\n", ®
);
535 sscanf(line
, " HEAD: 0x%08x [0x%08X]\n", ®
, &ring_head
);
536 sscanf(line
, " TAIL: 0x%08x\n", &ring_tail
);
538 matched
= sscanf(line
, " ACTHD: 0x%08x\n", ®
);
541 register_name_from_ring(acthd_registers
,
542 ARRAY_SIZE(acthd_registers
),
546 matched
= sscanf(line
, " PGTBL_ER: 0x%08x\n", ®
);
547 if (matched
== 1 && reg
)
548 print_pgtbl_err(reg
, &devinfo
);
550 matched
= sscanf(line
, " ERROR: 0x%08x\n", ®
);
551 if (matched
== 1 && reg
) {
552 print_register(spec
, "GFX_ARB_ERROR_RPT", reg
);
555 matched
= sscanf(line
, " INSTDONE: 0x%08x\n", ®
);
557 const char *reg_name
=
558 instdone_register_for_ring(&devinfo
, ring_name
);
560 print_register(spec
, reg_name
, reg
);
563 matched
= sscanf(line
, " SC_INSTDONE: 0x%08x\n", ®
);
565 print_register(spec
, "SC_INSTDONE", reg
);
567 matched
= sscanf(line
, " SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", ®
);
569 print_register(spec
, "SAMPLER_INSTDONE", reg
);
571 matched
= sscanf(line
, " ROW_INSTDONE[%*d][%*d]: 0x%08x\n", ®
);
573 print_register(spec
, "ROW_INSTDONE", reg
);
575 matched
= sscanf(line
, " INSTDONE1: 0x%08x\n", ®
);
577 print_register(spec
, "INSTDONE_1", reg
);
579 matched
= sscanf(line
, " fence[%i] = %Lx\n", ®
, &fence
);
581 print_fence(&devinfo
, fence
);
583 matched
= sscanf(line
, " FAULT_REG: 0x%08x\n", ®
);
584 if (matched
== 1 && reg
) {
585 const char *reg_name
=
586 register_name_from_ring(fault_registers
,
587 ARRAY_SIZE(fault_registers
),
589 if (reg_name
== NULL
)
590 reg_name
= "FAULT_REG";
591 print_register(spec
, reg_name
, reg
);
594 matched
= sscanf(line
, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", ®
, ®2
);
596 print_fault_data(&devinfo
, reg
, reg2
);
606 * Order sections so that the hardware context section is visited by the
607 * decoder before other command buffers. This will allow the decoder to see
608 * persistent state that was set before the current batch.
610 qsort(sections
, num_sections
, sizeof(sections
[0]), qsort_hw_context_first
);
612 for (int s
= 0; s
< num_sections
; s
++) {
613 if (strcmp(sections
[s
].buffer_name
, "ring buffer") != 0)
615 if (ring_head
== UINT32_MAX
) {
617 ring_tail
= UINT32_MAX
;
619 if (ring_tail
== UINT32_MAX
)
620 ring_tail
= (ring_head
- sizeof(uint32_t)) %
621 (sections
[s
].dword_count
* sizeof(uint32_t));
622 if (ring_head
> ring_tail
) {
623 size_t total_size
= sections
[s
].dword_count
* sizeof(uint32_t) -
624 ring_head
+ ring_tail
;
625 size_t size1
= total_size
- ring_tail
;
626 uint32_t *new_data
= calloc(total_size
, 1);
627 memcpy(new_data
, (uint8_t *)sections
[s
].data
+ ring_head
, size1
);
628 memcpy((uint8_t *)new_data
+ size1
, sections
[s
].data
, ring_tail
);
629 free(sections
[s
].data
);
630 sections
[s
].data
= new_data
;
632 ring_tail
= total_size
;
635 sections
[s
].data_offset
= ring_head
;
636 sections
[s
].dword_count
= (ring_tail
- ring_head
) / sizeof(uint32_t);
639 for (int s
= 0; s
< num_sections
; s
++) {
640 if (sections
[s
].dword_count
* 4 > intel_debug_identifier_size() &&
641 memcmp(sections
[s
].data
, intel_debug_identifier(),
642 intel_debug_identifier_size()) == 0) {
643 const struct gen_debug_block_driver
*driver_desc
=
644 intel_debug_get_identifier_block(sections
[s
].data
,
645 sections
[s
].dword_count
* 4,
646 GEN_DEBUG_BLOCK_TYPE_DRIVER
);
648 printf("Driver identifier: %s\n",
649 (const char *) driver_desc
->description
);
655 enum gen_batch_decode_flags batch_flags
= 0;
656 if (option_color
== COLOR_ALWAYS
)
657 batch_flags
|= GEN_BATCH_DECODE_IN_COLOR
;
658 if (option_full_decode
)
659 batch_flags
|= GEN_BATCH_DECODE_FULL
;
660 if (option_print_offsets
)
661 batch_flags
|= GEN_BATCH_DECODE_OFFSETS
;
662 batch_flags
|= GEN_BATCH_DECODE_FLOATS
;
664 struct gen_batch_decode_ctx batch_ctx
;
665 gen_batch_decode_ctx_init(&batch_ctx
, &devinfo
, stdout
, batch_flags
,
666 xml_path
, get_gen_batch_bo
, NULL
, NULL
);
669 for (int s
= 0; s
< num_sections
; s
++) {
670 enum drm_i915_gem_engine_class
class;
671 ring_name_to_class(sections
[s
].ring_name
, &class);
673 printf("--- %s (%s) at 0x%08x %08x\n",
674 sections
[s
].buffer_name
, sections
[s
].ring_name
,
675 (unsigned) (sections
[s
].gtt_offset
>> 32),
676 (unsigned) sections
[s
].gtt_offset
);
678 bool is_ring_buffer
= strcmp(sections
[s
].buffer_name
, "ring buffer") == 0;
679 if (option_print_all_bb
|| is_ring_buffer
||
680 strcmp(sections
[s
].buffer_name
, "batch buffer") == 0 ||
681 strcmp(sections
[s
].buffer_name
, "HW Context") == 0) {
682 if (is_ring_buffer
&& ring_wraps
)
683 batch_ctx
.flags
&= ~GEN_BATCH_DECODE_OFFSETS
;
684 batch_ctx
.engine
= class;
685 uint8_t *data
= (uint8_t *)sections
[s
].data
+ sections
[s
].data_offset
;
686 uint64_t batch_addr
= sections
[s
].gtt_offset
+ sections
[s
].data_offset
;
687 gen_print_batch(&batch_ctx
, (uint32_t *)data
,
688 sections
[s
].dword_count
* 4, batch_addr
,
690 batch_ctx
.flags
= batch_flags
;
694 gen_batch_decode_ctx_finish(&batch_ctx
);
696 for (int s
= 0; s
< num_sections
; s
++) {
697 free(sections
[s
].ring_name
);
698 free(sections
[s
].data
);
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"
745 " --all-bb print out all batchbuffers\n",
750 main(int argc
, char *argv
[])
756 bool help
= false, pager
= true;
757 const struct option aubinator_opts
[] = {
758 { "help", no_argument
, (int *) &help
, true },
759 { "no-pager", no_argument
, (int *) &pager
, false },
760 { "no-offsets", no_argument
, (int *) &option_print_offsets
, false },
761 { "headers", no_argument
, (int *) &option_full_decode
, false },
762 { "color", required_argument
, NULL
, 'c' },
763 { "xml", required_argument
, NULL
, 'x' },
764 { "all-bb", no_argument
, (int *) &option_print_all_bb
, true },
769 while ((c
= getopt_long(argc
, argv
, "", aubinator_opts
, &i
)) != -1) {
772 if (optarg
== NULL
|| strcmp(optarg
, "always") == 0)
773 option_color
= COLOR_ALWAYS
;
774 else if (strcmp(optarg
, "never") == 0)
775 option_color
= COLOR_NEVER
;
776 else if (strcmp(optarg
, "auto") == 0)
777 option_color
= COLOR_AUTO
;
779 fprintf(stderr
, "invalid value for --color: %s", optarg
);
784 xml_path
= strdup(optarg
);
791 if (help
|| argc
== 1) {
792 print_help(argv
[0], stderr
);
796 if (optind
>= argc
) {
798 path
= "/sys/class/drm/card0/error";
799 error
= stat(path
, &st
);
802 error
= stat(path
, &st
);
805 path
= "/sys/kernel/debug/dri";
806 error
= stat(path
, &st
);
810 "Couldn't find i915 debugfs directory.\n\n"
811 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
812 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
815 read_data_file(stdin
);
820 error
= stat(path
, &st
);
822 fprintf(stderr
, "Error opening %s: %s\n",
823 path
, strerror(errno
));
828 if (option_color
== COLOR_AUTO
)
829 option_color
= isatty(1) ? COLOR_ALWAYS
: COLOR_NEVER
;
831 if (isatty(1) && pager
)
834 if (S_ISDIR(st
.st_mode
)) {
838 ret
= asprintf(&filename
, "%s/i915_error_state", path
);
840 file
= fopen(filename
, "r");
844 for (minor
= 0; minor
< 64; minor
++) {
845 ret
= asprintf(&filename
, "%s/%d/i915_error_state", path
, minor
);
848 file
= fopen(filename
, "r");
856 fprintf(stderr
, "Failed to find i915_error_state beneath %s\n",
861 file
= fopen(path
, "r");
863 fprintf(stderr
, "Failed to open %s: %s\n",
864 path
, strerror(errno
));
869 read_data_file(file
);
872 /* close the stdout which is opened to write the output */
883 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/