diff options
| -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 |
