diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch new file mode 100644 index 00000000..5e7b4e77 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch @@ -0,0 +1,132 @@ +From 87e40d9c82472f1aba4f9d52e51acc413b7efeba Mon Sep 17 00:00:00 2001 +From: Mario Kleiner <mario.kleiner.de@gmail.com> +Date: Mon, 24 Apr 2017 11:46:44 +0200 +Subject: [PATCH 0333/4131] drm/amd/display: Fix race between vblank irq and + pageflip irq. (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since DC now uses CRTC_VERTICAL_INTERRUPT0 as VBLANK irq trigger +and vblank interrupts actually happen earliest at start of vblank, +instead of a bit before vblank, we no longer need some of the +fudging logic to deal with too early vblank irq handling (grep for +lb_vblank_lead_lines). This itself fixes a pageflip scheduling +bug in DC, caused by uninitialized use of lb_vblank_lead_lines, +with a wrong startup value of 0. Thanks to the new vblank irq +trigger this value of zero is now actually correct for DC :). + +A new problem is that vblank irq's race against pflip irq's, +and as both can fire at first line of vblank, it is no longer +guaranteed that vblank irq handling (therefore -> drm_handle_vblank() +-> drm_update_vblank_count()) executes before pflip irq handling +for a given vblank interval when a pageflip completes. Therefore +the vblank count and timestamps emitted to user-space as part of +the pageflip completion event will be often stale and cause new +timestamping and swap scheduling errors in user-space. + +This was observed with large frequency on R9 380 Tonga Pro. + +Fix this by enforcing a vblank count+timestamp update right +before emitting the pageflip completion event from the pflip +irq handler. The logic in core drm_update_vblank_count() makes +sure that no redundant or conflicting updates happen, iow. the +call turns into a no-op if it wasn't needed for that vblank, +burning a few microseconds of cpu time though. + +Successfully tested on AMD R9 380 "Tonga Pro" (VI/DCE 10) +with DC enabled on the current DC staging branch. Independent +measurement of pageflip completion timing with special hardware +measurement equipment now confirms correct pageflip timestamps +and counts in the pageflip completion events. + +v2: Review comments by Michel, drop outdated paragraph + about problem already fixed in 2nd patch of the series. + Add acked/r-b by Harry and Michel. + +Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> (v1) +Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> + +Cc: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com> +Cc: Alex Deucher <alexander.deucher@amd.com> +Cc: Michel Dänzer <michel.daenzer@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Kalyan Alle <kalyan.alle@amd.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ + drivers/gpu/drm/drm_vblank.c | 31 +++++++++++++++++++++++ + include/drm/drm_vblank.h | 1 + + 3 files changed, 35 insertions(+) + +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 c51e181..7ede233 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -202,6 +202,9 @@ static void dm_pflip_high_irq(void *interrupt_params) + if (amdgpu_crtc->event + && amdgpu_crtc->event->event.base.type + == DRM_EVENT_FLIP_COMPLETE) { ++ /* Update to correct count/ts if racing with vblank irq */ ++ drm_accurate_vblank_count(&amdgpu_crtc->base); ++ + drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event); + /* page flip completed. clean up */ + amdgpu_crtc->event = NULL; +diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c +index 17e8ef9..1b82d73 100644 +--- a/drivers/gpu/drm/drm_vblank.c ++++ b/drivers/gpu/drm/drm_vblank.c +@@ -293,6 +293,37 @@ static u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe) + return vblank->count; + } + ++ /** ++ * drm_accurate_vblank_count - retrieve the master vblank counter ++ * @crtc: which counter to retrieve ++ * ++ * This function is similar to @drm_crtc_vblank_count but this ++ * function interpolates to handle a race with vblank irq's. ++ * ++ * This is mostly useful for hardware that can obtain the scanout ++ * position, but doesn't have a frame counter. ++ */ ++u32 drm_accurate_vblank_count(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ unsigned int pipe = drm_crtc_index(crtc); ++ u32 vblank; ++ unsigned long flags; ++ ++ WARN(!dev->driver->get_vblank_timestamp, ++ "This function requires support for accurate vblank timestamps."); ++ ++ spin_lock_irqsave(&dev->vblank_time_lock, flags); ++ ++ drm_update_vblank_count(dev, pipe, false); ++ vblank = drm_vblank_count(dev, pipe); ++ ++ spin_unlock_irqrestore(&dev->vblank_time_lock, flags); ++ ++ return vblank; ++} ++EXPORT_SYMBOL(drm_accurate_vblank_count); ++ + /** + * drm_crtc_accurate_vblank_count - retrieve the master vblank counter + * @crtc: which counter to retrieve +diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h +index 7fba9ef..d0d1f2a 100644 +--- a/include/drm/drm_vblank.h ++++ b/include/drm/drm_vblank.h +@@ -169,6 +169,7 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc); + void drm_crtc_vblank_reset(struct drm_crtc *crtc); + void drm_crtc_vblank_on(struct drm_crtc *crtc); + u32 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); ++u32 drm_accurate_vblank_count(struct drm_crtc *crtc); + + bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, + unsigned int pipe, int *max_error, +-- +2.7.4 + |