xf86-video-amdgpu: Branch 'master' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jan 25 17:00:45 UTC 2019


 src/amdgpu_drm_queue.c |   19 ++++++++++++--
 src/amdgpu_kms.c       |   66 +++++++++++++++++++++++++------------------------
 src/drmmode_display.c  |   15 ++++++-----
 3 files changed, 60 insertions(+), 40 deletions(-)

New commits:
commit 9045fb310f88780e250e60b80431ca153330e61b
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Jan 24 18:31:40 2019 +0100

    Keep waiting for a pending flip if drm_handle_event returns 0
    
    drm_wait_pending_flip stopped waiting if drm_handle_event returned 0,
    but that might have processed only some unrelated DRM events. As long as
    the flip is pending, we have to keep waiting for its completion event.
    
    Noticed while working on the previous fix.
    
    Acked-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_drm_queue.c b/src/amdgpu_drm_queue.c
index 534ad32..0cf2224 100644
--- a/src/amdgpu_drm_queue.c
+++ b/src/amdgpu_drm_queue.c
@@ -325,7 +325,7 @@ void amdgpu_drm_wait_pending_flip(xf86CrtcPtr crtc)
 
 	while (drmmode_crtc->flip_pending
 	       && amdgpu_drm_handle_event(pAMDGPUEnt->fd,
-					  &drmmode_crtc->drmmode->event_context) > 0);
+					  &drmmode_crtc->drmmode->event_context) >= 0);
 }
 
 /*
commit 3ff2cc225f6bc08364ee007fa54e9d0150adaf11
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Tue Jan 22 18:36:56 2019 +0100

    Call drmHandleEvent again if it was interrupted by a signal
    
    drmHandleEvent can be interrupted by a signal in read(), in which case
    it doesn't process any events but returns -1, which
    drm_handle_event propagated to its callers. This could cause the
    following failure cascade:
    
    1. drm_wait_pending_flip stopped waiting for a pending flip.
    2. Its caller cleared drmmode_crtc->flip_pending before the flip
       completed.
    3. Another flip was attempted but got an unexpected EBUSY error because
       the previous flip was still pending.
    4. TearFree was disabled due to the error.
    
    The solution is to call drmHandleEvent if it was interrupted by a
    signal. We can do that in drm_handle_event, because when that is called,
    either it is known that there are events ready to be processed, or the
    caller has to wait for events to arrive anyway.
    
    v2:
    * Use ErrorF instead of xf86DrvMsg with hard-coded screen 0.
    
    Bugzilla: https://bugs.freedesktop.org/109364
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com> # v1

diff --git a/src/amdgpu_drm_queue.c b/src/amdgpu_drm_queue.c
index 56d593d..534ad32 100644
--- a/src/amdgpu_drm_queue.c
+++ b/src/amdgpu_drm_queue.c
@@ -30,6 +30,8 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
+
 #include <xorg-server.h>
 #include <X11/Xdefs.h>
 #include <list.h>
@@ -277,7 +279,20 @@ amdgpu_drm_handle_event(int fd, drmEventContext *event_context)
 	struct amdgpu_drm_queue_entry *e;
 	int r;
 
-	r = drmHandleEvent(fd, event_context);
+	/* Retry drmHandleEvent if it was interrupted by a signal in read() */
+	do {
+		r = drmHandleEvent(fd, event_context);
+	} while (r < 0 && (errno == EINTR || errno == EAGAIN));
+
+	if (r < 0) {
+		static Bool printed;
+
+		if (!printed) {
+			ErrorF("%s: drmHandleEvent returned %d, errno=%d (%s)\n",
+			       __func__, r, errno, strerror(errno));
+			printed = TRUE;
+		}
+	}
 
 	while (!xorg_list_is_empty(&amdgpu_drm_flip_signalled)) {
 		e = xorg_list_first_entry(&amdgpu_drm_flip_signalled,
commit e72a02ba1d35743fefd939458b9d8cddce86e7f5
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jan 16 10:26:59 2019 +0100

    Only update drmmode_crtc->flip_pending after actually submitting a flip
    
    And only clear it if it matches the framebuffer of the completed flip
    being processed.
    
    Fixes
    
     (WW) AMDGPU(0): flip queue failed: Device or resource busy
     (WW) AMDGPU(0): Page flip failed: Device or resource busy
     (EE) AMDGPU(0): present flip failed
    
    due to clobbering drmmode_crtc->flip_pending.
    
    Reproducer: Enable TearFree, run warzone2100 fullscreen, toggle
    Vertical sync on/off under Video Options. Discovered while investigating
    https://bugs.freedesktop.org/109364 .
    
    Acked-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index feefd67..05becb2 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -491,10 +491,14 @@ amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	struct drmmode_fb *fb = event_data;
 
 	drmmode_crtc->scanout_update_pending = 0;
-	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
-			     NULL);
+
+	if (drmmode_crtc->flip_pending == fb) {
+		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
+				     NULL);
+	}
 }
 
 static void
@@ -503,9 +507,9 @@ amdgpu_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
 {
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	struct drmmode_fb *fb = event_data;
 
-	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
-			     drmmode_crtc->flip_pending);
+	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
 	amdgpu_scanout_flip_abort(crtc, event_data);
 }
 
@@ -786,24 +790,31 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 	drmmode_crtc_private_ptr drmmode_crtc;
 	uintptr_t drm_queue_seq;
 	unsigned scanout_id;
+	struct drmmode_fb *fb;
 
 	if (!crtc || !crtc->enabled)
 		return;
 
 	drmmode_crtc = crtc->driver_private;
+	scanout_id = drmmode_crtc->scanout_id ^ 1;
 	if (drmmode_crtc->scanout_update_pending ||
-	    !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap ||
+	    !drmmode_crtc->scanout[scanout_id].pixmap ||
 	    drmmode_crtc->dpms_mode != DPMSModeOn)
 		return;
 
-	scanout_id = drmmode_crtc->scanout_id ^ 1;
 	if (!amdgpu_prime_scanout_do_update(crtc, scanout_id))
 		return;
 
+	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+	if (!fb) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "Failed to get FB for PRIME flip.\n");
+		return;
+	}
+	
 	drm_queue_seq = amdgpu_drm_queue_alloc(crtc,
 					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
-					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
-					       NULL,
+					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
 					       amdgpu_scanout_flip_handler,
 					       amdgpu_scanout_flip_abort, TRUE);
 	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
@@ -812,18 +823,9 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 		return;
 	}
 
-	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
-			     amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
-	if (!drmmode_crtc->flip_pending) {
-		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "Failed to get FB for PRIME flip.\n");
-		amdgpu_drm_abort_entry(drm_queue_seq);
-		return;
-	}
-
 	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
-					      drmmode_crtc->flip_pending->handle,
-					      0, drm_queue_seq, 1) != 0) {
+					      fb->handle, 0, drm_queue_seq, 1)
+	    != 0) {
 		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "flip queue failed in %s: %s, TearFree inactive\n",
@@ -842,6 +844,7 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 
 	drmmode_crtc->scanout_id = scanout_id;
 	drmmode_crtc->scanout_update_pending = drm_queue_seq;
+	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
 }
 
 static void
@@ -1094,6 +1097,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	uintptr_t drm_queue_seq;
 	unsigned scanout_id;
+	struct drmmode_fb *fb;
 
 	if (drmmode_crtc->scanout_update_pending ||
 	    drmmode_crtc->flip_pending ||
@@ -1109,10 +1113,16 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 	amdgpu_glamor_flush(scrn);
 	RegionEmpty(region);
 
+	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+	if (!fb) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "Failed to get FB for scanout flip.\n");
+		return;
+	}
+
 	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
 					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
-					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
-					       NULL,
+					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
 					       amdgpu_scanout_flip_handler,
 					       amdgpu_scanout_flip_abort, TRUE);
 	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
@@ -1121,18 +1131,9 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 		return;
 	}
 
-	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
-			     amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
-	if (!drmmode_crtc->flip_pending) {
-		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "Failed to get FB for scanout flip.\n");
-		amdgpu_drm_abort_entry(drm_queue_seq);
-		return;
-	}
-
 	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
-					      drmmode_crtc->flip_pending->handle,
-					      0, drm_queue_seq, 1) != 0) {
+					      fb->handle, 0, drm_queue_seq, 1)
+	    != 0) {
 		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "flip queue failed in %s: %s, TearFree inactive\n",
@@ -1158,6 +1159,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 
 	drmmode_crtc->scanout_id = scanout_id;
 	drmmode_crtc->scanout_update_pending = drm_queue_seq;
+	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
 }
 
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index aea53ad..859c01e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -3210,12 +3210,14 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
 		flipdata->fe_usec = usec;
 	}
 
-	if (drmmode_crtc->flip_pending == *fb) {
-		drmmode_fb_reference(pAMDGPUEnt->fd,
-				     &drmmode_crtc->flip_pending, NULL);
+	if (*fb) {
+		if (drmmode_crtc->flip_pending == *fb) {
+			drmmode_fb_reference(pAMDGPUEnt->fd,
+					     &drmmode_crtc->flip_pending, NULL);
+		}
+		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb);
+		drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL);
 	}
-	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb);
-	drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL);
 
 	if (--flipdata->flip_count == 0) {
 		/* Deliver MSC & UST from reference/current CRTC to flip event
@@ -4125,9 +4127,10 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			drmmode_crtc->ignore_damage = TRUE;
 		}
 
-	next:
 		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
 				     flipdata->fb[crtc_id]);
+
+	next:
 		drm_queue_seq = 0;
 	}
 


More information about the xorg-commit mailing list