[Why]
GPU reset disables the OTG and restarts the hardware frame counter. DRM
framework expects to be informed when the hardware frame counter changes
Without informing DRM, the last vblank value holds the last pre- reset
value causing the vblanck sequence jumps by a 24-bit wrap when display
comes up. This causes the page flip operations to timeout during GPU
reset because of the DRM vblank counter not reset.

[How]
Call drm_crtc_vblank_off() during suspend before streams tearing down,
and drm_crtc_vblank_on_config() in resume after they are restored which
helps DRM rebases onto the new hardware counter. Timestamping constants
need to restored before vblank_on, since vblank_off clears them.

Co-authored-by: Hemalatha Pinnamreddy <[email protected]>
Signed-off-by: Raghavendra Prasad Mallela <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 36 +++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 47a0ff2ed035..ef4e082182df 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1414,12 +1414,16 @@ static void dm_gpureset_toggle_interrupts(struct 
amdgpu_device *adev,
        struct amdgpu_crtc *acrtc;
        int rc = -EBUSY;
        int i = 0;
+       struct drm_display_mode hwmode;
 
        for (i = 0; i < state->stream_count; i++) {
                acrtc = amdgpu_dm_get_crtc_by_otg_inst(
                                adev, state->stream_status[i].primary_otg_inst);
 
-               if (acrtc && state->stream_status[i].plane_count != 0 &&
+               if(!acrtc)
+                       continue;
+
+               if (state->stream_status[i].plane_count != 0 &&
                    amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
                        irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
                        rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : 
-EBUSY;
@@ -1449,13 +1453,41 @@ static void dm_gpureset_toggle_interrupts(struct 
amdgpu_device *adev,
                        if (!amdgpu_dm_irq_set(adev, irq_source, enable))
                                drm_warn(adev_to_drm(adev), "Failed to %sable 
vblank interrupt\n", enable ? "en" : "dis");
 
-               } else if (acrtc && state->stream_status[i].plane_count != 0) {
+               } else if (state->stream_status[i].plane_count != 0) {
                        /* DCN only needs to toggle VUPDATE_NO_LOCK */
                        rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, 
enable);
                        if (rc)
                                drm_warn(adev_to_drm(adev), "Failed to %sable 
vupdate interrupt\n",
                                         enable ? "en" : "dis");
                }
+               /* During GPU reset, all the active streams are removed and 
disable the
+                * OPTC timing genrator and resets the HW vsync counter. If HW 
Vsync
+                * counter resets to 0, drm expects the SW vsync counter to be 
reset.
+                */
+               if (enable) {
+                       const struct drm_vblank_crtc_config config = 
drm_crtc_vblank_crtc(&acrtc->base)->config;
+                       /*
+                        * drm_crtc_vblank_off() leaves the per-CRTC config in
+                        * place. drm_crtc_vblank_on() would replace it with the
+                        * device defaults, so put the cached config back.
+                        */
+                       drm_calc_timestamping_constants(
+                                       &acrtc->base,
+                                       &acrtc->base.state->adjusted_mode);
+                       drm_crtc_vblank_on_config(&acrtc->base, &config);
+               }
+               else {
+                       drm_mode_init(&hwmode, 
&drm_crtc_vblank_crtc(&acrtc->base)->hwmode);
+                       drm_crtc_vblank_off(&acrtc->base);
+                       /*
+                        * drm_crtc_vblank_off() invalidates only crtc_clock in 
the
+                        * cached hwmode, but the CRTC state stays active 
across the
+                        * reset and comes back with the same mode. Restore the
+                        * timings so a commit racing the reset does not warn.
+                        */
+                       if (hwmode.crtc_clock)
+                               drm_calc_timestamping_constants(&acrtc->base, 
&hwmode);
+               }
        }
 
 }
-- 
2.17.1

Reply via email to