diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 143 |
1 files changed, 133 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 85785a8844ed..744225ebb4b2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -425,9 +425,11 @@ static struct drm_i915_error_object * | |||
425 | i915_error_object_create(struct drm_device *dev, | 425 | i915_error_object_create(struct drm_device *dev, |
426 | struct drm_gem_object *src) | 426 | struct drm_gem_object *src) |
427 | { | 427 | { |
428 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
428 | struct drm_i915_error_object *dst; | 429 | struct drm_i915_error_object *dst; |
429 | struct drm_i915_gem_object *src_priv; | 430 | struct drm_i915_gem_object *src_priv; |
430 | int page, page_count; | 431 | int page, page_count; |
432 | u32 reloc_offset; | ||
431 | 433 | ||
432 | if (src == NULL) | 434 | if (src == NULL) |
433 | return NULL; | 435 | return NULL; |
@@ -442,18 +444,27 @@ i915_error_object_create(struct drm_device *dev, | |||
442 | if (dst == NULL) | 444 | if (dst == NULL) |
443 | return NULL; | 445 | return NULL; |
444 | 446 | ||
447 | reloc_offset = src_priv->gtt_offset; | ||
445 | for (page = 0; page < page_count; page++) { | 448 | for (page = 0; page < page_count; page++) { |
446 | void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC); | ||
447 | unsigned long flags; | 449 | unsigned long flags; |
450 | void __iomem *s; | ||
451 | void *d; | ||
448 | 452 | ||
453 | d = kmalloc(PAGE_SIZE, GFP_ATOMIC); | ||
449 | if (d == NULL) | 454 | if (d == NULL) |
450 | goto unwind; | 455 | goto unwind; |
456 | |||
451 | local_irq_save(flags); | 457 | local_irq_save(flags); |
452 | s = kmap_atomic(src_priv->pages[page], KM_IRQ0); | 458 | s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, |
453 | memcpy(d, s, PAGE_SIZE); | 459 | reloc_offset, |
454 | kunmap_atomic(s, KM_IRQ0); | 460 | KM_IRQ0); |
461 | memcpy_fromio(d, s, PAGE_SIZE); | ||
462 | io_mapping_unmap_atomic(s, KM_IRQ0); | ||
455 | local_irq_restore(flags); | 463 | local_irq_restore(flags); |
464 | |||
456 | dst->pages[page] = d; | 465 | dst->pages[page] = d; |
466 | |||
467 | reloc_offset += PAGE_SIZE; | ||
457 | } | 468 | } |
458 | dst->page_count = page_count; | 469 | dst->page_count = page_count; |
459 | dst->gtt_offset = src_priv->gtt_offset; | 470 | dst->gtt_offset = src_priv->gtt_offset; |
@@ -489,6 +500,7 @@ i915_error_state_free(struct drm_device *dev, | |||
489 | i915_error_object_free(error->batchbuffer[1]); | 500 | i915_error_object_free(error->batchbuffer[1]); |
490 | i915_error_object_free(error->ringbuffer); | 501 | i915_error_object_free(error->ringbuffer); |
491 | kfree(error->active_bo); | 502 | kfree(error->active_bo); |
503 | kfree(error->overlay); | ||
492 | kfree(error); | 504 | kfree(error); |
493 | } | 505 | } |
494 | 506 | ||
@@ -612,18 +624,57 @@ static void i915_capture_error_state(struct drm_device *dev) | |||
612 | 624 | ||
613 | if (batchbuffer[1] == NULL && | 625 | if (batchbuffer[1] == NULL && |
614 | error->acthd >= obj_priv->gtt_offset && | 626 | error->acthd >= obj_priv->gtt_offset && |
615 | error->acthd < obj_priv->gtt_offset + obj->size && | 627 | error->acthd < obj_priv->gtt_offset + obj->size) |
616 | batchbuffer[0] != obj) | ||
617 | batchbuffer[1] = obj; | 628 | batchbuffer[1] = obj; |
618 | 629 | ||
619 | count++; | 630 | count++; |
620 | } | 631 | } |
632 | /* Scan the other lists for completeness for those bizarre errors. */ | ||
633 | if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { | ||
634 | list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { | ||
635 | struct drm_gem_object *obj = &obj_priv->base; | ||
636 | |||
637 | if (batchbuffer[0] == NULL && | ||
638 | bbaddr >= obj_priv->gtt_offset && | ||
639 | bbaddr < obj_priv->gtt_offset + obj->size) | ||
640 | batchbuffer[0] = obj; | ||
641 | |||
642 | if (batchbuffer[1] == NULL && | ||
643 | error->acthd >= obj_priv->gtt_offset && | ||
644 | error->acthd < obj_priv->gtt_offset + obj->size) | ||
645 | batchbuffer[1] = obj; | ||
646 | |||
647 | if (batchbuffer[0] && batchbuffer[1]) | ||
648 | break; | ||
649 | } | ||
650 | } | ||
651 | if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { | ||
652 | list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { | ||
653 | struct drm_gem_object *obj = &obj_priv->base; | ||
654 | |||
655 | if (batchbuffer[0] == NULL && | ||
656 | bbaddr >= obj_priv->gtt_offset && | ||
657 | bbaddr < obj_priv->gtt_offset + obj->size) | ||
658 | batchbuffer[0] = obj; | ||
659 | |||
660 | if (batchbuffer[1] == NULL && | ||
661 | error->acthd >= obj_priv->gtt_offset && | ||
662 | error->acthd < obj_priv->gtt_offset + obj->size) | ||
663 | batchbuffer[1] = obj; | ||
664 | |||
665 | if (batchbuffer[0] && batchbuffer[1]) | ||
666 | break; | ||
667 | } | ||
668 | } | ||
621 | 669 | ||
622 | /* We need to copy these to an anonymous buffer as the simplest | 670 | /* We need to copy these to an anonymous buffer as the simplest |
623 | * method to avoid being overwritten by userpace. | 671 | * method to avoid being overwritten by userpace. |
624 | */ | 672 | */ |
625 | error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); | 673 | error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); |
626 | error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); | 674 | if (batchbuffer[1] != batchbuffer[0]) |
675 | error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); | ||
676 | else | ||
677 | error->batchbuffer[1] = NULL; | ||
627 | 678 | ||
628 | /* Record the ringbuffer */ | 679 | /* Record the ringbuffer */ |
629 | error->ringbuffer = i915_error_object_create(dev, | 680 | error->ringbuffer = i915_error_object_create(dev, |
@@ -667,6 +718,8 @@ static void i915_capture_error_state(struct drm_device *dev) | |||
667 | 718 | ||
668 | do_gettimeofday(&error->time); | 719 | do_gettimeofday(&error->time); |
669 | 720 | ||
721 | error->overlay = intel_overlay_capture_error_state(dev); | ||
722 | |||
670 | spin_lock_irqsave(&dev_priv->error_lock, flags); | 723 | spin_lock_irqsave(&dev_priv->error_lock, flags); |
671 | if (dev_priv->first_error == NULL) { | 724 | if (dev_priv->first_error == NULL) { |
672 | dev_priv->first_error = error; | 725 | dev_priv->first_error = error; |
@@ -834,6 +887,49 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) | |||
834 | queue_work(dev_priv->wq, &dev_priv->error_work); | 887 | queue_work(dev_priv->wq, &dev_priv->error_work); |
835 | } | 888 | } |
836 | 889 | ||
890 | static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) | ||
891 | { | ||
892 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
893 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
894 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
895 | struct drm_i915_gem_object *obj_priv; | ||
896 | struct intel_unpin_work *work; | ||
897 | unsigned long flags; | ||
898 | bool stall_detected; | ||
899 | |||
900 | /* Ignore early vblank irqs */ | ||
901 | if (intel_crtc == NULL) | ||
902 | return; | ||
903 | |||
904 | spin_lock_irqsave(&dev->event_lock, flags); | ||
905 | work = intel_crtc->unpin_work; | ||
906 | |||
907 | if (work == NULL || work->pending || !work->enable_stall_check) { | ||
908 | /* Either the pending flip IRQ arrived, or we're too early. Don't check */ | ||
909 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ | ||
914 | obj_priv = to_intel_bo(work->pending_flip_obj); | ||
915 | if(IS_I965G(dev)) { | ||
916 | int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; | ||
917 | stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset; | ||
918 | } else { | ||
919 | int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR; | ||
920 | stall_detected = I915_READ(dspaddr) == (obj_priv->gtt_offset + | ||
921 | crtc->y * crtc->fb->pitch + | ||
922 | crtc->x * crtc->fb->bits_per_pixel/8); | ||
923 | } | ||
924 | |||
925 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
926 | |||
927 | if (stall_detected) { | ||
928 | DRM_DEBUG_DRIVER("Pageflip stall detected\n"); | ||
929 | intel_prepare_page_flip(dev, intel_crtc->plane); | ||
930 | } | ||
931 | } | ||
932 | |||
837 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 933 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
838 | { | 934 | { |
839 | struct drm_device *dev = (struct drm_device *) arg; | 935 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -951,15 +1047,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
951 | if (pipea_stats & vblank_status) { | 1047 | if (pipea_stats & vblank_status) { |
952 | vblank++; | 1048 | vblank++; |
953 | drm_handle_vblank(dev, 0); | 1049 | drm_handle_vblank(dev, 0); |
954 | if (!dev_priv->flip_pending_is_done) | 1050 | if (!dev_priv->flip_pending_is_done) { |
1051 | i915_pageflip_stall_check(dev, 0); | ||
955 | intel_finish_page_flip(dev, 0); | 1052 | intel_finish_page_flip(dev, 0); |
1053 | } | ||
956 | } | 1054 | } |
957 | 1055 | ||
958 | if (pipeb_stats & vblank_status) { | 1056 | if (pipeb_stats & vblank_status) { |
959 | vblank++; | 1057 | vblank++; |
960 | drm_handle_vblank(dev, 1); | 1058 | drm_handle_vblank(dev, 1); |
961 | if (!dev_priv->flip_pending_is_done) | 1059 | if (!dev_priv->flip_pending_is_done) { |
1060 | i915_pageflip_stall_check(dev, 1); | ||
962 | intel_finish_page_flip(dev, 1); | 1061 | intel_finish_page_flip(dev, 1); |
1062 | } | ||
963 | } | 1063 | } |
964 | 1064 | ||
965 | if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || | 1065 | if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || |
@@ -1250,7 +1350,25 @@ void i915_hangcheck_elapsed(unsigned long data) | |||
1250 | i915_seqno_passed(i915_get_gem_seqno(dev, | 1350 | i915_seqno_passed(i915_get_gem_seqno(dev, |
1251 | &dev_priv->render_ring), | 1351 | &dev_priv->render_ring), |
1252 | i915_get_tail_request(dev)->seqno)) { | 1352 | i915_get_tail_request(dev)->seqno)) { |
1353 | bool missed_wakeup = false; | ||
1354 | |||
1253 | dev_priv->hangcheck_count = 0; | 1355 | dev_priv->hangcheck_count = 0; |
1356 | |||
1357 | /* Issue a wake-up to catch stuck h/w. */ | ||
1358 | if (dev_priv->render_ring.waiting_gem_seqno && | ||
1359 | waitqueue_active(&dev_priv->render_ring.irq_queue)) { | ||
1360 | DRM_WAKEUP(&dev_priv->render_ring.irq_queue); | ||
1361 | missed_wakeup = true; | ||
1362 | } | ||
1363 | |||
1364 | if (dev_priv->bsd_ring.waiting_gem_seqno && | ||
1365 | waitqueue_active(&dev_priv->bsd_ring.irq_queue)) { | ||
1366 | DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); | ||
1367 | missed_wakeup = true; | ||
1368 | } | ||
1369 | |||
1370 | if (missed_wakeup) | ||
1371 | DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); | ||
1254 | return; | 1372 | return; |
1255 | } | 1373 | } |
1256 | 1374 | ||
@@ -1318,12 +1436,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev) | |||
1318 | I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); | 1436 | I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); |
1319 | (void) I915_READ(DEIER); | 1437 | (void) I915_READ(DEIER); |
1320 | 1438 | ||
1321 | /* user interrupt should be enabled, but masked initial */ | 1439 | /* Gen6 only needs render pipe_control now */ |
1440 | if (IS_GEN6(dev)) | ||
1441 | render_mask = GT_PIPE_NOTIFY; | ||
1442 | |||
1322 | dev_priv->gt_irq_mask_reg = ~render_mask; | 1443 | dev_priv->gt_irq_mask_reg = ~render_mask; |
1323 | dev_priv->gt_irq_enable_reg = render_mask; | 1444 | dev_priv->gt_irq_enable_reg = render_mask; |
1324 | 1445 | ||
1325 | I915_WRITE(GTIIR, I915_READ(GTIIR)); | 1446 | I915_WRITE(GTIIR, I915_READ(GTIIR)); |
1326 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); | 1447 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); |
1448 | if (IS_GEN6(dev)) | ||
1449 | I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT); | ||
1327 | I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); | 1450 | I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); |
1328 | (void) I915_READ(GTIER); | 1451 | (void) I915_READ(GTIER); |
1329 | 1452 | ||