Skip to content

Commit c8b5a95

Browse files
Alan Liualexdeucher
authored andcommitted
drm/amdgpu: Fix desktop freezed after gpu-reset
[Why] After gpu-reset, sometimes the driver fails to enable vblank irq, causing flip_done timed out and the desktop freezed. During gpu-reset, we disable and enable vblank irq in dm_suspend() and dm_resume(). Later on in amdgpu_irq_gpu_reset_resume_helper(), we check irqs' refcount and decide to enable or disable the irqs again. However, we have 2 sets of API for controling vblank irq, one is dm_vblank_get/put() and another is amdgpu_irq_get/put(). Each API has its own refcount and flag to store the state of vblank irq, and they are not synchronized. In drm we use the first API to control vblank irq but in amdgpu_irq_gpu_reset_resume_helper() we use the second set of API. The failure happens when vblank irq was enabled by dm_vblank_get() before gpu-reset, we have vblank->enabled true. However, during gpu-reset, in amdgpu_irq_gpu_reset_resume_helper() vblank irq's state checked from amdgpu_irq_update() is DISABLED. So finally it disables vblank irq again. After gpu-reset, if there is a cursor plane commit, the driver will try to enable vblank irq by calling drm_vblank_enable(), but the vblank->enabled is still true, so it fails to turn on vblank irq and causes flip_done can't be completed in vblank irq handler and desktop become freezed. [How] Combining the 2 vblank control APIs by letting drm's API finally calls amdgpu_irq's API, so the irq's refcount and state of both APIs can be synchronized. Also add a check to prevent refcount from being less then 0 in amdgpu_irq_put(). v2: - Add warning in amdgpu_irq_enable() if the irq is already disabled. - Call dc_interrupt_set() in dm_set_vblank() to avoid refcount change if it is in gpu-reset. v3: - Improve commit message and code comments. Signed-off-by: Alan Liu <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
1 parent 6a8f57a commit c8b5a95

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,9 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
596596
if (!src->enabled_types || !src->funcs->set)
597597
return -EINVAL;
598598

599+
if (WARN_ON(!amdgpu_irq_enabled(adev, src, type)))
600+
return -EINVAL;
601+
599602
if (atomic_dec_and_test(&src->enabled_types[type]))
600603
return amdgpu_irq_update(adev, src, type);
601604

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,21 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
169169
if (rc)
170170
return rc;
171171

172-
irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
172+
if (amdgpu_in_reset(adev)) {
173+
irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
174+
/* During gpu-reset we disable and then enable vblank irq, so
175+
* don't use amdgpu_irq_get/put() to avoid refcount change.
176+
*/
177+
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
178+
rc = -EBUSY;
179+
} else {
180+
rc = (enable)
181+
? amdgpu_irq_get(adev, &adev->crtc_irq, acrtc->crtc_id)
182+
: amdgpu_irq_put(adev, &adev->crtc_irq, acrtc->crtc_id);
183+
}
173184

174-
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
175-
return -EBUSY;
185+
if (rc)
186+
return rc;
176187

177188
skip:
178189
if (amdgpu_in_reset(adev))

0 commit comments

Comments
 (0)