On drmModeSetCrtc() fail, revert to last good settings

Change-Id: I9e475efc4491c998ce95fbf74306463e3fb01349
diff --git a/src/armsoc_dumb.c b/src/armsoc_dumb.c
index ba92d00..c232251 100644
--- a/src/armsoc_dumb.c
+++ b/src/armsoc_dumb.c
@@ -141,8 +141,9 @@
 	if (res) {
 		free(new_buf);
 		xf86DrvMsg(-1, X_ERROR,
-			"_CREATE_GEM({height: 0x%X, width: 0x%X, bpp: 0x%X, buf_type: 0x%X}) failed. errno:0x%X\n",
-				height, width, bpp, buf_type, errno);
+			"_CREATE_GEM({height: %d, width: %d, bpp: %d buf_type: 0x%X}) failed. errno: %d - %s\n",
+				height, width, bpp, buf_type,
+				errno, strerror(errno));
 		return NULL;
 	}
 
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index c20259c..ffd9dd1 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -182,6 +182,45 @@
 	/* TODO: MIDEGL-1431: Implement this function */
 }
 
+static int
+drmmode_revert_mode(xf86CrtcPtr crtc, uint32_t *output_ids, int output_count)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
+	uint32_t fb_id;
+	struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
+	drmModeModeInfo kmode;
+
+	if (!drmmode_crtc->last_good_mode) {
+		DEBUG_MSG("No last good values to use");
+		return FALSE;
+	}
+
+	/* revert to last good settings */
+	DEBUG_MSG("Reverting to last_good values");
+	if (!resize_scanout_bo(pScrn,
+			drmmode_crtc->last_good_mode->HDisplay,
+			drmmode_crtc->last_good_mode->VDisplay)) {
+		ERROR_MSG("Could not revert to last good mode");
+		return FALSE;
+	}
+
+	fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
+	drmmode_ConvertToKMode(crtc->scrn, &kmode,
+			drmmode_crtc->last_good_mode);
+	drmModeSetCrtc(drmmode_crtc->drmmode->fd,
+			drmmode_crtc->mode_crtc->crtc_id,
+			fb_id,
+			drmmode_crtc->last_good_x,
+			drmmode_crtc->last_good_y,
+			output_ids, output_count, &kmode);
+
+	/* let RandR know we changed things */
+	xf86RandR12TellChanged(pScrn->pScreen);
+
+	return TRUE;
+}
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		Rotation rotation, int x, int y)
@@ -194,6 +233,7 @@
 	uint32_t *output_ids = NULL;
 	int output_count = 0;
 	int ret = TRUE;
+	int err;
 	int i;
 	uint32_t fb_id;
 	drmModeModeInfo kmode;
@@ -207,8 +247,8 @@
 		DEBUG_MSG("create framebuffer: %dx%d",
 				pScrn->virtualX, pScrn->virtualY);
 
-		ret = armsoc_bo_add_fb(pARMSOC->scanout);
-		if (ret) {
+		err = armsoc_bo_add_fb(pARMSOC->scanout);
+		if (err) {
 			ERROR_MSG(
 					"Failed to add framebuffer to the scanout buffer");
 			return FALSE;
@@ -230,7 +270,7 @@
 		ERROR_MSG(
 				"memory allocation failed in drmmode_set_mode_major()");
 		ret = FALSE;
-		goto done;
+		goto cleanup;
 	}
 
 	for (i = 0; i < xf86_config->num_output; i++) {
@@ -250,7 +290,7 @@
 		ERROR_MSG(
 				"failed to assign rotation in drmmode_set_mode_major()");
 		ret = FALSE;
-		goto done;
+		goto cleanup;
 	}
 
 	if (crtc->funcs->gamma_set)
@@ -259,82 +299,67 @@
 
 	drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
-	ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+	err = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 			fb_id, x, y, output_ids, output_count, &kmode);
-	if (ret) {
+	if (err) {
 		ERROR_MSG(
-				"failed to set mode: %s", strerror(-ret));
+				"drm failed to set mode: %s", strerror(-err));
+
 		ret = FALSE;
-		goto done;
+		if (!drmmode_revert_mode(crtc, output_ids, output_count))
+			goto cleanup;
+		else
+			goto done_setting;
 	}
 
 	/* get the actual crtc info */
 	newcrtc = drmModeGetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id);
 	if (!newcrtc) {
 		ERROR_MSG("couldn't get actual mode back");
+
 		ret = FALSE;
-		goto done;
+		if (!drmmode_revert_mode(crtc, output_ids, output_count))
+			goto cleanup;
+		else
+			goto done_setting;
 	}
 
 	if (kmode.hdisplay != newcrtc->mode.hdisplay ||
 		kmode.vdisplay != newcrtc->mode.vdisplay) {
 
-		ret = FALSE;
 		ERROR_MSG(
-				"drm did not set requested mode! (requested %dx%d, actual %dx%d)",
-				kmode.hdisplay, kmode.vdisplay,
-				newcrtc->mode.hdisplay,
-				newcrtc->mode.vdisplay);
+			"drm did not set requested mode! (requested %dx%d, actual %dx%d)",
+			kmode.hdisplay, kmode.vdisplay,
+			newcrtc->mode.hdisplay,
+			newcrtc->mode.vdisplay);
 
-		if (!drmmode_crtc->last_good_mode) {
-			DEBUG_MSG("No last good values to use");
-			goto done;
-		}
-
-		/* revert to last good settings */
-		DEBUG_MSG("Reverting to last_good values");
-		if (!resize_scanout_bo(pScrn,
-				drmmode_crtc->last_good_mode->HDisplay,
-				drmmode_crtc->last_good_mode->VDisplay)) {
-			ERROR_MSG("Could not revert to last good mode");
-			goto done;
-		}
-
-		fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
-		drmmode_ConvertToKMode(crtc->scrn, &kmode,
-				drmmode_crtc->last_good_mode);
-		drmModeSetCrtc(drmmode->fd,
-				drmmode_crtc->mode_crtc->crtc_id,
-				fb_id,
-				drmmode_crtc->last_good_x,
-				drmmode_crtc->last_good_y,
-				output_ids, output_count, &kmode);
-
-		/* let RandR know we changed things */
-		xf86RandR12TellChanged(pScrn->pScreen);
-
-	} else {
-		/* When called on a resize, crtc->mode already contains the
-		 * resized values so we can't use this for recovery.
-		 * We can't read it out of the crtc either as mode_valid is 0.
-		 * Instead we save the last good mode set here & fallback to
-		 * that on failure.
-		 */
-		DEBUG_MSG("Setting last good values");
-		drmmode_crtc->last_good_x = crtc->x;
-		drmmode_crtc->last_good_y = crtc->y;
-		drmmode_crtc->last_good_rotation = crtc->rotation;
-		if (drmmode_crtc->last_good_mode) {
-			if (drmmode_crtc->last_good_mode->name) {
-				free(drmmode_crtc->last_good_mode->name);
-			}
-			free(drmmode_crtc->last_good_mode);
-		}
-		drmmode_crtc->last_good_mode = xf86DuplicateMode(&crtc->mode);
-
-		ret = TRUE;
+		ret = FALSE;
+		if (!drmmode_revert_mode(crtc, output_ids, output_count))
+			goto cleanup;
+		else
+			goto done_setting;
 	}
 
+	/* When called on a resize, crtc->mode already contains the
+	 * resized values so we can't use this for recovery.
+	 * We can't read it out of the crtc either as mode_valid is 0.
+	 * Instead we save the last good mode set here & fallback to
+	 * that on failure.
+	 */
+	DEBUG_MSG("Saving last good values");
+	drmmode_crtc->last_good_x = crtc->x;
+	drmmode_crtc->last_good_y = crtc->y;
+	drmmode_crtc->last_good_rotation = crtc->rotation;
+	if (drmmode_crtc->last_good_mode) {
+		if (drmmode_crtc->last_good_mode->name)
+			free(drmmode_crtc->last_good_mode->name);
+		free(drmmode_crtc->last_good_mode);
+	}
+	drmmode_crtc->last_good_mode = xf86DuplicateMode(&crtc->mode);
+
+	ret = TRUE;
+
+done_setting:
 	/* Turn on any outputs on this crtc that may have been disabled: */
 	for (i = 0; i < xf86_config->num_output; i++) {
 		xf86OutputPtr output = xf86_config->output[i];
@@ -349,7 +374,7 @@
 	if (drmmode->cursor)
 		xf86_reload_cursors(pScrn->pScreen);
 
-done:
+cleanup:
 	if (newcrtc)
 		drmModeFreeCrtc(newcrtc);
 
@@ -661,8 +686,8 @@
 
 	if (!xf86LoaderCheckSymbol("drmModeSetCursor") ||
 	    !xf86LoaderCheckSymbol("drmModeMoveCursor")) {
-		ERROR_MSG("standard HW cursor not supported "
-			  "(needs libdrm 2.4.3 or higher)");
+		ERROR_MSG(
+				"Standard HW cursor not supported (needs libdrm 2.4.3 or higher)");
 		return FALSE;
 	}
 
@@ -1415,7 +1440,6 @@
 	xf86CrtcConfigPtr xf86_config;
 
 	TRACE_ENTER();
-
 	if (!resize_scanout_bo(pScrn, width, height))
 		return FALSE;