diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-02-09 11:15:32 -0500 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-02-09 12:04:54 -0500 |
commit | ac66808814036b4c33dd98091b2176ae6157f1a8 (patch) | |
tree | fe50cbfadd2ee322b0eed6c8c0bdf17970e7c3a8 /drivers | |
parent | 72389a33b8878e6091f7ab8080f5ed07054c7c39 (diff) |
drm/i915: Disable RC6 on Ironlake
The automatic powersaving feature is once again causing havoc, with 100%
reliable hangs on boot and resume on affected machines.
Reported-by: Francesco Allertsen <fallertsen@gmail.com>
Reported-by: Gui Rui <chaos.proton@gmail.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=28582
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 92 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 1 |
4 files changed, 55 insertions, 44 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cfb56d0ff367..0ad533f06af9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -46,6 +46,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); | |||
46 | unsigned int i915_powersave = 1; | 46 | unsigned int i915_powersave = 1; |
47 | module_param_named(powersave, i915_powersave, int, 0600); | 47 | module_param_named(powersave, i915_powersave, int, 0600); |
48 | 48 | ||
49 | unsigned int i915_enable_rc6 = 0; | ||
50 | module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); | ||
51 | |||
49 | unsigned int i915_lvds_downclock = 0; | 52 | unsigned int i915_lvds_downclock = 0; |
50 | module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); | 53 | module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); |
51 | 54 | ||
@@ -360,7 +363,7 @@ static int i915_drm_thaw(struct drm_device *dev) | |||
360 | /* Resume the modeset for every activated CRTC */ | 363 | /* Resume the modeset for every activated CRTC */ |
361 | drm_helper_resume_force_mode(dev); | 364 | drm_helper_resume_force_mode(dev); |
362 | 365 | ||
363 | if (dev_priv->renderctx && dev_priv->pwrctx) | 366 | if (IS_IRONLAKE_M(dev)) |
364 | ironlake_enable_rc6(dev); | 367 | ironlake_enable_rc6(dev); |
365 | } | 368 | } |
366 | 369 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a0149c619cdd..65dfe81d0035 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -958,6 +958,7 @@ extern unsigned int i915_fbpercrtc; | |||
958 | extern unsigned int i915_powersave; | 958 | extern unsigned int i915_powersave; |
959 | extern unsigned int i915_lvds_downclock; | 959 | extern unsigned int i915_lvds_downclock; |
960 | extern unsigned int i915_panel_use_ssc; | 960 | extern unsigned int i915_panel_use_ssc; |
961 | extern unsigned int i915_enable_rc6; | ||
961 | 962 | ||
962 | extern int i915_suspend(struct drm_device *dev, pm_message_t state); | 963 | extern int i915_suspend(struct drm_device *dev, pm_message_t state); |
963 | extern int i915_resume(struct drm_device *dev); | 964 | extern int i915_resume(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e42aa586504..94622e3a202e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -6463,52 +6463,60 @@ void intel_enable_clock_gating(struct drm_device *dev) | |||
6463 | } | 6463 | } |
6464 | } | 6464 | } |
6465 | 6465 | ||
6466 | void intel_disable_clock_gating(struct drm_device *dev) | 6466 | static void ironlake_teardown_rc6(struct drm_device *dev) |
6467 | { | 6467 | { |
6468 | struct drm_i915_private *dev_priv = dev->dev_private; | 6468 | struct drm_i915_private *dev_priv = dev->dev_private; |
6469 | 6469 | ||
6470 | if (dev_priv->renderctx) { | 6470 | if (dev_priv->renderctx) { |
6471 | struct drm_i915_gem_object *obj = dev_priv->renderctx; | 6471 | i915_gem_object_unpin(dev_priv->renderctx); |
6472 | 6472 | drm_gem_object_unreference(&dev_priv->renderctx->base); | |
6473 | I915_WRITE(CCID, 0); | ||
6474 | POSTING_READ(CCID); | ||
6475 | |||
6476 | i915_gem_object_unpin(obj); | ||
6477 | drm_gem_object_unreference(&obj->base); | ||
6478 | dev_priv->renderctx = NULL; | 6473 | dev_priv->renderctx = NULL; |
6479 | } | 6474 | } |
6480 | 6475 | ||
6481 | if (dev_priv->pwrctx) { | 6476 | if (dev_priv->pwrctx) { |
6482 | struct drm_i915_gem_object *obj = dev_priv->pwrctx; | 6477 | i915_gem_object_unpin(dev_priv->pwrctx); |
6478 | drm_gem_object_unreference(&dev_priv->pwrctx->base); | ||
6479 | dev_priv->pwrctx = NULL; | ||
6480 | } | ||
6481 | } | ||
6482 | |||
6483 | static void ironlake_disable_rc6(struct drm_device *dev) | ||
6484 | { | ||
6485 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
6486 | |||
6487 | if (I915_READ(PWRCTXA)) { | ||
6488 | /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ | ||
6489 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); | ||
6490 | wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), | ||
6491 | 50); | ||
6483 | 6492 | ||
6484 | I915_WRITE(PWRCTXA, 0); | 6493 | I915_WRITE(PWRCTXA, 0); |
6485 | POSTING_READ(PWRCTXA); | 6494 | POSTING_READ(PWRCTXA); |
6486 | 6495 | ||
6487 | i915_gem_object_unpin(obj); | 6496 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); |
6488 | drm_gem_object_unreference(&obj->base); | 6497 | POSTING_READ(RSTDBYCTL); |
6489 | dev_priv->pwrctx = NULL; | ||
6490 | } | 6498 | } |
6499 | |||
6500 | ironlake_disable_rc6(dev); | ||
6491 | } | 6501 | } |
6492 | 6502 | ||
6493 | static void ironlake_disable_rc6(struct drm_device *dev) | 6503 | static int ironlake_setup_rc6(struct drm_device *dev) |
6494 | { | 6504 | { |
6495 | struct drm_i915_private *dev_priv = dev->dev_private; | 6505 | struct drm_i915_private *dev_priv = dev->dev_private; |
6496 | 6506 | ||
6497 | /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ | 6507 | if (dev_priv->renderctx == NULL) |
6498 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); | 6508 | dev_priv->renderctx = intel_alloc_context_page(dev); |
6499 | wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), | 6509 | if (!dev_priv->renderctx) |
6500 | 10); | 6510 | return -ENOMEM; |
6501 | POSTING_READ(CCID); | 6511 | |
6502 | I915_WRITE(PWRCTXA, 0); | 6512 | if (dev_priv->pwrctx == NULL) |
6503 | POSTING_READ(PWRCTXA); | 6513 | dev_priv->pwrctx = intel_alloc_context_page(dev); |
6504 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); | 6514 | if (!dev_priv->pwrctx) { |
6505 | POSTING_READ(RSTDBYCTL); | 6515 | ironlake_teardown_rc6(dev); |
6506 | i915_gem_object_unpin(dev_priv->renderctx); | 6516 | return -ENOMEM; |
6507 | drm_gem_object_unreference(&dev_priv->renderctx->base); | 6517 | } |
6508 | dev_priv->renderctx = NULL; | 6518 | |
6509 | i915_gem_object_unpin(dev_priv->pwrctx); | 6519 | return 0; |
6510 | drm_gem_object_unreference(&dev_priv->pwrctx->base); | ||
6511 | dev_priv->pwrctx = NULL; | ||
6512 | } | 6520 | } |
6513 | 6521 | ||
6514 | void ironlake_enable_rc6(struct drm_device *dev) | 6522 | void ironlake_enable_rc6(struct drm_device *dev) |
@@ -6516,15 +6524,26 @@ void ironlake_enable_rc6(struct drm_device *dev) | |||
6516 | struct drm_i915_private *dev_priv = dev->dev_private; | 6524 | struct drm_i915_private *dev_priv = dev->dev_private; |
6517 | int ret; | 6525 | int ret; |
6518 | 6526 | ||
6527 | /* rc6 disabled by default due to repeated reports of hanging during | ||
6528 | * boot and resume. | ||
6529 | */ | ||
6530 | if (!i915_enable_rc6) | ||
6531 | return; | ||
6532 | |||
6533 | ret = ironlake_setup_rc6(dev); | ||
6534 | if (ret) | ||
6535 | return; | ||
6536 | |||
6519 | /* | 6537 | /* |
6520 | * GPU can automatically power down the render unit if given a page | 6538 | * GPU can automatically power down the render unit if given a page |
6521 | * to save state. | 6539 | * to save state. |
6522 | */ | 6540 | */ |
6523 | ret = BEGIN_LP_RING(6); | 6541 | ret = BEGIN_LP_RING(6); |
6524 | if (ret) { | 6542 | if (ret) { |
6525 | ironlake_disable_rc6(dev); | 6543 | ironlake_teardown_rc6(dev); |
6526 | return; | 6544 | return; |
6527 | } | 6545 | } |
6546 | |||
6528 | OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); | 6547 | OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); |
6529 | OUT_RING(MI_SET_CONTEXT); | 6548 | OUT_RING(MI_SET_CONTEXT); |
6530 | OUT_RING(dev_priv->renderctx->gtt_offset | | 6549 | OUT_RING(dev_priv->renderctx->gtt_offset | |
@@ -6541,6 +6560,7 @@ void ironlake_enable_rc6(struct drm_device *dev) | |||
6541 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); | 6560 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); |
6542 | } | 6561 | } |
6543 | 6562 | ||
6563 | |||
6544 | /* Set up chip specific display functions */ | 6564 | /* Set up chip specific display functions */ |
6545 | static void intel_init_display(struct drm_device *dev) | 6565 | static void intel_init_display(struct drm_device *dev) |
6546 | { | 6566 | { |
@@ -6783,21 +6803,9 @@ void intel_modeset_init(struct drm_device *dev) | |||
6783 | if (IS_GEN6(dev)) | 6803 | if (IS_GEN6(dev)) |
6784 | gen6_enable_rps(dev_priv); | 6804 | gen6_enable_rps(dev_priv); |
6785 | 6805 | ||
6786 | if (IS_IRONLAKE_M(dev)) { | 6806 | if (IS_IRONLAKE_M(dev)) |
6787 | dev_priv->renderctx = intel_alloc_context_page(dev); | ||
6788 | if (!dev_priv->renderctx) | ||
6789 | goto skip_rc6; | ||
6790 | dev_priv->pwrctx = intel_alloc_context_page(dev); | ||
6791 | if (!dev_priv->pwrctx) { | ||
6792 | i915_gem_object_unpin(dev_priv->renderctx); | ||
6793 | drm_gem_object_unreference(&dev_priv->renderctx->base); | ||
6794 | dev_priv->renderctx = NULL; | ||
6795 | goto skip_rc6; | ||
6796 | } | ||
6797 | ironlake_enable_rc6(dev); | 6807 | ironlake_enable_rc6(dev); |
6798 | } | ||
6799 | 6808 | ||
6800 | skip_rc6: | ||
6801 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); | 6809 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); |
6802 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, | 6810 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, |
6803 | (unsigned long)dev); | 6811 | (unsigned long)dev); |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 74db2557d644..2c431049963c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -298,7 +298,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | |||
298 | extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | 298 | extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, |
299 | u16 *blue, int regno); | 299 | u16 *blue, int regno); |
300 | extern void intel_enable_clock_gating(struct drm_device *dev); | 300 | extern void intel_enable_clock_gating(struct drm_device *dev); |
301 | extern void intel_disable_clock_gating(struct drm_device *dev); | ||
302 | extern void ironlake_enable_drps(struct drm_device *dev); | 301 | extern void ironlake_enable_drps(struct drm_device *dev); |
303 | extern void ironlake_disable_drps(struct drm_device *dev); | 302 | extern void ironlake_disable_drps(struct drm_device *dev); |
304 | extern void gen6_enable_rps(struct drm_i915_private *dev_priv); | 303 | extern void gen6_enable_rps(struct drm_i915_private *dev_priv); |