diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-02-18 05:24:56 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-02-22 12:01:39 -0500 |
commit | 9df30794f609d9412f14cfd0eb7b45dd64d0b14e (patch) | |
tree | 17e2658af3fe1af83c6a89ca13c3c93752bdfd13 /drivers/gpu/drm/i915/i915_debugfs.c | |
parent | 7b9c5abee98c54f85bcc04bd4d7ec8d5094c73f4 (diff) |
drm/i915: Record batch buffer following GPU error
In order to improve our diagnostic capabilities following a GPU hang
and subsequent reset, we need to record the batch buffer that triggered
the error. We assume that the current batch buffer, plus a few details
about what else is on the active list, will be sufficient -- at the very
least an improvement over nothing.
The extra information is stored in /debug/dri/.../i915_error_state
following an error, and may be decoded using
intel_gpu_tools/tools/intel_error_decode.
v2: Avoid excessive work under spinlocks.
v3: Include ringbuffer for later analysis.
v4: Use kunmap correctly and record more buffer state.
v5: Search ringbuffer for current batch buffer
v6: Use a work fn for the impossible IRQ error case.
v7: Avoid non-atomic paths whilst in IRQ context.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_debugfs.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 56095b3d28ce..5eed46312442 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -350,6 +350,36 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) | |||
350 | return 0; | 350 | return 0; |
351 | } | 351 | } |
352 | 352 | ||
353 | static const char *pin_flag(int pinned) | ||
354 | { | ||
355 | if (pinned > 0) | ||
356 | return " P"; | ||
357 | else if (pinned < 0) | ||
358 | return " p"; | ||
359 | else | ||
360 | return ""; | ||
361 | } | ||
362 | |||
363 | static const char *tiling_flag(int tiling) | ||
364 | { | ||
365 | switch (tiling) { | ||
366 | default: | ||
367 | case I915_TILING_NONE: return ""; | ||
368 | case I915_TILING_X: return " X"; | ||
369 | case I915_TILING_Y: return " Y"; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | static const char *dirty_flag(int dirty) | ||
374 | { | ||
375 | return dirty ? " dirty" : ""; | ||
376 | } | ||
377 | |||
378 | static const char *purgeable_flag(int purgeable) | ||
379 | { | ||
380 | return purgeable ? " purgeable" : ""; | ||
381 | } | ||
382 | |||
353 | static int i915_error_state(struct seq_file *m, void *unused) | 383 | static int i915_error_state(struct seq_file *m, void *unused) |
354 | { | 384 | { |
355 | struct drm_info_node *node = (struct drm_info_node *) m->private; | 385 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
@@ -357,6 +387,7 @@ static int i915_error_state(struct seq_file *m, void *unused) | |||
357 | drm_i915_private_t *dev_priv = dev->dev_private; | 387 | drm_i915_private_t *dev_priv = dev->dev_private; |
358 | struct drm_i915_error_state *error; | 388 | struct drm_i915_error_state *error; |
359 | unsigned long flags; | 389 | unsigned long flags; |
390 | int i, page, offset, elt; | ||
360 | 391 | ||
361 | spin_lock_irqsave(&dev_priv->error_lock, flags); | 392 | spin_lock_irqsave(&dev_priv->error_lock, flags); |
362 | if (!dev_priv->first_error) { | 393 | if (!dev_priv->first_error) { |
@@ -368,6 +399,7 @@ static int i915_error_state(struct seq_file *m, void *unused) | |||
368 | 399 | ||
369 | seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, | 400 | seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, |
370 | error->time.tv_usec); | 401 | error->time.tv_usec); |
402 | seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); | ||
371 | seq_printf(m, "EIR: 0x%08x\n", error->eir); | 403 | seq_printf(m, "EIR: 0x%08x\n", error->eir); |
372 | seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); | 404 | seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); |
373 | seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); | 405 | seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); |
@@ -379,6 +411,59 @@ static int i915_error_state(struct seq_file *m, void *unused) | |||
379 | seq_printf(m, " INSTPS: 0x%08x\n", error->instps); | 411 | seq_printf(m, " INSTPS: 0x%08x\n", error->instps); |
380 | seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); | 412 | seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); |
381 | } | 413 | } |
414 | seq_printf(m, "seqno: 0x%08x\n", error->seqno); | ||
415 | |||
416 | if (error->active_bo_count) { | ||
417 | seq_printf(m, "Buffers [%d]:\n", error->active_bo_count); | ||
418 | |||
419 | for (i = 0; i < error->active_bo_count; i++) { | ||
420 | seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s", | ||
421 | error->active_bo[i].gtt_offset, | ||
422 | error->active_bo[i].size, | ||
423 | error->active_bo[i].read_domains, | ||
424 | error->active_bo[i].write_domain, | ||
425 | error->active_bo[i].seqno, | ||
426 | pin_flag(error->active_bo[i].pinned), | ||
427 | tiling_flag(error->active_bo[i].tiling), | ||
428 | dirty_flag(error->active_bo[i].dirty), | ||
429 | purgeable_flag(error->active_bo[i].purgeable)); | ||
430 | |||
431 | if (error->active_bo[i].name) | ||
432 | seq_printf(m, " (name: %d)", error->active_bo[i].name); | ||
433 | if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE) | ||
434 | seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg); | ||
435 | |||
436 | seq_printf(m, "\n"); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) { | ||
441 | if (error->batchbuffer[i]) { | ||
442 | struct drm_i915_error_object *obj = error->batchbuffer[i]; | ||
443 | |||
444 | seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset); | ||
445 | offset = 0; | ||
446 | for (page = 0; page < obj->page_count; page++) { | ||
447 | for (elt = 0; elt < PAGE_SIZE/4; elt++) { | ||
448 | seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); | ||
449 | offset += 4; | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | if (error->ringbuffer) { | ||
456 | struct drm_i915_error_object *obj = error->ringbuffer; | ||
457 | |||
458 | seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset); | ||
459 | offset = 0; | ||
460 | for (page = 0; page < obj->page_count; page++) { | ||
461 | for (elt = 0; elt < PAGE_SIZE/4; elt++) { | ||
462 | seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); | ||
463 | offset += 4; | ||
464 | } | ||
465 | } | ||
466 | } | ||
382 | 467 | ||
383 | out: | 468 | out: |
384 | spin_unlock_irqrestore(&dev_priv->error_lock, flags); | 469 | spin_unlock_irqrestore(&dev_priv->error_lock, flags); |