aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-01-04 13:57:56 -0500
committerEric Anholt <eric@anholt.net>2010-01-06 12:40:10 -0500
commit9ea8d05932c082a7ccbd9dc2e10687c88a70bd13 (patch)
treef41ae389dac10fb80e0d32d6b4f47da4d51889da /drivers/gpu/drm/i915/intel_display.c
parent29bd0ae25f8cb96b63560c2cbccec77b425e1603 (diff)
drm/i915: Hold struct mutex whilst pinning power context bo.
Hugh found an error path where we were attempting to unref a bo without holding the struct mutex: [drm:intel_init_clock_gating] *ERROR* failed to pin power context: -16 ------------[ cut here ]------------ WARNING: at drivers/gpu/drm/drm_gem.c:438 drm_gem_object_free+0x20/0x5e() Hardware name: ESPRIMO Mobile V5505 Modules linked in: snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device Pid: 3793, comm: s2ram Not tainted 2.6.33-rc2 #4 Call Trace: [<7815298e>] warn_slowpath_common+0x59/0x6b [<781529b3>] warn_slowpath_null+0x13/0x18 [<78317c1a>] ? drm_gem_object_free+0x20/0x5e [<78317c1a>] drm_gem_object_free+0x20/0x5e [<78317bfa>] ? drm_gem_object_free+0x0/0x5e [<7829df11>] kref_put+0x38/0x45 [<7833a5f0>] intel_init_clock_gating+0x232/0x271 [<78317bfa>] ? drm_gem_object_free+0x0/0x5e [<7832c307>] i915_restore_state+0x21a/0x2b3 [<7832379d>] i915_resume+0x3c/0xbb [<78174fe5>] ? trace_hardirqs_on_caller+0xfc/0x123 [<7831c756>] ? drm_class_resume+0x0/0x3e [<7831c78d>] drm_class_resume+0x37/0x3e [<78351e0a>] legacy_resume+0x1e/0x51 [<78351ece>] device_resume+0x91/0xab [<7831c756>] ? drm_class_resume+0x0/0x3e [<78352226>] dpm_resume+0x58/0x10f [<783522fb>] dpm_resume_end+0x1e/0x2c [<78180f80>] suspend_devices_and_enter+0x61/0x84 [<78180ff8>] enter_state+0x55/0x83 [<7818091c>] state_store+0x94/0xaa [<7829d09e>] kobj_attr_store+0x1e/0x23 [<782098e0>] sysfs_write_file+0x66/0x99 [<781cd2f0>] vfs_write+0x8a/0x108 [<781cd408>] sys_write+0x3c/0x63 [<78125c10>] sysenter_do_call+0x12/0x36 ---[ end trace a343537f29950fda ]--- It is in fact slightly more insiduous that first appears since we are attempting to not just free the object without the lock, but are trying to do the whole bo manipulation without holding the lock. Reported-by: Hugh Dickins <hugh.dickins@tiscali.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c73
1 files changed, 47 insertions, 26 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index af61dd915f2b..84705b7e01ec 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4414,6 +4414,42 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
4414 .fb_changed = intelfb_probe, 4414 .fb_changed = intelfb_probe,
4415}; 4415};
4416 4416
4417static struct drm_gem_object *
4418intel_alloc_power_context(struct drm_device *dev)
4419{
4420 struct drm_gem_object *pwrctx;
4421 int ret;
4422
4423 pwrctx = drm_gem_object_alloc(dev, 4096);
4424 if (!pwrctx) {
4425 DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
4426 return NULL;
4427 }
4428
4429 mutex_lock(&dev->struct_mutex);
4430 ret = i915_gem_object_pin(pwrctx, 4096);
4431 if (ret) {
4432 DRM_ERROR("failed to pin power context: %d\n", ret);
4433 goto err_unref;
4434 }
4435
4436 ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1);
4437 if (ret) {
4438 DRM_ERROR("failed to set-domain on power context: %d\n", ret);
4439 goto err_unpin;
4440 }
4441 mutex_unlock(&dev->struct_mutex);
4442
4443 return pwrctx;
4444
4445err_unpin:
4446 i915_gem_object_unpin(pwrctx);
4447err_unref:
4448 drm_gem_object_unreference(pwrctx);
4449 mutex_unlock(&dev->struct_mutex);
4450 return NULL;
4451}
4452
4417void intel_init_clock_gating(struct drm_device *dev) 4453void intel_init_clock_gating(struct drm_device *dev)
4418{ 4454{
4419 struct drm_i915_private *dev_priv = dev->dev_private; 4455 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4467,41 +4503,26 @@ void intel_init_clock_gating(struct drm_device *dev)
4467 * to save state. 4503 * to save state.
4468 */ 4504 */
4469 if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { 4505 if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) {
4470 struct drm_gem_object *pwrctx; 4506 struct drm_i915_gem_object *obj_priv = NULL;
4471 struct drm_i915_gem_object *obj_priv;
4472 int ret;
4473 4507
4474 if (dev_priv->pwrctx) { 4508 if (dev_priv->pwrctx) {
4475 obj_priv = dev_priv->pwrctx->driver_private; 4509 obj_priv = dev_priv->pwrctx->driver_private;
4476 } else { 4510 } else {
4477 pwrctx = drm_gem_object_alloc(dev, 4096); 4511 struct drm_gem_object *pwrctx;
4478 if (!pwrctx) {
4479 DRM_DEBUG("failed to alloc power context, "
4480 "RC6 disabled\n");
4481 goto out;
4482 }
4483 4512
4484 ret = i915_gem_object_pin(pwrctx, 4096); 4513 pwrctx = intel_alloc_power_context(dev);
4485 if (ret) { 4514 if (pwrctx) {
4486 DRM_ERROR("failed to pin power context: %d\n", 4515 dev_priv->pwrctx = pwrctx;
4487 ret); 4516 obj_priv = pwrctx->driver_private;
4488 drm_gem_object_unreference(pwrctx);
4489 goto out;
4490 } 4517 }
4491
4492 i915_gem_object_set_to_gtt_domain(pwrctx, 1);
4493
4494 dev_priv->pwrctx = pwrctx;
4495 obj_priv = pwrctx->driver_private;
4496 } 4518 }
4497 4519
4498 I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN); 4520 if (obj_priv) {
4499 I915_WRITE(MCHBAR_RENDER_STANDBY, 4521 I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
4500 I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); 4522 I915_WRITE(MCHBAR_RENDER_STANDBY,
4523 I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
4524 }
4501 } 4525 }
4502
4503out:
4504 return;
4505} 4526}
4506 4527
4507/* Set up chip specific display functions */ 4528/* Set up chip specific display functions */