[Intel-gfx] [PATCH 1/4] drm/i915: Hold struct mutex whilst pinning power context bo.
Jesse Barnes
jbarnes at virtuousgeek.org
Mon Jan 4 20:30:02 CET 2010
On Mon, 4 Jan 2010 18:57:56 +0000
Chris Wilson <chris at chris-wilson.co.uk> wrote:
> 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 at tiscali.co.uk>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: stable at kernel.org
> ---
> drivers/gpu/drm/i915/intel_display.c | 73
> ++++++++++++++++++++++------------ 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 9187a17..e9f0c72 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 = { .fb_changed = intelfb_probe,
> };
>
> +static struct drm_gem_object *
> +intel_alloc_power_context(struct drm_device *dev)
> +{
> + struct drm_gem_object *pwrctx;
> + int ret;
> +
> + pwrctx = drm_gem_object_alloc(dev, 4096);
> + if (!pwrctx) {
> + DRM_DEBUG("failed to alloc power context, RC6
> disabled\n");
> + return NULL;
> + }
> +
> + mutex_lock(&dev->struct_mutex);
> + ret = i915_gem_object_pin(pwrctx, 4096);
> + if (ret) {
> + DRM_ERROR("failed to pin power context: %d\n", ret);
> + goto err_unref;
> + }
> +
> + ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1);
> + if (ret) {
> + DRM_ERROR("failed to set-domain on power context:
> %d\n", ret);
> + goto err_unpin;
> + }
> + mutex_unlock(&dev->struct_mutex);
> +
> + return pwrctx;
> +
> +err_unpin:
> + i915_gem_object_unpin(pwrctx);
> +err_unref:
> + drm_gem_object_unreference(pwrctx);
> + mutex_unlock(&dev->struct_mutex);
> + return NULL;
> +}
> +
> void intel_init_clock_gating(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -4467,41 +4503,26 @@ void intel_init_clock_gating(struct
> drm_device *dev)
> * to save state.
> */
> if (I915_HAS_RC6(dev) && drm_core_check_feature(dev,
> DRIVER_MODESET)) {
> - struct drm_gem_object *pwrctx;
> - struct drm_i915_gem_object *obj_priv;
> - int ret;
> + struct drm_i915_gem_object *obj_priv = NULL;
>
> if (dev_priv->pwrctx) {
> obj_priv = dev_priv->pwrctx->driver_private;
> } else {
> - pwrctx = drm_gem_object_alloc(dev, 4096);
> - if (!pwrctx) {
> - DRM_DEBUG("failed to alloc power
> context, "
> - "RC6 disabled\n");
> - goto out;
> - }
> + struct drm_gem_object *pwrctx;
>
> - ret = i915_gem_object_pin(pwrctx, 4096);
> - if (ret) {
> - DRM_ERROR("failed to pin power
> context: %d\n",
> - ret);
> - drm_gem_object_unreference(pwrctx);
> - goto out;
> + pwrctx = intel_alloc_power_context(dev);
> + if (pwrctx) {
> + dev_priv->pwrctx = pwrctx;
> + obj_priv = pwrctx->driver_private;
> }
> -
> - i915_gem_object_set_to_gtt_domain(pwrctx, 1);
> -
> - dev_priv->pwrctx = pwrctx;
> - obj_priv = pwrctx->driver_private;
> }
>
> - I915_WRITE(PWRCTXA, obj_priv->gtt_offset |
> PWRCTX_EN);
> - I915_WRITE(MCHBAR_RENDER_STANDBY,
> - I915_READ(MCHBAR_RENDER_STANDBY) &
> ~RCX_SW_EXIT);
> + if (obj_priv) {
> + I915_WRITE(PWRCTXA, obj_priv->gtt_offset |
> PWRCTX_EN);
> + I915_WRITE(MCHBAR_RENDER_STANDBY,
> + I915_READ(MCHBAR_RENDER_STANDBY)
> & ~RCX_SW_EXIT);
> + }
> }
> -
> -out:
> - return;
> }
>
> /* Set up chip specific display functions */
Looks good to me Chris, thanks.
Reviewed-by: Jesse Barnes <jbarnes at virtuousgeek.org>
--
Jesse Barnes, Intel Open Source Technology Center
More information about the Intel-gfx
mailing list