diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_debugfs.c | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 139 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 14 |
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 | ||
136 | struct 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 | |||
136 | typedef struct drm_i915_private { | 152 | typedef 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 | ||
326 | static 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 | |||
354 | out: | ||
355 | spin_unlock_irqrestore(&dev_priv->error_lock, flags); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
326 | 359 | ||
327 | static struct drm_info_list i915_gem_debugfs_list[] = { | 360 | static 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 | ||
293 | static 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 | |||
330 | out: | ||
331 | spin_unlock_irqrestore(&dev_priv->error_lock, flags); | ||
332 | } | ||
333 | |||
291 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 334 | irqreturn_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 |