On Mon, Apr 11, 2016 at 08:23:33AM +0200, Maarten Lankhorst wrote: > This function would call drm_modeset_lock_all, while the suspend/resume > functions already have their own locking. Fix this by factoring out > __intel_display_resume, and calling the atomic helpers for duplicating > atomic state and disabling all crtc's during suspend. > > Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> > Fixes: e2c8b8701e2d ("drm/i915: Use atomic helpers for suspend, v2.") > Cc: drm-intel-fixes@xxxxxxxxxxxxxxxxxxxxx > --- > drivers/gpu/drm/i915/intel_display.c | 123 +++++++++++++++++++++++------------ > 1 file changed, 83 insertions(+), 40 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index feb7028341b8..2f76efc86417 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -3126,8 +3126,44 @@ static void intel_update_primary_planes(struct drm_device *dev) > } > } > > +static int > +__intel_display_resume(struct drm_device *dev, > + struct drm_atomic_state *state, > + bool *setup) > +{ > + struct drm_crtc_state *crtc_state; > + struct drm_crtc *crtc; > + int i; > + > + if (!setup || !*setup) { > + if (setup) > + *setup = true; This is getting nasty. How about dealing with -EDEADLK right after the modeset_lock_all() in the caller, so that we don't have to be concerned with getting called mutiple times here? > + > + intel_modeset_setup_hw_state(dev); > + i915_redisable_vga(dev); > + } > + > + if (!state) > + return 0; > + > + for_each_crtc_in_state(state, crtc, crtc_state, i) { > + /* > + * Force recalculation even if we restore > + * current state. With fast modeset this may not result > + * in a modeset when the state is compatible. > + */ > + crtc_state->mode_changed = true; > + } > + > + return drm_atomic_commit(state); To go along with my suggestion about dealing with -EDEADLK upfront, we could then have a WARN_ON(ret == -EDEADLK) here to make sure we didn't make a mess of things. > +} > + > void intel_prepare_reset(struct drm_device *dev) > { > + struct drm_atomic_state *state; > + struct drm_modeset_acquire_ctx *pctx; > + int ret; > + > /* no reset support for gen2 */ > if (IS_GEN2(dev)) > return; > @@ -3137,16 +3173,39 @@ void intel_prepare_reset(struct drm_device *dev) > return; > > drm_modeset_lock_all(dev); > + pctx = dev->mode_config.acquire_ctx; Still looks like "power context" to me. I was wondering if we should have a private context here, but I guess that would fall over with some mode_config.acquire_ctx usage in the display init code? > + > /* > * Disabling the crtcs gracefully seems nicer. Also the > * g33 docs say we should at least disable all the planes. > */ > - intel_display_suspend(dev); > + > + state = drm_atomic_helper_duplicate_state(dev, pctx); > + if (IS_ERR(state)) { > + ret = PTR_ERR(state); > + state = NULL; > + DRM_ERROR("Duplicating state failed with %i\n", ret); > + goto err; > + } > + > + ret = drm_atomic_helper_disable_all(dev, pctx); > + if (ret) { > + DRM_ERROR("Suspending crtc's failed with %i\n", ret); > + goto err; > + } > + > + to_i915(dev)->modeset_restore_state = state; > + return; > + > +err: > + drm_atomic_state_free(state); > } > > void intel_finish_reset(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = to_i915(dev); > + struct drm_atomic_state *state = dev_priv->modeset_restore_state; > + int ret; > > /* > * Flips in the rings will be nuked by the reset, > @@ -3172,23 +3231,29 @@ void intel_finish_reset(struct drm_device *dev) > */ > intel_update_primary_planes(dev); > return; > - } > + } else { > + /* > + * The display has been reset as well, > + * so need a full re-initialization. > + */ > + intel_runtime_pm_disable_interrupts(dev_priv); > + intel_runtime_pm_enable_interrupts(dev_priv); > > - /* > - * The display has been reset as well, > - * so need a full re-initialization. > - */ > - intel_runtime_pm_disable_interrupts(dev_priv); > - intel_runtime_pm_enable_interrupts(dev_priv); > + intel_modeset_init_hw(dev); > > - intel_modeset_init_hw(dev); > + spin_lock_irq(&dev_priv->irq_lock); > + if (dev_priv->display.hpd_irq_setup) > + dev_priv->display.hpd_irq_setup(dev); > + spin_unlock_irq(&dev_priv->irq_lock); > + } This seems like an unrelated change. More to do with the second patch I guess, though I'm still wondering if we can't just run through the whole thing every time? > > - spin_lock_irq(&dev_priv->irq_lock); > - if (dev_priv->display.hpd_irq_setup) > - dev_priv->display.hpd_irq_setup(dev); > - spin_unlock_irq(&dev_priv->irq_lock); > + dev_priv->modeset_restore_state = NULL; > + if (state) > + state->acquire_ctx = dev->mode_config.acquire_ctx; > > - intel_display_resume(dev); > + ret = __intel_display_resume(dev, state, NULL); > + if (ret) > + DRM_ERROR("Restoring old state failed with %i\n", ret); > > intel_hpd_init(dev_priv); > > @@ -15885,6 +15950,8 @@ void intel_display_resume(struct drm_device *dev) > bool setup = false; > > dev_priv->modeset_restore_state = NULL; > + if (state) > + state->acquire_ctx = &ctx; > > /* > * This is a cludge because with real atomic modeset mode_config.mutex > @@ -15897,32 +15964,8 @@ void intel_display_resume(struct drm_device *dev) > > retry: > ret = drm_modeset_lock_all_ctx(dev, &ctx); > - > - if (ret == 0 && !setup) { > - setup = true; > - > - intel_modeset_setup_hw_state(dev); > - i915_redisable_vga(dev); > - } > - > - if (ret == 0 && state) { > - struct drm_crtc_state *crtc_state; > - struct drm_crtc *crtc; > - int i; > - > - state->acquire_ctx = &ctx; > - > - for_each_crtc_in_state(state, crtc, crtc_state, i) { > - /* > - * Force recalculation even if we restore > - * current state. With fast modeset this may not result > - * in a modeset when the state is compatible. > - */ > - crtc_state->mode_changed = true; > - } > - > - ret = drm_atomic_commit(state); > - } > + if (!ret) > + ret = __intel_display_resume(dev, state, &setup); > > if (ret == -EDEADLK) { > drm_modeset_backoff(&ctx); > -- > 2.1.0 -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx