aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/0333-drm-amd-display-Fix-race-between-vblank-irq-and-page.patch
diff options
context:
space:
mode:
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.patch132
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
+