OSDN Git Service

drm/amdgpu: Fix dead lock issue for vblank
authorEmily.Deng <Emily.Deng@amd.com>
Mon, 14 Sep 2020 09:57:01 +0000 (17:57 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 22 Sep 2020 16:25:15 +0000 (12:25 -0400)
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>
drivers/gpu/drm/amd/amdgpu/dce_virtual.c

index cc93577..469c05f 100644 (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 int dce_virtual_connector_encoder_init(struct amdgpu_device *adev,
                                              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,
                                                        int crtc,
                                                        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;
        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;
 }
 
@@ -476,7 +484,7 @@ static int dce_virtual_hw_fini(void *handle)
 
        for (i = 0; i<adev->mode_info.num_crtc; 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;
 }
@@ -698,9 +706,15 @@ static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vbla
                                                       struct amdgpu_crtc, vblank_timer);
        struct drm_device *ddev = amdgpu_crtc->base.dev;
        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);
 
-       drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
-       dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
+       if (amdgpu_irq_enabled(adev, source, irq_type)) {
+               drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
+               dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
+       }
        hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD,
                      HRTIMER_MODE_REL);
 
@@ -716,21 +730,6 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad
                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;
        DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
 }