drm/amdgpu: Fix dead lock issue for vblank

Always start vblank timer, but only calls vblank function
when vblank is enabled.

This is used to fix the dead lock issue.
When drm_crtc_vblank_off want to disable vblank,
it first get event_lock, and then call hrtimer_cancel,
but hrtimer_cancel want to wait timer handler function finished.
Timer handler also want to aquire event_lock in drm_handle_vblank.

Signed-off-by: Emily.Deng <Emily.Deng@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Emily.Deng 2020-09-14 17:57:01 +08:00 committed by Alex Deucher
parent 9de9a54aba
commit 36499e4c77

View file

@ -47,6 +47,9 @@ static void dce_virtual_set_display_funcs(struct amdgpu_device *adev);
static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev);
static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
int index); int index);
static int dce_virtual_pageflip(struct amdgpu_device *adev,
unsigned crtc_id);
static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer);
static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
int crtc, int crtc,
enum amdgpu_interrupt_state state); enum amdgpu_interrupt_state state);
@ -247,6 +250,11 @@ static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_set_expires(&amdgpu_crtc->vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD);
amdgpu_crtc->vblank_timer.function = dce_virtual_vblank_timer_handle;
hrtimer_start(&amdgpu_crtc->vblank_timer,
DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL);
return 0; return 0;
} }
@ -476,7 +484,7 @@ static int dce_virtual_hw_fini(void *handle)
for (i = 0; i<adev->mode_info.num_crtc; i++) for (i = 0; i<adev->mode_info.num_crtc; i++)
if (adev->mode_info.crtcs[i]) if (adev->mode_info.crtcs[i])
dce_virtual_set_crtc_vblank_interrupt_state(adev, i, AMDGPU_IRQ_STATE_DISABLE); hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);
return 0; return 0;
} }
@ -698,9 +706,15 @@ static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vbla
struct amdgpu_crtc, vblank_timer); struct amdgpu_crtc, vblank_timer);
struct drm_device *ddev = amdgpu_crtc->base.dev; struct drm_device *ddev = amdgpu_crtc->base.dev;
struct amdgpu_device *adev = drm_to_adev(ddev); struct amdgpu_device *adev = drm_to_adev(ddev);
struct amdgpu_irq_src *source = adev->irq.client[AMDGPU_IRQ_CLIENTID_LEGACY].sources
[VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER];
int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev,
amdgpu_crtc->crtc_id);
if (amdgpu_irq_enabled(adev, source, irq_type)) {
drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
}
hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD, hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD,
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
@ -716,21 +730,6 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad
return; return;
} }
if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
DRM_DEBUG("Enable software vsync timer\n");
hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer,
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer,
DCE_VIRTUAL_VBLANK_PERIOD);
adev->mode_info.crtcs[crtc]->vblank_timer.function =
dce_virtual_vblank_timer_handle;
hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer,
DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL);
} else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
DRM_DEBUG("Disable software vsync timer\n");
hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer);
}
adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state; adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state;
DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state); DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
} }