From c77d7162a7ae451c2e895d7ef7fbeb0906107472 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Sat, 6 Oct 2012 10:20:16 +0200
Subject: [PATCH 01/11] drm/i915: remove useless BUG_ON which caused a
 regression in 3.5.

starting an old X server causes a kernel BUG since commit 1b50247a8d:

------------[ cut here ]------------
kernel BUG at drivers/gpu/drm/i915/i915_gem.c:3661!
invalid opcode: 0000 [#1] SMP
Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss uvcvideo
+videobuf2_core videodev videobuf2_vmalloc videobuf2_memops uhci_hcd ath9k mac80211 snd_hda_codec_realtek ath9k_common microcode
+ath9k_hw psmouse serio_raw sg ath cfg80211 atl1c lpc_ich mfd_core ehci_hcd snd_hda_intel snd_hda_codec snd_hwdep snd_pcm rtc_cmos
+snd_timer snd evdev eeepc_laptop snd_page_alloc sparse_keymap

Pid: 2866, comm: X Not tainted 3.5.6-rc1-eeepc #1 ASUSTeK Computer INC. 1005HA/1005HA
EIP: 0060:[<c12dc291>] EFLAGS: 00013297 CPU: 0
EIP is at i915_gem_entervt_ioctl+0xf1/0x110
EAX: f5941df4 EBX: f5940000 ECX: 00000000 EDX: 00020000
ESI: f5835400 EDI: 00000000 EBP: f51d7e38 ESP: f51d7e20
 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
CR0: 8005003b CR2: b760e0a0 CR3: 351b6000 CR4: 000007d0
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: ffff0ff0 DR7: 00000400
Process X (pid: 2866, ti=f51d6000 task=f61af8d0 task.ti=f51d6000)
Stack:
 00000001 00000000 f5835414 f51d7e84 f5835400 f54f85c0 f51d7f10 c12b530b
 00000001 c151b139 c14751b6 c152e030 00000b32 00006459 00000059 0000e200
 00000001 00000000 00006459 c159ddd0 c12dc1a0 ffffffea 00000000 00000000
Call Trace:
 [<c12b530b>] drm_ioctl+0x2eb/0x440
 [<c12dc1a0>] ? i915_gem_init+0xe0/0xe0
 [<c1052b2b>] ? enqueue_hrtimer+0x1b/0x50
 [<c1053321>] ? __hrtimer_start_range_ns+0x161/0x330
 [<c10530b3>] ? lock_hrtimer_base+0x23/0x50
 [<c1053163>] ? hrtimer_try_to_cancel+0x33/0x70
 [<c12b5020>] ? drm_version+0x90/0x90
 [<c10ca171>] vfs_ioctl+0x31/0x50
 [<c10ca2e4>] do_vfs_ioctl+0x64/0x510
 [<c10535de>] ? hrtimer_nanosleep+0x8e/0x100
 [<c1052c20>] ? update_rmtp+0x80/0x80
 [<c10ca7c9>] sys_ioctl+0x39/0x60
 [<c1433949>] syscall_call+0x7/0xb
Code: 83 c4 0c 5b 5e 5f 5d c3 c7 44 24 04 2c 05 53 c1 c7 04 24 6f ef 47 c1 e8 6e e0 fd ff c7 83 38 1e 00 00 00 00 00 00 e9 3f ff ff
+ff <0f> 0b eb fe 0f 0b eb fe 8d b4 26 00 00 00 00 0f 0b eb fe 8d b6
EIP: [<c12dc291>] i915_gem_entervt_ioctl+0xf1/0x110 SS:ESP 0068:f51d7e20
---[ end trace dd332ec083cbd513 ]---

The crash happens here in i915_gem_entervt_ioctl() :

    3659          BUG_ON(!list_empty(&dev_priv->mm.active_list));
    3660          BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 -> 3661          BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
    3662          mutex_unlock(&dev->struct_mutex);

Quoting Chris :
  "That BUG_ON there is silly and can simply be removed. The check is to
   verify that no batches were submitted to the kernel whilst the UMS/GEM
   client was suspended - to which the BUG_ONs are a crude approximation.
   Furthermore, the checks are too late, since it means we attempted to
   program the hardware whilst it was in an invalid state, the BUG_ONs are
   the least of your concerns at that point."

Note that this regression has been introduced in

commit 1b50247a8ddde4af5aaa0e6bc125615372ce6c16
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Apr 24 15:47:30 2012 +0100

    drm/i915: Remove the list of pinned inactive objects

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Willy Tarreau <w@1wt.eu>
[danvet: Added note about the regressing commit and cc: stable.]
Cc: stable@vger.kernel.org
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_gem.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index b55eee38af76..53de95c05b16 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4099,7 +4099,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
 	}
 
 	BUG_ON(!list_empty(&dev_priv->mm.active_list));
-	BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
 	mutex_unlock(&dev->struct_mutex);
 
 	ret = drm_irq_install(dev);

From 6ce9410047f9f06c1b3336d5215402b77d6fd70f Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Thu, 4 Oct 2012 19:20:03 +0200
Subject: [PATCH 02/11] drm/i915: paper over a pipe-enable vs pageflip race

I've discovered this on my ivb machine while stress-testing the new
flip_tests. Only harmful effect observed is that the timestamp is a
bit bogus.

Note that this is empirical duct-tape: I've noticed that we seem to
only ever miss the very first vblank irq right after enabling the
pipe. And with this hack applied I couldn't reproduce the failure case
anywhere else any more.

Tested-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 67912febb322..9cecfd73b0b1 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3253,6 +3253,16 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
 	if (HAS_PCH_CPT(dev))
 		intel_cpt_verify_modeset(dev, intel_crtc->pipe);
+
+	/*
+	 * There seems to be a race in PCH platform hw (at least on some
+	 * outputs) where an enabled pipe still completes any pageflip right
+	 * away (as if the pipe is off) instead of waiting for vblank. As soon
+	 * as the first vblank happend, everything works as expected. Hence just
+	 * wait for one vblank before returning to avoid strange things
+	 * happening.
+	 */
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
 }
 
 static void ironlake_crtc_disable(struct drm_crtc *crtc)

From 26b6e44afb58432a5e998da0343757404f9de9ee Mon Sep 17 00:00:00 2001
From: Kenneth Graunke <kenneth@whitecape.org>
Date: Sun, 7 Oct 2012 08:51:07 -0700
Subject: [PATCH 03/11] drm/i915: Set guardband clipping workaround bit in the
 right register.

A previous patch, namely:

commit bf97b276ca04cee9ab65ffd378fa8e6aedd71ff6
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Wed Apr 11 20:42:41 2012 +0200

    drm/i915: implement w/a for incorrect guarband clipping

accidentally set bit 5 in 3D_CHICKEN, which has nothing to do with
clipping.  This patch changes it to be set in 3D_CHICKEN3, where it
belongs.

The game "Dante" demonstrates random clipping issues when guardband
clipping is enabled and bit 5 of 3D_CHICKEN3 isn't set.  So the
workaround is actually necessary.

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Oliver McFadden <oliver.mcfadden@linux.intel.com>
Acked-by: Paul Menzel <paulepanter@users.sourceforge.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_reg.h | 2 +-
 drivers/gpu/drm/i915/intel_pm.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 64c1be0a9cfd..a4162ddff6c5 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -521,7 +521,7 @@
  */
 # define _3D_CHICKEN2_WM_READ_PIPELINED			(1 << 14)
 #define _3D_CHICKEN3	0x02090
-#define  _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL		(1 << 5)
+#define  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL		(1 << 5)
 
 #define MI_MODE		0x0209c
 # define VS_TIMER_DISPATCH				(1 << 6)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b3b4b6cea8b0..72f41aaa71ff 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3442,8 +3442,8 @@ static void gen6_init_clock_gating(struct drm_device *dev)
 		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 
 	/* Bspec says we need to always set all mask bits. */
-	I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) |
-		   _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL);
+	I915_WRITE(_3D_CHICKEN3, (0xFFFF << 16) |
+		   _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL);
 
 	/*
 	 * According to the spec the following bits should be

From acb868d3d710b09a356d848e0cd44d9713a9e274 Mon Sep 17 00:00:00 2001
From: Chris Wilson <chris@chris-wilson.co.uk>
Date: Wed, 26 Sep 2012 13:47:30 +0100
Subject: [PATCH 04/11] drm/i915: Disallow preallocation of requests

The intention was to allow the caller to avoid a failure to queue a
request having already written commands to the ring. However, this is a
moot point as the i915_add_request() can fail for other reasons than a
mere allocation failure and those failure cases are more likely than
ENOMEM. So the overlay code already had to handle i915_add_request()
failures, and due to

commit 3bb73aba1ed5198a2c1dfaac4f3c95459930d84a
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Fri Jul 20 12:40:59 2012 +0100

    drm/i915: Allow late allocation of request for i915_add_request()

the error handling code in intel_overlay.c was subject to causing
double-frees, as found by coverity.

Rather than further complicate i915_add_request() and callers, realise
the battle is lost and adapt intel_overlay.c to take advantage of the
late allocation of requests.

v2: Handle callers passing in a NULL seqno.
v3: Ditto. This time for sure.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_drv.h      |  2 +-
 drivers/gpu/drm/i915/i915_gem.c      | 15 +++---
 drivers/gpu/drm/i915/intel_overlay.c | 72 ++++++----------------------
 3 files changed, 24 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4f2831aa5fed..d5138c3a156b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1427,7 +1427,7 @@ int __must_check i915_gpu_idle(struct drm_device *dev);
 int __must_check i915_gem_idle(struct drm_device *dev);
 int i915_add_request(struct intel_ring_buffer *ring,
 		     struct drm_file *file,
-		     struct drm_i915_gem_request *request);
+		     u32 *seqno);
 int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
 				 uint32_t seqno);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 53de95c05b16..04b0c070cdf8 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1956,11 +1956,12 @@ i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
 int
 i915_add_request(struct intel_ring_buffer *ring,
 		 struct drm_file *file,
-		 struct drm_i915_gem_request *request)
+		 u32 *out_seqno)
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
-	uint32_t seqno;
+	struct drm_i915_gem_request *request;
 	u32 request_ring_position;
+	u32 seqno;
 	int was_empty;
 	int ret;
 
@@ -1975,11 +1976,9 @@ i915_add_request(struct intel_ring_buffer *ring,
 	if (ret)
 		return ret;
 
-	if (request == NULL) {
-		request = kmalloc(sizeof(*request), GFP_KERNEL);
-		if (request == NULL)
-			return -ENOMEM;
-	}
+	request = kmalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
 
 	seqno = i915_gem_next_request_seqno(ring);
 
@@ -2031,6 +2030,8 @@ i915_add_request(struct intel_ring_buffer *ring,
 		}
 	}
 
+	if (out_seqno)
+		*out_seqno = seqno;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index afd0f30ab882..555912f510a9 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -210,7 +210,6 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
 }
 
 static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
-					 struct drm_i915_gem_request *request,
 					 void (*tail)(struct intel_overlay *))
 {
 	struct drm_device *dev = overlay->dev;
@@ -219,12 +218,10 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
 	int ret;
 
 	BUG_ON(overlay->last_flip_req);
-	ret = i915_add_request(ring, NULL, request);
-	if (ret) {
-	    kfree(request);
-	    return ret;
-	}
-	overlay->last_flip_req = request->seqno;
+	ret = i915_add_request(ring, NULL, &overlay->last_flip_req);
+	if (ret)
+		return ret;
+
 	overlay->flip_tail = tail;
 	ret = i915_wait_seqno(ring, overlay->last_flip_req);
 	if (ret)
@@ -241,7 +238,6 @@ static int intel_overlay_on(struct intel_overlay *overlay)
 	struct drm_device *dev = overlay->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
-	struct drm_i915_gem_request *request;
 	int ret;
 
 	BUG_ON(overlay->active);
@@ -249,17 +245,9 @@ static int intel_overlay_on(struct intel_overlay *overlay)
 
 	WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
 
-	request = kzalloc(sizeof(*request), GFP_KERNEL);
-	if (request == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	ret = intel_ring_begin(ring, 4);
-	if (ret) {
-		kfree(request);
-		goto out;
-	}
+	if (ret)
+		return ret;
 
 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
 	intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
@@ -267,9 +255,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
 	intel_ring_emit(ring, MI_NOOP);
 	intel_ring_advance(ring);
 
-	ret = intel_overlay_do_wait_request(overlay, request, NULL);
-out:
-	return ret;
+	return intel_overlay_do_wait_request(overlay, NULL);
 }
 
 /* overlay needs to be enabled in OCMD reg */
@@ -279,17 +265,12 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
 	struct drm_device *dev = overlay->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
-	struct drm_i915_gem_request *request;
 	u32 flip_addr = overlay->flip_addr;
 	u32 tmp;
 	int ret;
 
 	BUG_ON(!overlay->active);
 
-	request = kzalloc(sizeof(*request), GFP_KERNEL);
-	if (request == NULL)
-		return -ENOMEM;
-
 	if (load_polyphase_filter)
 		flip_addr |= OFC_UPDATE;
 
@@ -299,22 +280,14 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
 		DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
 
 	ret = intel_ring_begin(ring, 2);
-	if (ret) {
-		kfree(request);
+	if (ret)
 		return ret;
-	}
+
 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
 	intel_ring_emit(ring, flip_addr);
 	intel_ring_advance(ring);
 
-	ret = i915_add_request(ring, NULL, request);
-	if (ret) {
-		kfree(request);
-		return ret;
-	}
-
-	overlay->last_flip_req = request->seqno;
-	return 0;
+	return i915_add_request(ring, NULL, &overlay->last_flip_req);
 }
 
 static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
@@ -350,15 +323,10 @@ static int intel_overlay_off(struct intel_overlay *overlay)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
 	u32 flip_addr = overlay->flip_addr;
-	struct drm_i915_gem_request *request;
 	int ret;
 
 	BUG_ON(!overlay->active);
 
-	request = kzalloc(sizeof(*request), GFP_KERNEL);
-	if (request == NULL)
-		return -ENOMEM;
-
 	/* According to intel docs the overlay hw may hang (when switching
 	 * off) without loading the filter coeffs. It is however unclear whether
 	 * this applies to the disabling of the overlay or to the switching off
@@ -366,10 +334,9 @@ static int intel_overlay_off(struct intel_overlay *overlay)
 	flip_addr |= OFC_UPDATE;
 
 	ret = intel_ring_begin(ring, 6);
-	if (ret) {
-		kfree(request);
+	if (ret)
 		return ret;
-	}
+
 	/* wait for overlay to go idle */
 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
 	intel_ring_emit(ring, flip_addr);
@@ -380,8 +347,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
 	intel_ring_advance(ring);
 
-	return intel_overlay_do_wait_request(overlay, request,
-					     intel_overlay_off_tail);
+	return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
@@ -426,24 +392,16 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 		return 0;
 
 	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
-		struct drm_i915_gem_request *request;
-
 		/* synchronous slowpath */
-		request = kzalloc(sizeof(*request), GFP_KERNEL);
-		if (request == NULL)
-			return -ENOMEM;
-
 		ret = intel_ring_begin(ring, 2);
-		if (ret) {
-			kfree(request);
+		if (ret)
 			return ret;
-		}
 
 		intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
 		intel_ring_emit(ring, MI_NOOP);
 		intel_ring_advance(ring);
 
-		ret = intel_overlay_do_wait_request(overlay, request,
+		ret = intel_overlay_do_wait_request(overlay,
 						    intel_overlay_release_old_vid_tail);
 		if (ret)
 			return ret;

From 1cf8378906b2d5a6449147914fe04c56d6f4fd87 Mon Sep 17 00:00:00 2001
From: Chris Wilson <chris@chris-wilson.co.uk>
Date: Wed, 10 Oct 2012 12:11:52 +0100
Subject: [PATCH 05/11] drm/i915: fixup i915_gem_object_get_page inline helper

Note that just because we have n == MAX elements left, does not imply
that there are only MAX elements left in the scatterlist and so we may
not be on the last chain, and the nth element may in fact be a chain ptr.

This is exercised by the improved hangman tests and the gem_exec_big
test in i-g-t.

This regression has been introduced in

commit 9da3da660d8c19a54f6e93361d147509be3fff84
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Fri Jun 1 15:20:22 2012 +0100

   drm/i915: Replace the array of pages with a scatterlist

v2: KISS, replace the direct lookup with a for_each_sg() [danvet]
v3: Try to be clever again.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_drv.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d5138c3a156b..b84f7861e438 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1341,9 +1341,14 @@ int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
 static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
 {
 	struct scatterlist *sg = obj->pages->sgl;
-	while (n >= SG_MAX_SINGLE_ALLOC) {
+	int nents = obj->pages->nents;
+	while (nents > SG_MAX_SINGLE_ALLOC) {
+		if (n < SG_MAX_SINGLE_ALLOC - 1)
+			break;
+
 		sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1);
 		n -= SG_MAX_SINGLE_ALLOC - 1;
+		nents -= SG_MAX_SINGLE_ALLOC - 1;
 	}
 	return sg_page(sg+n);
 }

From 9169d3a88072b20f42e68a946e916bd7dfbc7f2c Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Wed, 10 Oct 2012 23:14:01 +0200
Subject: [PATCH 06/11] drm/i915: disable wc gtt pte mappings on gen2

It doesn't work since the gtt pte range sits in the middle of the mmio
bar. We didn't notice that since both my and Chris' gen2 machines
don't support PAT and hence all wc io mapping request will
automatically be demoted to uc.

This regression has been introduce in

commit edef7e685da05c13cce50c0126189c80fe2c8f71
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Fri Sep 14 11:57:47 2012 +0100

    agp/intel: Use a write-combining map for updating PTEs

Reported-by: Egbert Eich <eich@pdx.freedesktop.org>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55834
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/char/agp/intel-gtt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index e01f5eaaec82..38390f7c6ab6 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -667,7 +667,7 @@ static int intel_gtt_init(void)
 	gtt_map_size = intel_private.base.gtt_total_entries * 4;
 
 	intel_private.gtt = NULL;
-	if (INTEL_GTT_GEN < 6)
+	if (INTEL_GTT_GEN < 6 && INTEL_GTT_GEN > 2)
 		intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr,
 					       gtt_map_size);
 	if (intel_private.gtt == NULL)

From ccd0d36e2a8ab8b4d314ff87779366ada33ffe00 Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Wed, 10 Oct 2012 23:13:59 +0200
Subject: [PATCH 07/11] drm/i915: rip out the pipe A quirk for i855gm

This seems to be the root-cause that breaks resume on my i855gm when I
apply the "drm/i915: fixup the plane->pipe fixup code" patch. And that
code doesn't even run on my machine, so it's pure timing changes
causing the regression.

Furthermore resume has been constantly switching between working and
broken on this machine ever since kms support has been merged,
seemingly with no related change as a root cause. And always with the
same symptoms of the backlight lighting up, but the lvds panel only
displaying black.

Also, of both i855gm variants only one is in the table. And in the
past we've only ever removed entries from this quirk table because it
breaks things.

So let's just remove it - in case there's indeed a bios out there
relying on a running pipe A, we can add back in a more precise quirk
entry, like all the others (save for i830/i845).

Tested-by: Chris Wilson <chris@chris-wilson.co.uk> #855gm
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_display.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9cecfd73b0b1..f3b2d18482d8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7902,8 +7902,7 @@ static struct intel_quirk intel_quirks[] = {
 	/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
 	{ 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
 
-	/* 855 & before need to leave pipe A & dpll A up */
-	{ 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+	/* 830/845 need to leave pipe A & dpll A up */
 	{ 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
 	{ 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
 

From fa55583797d12b10928a1813f3dcf066637caf5e Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Wed, 10 Oct 2012 23:14:00 +0200
Subject: [PATCH 08/11] drm/i915: fixup the plane->pipe fixup code

We need to check whether the _other plane is on our pipe, not whether
our plane is on the other pipe. Otherwise if not both pipes/planes are
active, we won't properly clean up the mess and set up our desired
plane->pipe mapping.

v2: Fixup the logic, I've totally fumbled it. Noticed by Chris Wilson.

v3: I've checked Bspec, and the flexible plane->pipe mapping is a
gen2/3 feature, so test for that instead of PCH_SPLIT

v4: Check whether we indeed have 2 pipes before checking the other
pipe, to avoid upsetting i845g/i865g. Noticed by Chris Wilson.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=51265
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=49838
Tested-by: Dave Airlie <airlied@gmail.com>
Tested-by: Chris Wilson <chris@chris-wilson.co.uk> #855gm
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_display.c | 34 +++++++++++++++++++---------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f3b2d18482d8..3511effa01ec 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8058,29 +8058,42 @@ static void intel_enable_pipe_a(struct drm_device *dev)
 
 }
 
+static bool
+intel_check_plane_mapping(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+	u32 reg, val;
+
+	if (dev_priv->num_pipe == 1)
+		return true;
+
+	reg = DSPCNTR(!crtc->plane);
+	val = I915_READ(reg);
+
+	if ((val & DISPLAY_PLANE_ENABLE) &&
+	    (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
+		return false;
+
+	return true;
+}
+
 static void intel_sanitize_crtc(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg, val;
+	u32 reg;
 
 	/* Clear any frame start delays used for debugging left by the BIOS */
 	reg = PIPECONF(crtc->pipe);
 	I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
 	/* We need to sanitize the plane -> pipe mapping first because this will
-	 * disable the crtc (and hence change the state) if it is wrong. */
-	if (!HAS_PCH_SPLIT(dev)) {
+	 * disable the crtc (and hence change the state) if it is wrong. Note
+	 * that gen4+ has a fixed plane -> pipe mapping.  */
+	if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) {
 		struct intel_connector *connector;
 		bool plane;
 
-		reg = DSPCNTR(crtc->plane);
-		val = I915_READ(reg);
-
-		if ((val & DISPLAY_PLANE_ENABLE) == 0 &&
-		    (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
-			goto ok;
-
 		DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
 			      crtc->base.base.id);
 
@@ -8104,7 +8117,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
 		WARN_ON(crtc->active);
 		crtc->base.enabled = false;
 	}
-ok:
 
 	if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
 	    crtc->pipe == PIPE_A && !crtc->active) {

From 4afa0ace429624fde392b29d05a803672a41192e Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Thu, 11 Oct 2012 18:43:52 +0200
Subject: [PATCH 09/11] drm/i915/dvo-ch7xxx: fix get_hw_state

The boot-up state seems to be all-zeros, so it's safer to check for
the bits that need to be set when the dvo encoder is in the dpms on
state, than checking the bits we set when it's in the off state.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55047
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/dvo_ch7xxx.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 38f3a6cb8c7d..3edd981e0770 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -303,10 +303,10 @@ static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
 
 	ch7xxx_readb(dvo, CH7xxx_PM, &val);
 
-	if (val & CH7xxx_PM_FPD)
-		return false;
-	else
+	if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
 		return true;
+	else
+		return false;
 }
 
 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)

From eda2d7f582d51a4b5e01d48845ea28321357b136 Mon Sep 17 00:00:00 2001
From: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Date: Wed, 10 Oct 2012 18:35:28 -0300
Subject: [PATCH 10/11] drm/i915: HSW CRW stability magic

This magic brings stability to HSW CRW machines.

Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_gem.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 04b0c070cdf8..bb941f8cd556 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3961,6 +3961,9 @@ i915_gem_init_hw(struct drm_device *dev)
 	if (!intel_enable_gtt())
 		return -EIO;
 
+	if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1))
+		I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000);
+
 	i915_gem_l3_remap(dev);
 
 	i915_gem_init_swizzling(dev);

From be3cd5e37716bcf1579f63bdd919345a1f9692b9 Mon Sep 17 00:00:00 2001
From: Jani Nikula <jani.nikula@intel.com>
Date: Fri, 12 Oct 2012 10:33:05 +0300
Subject: [PATCH 11/11] drm/i915: fix non-DP-D eDP backlight cleanup and module
 reload

Backlight is initialized for eDP, but cleaned up only for eDP on DP-D
port. This leaves behind a dangling backlight interface on module unload on
machines that have eDP connected to something other than DP-D, and breaks
the backlight interface for subsequent module reloads. Fix the cleanup, and
thus module reload on affected machines.

Reported-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Tested-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_dp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c14d407d41e8..bd2c34a0aa9a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2370,8 +2370,9 @@ static void
 intel_dp_destroy(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
 
-	if (intel_dpd_is_edp(dev))
+	if (is_edp(intel_dp))
 		intel_panel_destroy_backlight(dev);
 
 	drm_sysfs_connector_remove(connector);