drm_client_modeset_wait_for_vblank() only rate-limits fbdev damage
updates and serves FBIO_WAITFORVSYNC, but it waits with
drm_crtc_wait_one_vblank(), which warns if no VBLANK arrives in time.

VBLANK interrupts can stop while the fbdev client keeps running. Since
commit ebc3351cc4a9 ("drm/amdgpu: remove suspend/resume DRM clients
during GPU recovery"), amdgpu no longer suspends DRM clients for GPU
recovery, as that made recovery wait for clientlist_mutex, the console
lock and the damage worker, whose holders can depend on fences that
only signal after the reset. The display is still shut down for the
reset, so the damage worker now times out and warns:

  amdgpu 0000:03:00.0: [drm] vblank wait timed out on crtc 0
  WARNING: drivers/gpu/drm/drm_vblank.c:1320 at 
drm_crtc_wait_one_vblank+0x194/0x200
  Workqueue: events drm_fb_helper_damage_work
  Call Trace:
   drm_client_modeset_wait_for_vblank+0x63/0x80
   drm_fb_helper_damage_work+0x89/0x1a0

Userspace can trigger the same warning with FBIO_WAITFORVSYNC. Wait on
the VBLANK queue with the same timeout, but log a debug message instead
of warning when it expires; a missed VBLANK only means the update isn't
synchronized.

Fixes: d8c4bddcd8bc ("drm/fb-helper: Synchronize dirty worker with vblank")
Signed-off-by: Prike Liang <[email protected]>
Cc: David Airlie <[email protected]>
Cc: [email protected]
Cc: Harry Wentland <[email protected]>
Cc: Leo Li <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Christian König <[email protected]>
---
 drivers/gpu/drm/drm_client_modeset.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c 
b/drivers/gpu/drm/drm_client_modeset.c
index 0080a8e9556a..7b3193d73bbf 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -1301,7 +1301,8 @@ EXPORT_SYMBOL(drm_client_modeset_dpms);
  *
  * Block the caller until the given CRTC has seen a VBLANK. Do nothing
  * if the CRTC is disabled. If there's another DRM master present, fail
- * with -EBUSY.
+ * with -EBUSY. Give up without a warning if no VBLANK arrives within a
+ * second, e.g. while the driver resets the display hardware.
  *
  * Returns:
  * 0 on success, or negative error code otherwise.
@@ -1328,7 +1329,14 @@ int drm_client_modeset_wait_for_vblank(struct 
drm_client_dev *client, unsigned i
         */
        ret = drm_crtc_vblank_get(crtc);
        if (!ret) {
-               drm_crtc_wait_one_vblank(crtc);
+               u64 last = drm_crtc_vblank_count(crtc);
+
+               /* Unlike drm_crtc_wait_one_vblank(), don't warn if VBLANKs 
stop. */
+               if (!wait_event_timeout(*drm_crtc_vblank_waitqueue(crtc),
+                                       drm_crtc_vblank_count(crtc) != last,
+                                       msecs_to_jiffies(1000)))
+                       drm_dbg_vbl(dev, "[CRTC:%d:%s] vblank wait timed out\n",
+                                   crtc->base.id, crtc->name);
                drm_crtc_vblank_put(crtc);
        }
 
-- 
2.34.1

Reply via email to