[PATCH v6 1/2] drm/atomic: attempt full modeset on page flip timeout

Hamza Mahfooz
2026-05-05T18:31:57Z

We should try to recover from page flip timeouts. Forcing
a full modeset should be generic across all atomic KMS drivers,
so try that first.

Signed-off-by: Hamza Mahfooz <someguy@effective-light.com>
---
drivers/gpu/drm/drm_atomic_helper.c | 49 +++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index a768398a1884..7ee9d52f63c5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1926,6 +1926,43 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);

+static int force_full_modeset(struct drm_crtc *crtc)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ int ret;
+ int err;
+
+ if (drm_atomic_crtc_needs_modeset(crtc->state))
+ return -EBUSY;
+
+ DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, err);
+ state = drm_atomic_state_alloc(crtc->dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = &ctx;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto out;
+ }
+
+ crtc_state->mode_changed = true;
+
+ drm_info(crtc->dev,
+ "[CRTC:%d:%s] Attempting force full modeset...\n",
+ crtc->base.id, crtc->name);
+
+ ret = drm_atomic_commit(state);
+out:
+ drm_atomic_state_put(state);
+ DRM_MODESET_LOCK_ALL_END(crtc->dev, ctx, err);
+ return ret;
+}
+
/**
* drm_atomic_helper_wait_for_flip_done - wait for all page flips to be done
* @dev: DRM device
@@ -1949,17 +1986,23 @@ void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,

for (i = 0; i < dev->mode_config.num_crtc; i++) {
struct drm_crtc_commit *commit = state->crtcs[i].commit;
- int ret;

crtc = state->crtcs[i].ptr;

if (!crtc || !commit)
continue;

- ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
- if (ret == 0)
+ if (!wait_for_completion_timeout(&commit->flip_done, 10 * HZ)) {
+ int ret;
drm_err(dev, "[CRTC:%d:%s] flip_done timed out\n",
crtc->base.id, crtc->name);
+
+ ret = force_full_modeset(crtc);
+ if (ret)
+ drm_err(dev,
+ "[CRTC:%d:%s] force full modeset failed! ret=%d\n",
+ crtc->base.id, crtc->name, ret);
+ }
}

if (state->fake_commit)
--
2.54.0