From: James Lin <[email protected]>
amdgpu_get_vblank_counter_kms() is DRM's hardware ->get_vblank_counter
callback, so drm_update_vblank_count() stores its return value into
vblank->last and derives diff = cur_vblank - vblank->last.
Commit f2bc71d16e73 ("drm/amdgpu: serialize vblank counter reads
against GPU reset") made the callback fall back to
drm_crtc_vblank_count() when the reset semaphore is held. That returns
DRM's software vblank count, which is a different numeric domain than
the hardware counter. It poisons vblank->last, so a later update hits
diff == 0 while cur_vblank != vblank->last and trips
drm_WARN_ON_ONCE() in drm_update_vblank_count(). Reset still succeeds,
but the WARN fails the mode1_reset dmesg check.
Return the cached hardware value vblank->last via drm_crtc_vblank_crtc()
instead, so the core sees "no new vblanks" and keeps its accounting
consistent. vblank->last is protected by drm_device.vbl_lock, already
held across this callback.
Fixes: f2bc71d16e73 ("drm/amdgpu: serialize vblank counter reads against GPU
reset")
Signed-off-by: James Lin <[email protected]>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 14a72a406d37..365b4fc86a9e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1699,9 +1699,18 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
- if (!down_read_trylock(&adev->reset_domain->sem))
- return drm_crtc_vblank_count(crtc);
+ /*
+ * A GPU reset is in progress and the display hardware cannot be read
+ * safely. Return the hardware counter value DRM already cached rather
+ * than the software vblank count: the core feeds this callback's
+ * result back into vblank->last, and a software count lives in a
+ * different numeric domain, which later trips
+ * drm_WARN_ON_ONCE(cur_vblank != vblank->last) in
+ * drm_update_vblank_count().
+ */
+ if (!down_read_trylock(&adev->reset_domain->sem))
+ return drm_crtc_vblank_crtc(crtc)->last;
/* The hw increments its frame counter at start of vsync, not at start
* of vblank, as is required by DRM core vblank counter handling.
--
2.43.0