aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h19
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debugfs.c34
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c139
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h14
5 files changed, 204 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index f112c769d533..f83364974a8a 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1180,6 +1180,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1180 pci_enable_msi(dev->pdev); 1180 pci_enable_msi(dev->pdev);
1181 1181
1182 spin_lock_init(&dev_priv->user_irq_lock); 1182 spin_lock_init(&dev_priv->user_irq_lock);
1183 spin_lock_init(&dev_priv->error_lock);
1183 dev_priv->user_irq_refcount = 0; 1184 dev_priv->user_irq_refcount = 0;
1184 1185
1185 ret = drm_vblank_init(dev, I915_NUM_PIPE); 1186 ret = drm_vblank_init(dev, I915_NUM_PIPE);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bb4c2d387b6c..596e119d3e0e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -133,6 +133,22 @@ struct sdvo_device_mapping {
133 u8 initialized; 133 u8 initialized;
134}; 134};
135 135
136struct drm_i915_error_state {
137 u32 eir;
138 u32 pgtbl_er;
139 u32 pipeastat;
140 u32 pipebstat;
141 u32 ipeir;
142 u32 ipehr;
143 u32 instdone;
144 u32 acthd;
145 u32 instpm;
146 u32 instps;
147 u32 instdone1;
148 u32 seqno;
149 struct timeval time;
150};
151
136typedef struct drm_i915_private { 152typedef struct drm_i915_private {
137 struct drm_device *dev; 153 struct drm_device *dev;
138 154
@@ -209,6 +225,9 @@ typedef struct drm_i915_private {
209 int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ 225 int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
210 int num_fence_regs; /* 8 on pre-965, 16 otherwise */ 226 int num_fence_regs; /* 8 on pre-965, 16 otherwise */
211 227
228 spinlock_t error_lock;
229 struct drm_i915_error_state *first_error;
230
212 /* Register state */ 231 /* Register state */
213 u8 saveLBB; 232 u8 saveLBB;
214 u32 saveDSPACNTR; 233 u32 saveDSPACNTR;
diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c
index 28146e405e87..cacae945338b 100644
--- a/drivers/gpu/drm/i915/i915_gem_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c
@@ -323,6 +323,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
323 return 0; 323 return 0;
324} 324}
325 325
326static int i915_error_state(struct seq_file *m, void *unused)
327{
328 struct drm_info_node *node = (struct drm_info_node *) m->private;
329 struct drm_device *dev = node->minor->dev;
330 drm_i915_private_t *dev_priv = dev->dev_private;
331 struct drm_i915_error_state *error;
332 unsigned long flags;
333
334 spin_lock_irqsave(&dev_priv->error_lock, flags);
335 if (!dev_priv->first_error) {
336 seq_printf(m, "no error state collected\n");
337 goto out;
338 }
339
340 error = dev_priv->first_error;
341
342 seq_printf(m, "EIR: 0x%08x\n", error->eir);
343 seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
344 seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
345 seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir);
346 seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
347 seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
348 seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
349 if (IS_I965G(dev)) {
350 seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
351 seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
352 }
353
354out:
355 spin_unlock_irqrestore(&dev_priv->error_lock, flags);
356
357 return 0;
358}
326 359
327static struct drm_info_list i915_gem_debugfs_list[] = { 360static struct drm_info_list i915_gem_debugfs_list[] = {
328 {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, 361 {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
@@ -336,6 +369,7 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
336 {"i915_ringbuffer_data", i915_ringbuffer_data, 0}, 369 {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
337 {"i915_ringbuffer_info", i915_ringbuffer_info, 0}, 370 {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
338 {"i915_batchbuffers", i915_batchbuffer_info, 0}, 371 {"i915_batchbuffers", i915_batchbuffer_info, 0},
372 {"i915_error_state", i915_error_state, 0},
339}; 373};
340#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list) 374#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
341 375
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);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 88bf7521405f..ad3d1b5db95e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -206,6 +206,7 @@
206/* 206/*
207 * Instruction and interrupt control regs 207 * Instruction and interrupt control regs
208 */ 208 */
209#define PGTBL_ER 0x02024
209#define PRB0_TAIL 0x02030 210#define PRB0_TAIL 0x02030
210#define PRB0_HEAD 0x02034 211#define PRB0_HEAD 0x02034
211#define PRB0_START 0x02038 212#define PRB0_START 0x02038
@@ -226,11 +227,18 @@
226#define PRB1_HEAD 0x02044 /* 915+ only */ 227#define PRB1_HEAD 0x02044 /* 915+ only */
227#define PRB1_START 0x02048 /* 915+ only */ 228#define PRB1_START 0x02048 /* 915+ only */
228#define PRB1_CTL 0x0204c /* 915+ only */ 229#define PRB1_CTL 0x0204c /* 915+ only */
230#define IPEIR_I965 0x02064
231#define IPEHR_I965 0x02068
232#define INSTDONE_I965 0x0206c
233#define INSTPS 0x02070 /* 965+ only */
234#define INSTDONE1 0x0207c /* 965+ only */
229#define ACTHD_I965 0x02074 235#define ACTHD_I965 0x02074
230#define HWS_PGA 0x02080 236#define HWS_PGA 0x02080
231#define HWS_ADDRESS_MASK 0xfffff000 237#define HWS_ADDRESS_MASK 0xfffff000
232#define HWS_START_ADDRESS_SHIFT 4 238#define HWS_START_ADDRESS_SHIFT 4
233#define IPEIR 0x02088 239#define IPEIR 0x02088
240#define IPEHR 0x0208c
241#define INSTDONE 0x02090
234#define NOPID 0x02094 242#define NOPID 0x02094
235#define HWSTAM 0x02098 243#define HWSTAM 0x02098
236#define SCPD0 0x0209c /* 915+ only */ 244#define SCPD0 0x0209c /* 915+ only */
@@ -258,6 +266,12 @@
258#define EIR 0x020b0 266#define EIR 0x020b0
259#define EMR 0x020b4 267#define EMR 0x020b4
260#define ESR 0x020b8 268#define ESR 0x020b8
269#define GM45_ERROR_PAGE_TABLE (1<<5)
270#define GM45_ERROR_MEM_PRIV (1<<4)
271#define I915_ERROR_PAGE_TABLE (1<<4)
272#define GM45_ERROR_CP_PRIV (1<<3)
273#define I915_ERROR_MEMORY_REFRESH (1<<1)
274#define I915_ERROR_INSTRUCTION (1<<0)
261#define INSTPM 0x020c0 275#define INSTPM 0x020c0
262#define ACTHD 0x020c8 276#define ACTHD 0x020c8
263#define FW_BLC 0x020d8 277#define FW_BLC 0x020d8