aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
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