[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
