Merge tag 'drm-intel-fixes-2014-10-02' of git://anongit.freedesktop.org/drm-intel into drm-fixes

final regression fix for 3.17.

* tag 'drm-intel-fixes-2014-10-02' of git://anongit.freedesktop.org/drm-intel:
  drm/i915: Flush the PTEs after updating them before suspend
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 4b5bb5d..f8cbb51 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1763,9 +1763,10 @@
 	const int   or = ffs(outp->or) - 1;
 	const u32 loff = (or * 0x800) + (link * 0x80);
 	const u16 mask = (outp->sorconf.link << 6) | outp->or;
+	struct dcb_output match;
 	u8  ver, hdr;
 
-	if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
+	if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
 		nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 99cd9e4..3440fc9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -285,6 +285,7 @@
 	struct nouveau_software_chan *swch;
 	struct nv_dma_v0 args = {};
 	int ret, i;
+	bool save;
 
 	nvif_object_map(chan->object);
 
@@ -386,7 +387,11 @@
 	}
 
 	/* initialise synchronisation */
-	return nouveau_fence(chan->drm)->context_new(chan);
+	save = cli->base.super;
+	cli->base.super = true; /* hack until fencenv50 fixed */
+	ret = nouveau_fence(chan->drm)->context_new(chan);
+	cli->base.super = save;
+	return ret;
 }
 
 int
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 65b4fd5..4a21b2b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -550,14 +550,12 @@
 }
 
 int
-nouveau_display_suspend(struct drm_device *dev)
+nouveau_display_suspend(struct drm_device *dev, bool runtime)
 {
-	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct drm_crtc *crtc;
 
 	nouveau_display_fini(dev);
 
-	NV_INFO(drm, "unpinning framebuffer(s)...\n");
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
 
@@ -579,12 +577,13 @@
 }
 
 void
-nouveau_display_repin(struct drm_device *dev)
+nouveau_display_resume(struct drm_device *dev, bool runtime)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct drm_crtc *crtc;
-	int ret;
+	int ret, head;
 
+	/* re-pin fb/cursors */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
 
@@ -606,13 +605,6 @@
 		if (ret)
 			NV_ERROR(drm, "Could not pin/map cursor.\n");
 	}
-}
-
-void
-nouveau_display_resume(struct drm_device *dev)
-{
-	struct drm_crtc *crtc;
-	int head;
 
 	nouveau_display_init(dev);
 
@@ -627,6 +619,13 @@
 	for (head = 0; head < dev->mode_config.num_crtc; head++)
 		drm_vblank_on(dev, head);
 
+	/* This should ensure we don't hit a locking problem when someone
+	 * wakes us up via a connector.  We should never go into suspend
+	 * while the display is on anyways.
+	 */
+	if (runtime)
+		return;
+
 	drm_helper_resume_force_mode(dev);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 88ca177..be3d594 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -63,9 +63,8 @@
 void nouveau_display_destroy(struct drm_device *dev);
 int  nouveau_display_init(struct drm_device *dev);
 void nouveau_display_fini(struct drm_device *dev);
-int  nouveau_display_suspend(struct drm_device *dev);
-void nouveau_display_repin(struct drm_device *dev);
-void nouveau_display_resume(struct drm_device *dev);
+int  nouveau_display_suspend(struct drm_device *dev, bool runtime);
+void nouveau_display_resume(struct drm_device *dev, bool runtime);
 int  nouveau_display_vblank_enable(struct drm_device *, int);
 void nouveau_display_vblank_disable(struct drm_device *, int);
 int  nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 9c3af96..3ed32dd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -547,9 +547,11 @@
 	struct nouveau_cli *cli;
 	int ret;
 
-	if (dev->mode_config.num_crtc && !runtime) {
+	if (dev->mode_config.num_crtc) {
+		NV_INFO(drm, "suspending console...\n");
+		nouveau_fbcon_set_suspend(dev, 1);
 		NV_INFO(drm, "suspending display...\n");
-		ret = nouveau_display_suspend(dev);
+		ret = nouveau_display_suspend(dev, runtime);
 		if (ret)
 			return ret;
 	}
@@ -603,7 +605,7 @@
 fail_display:
 	if (dev->mode_config.num_crtc) {
 		NV_INFO(drm, "resuming display...\n");
-		nouveau_display_resume(dev);
+		nouveau_display_resume(dev, runtime);
 	}
 	return ret;
 }
@@ -618,9 +620,6 @@
 	    drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
 		return 0;
 
-	if (drm_dev->mode_config.num_crtc)
-		nouveau_fbcon_set_suspend(drm_dev, 1);
-
 	ret = nouveau_do_suspend(drm_dev, false);
 	if (ret)
 		return ret;
@@ -633,7 +632,7 @@
 }
 
 static int
-nouveau_do_resume(struct drm_device *dev)
+nouveau_do_resume(struct drm_device *dev, bool runtime)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nouveau_cli *cli;
@@ -658,7 +657,9 @@
 
 	if (dev->mode_config.num_crtc) {
 		NV_INFO(drm, "resuming display...\n");
-		nouveau_display_repin(dev);
+		nouveau_display_resume(dev, runtime);
+		NV_INFO(drm, "resuming console...\n");
+		nouveau_fbcon_set_suspend(dev, 0);
 	}
 
 	return 0;
@@ -681,47 +682,21 @@
 		return ret;
 	pci_set_master(pdev);
 
-	ret = nouveau_do_resume(drm_dev);
-	if (ret)
-		return ret;
-
-	if (drm_dev->mode_config.num_crtc) {
-		nouveau_display_resume(drm_dev);
-		nouveau_fbcon_set_suspend(drm_dev, 0);
-	}
-
-	return 0;
+	return nouveau_do_resume(drm_dev, false);
 }
 
 static int nouveau_pmops_freeze(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
-	int ret;
-
-	if (drm_dev->mode_config.num_crtc)
-		nouveau_fbcon_set_suspend(drm_dev, 1);
-
-	ret = nouveau_do_suspend(drm_dev, false);
-	return ret;
+	return nouveau_do_suspend(drm_dev, false);
 }
 
 static int nouveau_pmops_thaw(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
-	int ret;
-
-	ret = nouveau_do_resume(drm_dev);
-	if (ret)
-		return ret;
-
-	if (drm_dev->mode_config.num_crtc) {
-		nouveau_display_resume(drm_dev);
-		nouveau_fbcon_set_suspend(drm_dev, 0);
-	}
-
-	return 0;
+	return nouveau_do_resume(drm_dev, false);
 }
 
 
@@ -977,7 +952,7 @@
 		return ret;
 	pci_set_master(pdev);
 
-	ret = nouveau_do_resume(drm_dev);
+	ret = nouveau_do_resume(drm_dev, true);
 	drm_kms_helper_poll_enable(drm_dev);
 	/* do magic */
 	nvif_mask(device, 0x88488, (1 << 25), (1 << 25));
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 8bdd270..49fe607 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -486,6 +486,16 @@
 	.fb_probe = nouveau_fbcon_create,
 };
 
+static void
+nouveau_fbcon_set_suspend_work(struct work_struct *work)
+{
+	struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work);
+	console_lock();
+	nouveau_fbcon_accel_restore(fbcon->dev);
+	nouveau_fbcon_zfill(fbcon->dev, fbcon);
+	fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING);
+	console_unlock();
+}
 
 int
 nouveau_fbcon_init(struct drm_device *dev)
@@ -503,6 +513,7 @@
 	if (!fbcon)
 		return -ENOMEM;
 
+	INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work);
 	fbcon->dev = dev;
 	drm->fbcon = fbcon;
 
@@ -551,14 +562,14 @@
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	if (drm->fbcon) {
-		console_lock();
-		if (state == 0) {
-			nouveau_fbcon_accel_restore(dev);
-			nouveau_fbcon_zfill(dev, drm->fbcon);
+		if (state == FBINFO_STATE_RUNNING) {
+			schedule_work(&drm->fbcon->work);
+			return;
 		}
+		flush_work(&drm->fbcon->work);
+		console_lock();
 		fb_set_suspend(drm->fbcon->helper.fbdev, state);
-		if (state == 1)
-			nouveau_fbcon_accel_save_disable(dev);
+		nouveau_fbcon_accel_save_disable(dev);
 		console_unlock();
 	}
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 34658cf..0b465c7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -36,6 +36,7 @@
 	struct nouveau_framebuffer nouveau_fb;
 	struct list_head fbdev_list;
 	struct drm_device *dev;
+	struct work_struct work;
 	unsigned int saved_flags;
 	struct nvif_object surf2d;
 	struct nvif_object clip;