Skip to content

Commit dfa2997

Browse files
mlankhorstjnikula
authored andcommitted
drm/i915: Fix modeset handling during gpu reset, v5.
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. Changes since v1: - Deal with -EDEADLK right after lock_all and clean up calls to hw readout. - Always take all modeset locks so updates during gpu reset are blocked. Changes since v2: - Fix deadlock in intel_update_primary_planes. - Move WARN_ON(EDEADLK) to __intel_display_resume. - pctx -> ctx - only call __intel_display_resume on success in intel_display_resume. Changes since v3: - Rebase on top of dev_priv -> dev change. - Use drm_modeset_lock_all_ctx instead of drm_modeset_lock_all. Changes since v4 [by vsyrjala]: - Deal with skip_intermediate_wm - Update comment w.r.t. mode_config.mutex vs. ->detect() - Rebase due to INTEL_GEN() etc. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Fixes: e2c8b87 ("drm/i915: Use atomic helpers for suspend, v2.") Cc: stable@vger.kernel.org Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1470428910-12125-2-git-send-email-ville.syrjala@linux.intel.com (cherry picked from commit 7397489) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
1 parent 3871f42 commit dfa2997

File tree

2 files changed

+111
-60
lines changed

2 files changed

+111
-60
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,7 @@ struct drm_i915_private {
18541854
enum modeset_restore modeset_restore;
18551855
struct mutex modeset_restore_lock;
18561856
struct drm_atomic_state *modeset_restore_state;
1857+
struct drm_modeset_acquire_ctx reset_ctx;
18571858

18581859
struct list_head vm_list; /* Global list of all address spaces */
18591860
struct i915_ggtt ggtt; /* VM representing the global address space */

drivers/gpu/drm/i915/intel_display.c

Lines changed: 110 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3093,40 +3093,110 @@ static void intel_update_primary_planes(struct drm_device *dev)
30933093

30943094
for_each_crtc(dev, crtc) {
30953095
struct intel_plane *plane = to_intel_plane(crtc->primary);
3096-
struct intel_plane_state *plane_state;
3097-
3098-
drm_modeset_lock_crtc(crtc, &plane->base);
3099-
plane_state = to_intel_plane_state(plane->base.state);
3096+
struct intel_plane_state *plane_state =
3097+
to_intel_plane_state(plane->base.state);
31003098

31013099
if (plane_state->visible)
31023100
plane->update_plane(&plane->base,
31033101
to_intel_crtc_state(crtc->state),
31043102
plane_state);
3103+
}
3104+
}
3105+
3106+
static int
3107+
__intel_display_resume(struct drm_device *dev,
3108+
struct drm_atomic_state *state)
3109+
{
3110+
struct drm_crtc_state *crtc_state;
3111+
struct drm_crtc *crtc;
3112+
int i, ret;
3113+
3114+
intel_modeset_setup_hw_state(dev);
3115+
i915_redisable_vga(dev);
31053116

3106-
drm_modeset_unlock_crtc(crtc);
3117+
if (!state)
3118+
return 0;
3119+
3120+
for_each_crtc_in_state(state, crtc, crtc_state, i) {
3121+
/*
3122+
* Force recalculation even if we restore
3123+
* current state. With fast modeset this may not result
3124+
* in a modeset when the state is compatible.
3125+
*/
3126+
crtc_state->mode_changed = true;
31073127
}
3128+
3129+
/* ignore any reset values/BIOS leftovers in the WM registers */
3130+
to_intel_atomic_state(state)->skip_intermediate_wm = true;
3131+
3132+
ret = drm_atomic_commit(state);
3133+
3134+
WARN_ON(ret == -EDEADLK);
3135+
return ret;
31083136
}
31093137

31103138
void intel_prepare_reset(struct drm_i915_private *dev_priv)
31113139
{
3140+
struct drm_device *dev = &dev_priv->drm;
3141+
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
3142+
struct drm_atomic_state *state;
3143+
int ret;
3144+
31123145
/* no reset support for gen2 */
31133146
if (IS_GEN2(dev_priv))
31143147
return;
31153148

3116-
/* reset doesn't touch the display */
3149+
/*
3150+
* Need mode_config.mutex so that we don't
3151+
* trample ongoing ->detect() and whatnot.
3152+
*/
3153+
mutex_lock(&dev->mode_config.mutex);
3154+
drm_modeset_acquire_init(ctx, 0);
3155+
while (1) {
3156+
ret = drm_modeset_lock_all_ctx(dev, ctx);
3157+
if (ret != -EDEADLK)
3158+
break;
3159+
3160+
drm_modeset_backoff(ctx);
3161+
}
3162+
3163+
/* reset doesn't touch the display, but flips might get nuked anyway, */
31173164
if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
31183165
return;
31193166

3120-
drm_modeset_lock_all(&dev_priv->drm);
31213167
/*
31223168
* Disabling the crtcs gracefully seems nicer. Also the
31233169
* g33 docs say we should at least disable all the planes.
31243170
*/
3125-
intel_display_suspend(&dev_priv->drm);
3171+
state = drm_atomic_helper_duplicate_state(dev, ctx);
3172+
if (IS_ERR(state)) {
3173+
ret = PTR_ERR(state);
3174+
state = NULL;
3175+
DRM_ERROR("Duplicating state failed with %i\n", ret);
3176+
goto err;
3177+
}
3178+
3179+
ret = drm_atomic_helper_disable_all(dev, ctx);
3180+
if (ret) {
3181+
DRM_ERROR("Suspending crtc's failed with %i\n", ret);
3182+
goto err;
3183+
}
3184+
3185+
dev_priv->modeset_restore_state = state;
3186+
state->acquire_ctx = ctx;
3187+
return;
3188+
3189+
err:
3190+
drm_atomic_state_free(state);
31263191
}
31273192

31283193
void intel_finish_reset(struct drm_i915_private *dev_priv)
31293194
{
3195+
struct drm_device *dev = &dev_priv->drm;
3196+
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
3197+
struct drm_atomic_state *state = dev_priv->modeset_restore_state;
3198+
int ret;
3199+
31303200
/*
31313201
* Flips in the rings will be nuked by the reset,
31323202
* so complete all pending flips so that user space
@@ -3138,6 +3208,8 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
31383208
if (IS_GEN2(dev_priv))
31393209
return;
31403210

3211+
dev_priv->modeset_restore_state = NULL;
3212+
31413213
/* reset doesn't touch the display */
31423214
if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
31433215
/*
@@ -3149,29 +3221,32 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
31493221
* FIXME: Atomic will make this obsolete since we won't schedule
31503222
* CS-based flips (which might get lost in gpu resets) any more.
31513223
*/
3152-
intel_update_primary_planes(&dev_priv->drm);
3153-
return;
3154-
}
3155-
3156-
/*
3157-
* The display has been reset as well,
3158-
* so need a full re-initialization.
3159-
*/
3160-
intel_runtime_pm_disable_interrupts(dev_priv);
3161-
intel_runtime_pm_enable_interrupts(dev_priv);
3224+
intel_update_primary_planes(dev);
3225+
} else {
3226+
/*
3227+
* The display has been reset as well,
3228+
* so need a full re-initialization.
3229+
*/
3230+
intel_runtime_pm_disable_interrupts(dev_priv);
3231+
intel_runtime_pm_enable_interrupts(dev_priv);
31623232

3163-
intel_modeset_init_hw(&dev_priv->drm);
3233+
intel_modeset_init_hw(dev);
31643234

3165-
spin_lock_irq(&dev_priv->irq_lock);
3166-
if (dev_priv->display.hpd_irq_setup)
3167-
dev_priv->display.hpd_irq_setup(dev_priv);
3168-
spin_unlock_irq(&dev_priv->irq_lock);
3235+
spin_lock_irq(&dev_priv->irq_lock);
3236+
if (dev_priv->display.hpd_irq_setup)
3237+
dev_priv->display.hpd_irq_setup(dev_priv);
3238+
spin_unlock_irq(&dev_priv->irq_lock);
31693239

3170-
intel_display_resume(&dev_priv->drm);
3240+
ret = __intel_display_resume(dev, state);
3241+
if (ret)
3242+
DRM_ERROR("Restoring old state failed with %i\n", ret);
31713243

3172-
intel_hpd_init(dev_priv);
3244+
intel_hpd_init(dev_priv);
3245+
}
31733246

3174-
drm_modeset_unlock_all(&dev_priv->drm);
3247+
drm_modeset_drop_locks(ctx);
3248+
drm_modeset_acquire_fini(ctx);
3249+
mutex_unlock(&dev->mode_config.mutex);
31753250
}
31763251

31773252
static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
@@ -16174,9 +16249,10 @@ void intel_display_resume(struct drm_device *dev)
1617416249
struct drm_atomic_state *state = dev_priv->modeset_restore_state;
1617516250
struct drm_modeset_acquire_ctx ctx;
1617616251
int ret;
16177-
bool setup = false;
1617816252

1617916253
dev_priv->modeset_restore_state = NULL;
16254+
if (state)
16255+
state->acquire_ctx = &ctx;
1618016256

1618116257
/*
1618216258
* This is a cludge because with real atomic modeset mode_config.mutex
@@ -16187,43 +16263,17 @@ void intel_display_resume(struct drm_device *dev)
1618716263
mutex_lock(&dev->mode_config.mutex);
1618816264
drm_modeset_acquire_init(&ctx, 0);
1618916265

16190-
retry:
16191-
ret = drm_modeset_lock_all_ctx(dev, &ctx);
16192-
16193-
if (ret == 0 && !setup) {
16194-
setup = true;
16195-
16196-
intel_modeset_setup_hw_state(dev);
16197-
i915_redisable_vga(dev);
16198-
}
16199-
16200-
if (ret == 0 && state) {
16201-
struct drm_crtc_state *crtc_state;
16202-
struct drm_crtc *crtc;
16203-
int i;
16204-
16205-
state->acquire_ctx = &ctx;
16206-
16207-
/* ignore any reset values/BIOS leftovers in the WM registers */
16208-
to_intel_atomic_state(state)->skip_intermediate_wm = true;
16209-
16210-
for_each_crtc_in_state(state, crtc, crtc_state, i) {
16211-
/*
16212-
* Force recalculation even if we restore
16213-
* current state. With fast modeset this may not result
16214-
* in a modeset when the state is compatible.
16215-
*/
16216-
crtc_state->mode_changed = true;
16217-
}
16218-
16219-
ret = drm_atomic_commit(state);
16220-
}
16266+
while (1) {
16267+
ret = drm_modeset_lock_all_ctx(dev, &ctx);
16268+
if (ret != -EDEADLK)
16269+
break;
1622116270

16222-
if (ret == -EDEADLK) {
1622316271
drm_modeset_backoff(&ctx);
16224-
goto retry;
1622516272
}
1622616273

16274+
if (!ret)
16275+
ret = __intel_display_resume(dev, state);
16276+
1622716277
drm_modeset_drop_locks(&ctx);
1622816278
drm_modeset_acquire_fini(&ctx);
1622916279
mutex_unlock(&dev->mode_config.mutex);

0 commit comments

Comments
 (0)