Path: blob/21.2-virgl/src/intel/tools/aubinator_error_decode.c
4547 views
/*1* Copyright © 2007-2017 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*22*/2324#include <stdbool.h>25#include <stdio.h>26#include <stdlib.h>27#include <stdarg.h>28#include <string.h>29#include <unistd.h>30#include <inttypes.h>31#include <errno.h>32#include <sys/stat.h>33#include <sys/types.h>34#include <sys/wait.h>35#include <err.h>36#include <assert.h>37#include <getopt.h>38#include <zlib.h>3940#include "common/intel_decoder.h"41#include "dev/intel_debug.h"42#include "util/macros.h"4344#define MIN(a, b) ((a) < (b) ? (a) : (b))4546/* options */4748static bool option_full_decode = true;49static bool option_print_all_bb = false;50static bool option_print_offsets = true;51static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;52static char *xml_path = NULL;5354static uint32_t55print_head(unsigned int reg)56{57printf(" head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21);58return reg & (0x7ffff<<2);59}6061static void62print_register(struct intel_spec *spec, const char *name, uint32_t reg)63{64struct intel_group *reg_spec =65name ? intel_spec_find_register_by_name(spec, name) : NULL;6667if (reg_spec) {68intel_print_group(stdout, reg_spec, 0, ®, 0,69option_color == COLOR_ALWAYS);70}71}7273struct ring_register_mapping {74enum drm_i915_gem_engine_class ring_class;75unsigned ring_instance;76const char *register_name;77};7879static const struct ring_register_mapping acthd_registers[] = {80{ I915_ENGINE_CLASS_COPY, 0, "BCS_ACTHD_UDW" },81{ I915_ENGINE_CLASS_VIDEO, 0, "VCS_ACTHD_UDW" },82{ I915_ENGINE_CLASS_VIDEO, 1, "VCS2_ACTHD_UDW" },83{ I915_ENGINE_CLASS_RENDER, 0, "ACTHD_UDW" },84{ I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_ACTHD_UDW" },85};8687static const struct ring_register_mapping ctl_registers[] = {88{ I915_ENGINE_CLASS_COPY, 0, "BCS_RING_BUFFER_CTL" },89{ I915_ENGINE_CLASS_VIDEO, 0, "VCS_RING_BUFFER_CTL" },90{ I915_ENGINE_CLASS_VIDEO, 1, "VCS2_RING_BUFFER_CTL" },91{ I915_ENGINE_CLASS_RENDER, 0, "RCS_RING_BUFFER_CTL" },92{ I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_RING_BUFFER_CTL" },93};9495static const struct ring_register_mapping fault_registers[] = {96{ I915_ENGINE_CLASS_COPY, 0, "BCS_FAULT_REG" },97{ I915_ENGINE_CLASS_VIDEO, 0, "VCS_FAULT_REG" },98{ I915_ENGINE_CLASS_RENDER, 0, "RCS_FAULT_REG" },99{ I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_FAULT_REG" },100};101102static int ring_name_to_class(const char *ring_name,103enum drm_i915_gem_engine_class *class)104{105static const char *class_names[] = {106[I915_ENGINE_CLASS_RENDER] = "rcs",107[I915_ENGINE_CLASS_COPY] = "bcs",108[I915_ENGINE_CLASS_VIDEO] = "vcs",109[I915_ENGINE_CLASS_VIDEO_ENHANCE] = "vecs",110};111for (size_t i = 0; i < ARRAY_SIZE(class_names); i++) {112if (strncmp(ring_name, class_names[i], strlen(class_names[i])))113continue;114115*class = i;116return atoi(ring_name + strlen(class_names[i]));117}118119static const struct {120const char *name;121unsigned int class;122int instance;123} legacy_names[] = {124{ "render", I915_ENGINE_CLASS_RENDER, 0 },125{ "blt", I915_ENGINE_CLASS_COPY, 0 },126{ "bsd", I915_ENGINE_CLASS_VIDEO, 0 },127{ "bsd2", I915_ENGINE_CLASS_VIDEO, 1 },128{ "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE, 0 },129};130for (size_t i = 0; i < ARRAY_SIZE(legacy_names); i++) {131if (strcmp(ring_name, legacy_names[i].name))132continue;133134*class = legacy_names[i].class;135return legacy_names[i].instance;136}137138return -1;139}140141static const char *142register_name_from_ring(const struct ring_register_mapping *mapping,143unsigned nb_mapping,144const char *ring_name)145{146enum drm_i915_gem_engine_class class;147int instance;148149instance = ring_name_to_class(ring_name, &class);150if (instance < 0)151return NULL;152153for (unsigned i = 0; i < nb_mapping; i++) {154if (mapping[i].ring_class == class &&155mapping[i].ring_instance == instance)156return mapping[i].register_name;157}158return NULL;159}160161static const char *162instdone_register_for_ring(const struct intel_device_info *devinfo,163const char *ring_name)164{165enum drm_i915_gem_engine_class class;166int instance;167168instance = ring_name_to_class(ring_name, &class);169if (instance < 0)170return NULL;171172switch (class) {173case I915_ENGINE_CLASS_RENDER:174if (devinfo->ver == 6)175return "INSTDONE_2";176else177return "INSTDONE_1";178179case I915_ENGINE_CLASS_COPY:180return "BCS_INSTDONE";181182case I915_ENGINE_CLASS_VIDEO:183switch (instance) {184case 0:185return "VCS_INSTDONE";186case 1:187return "VCS2_INSTDONE";188default:189return NULL;190}191192case I915_ENGINE_CLASS_VIDEO_ENHANCE:193return "VECS_INSTDONE";194195default:196return NULL;197}198199return NULL;200}201202static void203print_pgtbl_err(unsigned int reg, struct intel_device_info *devinfo)204{205if (reg & (1 << 26))206printf(" Invalid Sampler Cache GTT entry\n");207if (reg & (1 << 24))208printf(" Invalid Render Cache GTT entry\n");209if (reg & (1 << 23))210printf(" Invalid Instruction/State Cache GTT entry\n");211if (reg & (1 << 22))212printf(" There is no ROC, this cannot occur!\n");213if (reg & (1 << 21))214printf(" Invalid GTT entry during Vertex Fetch\n");215if (reg & (1 << 20))216printf(" Invalid GTT entry during Command Fetch\n");217if (reg & (1 << 19))218printf(" Invalid GTT entry during CS\n");219if (reg & (1 << 18))220printf(" Invalid GTT entry during Cursor Fetch\n");221if (reg & (1 << 17))222printf(" Invalid GTT entry during Overlay Fetch\n");223if (reg & (1 << 8))224printf(" Invalid GTT entry during Display B Fetch\n");225if (reg & (1 << 4))226printf(" Invalid GTT entry during Display A Fetch\n");227if (reg & (1 << 1))228printf(" Valid PTE references illegal memory\n");229if (reg & (1 << 0))230printf(" Invalid GTT entry during fetch for host\n");231}232233static void234print_snb_fence(struct intel_device_info *devinfo, uint64_t fence)235{236printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",237fence & 1 ? "" : "in",238fence & (1<<1) ? 'y' : 'x',239(int)(((fence>>32)&0xfff)+1)*128,240(uint32_t)fence & 0xfffff000,241(uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));242}243244static void245print_i965_fence(struct intel_device_info *devinfo, uint64_t fence)246{247printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",248fence & 1 ? "" : "in",249fence & (1<<1) ? 'y' : 'x',250(int)(((fence>>2)&0x1ff)+1)*128,251(uint32_t)fence & 0xfffff000,252(uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));253}254255static void256print_fence(struct intel_device_info *devinfo, uint64_t fence)257{258if (devinfo->ver == 6 || devinfo->ver == 7) {259return print_snb_fence(devinfo, fence);260} else if (devinfo->ver == 4 || devinfo->ver == 5) {261return print_i965_fence(devinfo, fence);262}263}264265static void266print_fault_data(struct intel_device_info *devinfo, uint32_t data1, uint32_t data0)267{268uint64_t address;269270if (devinfo->ver < 8)271return;272273address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;274printf(" Address 0x%016" PRIx64 " %s\n", address,275data1 & (1 << 4) ? "GGTT" : "PPGTT");276}277278#define CSI "\e["279#define NORMAL CSI "0m"280281struct section {282uint64_t gtt_offset;283char *ring_name;284const char *buffer_name;285uint32_t *data;286int dword_count;287size_t data_offset;288};289290#define MAX_SECTIONS 256291static unsigned num_sections;292static struct section sections[MAX_SECTIONS];293294static int zlib_inflate(uint32_t **ptr, int len)295{296struct z_stream_s zstream;297void *out;298const uint32_t out_size = 128*4096; /* approximate obj size */299300memset(&zstream, 0, sizeof(zstream));301302zstream.next_in = (unsigned char *)*ptr;303zstream.avail_in = 4*len;304305if (inflateInit(&zstream) != Z_OK)306return 0;307308out = malloc(out_size);309zstream.next_out = out;310zstream.avail_out = out_size;311312do {313switch (inflate(&zstream, Z_SYNC_FLUSH)) {314case Z_STREAM_END:315goto end;316case Z_OK:317break;318default:319inflateEnd(&zstream);320return 0;321}322323if (zstream.avail_out)324break;325326out = realloc(out, 2*zstream.total_out);327if (out == NULL) {328inflateEnd(&zstream);329return 0;330}331332zstream.next_out = (unsigned char *)out + zstream.total_out;333zstream.avail_out = zstream.total_out;334} while (1);335end:336inflateEnd(&zstream);337free(*ptr);338*ptr = out;339return zstream.total_out / 4;340}341342static int ascii85_decode(const char *in, uint32_t **out, bool inflate)343{344int len = 0, size = 1024;345346*out = realloc(*out, sizeof(uint32_t)*size);347if (*out == NULL)348return 0;349350while (*in >= '!' && *in <= 'z') {351uint32_t v = 0;352353if (len == size) {354size *= 2;355*out = realloc(*out, sizeof(uint32_t)*size);356if (*out == NULL)357return 0;358}359360if (*in == 'z') {361in++;362} else {363v += in[0] - 33; v *= 85;364v += in[1] - 33; v *= 85;365v += in[2] - 33; v *= 85;366v += in[3] - 33; v *= 85;367v += in[4] - 33;368in += 5;369}370(*out)[len++] = v;371}372373if (!inflate)374return len;375376return zlib_inflate(out, len);377}378379static int qsort_hw_context_first(const void *a, const void *b)380{381const struct section *sa = a, *sb = b;382if (strcmp(sa->buffer_name, "HW Context") == 0)383return -1;384if (strcmp(sb->buffer_name, "HW Context") == 0)385return 1;386else387return 0;388}389390static struct intel_batch_decode_bo391get_intel_batch_bo(void *user_data, bool ppgtt, uint64_t address)392{393for (int s = 0; s < num_sections; s++) {394if (sections[s].gtt_offset <= address &&395address < sections[s].gtt_offset + sections[s].dword_count * 4) {396return (struct intel_batch_decode_bo) {397.addr = sections[s].gtt_offset,398.map = sections[s].data,399.size = sections[s].dword_count * 4,400};401}402}403404return (struct intel_batch_decode_bo) { .map = NULL };405}406407static void408read_data_file(FILE *file)409{410struct intel_spec *spec = NULL;411long long unsigned fence;412int matched;413char *line = NULL;414size_t line_size;415uint32_t offset, value;416uint32_t ring_head = UINT32_MAX, ring_tail = UINT32_MAX;417bool ring_wraps = false;418char *ring_name = NULL;419struct intel_device_info devinfo;420421while (getline(&line, &line_size, file) > 0) {422char *new_ring_name = NULL;423char *dashes;424425if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {426free(ring_name);427ring_name = new_ring_name;428}429430if (line[0] == ':' || line[0] == '~') {431uint32_t *data = NULL;432int dword_count = ascii85_decode(line+1, &data, line[0] == ':');433if (dword_count == 0) {434fprintf(stderr, "ASCII85 decode failed.\n");435exit(EXIT_FAILURE);436}437assert(num_sections < MAX_SECTIONS);438sections[num_sections].data = data;439sections[num_sections].dword_count = dword_count;440num_sections++;441continue;442}443444dashes = strstr(line, "---");445if (dashes) {446const struct {447const char *match;448const char *name;449} buffers[] = {450{ "ringbuffer", "ring buffer" },451{ "ring", "ring buffer" },452{ "gtt_offset", "batch buffer" },453{ "batch", "batch buffer" },454{ "hw context", "HW Context" },455{ "hw status", "HW status" },456{ "wa context", "WA context" },457{ "wa batchbuffer", "WA batch" },458{ "NULL context", "Kernel context" },459{ "user", "user" },460{ "semaphores", "semaphores", },461{ "guc log buffer", "GuC log", },462{ NULL, "unknown" },463}, *b;464465free(ring_name);466ring_name = malloc(dashes - line);467strncpy(ring_name, line, dashes - line);468ring_name[dashes - line - 1] = '\0';469470dashes += 4;471for (b = buffers; b->match; b++) {472if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)473break;474}475476assert(num_sections < MAX_SECTIONS);477sections[num_sections].buffer_name = b->name;478sections[num_sections].ring_name = strdup(ring_name);479480uint32_t hi, lo;481dashes = strchr(dashes, '=');482if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo))483sections[num_sections].gtt_offset = ((uint64_t) hi) << 32 | lo;484485continue;486}487488matched = sscanf(line, "%08x : %08x", &offset, &value);489if (matched != 2) {490uint32_t reg, reg2;491492/* display reg section is after the ringbuffers, don't mix them */493printf("%s", line);494495matched = sscanf(line, "PCI ID: 0x%04x\n", ®);496if (matched == 0)497matched = sscanf(line, " PCI ID: 0x%04x\n", ®);498if (matched == 0) {499const char *pci_id_start = strstr(line, "PCI ID");500if (pci_id_start)501matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", ®);502}503if (matched == 1) {504if (!intel_get_device_info_from_pci_id(reg, &devinfo)) {505printf("Unable to identify devid=%x\n", reg);506exit(EXIT_FAILURE);507}508509printf("Detected GEN%i chipset\n", devinfo.ver);510511if (xml_path == NULL)512spec = intel_spec_load(&devinfo);513else514spec = intel_spec_load_from_path(&devinfo, xml_path);515}516517matched = sscanf(line, " CTL: 0x%08x\n", ®);518if (matched == 1) {519print_register(spec,520register_name_from_ring(ctl_registers,521ARRAY_SIZE(ctl_registers),522ring_name), reg);523}524525matched = sscanf(line, " HEAD: 0x%08x\n", ®);526if (matched == 1)527print_head(reg);528529sscanf(line, " HEAD: 0x%08x [0x%08X]\n", ®, &ring_head);530sscanf(line, " TAIL: 0x%08x\n", &ring_tail);531532matched = sscanf(line, " ACTHD: 0x%08x\n", ®);533if (matched == 1) {534print_register(spec,535register_name_from_ring(acthd_registers,536ARRAY_SIZE(acthd_registers),537ring_name), reg);538}539540matched = sscanf(line, " PGTBL_ER: 0x%08x\n", ®);541if (matched == 1 && reg)542print_pgtbl_err(reg, &devinfo);543544matched = sscanf(line, " ERROR: 0x%08x\n", ®);545if (matched == 1 && reg) {546print_register(spec, "GFX_ARB_ERROR_RPT", reg);547}548549matched = sscanf(line, " INSTDONE: 0x%08x\n", ®);550if (matched == 1) {551const char *reg_name =552instdone_register_for_ring(&devinfo, ring_name);553if (reg_name)554print_register(spec, reg_name, reg);555}556557matched = sscanf(line, " SC_INSTDONE: 0x%08x\n", ®);558if (matched == 1)559print_register(spec, "SC_INSTDONE", reg);560561matched = sscanf(line, " SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", ®);562if (matched == 1)563print_register(spec, "SAMPLER_INSTDONE", reg);564565matched = sscanf(line, " ROW_INSTDONE[%*d][%*d]: 0x%08x\n", ®);566if (matched == 1)567print_register(spec, "ROW_INSTDONE", reg);568569matched = sscanf(line, " INSTDONE1: 0x%08x\n", ®);570if (matched == 1)571print_register(spec, "INSTDONE_1", reg);572573matched = sscanf(line, " fence[%i] = %Lx\n", ®, &fence);574if (matched == 2)575print_fence(&devinfo, fence);576577matched = sscanf(line, " FAULT_REG: 0x%08x\n", ®);578if (matched == 1 && reg) {579const char *reg_name =580register_name_from_ring(fault_registers,581ARRAY_SIZE(fault_registers),582ring_name);583if (reg_name == NULL)584reg_name = "FAULT_REG";585print_register(spec, reg_name, reg);586}587588matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", ®, ®2);589if (matched == 2)590print_fault_data(&devinfo, reg, reg2);591592continue;593}594}595596free(line);597free(ring_name);598599/*600* Order sections so that the hardware context section is visited by the601* decoder before other command buffers. This will allow the decoder to see602* persistent state that was set before the current batch.603*/604qsort(sections, num_sections, sizeof(sections[0]), qsort_hw_context_first);605606for (int s = 0; s < num_sections; s++) {607if (strcmp(sections[s].buffer_name, "ring buffer") != 0)608continue;609if (ring_head == UINT32_MAX) {610ring_head = 0;611ring_tail = UINT32_MAX;612}613if (ring_tail == UINT32_MAX)614ring_tail = (ring_head - sizeof(uint32_t)) %615(sections[s].dword_count * sizeof(uint32_t));616if (ring_head > ring_tail) {617size_t total_size = sections[s].dword_count * sizeof(uint32_t) -618ring_head + ring_tail;619size_t size1 = total_size - ring_tail;620uint32_t *new_data = calloc(total_size, 1);621memcpy(new_data, (uint8_t *)sections[s].data + ring_head, size1);622memcpy((uint8_t *)new_data + size1, sections[s].data, ring_tail);623free(sections[s].data);624sections[s].data = new_data;625ring_head = 0;626ring_tail = total_size;627ring_wraps = true;628}629sections[s].data_offset = ring_head;630sections[s].dword_count = (ring_tail - ring_head) / sizeof(uint32_t);631}632633for (int s = 0; s < num_sections; s++) {634if (sections[s].dword_count * 4 > intel_debug_identifier_size() &&635memcmp(sections[s].data, intel_debug_identifier(),636intel_debug_identifier_size()) == 0) {637const struct intel_debug_block_driver *driver_desc =638intel_debug_get_identifier_block(sections[s].data,639sections[s].dword_count * 4,640INTEL_DEBUG_BLOCK_TYPE_DRIVER);641if (driver_desc) {642printf("Driver identifier: %s\n",643(const char *) driver_desc->description);644}645break;646}647}648649enum intel_batch_decode_flags batch_flags = 0;650if (option_color == COLOR_ALWAYS)651batch_flags |= INTEL_BATCH_DECODE_IN_COLOR;652if (option_full_decode)653batch_flags |= INTEL_BATCH_DECODE_FULL;654if (option_print_offsets)655batch_flags |= INTEL_BATCH_DECODE_OFFSETS;656batch_flags |= INTEL_BATCH_DECODE_FLOATS;657658struct intel_batch_decode_ctx batch_ctx;659intel_batch_decode_ctx_init(&batch_ctx, &devinfo, stdout, batch_flags,660xml_path, get_intel_batch_bo, NULL, NULL);661662663for (int s = 0; s < num_sections; s++) {664enum drm_i915_gem_engine_class class;665ring_name_to_class(sections[s].ring_name, &class);666667printf("--- %s (%s) at 0x%08x %08x\n",668sections[s].buffer_name, sections[s].ring_name,669(unsigned) (sections[s].gtt_offset >> 32),670(unsigned) sections[s].gtt_offset);671672bool is_ring_buffer = strcmp(sections[s].buffer_name, "ring buffer") == 0;673if (option_print_all_bb || is_ring_buffer ||674strcmp(sections[s].buffer_name, "batch buffer") == 0 ||675strcmp(sections[s].buffer_name, "HW Context") == 0) {676if (is_ring_buffer && ring_wraps)677batch_ctx.flags &= ~INTEL_BATCH_DECODE_OFFSETS;678batch_ctx.engine = class;679uint8_t *data = (uint8_t *)sections[s].data + sections[s].data_offset;680uint64_t batch_addr = sections[s].gtt_offset + sections[s].data_offset;681intel_print_batch(&batch_ctx, (uint32_t *)data,682sections[s].dword_count * 4, batch_addr,683is_ring_buffer);684batch_ctx.flags = batch_flags;685}686}687688intel_batch_decode_ctx_finish(&batch_ctx);689690for (int s = 0; s < num_sections; s++) {691free(sections[s].ring_name);692free(sections[s].data);693}694}695696static void697setup_pager(void)698{699int fds[2];700pid_t pid;701702if (!isatty(1))703return;704705if (pipe(fds) == -1)706return;707708pid = fork();709if (pid == -1)710return;711712if (pid == 0) {713close(fds[1]);714dup2(fds[0], 0);715execlp("less", "less", "-FRSi", NULL);716}717718close(fds[0]);719dup2(fds[1], 1);720close(fds[1]);721}722723static void724print_help(const char *progname, FILE *file)725{726fprintf(file,727"Usage: %s [OPTION]... [FILE]\n"728"Parse an Intel GPU i915_error_state.\n"729"With no FILE, debugfs-dri-directory is probed for in /debug and \n"730"/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"731"it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"732" --help display this help and exit\n"733" --headers decode only command headers\n"734" --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"735" if omitted), 'always', or 'never'\n"736" --no-pager don't launch pager\n"737" --no-offsets don't print instruction offsets\n"738" --xml=DIR load hardware xml description from directory DIR\n"739" --all-bb print out all batchbuffers\n",740progname);741}742743static FILE *744open_error_state_file(const char *path)745{746FILE *file;747struct stat st;748749if (stat(path, &st))750return NULL;751752if (S_ISDIR(st.st_mode)) {753ASSERTED int ret;754char *filename;755756ret = asprintf(&filename, "%s/i915_error_state", path);757assert(ret > 0);758file = fopen(filename, "r");759free(filename);760if (!file) {761int minor;762for (minor = 0; minor < 64; minor++) {763ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);764assert(ret > 0);765766file = fopen(filename, "r");767free(filename);768if (file)769break;770}771}772if (!file) {773fprintf(stderr, "Failed to find i915_error_state beneath %s\n",774path);775exit(EXIT_FAILURE);776}777} else {778file = fopen(path, "r");779if (!file) {780fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));781exit(EXIT_FAILURE);782}783}784785return file;786}787788int789main(int argc, char *argv[])790{791FILE *file;792int c, i;793bool help = false, pager = true;794const struct option aubinator_opts[] = {795{ "help", no_argument, (int *) &help, true },796{ "no-pager", no_argument, (int *) &pager, false },797{ "no-offsets", no_argument, (int *) &option_print_offsets, false },798{ "headers", no_argument, (int *) &option_full_decode, false },799{ "color", optional_argument, NULL, 'c' },800{ "xml", required_argument, NULL, 'x' },801{ "all-bb", no_argument, (int *) &option_print_all_bb, true },802{ NULL, 0, NULL, 0 }803};804805i = 0;806while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {807switch (c) {808case 'c':809if (optarg == NULL || strcmp(optarg, "always") == 0)810option_color = COLOR_ALWAYS;811else if (strcmp(optarg, "never") == 0)812option_color = COLOR_NEVER;813else if (strcmp(optarg, "auto") == 0)814option_color = COLOR_AUTO;815else {816fprintf(stderr, "invalid value for --color: %s", optarg);817exit(EXIT_FAILURE);818}819break;820case 'x':821xml_path = strdup(optarg);822break;823case '?':824print_help(argv[0], stderr);825exit(EXIT_FAILURE);826default:827break;828}829}830831if (help) {832print_help(argv[0], stderr);833exit(EXIT_SUCCESS);834}835836if (optind >= argc) {837if (isatty(0)) {838file = open_error_state_file("/sys/class/drm/card0/error");839if (!file)840file = open_error_state_file("/debug/dri");841if (!file)842file = open_error_state_file("/sys/kernel/debug/dri");843844if (file == NULL) {845errx(1,846"Couldn't find i915 debugfs directory.\n\n"847"Is debugfs mounted? You might try mounting it with a command such as:\n\n"848"\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");849}850} else {851file = stdin;852}853} else {854const char *path = argv[optind];855if (strcmp(path, "-") == 0) {856file = stdin;857} else {858file = open_error_state_file(path);859if (file == NULL) {860fprintf(stderr, "Error opening %s: %s\n", path, strerror(errno));861exit(EXIT_FAILURE);862}863}864}865866if (option_color == COLOR_AUTO)867option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;868869if (isatty(1) && pager)870setup_pager();871872read_data_file(file);873fclose(file);874875/* close the stdout which is opened to write the output */876fflush(stdout);877close(1);878wait(NULL);879880if (xml_path)881free(xml_path);882883return EXIT_SUCCESS;884}885886/* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/887888889