aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c17
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h9
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c167
3 files changed, 159 insertions, 34 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6f818fadcbe3..7d3309bc0fd2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1784,11 +1784,26 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
1784static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) 1784static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
1785{ 1785{
1786 struct intel_overlay *overlay; 1786 struct intel_overlay *overlay;
1787 int ret;
1787 1788
1788 if (!enable && intel_crtc->overlay) { 1789 if (!enable && intel_crtc->overlay) {
1789 overlay = intel_crtc->overlay; 1790 overlay = intel_crtc->overlay;
1790 mutex_lock(&overlay->dev->struct_mutex); 1791 mutex_lock(&overlay->dev->struct_mutex);
1791 intel_overlay_switch_off(overlay); 1792 for (;;) {
1793 ret = intel_overlay_switch_off(overlay);
1794 if (ret == 0)
1795 break;
1796
1797 ret = intel_overlay_recover_from_interrupt(overlay, 0);
1798 if (ret != 0) {
1799 /* overlay doesn't react anymore. Usually
1800 * results in a black screen and an unkillable
1801 * X server. */
1802 BUG();
1803 overlay->hw_wedged = HW_WEDGED;
1804 break;
1805 }
1806 }
1792 mutex_unlock(&overlay->dev->struct_mutex); 1807 mutex_unlock(&overlay->dev->struct_mutex);
1793 } 1808 }
1794 /* Let userspace switch the overlay on again. In most cases userspace 1809 /* Let userspace switch the overlay on again. In most cases userspace
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5b503cb793ba..497240581c6a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -127,8 +127,13 @@ struct intel_overlay {
127 struct drm_i915_gem_object *reg_bo; 127 struct drm_i915_gem_object *reg_bo;
128 void *virt_addr; 128 void *virt_addr;
129 /* flip handling */ 129 /* flip handling */
130 int hw_wedged;
131 uint32_t last_flip_req; 130 uint32_t last_flip_req;
131 int hw_wedged;
132#define HW_WEDGED 1
133#define NEEDS_WAIT_FOR_FLIP 2
134#define RELEASE_OLD_VID 3
135#define SWITCH_OFF_STAGE_1 4
136#define SWITCH_OFF_STAGE_2 5
132}; 137};
133 138
134struct intel_crtc { 139struct intel_crtc {
@@ -209,6 +214,8 @@ extern int intel_framebuffer_create(struct drm_device *dev,
209extern void intel_setup_overlay(struct drm_device *dev); 214extern void intel_setup_overlay(struct drm_device *dev);
210extern void intel_cleanup_overlay(struct drm_device *dev); 215extern void intel_cleanup_overlay(struct drm_device *dev);
211extern int intel_overlay_switch_off(struct intel_overlay *overlay); 216extern int intel_overlay_switch_off(struct intel_overlay *overlay);
217extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
218 int interruptible);
212extern int intel_overlay_put_image(struct drm_device *dev, void *data, 219extern int intel_overlay_put_image(struct drm_device *dev, void *data,
213 struct drm_file *file_priv); 220 struct drm_file *file_priv);
214extern int intel_overlay_attrs(struct drm_device *dev, void *data, 221extern int intel_overlay_attrs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 85e07e4459ce..972d715245be 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -222,6 +222,9 @@ static int intel_overlay_on(struct intel_overlay *overlay)
222 222
223 BUG_ON(overlay->active); 223 BUG_ON(overlay->active);
224 224
225 overlay->active = 1;
226 overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
227
225 BEGIN_LP_RING(6); 228 BEGIN_LP_RING(6);
226 OUT_RING(MI_FLUSH); 229 OUT_RING(MI_FLUSH);
227 OUT_RING(MI_NOOP); 230 OUT_RING(MI_NOOP);
@@ -231,15 +234,16 @@ static int intel_overlay_on(struct intel_overlay *overlay)
231 OUT_RING(MI_NOOP); 234 OUT_RING(MI_NOOP);
232 ADVANCE_LP_RING(); 235 ADVANCE_LP_RING();
233 236
234 ret = i915_lp_ring_sync(dev); 237 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
235 if (ret != 0) { 238 if (overlay->last_flip_req == 0)
236 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n"); 239 return -ENOMEM;
237 overlay->hw_wedged = 1;
238 return 0;
239 }
240 240
241 overlay->active = 1; 241 ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
242 if (ret != 0)
243 return ret;
242 244
245 overlay->hw_wedged = 0;
246 overlay->last_flip_req = 0;
243 return 0; 247 return 0;
244} 248}
245 249
@@ -283,7 +287,6 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay)
283 287
284 if (overlay->last_flip_req != 0) { 288 if (overlay->last_flip_req != 0) {
285 ret = i915_do_wait_request(dev, overlay->last_flip_req, 0); 289 ret = i915_do_wait_request(dev, overlay->last_flip_req, 0);
286
287 if (ret != 0) 290 if (ret != 0)
288 return ret; 291 return ret;
289 292
@@ -296,19 +299,24 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay)
296 } 299 }
297 300
298 /* synchronous slowpath */ 301 /* synchronous slowpath */
302 overlay->hw_wedged = RELEASE_OLD_VID;
303
299 BEGIN_LP_RING(2); 304 BEGIN_LP_RING(2);
300 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 305 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
301 OUT_RING(MI_NOOP); 306 OUT_RING(MI_NOOP);
302 ADVANCE_LP_RING(); 307 ADVANCE_LP_RING();
303 308
304 /* run in lockstep with the hw for easier testing */ 309 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
305 ret = i915_lp_ring_sync(dev); 310 if (overlay->last_flip_req == 0)
306 if (ret != 0) { 311 return -ENOMEM;
307 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
308 overlay->hw_wedged = 1;
309 }
310 312
311 return ret; 313 ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
314 if (ret != 0)
315 return ret;
316
317 overlay->hw_wedged = 0;
318 overlay->last_flip_req = 0;
319 return 0;
312} 320}
313 321
314/* overlay needs to be disabled in OCMD reg */ 322/* overlay needs to be disabled in OCMD reg */
@@ -329,6 +337,8 @@ static int intel_overlay_off(struct intel_overlay *overlay)
329 flip_addr |= OFC_UPDATE; 337 flip_addr |= OFC_UPDATE;
330 338
331 /* wait for overlay to go idle */ 339 /* wait for overlay to go idle */
340 overlay->hw_wedged = SWITCH_OFF_STAGE_1;
341
332 BEGIN_LP_RING(6); 342 BEGIN_LP_RING(6);
333 OUT_RING(MI_FLUSH); 343 OUT_RING(MI_FLUSH);
334 OUT_RING(MI_NOOP); 344 OUT_RING(MI_NOOP);
@@ -338,14 +348,17 @@ static int intel_overlay_off(struct intel_overlay *overlay)
338 OUT_RING(MI_NOOP); 348 OUT_RING(MI_NOOP);
339 ADVANCE_LP_RING(); 349 ADVANCE_LP_RING();
340 350
341 ret = i915_lp_ring_sync(dev); 351 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
342 if (ret != 0) { 352 if (overlay->last_flip_req == 0)
343 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n"); 353 return -ENOMEM;
344 overlay->hw_wedged = 1; 354
355 ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
356 if (ret != 0)
345 return ret; 357 return ret;
346 }
347 358
348 /* turn overlay off */ 359 /* turn overlay off */
360 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
361
349 BEGIN_LP_RING(6); 362 BEGIN_LP_RING(6);
350 OUT_RING(MI_FLUSH); 363 OUT_RING(MI_FLUSH);
351 OUT_RING(MI_NOOP); 364 OUT_RING(MI_NOOP);
@@ -355,18 +368,100 @@ static int intel_overlay_off(struct intel_overlay *overlay)
355 OUT_RING(MI_NOOP); 368 OUT_RING(MI_NOOP);
356 ADVANCE_LP_RING(); 369 ADVANCE_LP_RING();
357 370
358 ret = i915_lp_ring_sync(dev); 371 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
359 if (ret != 0) { 372 if (overlay->last_flip_req == 0)
360 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n"); 373 return -ENOMEM;
361 overlay->hw_wedged = 1; 374
375 ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
376 if (ret != 0)
362 return ret; 377 return ret;
363 }
364 378
365 overlay->active = 0; 379 overlay->active = 0;
366 380 overlay->hw_wedged = 0;
381 overlay->last_flip_req = 0;
367 return ret; 382 return ret;
368} 383}
369 384
385/* recover from an interruption due to a signal
386 * We have to be careful not to repeat work forever an make forward progess. */
387int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
388 int interruptible)
389{
390 struct drm_device *dev = overlay->dev;
391 drm_i915_private_t *dev_priv = dev->dev_private;
392 struct drm_gem_object *obj;
393 u32 flip_addr;
394 int ret;
395 RING_LOCALS;
396
397 if (overlay->hw_wedged == HW_WEDGED)
398 return -EIO;
399
400 if (overlay->last_flip_req == 0) {
401 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
402 if (overlay->last_flip_req == 0)
403 return -ENOMEM;
404 }
405
406 ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible);
407 if (ret != 0)
408 return ret;
409
410 switch (overlay->hw_wedged) {
411 case RELEASE_OLD_VID:
412 obj = overlay->old_vid_bo->obj;
413 i915_gem_object_unpin(obj);
414 drm_gem_object_unreference(obj);
415 overlay->old_vid_bo = NULL;
416 break;
417 case SWITCH_OFF_STAGE_1:
418 flip_addr = overlay->flip_addr;
419 flip_addr |= OFC_UPDATE;
420
421 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
422
423 BEGIN_LP_RING(6);
424 OUT_RING(MI_FLUSH);
425 OUT_RING(MI_NOOP);
426 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
427 OUT_RING(flip_addr);
428 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
429 OUT_RING(MI_NOOP);
430 ADVANCE_LP_RING();
431
432 overlay->last_flip_req = i915_add_request(dev, NULL, 0);
433 if (overlay->last_flip_req == 0)
434 return -ENOMEM;
435
436 ret = i915_do_wait_request(dev, overlay->last_flip_req,
437 interruptible);
438 if (ret != 0)
439 return ret;
440
441 case SWITCH_OFF_STAGE_2:
442 printk("switch off 2\n");
443
444 BUG_ON(!overlay->vid_bo);
445 obj = overlay->vid_bo->obj;
446
447 i915_gem_object_unpin(obj);
448 drm_gem_object_unreference(obj);
449 overlay->vid_bo = NULL;
450
451 overlay->crtc->overlay = NULL;
452 overlay->crtc = NULL;
453
454 overlay->active = 0;
455 break;
456 default:
457 BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
458 }
459
460 overlay->hw_wedged = 0;
461 overlay->last_flip_req = 0;
462 return 0;
463}
464
370/* Wait for pending overlay flip and release old frame. 465/* Wait for pending overlay flip and release old frame.
371 * Needs to be called before the overlay register are changed 466 * Needs to be called before the overlay register are changed
372 * via intel_overlay_(un)map_regs_atomic */ 467 * via intel_overlay_(un)map_regs_atomic */
@@ -375,13 +470,15 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
375 int ret; 470 int ret;
376 struct drm_gem_object *obj; 471 struct drm_gem_object *obj;
377 472
473 /* only wait if there is actually an old frame to release to
474 * guarantee forward progress */
475 if (!overlay->old_vid_bo)
476 return 0;
477
378 ret = intel_overlay_wait_flip(overlay); 478 ret = intel_overlay_wait_flip(overlay);
379 if (ret != 0) 479 if (ret != 0)
380 return ret; 480 return ret;
381 481
382 if (!overlay->old_vid_bo)
383 return 0;
384
385 obj = overlay->old_vid_bo->obj; 482 obj = overlay->old_vid_bo->obj;
386 i915_gem_object_unpin(obj); 483 i915_gem_object_unpin(obj);
387 drm_gem_object_unreference(obj); 484 drm_gem_object_unreference(obj);
@@ -646,9 +743,6 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
646 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); 743 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
647 BUG_ON(!overlay); 744 BUG_ON(!overlay);
648 745
649 if (overlay->hw_wedged)
650 return -EBUSY;
651
652 ret = intel_overlay_release_old_vid(overlay); 746 ret = intel_overlay_release_old_vid(overlay);
653 if (ret != 0) 747 if (ret != 0)
654 return ret; 748 return ret;
@@ -761,6 +855,9 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
761 intel_overlay_unmap_regs_atomic(overlay); 855 intel_overlay_unmap_regs_atomic(overlay);
762 856
763 ret = intel_overlay_off(overlay); 857 ret = intel_overlay_off(overlay);
858 if (ret != 0)
859 return ret;
860
764 /* never have the overlay hw on without showing a frame */ 861 /* never have the overlay hw on without showing a frame */
765 BUG_ON(!overlay->vid_bo); 862 BUG_ON(!overlay->vid_bo);
766 obj = overlay->vid_bo->obj; 863 obj = overlay->vid_bo->obj;
@@ -1002,6 +1099,12 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
1002 mutex_lock(&dev->mode_config.mutex); 1099 mutex_lock(&dev->mode_config.mutex);
1003 mutex_lock(&dev->struct_mutex); 1100 mutex_lock(&dev->struct_mutex);
1004 1101
1102 if (overlay->hw_wedged) {
1103 ret = intel_overlay_recover_from_interrupt(overlay, 1);
1104 if (ret != 0)
1105 goto out_unlock;
1106 }
1107
1005 if (overlay->crtc != crtc) { 1108 if (overlay->crtc != crtc) {
1006 struct drm_display_mode *mode = &crtc->base.mode; 1109 struct drm_display_mode *mode = &crtc->base.mode;
1007 ret = intel_overlay_switch_off(overlay); 1110 ret = intel_overlay_switch_off(overlay);