aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-06-18 19:56:52 -0400
committerEric Anholt <eric@anholt.net>2009-07-01 13:50:02 -0400
commit63eeaf38251183ec2b1caee11e4a2c040cb5ce6c (patch)
treefca34774fbd842612f4e366afa6b037b0f3f39ea /drivers/gpu/drm/i915/i915_irq.c
parente83c2b0ff325f52dda1aff3572d0e1516216c54b (diff)
drm/i915: enable error detection & state collection
This patch enables error detection by enabling several types of error interrupts. When an error interrupt is received, the interrupt handler captures the error state; hopefully resulting in an accurate set of error data (error type, active head pointer, etc.). The new record is then available from sysfs. The current code will also dump the error state to the system log. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c139
1 files changed, 136 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 228546f6eaa4..17b308592c4f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -26,6 +26,7 @@
26 * 26 *
27 */ 27 */
28 28
29#include <linux/sysrq.h>
29#include "drmP.h" 30#include "drmP.h"
30#include "drm.h" 31#include "drm.h"
31#include "i915_drm.h" 32#include "i915_drm.h"
@@ -41,9 +42,10 @@
41 * we leave them always unmasked in IMR and then control enabling them through 42 * we leave them always unmasked in IMR and then control enabling them through
42 * PIPESTAT alone. 43 * PIPESTAT alone.
43 */ 44 */
44#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ 45#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
45 I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ 46 I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
46 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) 47 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
48 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
47 49
48/** Interrupts that we mask and unmask at runtime. */ 50/** Interrupts that we mask and unmask at runtime. */
49#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) 51#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
@@ -288,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
288 return ret; 290 return ret;
289} 291}
290 292
293static void i915_capture_error_state(struct drm_device *dev)
294{
295 struct drm_i915_private *dev_priv = dev->dev_private;
296 struct drm_i915_error_state *error;
297 unsigned long flags;
298
299 spin_lock_irqsave(&dev_priv->error_lock, flags);
300 if (dev_priv->first_error)
301 goto out;
302
303 error = kmalloc(sizeof(*error), GFP_ATOMIC);
304 if (!error) {
305 DRM_DEBUG("out ot memory, not capturing error state\n");
306 goto out;
307 }
308
309 error->eir = I915_READ(EIR);
310 error->pgtbl_er = I915_READ(PGTBL_ER);
311 error->pipeastat = I915_READ(PIPEASTAT);
312 error->pipebstat = I915_READ(PIPEBSTAT);
313 error->instpm = I915_READ(INSTPM);
314 if (!IS_I965G(dev)) {
315 error->ipeir = I915_READ(IPEIR);
316 error->ipehr = I915_READ(IPEHR);
317 error->instdone = I915_READ(INSTDONE);
318 error->acthd = I915_READ(ACTHD);
319 } else {
320 error->ipeir = I915_READ(IPEIR_I965);
321 error->ipehr = I915_READ(IPEHR_I965);
322 error->instdone = I915_READ(INSTDONE_I965);
323 error->instps = I915_READ(INSTPS);
324 error->instdone1 = I915_READ(INSTDONE1);
325 error->acthd = I915_READ(ACTHD_I965);
326 }
327
328 dev_priv->first_error = error;
329
330out:
331 spin_unlock_irqrestore(&dev_priv->error_lock, flags);
332}
333
291irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 334irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
292{ 335{
293 struct drm_device *dev = (struct drm_device *) arg; 336 struct drm_device *dev = (struct drm_device *) arg;
@@ -362,6 +405,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
362 I915_READ(PORT_HOTPLUG_STAT); 405 I915_READ(PORT_HOTPLUG_STAT);
363 } 406 }
364 407
408 if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
409 u32 eir = I915_READ(EIR);
410
411 i915_capture_error_state(dev);
412
413 printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
414 eir);
415 if (eir & I915_ERROR_PAGE_TABLE) {
416 u32 pgtbl_err = I915_READ(PGTBL_ER);
417 printk(KERN_ERR "page table error\n");
418 printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
419 pgtbl_err);
420 I915_WRITE(PGTBL_ER, pgtbl_err);
421 (void)I915_READ(PGTBL_ER);
422 }
423 if (eir & I915_ERROR_MEMORY_REFRESH) {
424 printk(KERN_ERR "memory refresh error\n");
425 printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
426 pipea_stats);
427 printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
428 pipeb_stats);
429 /* pipestat has already been acked */
430 }
431 if (eir & I915_ERROR_INSTRUCTION) {
432 printk(KERN_ERR "instruction error\n");
433 printk(KERN_ERR " INSTPM: 0x%08x\n",
434 I915_READ(INSTPM));
435 if (!IS_I965G(dev)) {
436 u32 ipeir = I915_READ(IPEIR);
437
438 printk(KERN_ERR " IPEIR: 0x%08x\n",
439 I915_READ(IPEIR));
440 printk(KERN_ERR " IPEHR: 0x%08x\n",
441 I915_READ(IPEHR));
442 printk(KERN_ERR " INSTDONE: 0x%08x\n",
443 I915_READ(INSTDONE));
444 printk(KERN_ERR " ACTHD: 0x%08x\n",
445 I915_READ(ACTHD));
446 I915_WRITE(IPEIR, ipeir);
447 (void)I915_READ(IPEIR);
448 } else {
449 u32 ipeir = I915_READ(IPEIR_I965);
450
451 printk(KERN_ERR " IPEIR: 0x%08x\n",
452 I915_READ(IPEIR_I965));
453 printk(KERN_ERR " IPEHR: 0x%08x\n",
454 I915_READ(IPEHR_I965));
455 printk(KERN_ERR " INSTDONE: 0x%08x\n",
456 I915_READ(INSTDONE_I965));
457 printk(KERN_ERR " INSTPS: 0x%08x\n",
458 I915_READ(INSTPS));
459 printk(KERN_ERR " INSTDONE1: 0x%08x\n",
460 I915_READ(INSTDONE1));
461 printk(KERN_ERR " ACTHD: 0x%08x\n",
462 I915_READ(ACTHD_I965));
463 I915_WRITE(IPEIR_I965, ipeir);
464 (void)I915_READ(IPEIR_I965);
465 }
466 }
467
468 I915_WRITE(EIR, eir);
469 (void)I915_READ(EIR);
470 eir = I915_READ(EIR);
471 if (eir) {
472 /*
473 * some errors might have become stuck,
474 * mask them.
475 */
476 DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
477 I915_WRITE(EMR, I915_READ(EMR) | eir);
478 I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
479 }
480 }
481
365 I915_WRITE(IIR, iir); 482 I915_WRITE(IIR, iir);
366 new_iir = I915_READ(IIR); /* Flush posted writes */ 483 new_iir = I915_READ(IIR); /* Flush posted writes */
367 484
@@ -732,6 +849,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
732{ 849{
733 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 850 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
734 u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; 851 u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
852 u32 error_mask;
735 853
736 DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); 854 DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
737 855
@@ -768,6 +886,21 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
768 i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); 886 i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
769 } 887 }
770 888
889 /*
890 * Enable some error detection, note the instruction error mask
891 * bit is reserved, so we leave it masked.
892 */
893 if (IS_G4X(dev)) {
894 error_mask = ~(GM45_ERROR_PAGE_TABLE |
895 GM45_ERROR_MEM_PRIV |
896 GM45_ERROR_CP_PRIV |
897 I915_ERROR_MEMORY_REFRESH);
898 } else {
899 error_mask = ~(I915_ERROR_PAGE_TABLE |
900 I915_ERROR_MEMORY_REFRESH);
901 }
902 I915_WRITE(EMR, error_mask);
903
771 /* Disable pipe interrupt enables, clear pending pipe status */ 904 /* Disable pipe interrupt enables, clear pending pipe status */
772 I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); 905 I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
773 I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); 906 I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);