]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 14 Jan 2013 18:32:43 +0000 (10:32 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 14 Jan 2013 18:32:43 +0000 (10:32 -0800)
added patches:
drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch
drm-i915-don-t-disable-disconnected-outputs.patch
drm-i915-fix-flags-in-dma-buf-exporting.patch
drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch
drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch
drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch
drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch
drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch
mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch

queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch [new file with mode: 0644]
queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch [new file with mode: 0644]
queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch [new file with mode: 0644]
queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch [new file with mode: 0644]
queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch [new file with mode: 0644]
queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch [new file with mode: 0644]
queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch [new file with mode: 0644]
queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch [new file with mode: 0644]
queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch [new file with mode: 0644]
queue-3.7/series

diff --git a/queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch b/queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch
new file mode 100644 (file)
index 0000000..80fd7ab
--- /dev/null
@@ -0,0 +1,187 @@
+From e7d841ca03b7ab668620045cd7b428eda9f41601 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Mon, 3 Dec 2012 11:36:30 +0000
+Subject: drm/i915: Close race between processing unpin task and queueing the flip
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit e7d841ca03b7ab668620045cd7b428eda9f41601 upstream.
+
+Before queuing the flip but crucially after attaching the unpin-work to
+the crtc, we continue to setup the unpin-work. However, should the
+hardware fire early, we see the connected unpin-work and queue the task.
+The task then promptly runs and unpins the fb before we finish taking
+the required references or even pinning it... Havoc.
+
+To close the race, we use the flip-pending atomic to indicate when the
+flip is finally setup and enqueued. So during the flip-done processing,
+we can check more accurately whether the flip was expected.
+
+v2: Add the appropriate mb() to ensure that the writes to the page-flip
+worker are complete prior to marking it active and emitting the MI_FLIP.
+On the read side, the mb should be enforced by the spinlocks.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+[danvet: Review the barriers a bit, we need a write barrier both
+before and after updating ->pending. Similarly we need a read barrier
+in the interrupt handler both before and after reading ->pending. With
+well-ordered irqs only one barrier in each place should be required,
+but since this patch explicitly sets out to combat spurious interrupts
+with is staged activation of the unpin work we need to go full-bore on
+the barriers, too. Discussed with Chris Wilson on irc and changes
+acked by him.]
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/i915_debugfs.c  |    4 +--
+ drivers/gpu/drm/i915/i915_irq.c      |    4 ++-
+ drivers/gpu/drm/i915/intel_display.c |   39 ++++++++++++++++++++++++++++-------
+ drivers/gpu/drm/i915/intel_drv.h     |    5 +++-
+ 4 files changed, 41 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_debugfs.c
++++ b/drivers/gpu/drm/i915/i915_debugfs.c
+@@ -317,7 +317,7 @@ static int i915_gem_pageflip_info(struct
+                       seq_printf(m, "No flip due on pipe %c (plane %c)\n",
+                                  pipe, plane);
+               } else {
+-                      if (!work->pending) {
++                      if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
+                               seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
+                                          pipe, plane);
+                       } else {
+@@ -328,7 +328,7 @@ static int i915_gem_pageflip_info(struct
+                               seq_printf(m, "Stall check enabled, ");
+                       else
+                               seq_printf(m, "Stall check waiting for page flip ioctl, ");
+-                      seq_printf(m, "%d prepares\n", work->pending);
++                      seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
+                       if (work->old_fb_obj) {
+                               struct drm_i915_gem_object *obj = work->old_fb_obj;
+--- a/drivers/gpu/drm/i915/i915_irq.c
++++ b/drivers/gpu/drm/i915/i915_irq.c
+@@ -1464,7 +1464,9 @@ static void i915_pageflip_stall_check(st
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+-      if (work == NULL || work->pending || !work->enable_stall_check) {
++      if (work == NULL ||
++          atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE ||
++          !work->enable_stall_check) {
+               /* Either the pending flip IRQ arrived, or we're too early. Don't check */
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               return;
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -6215,11 +6215,18 @@ static void do_intel_finish_page_flip(st
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+-      if (work == NULL || !work->pending) {
++
++      /* Ensure we don't miss a work->pending update ... */
++      smp_rmb();
++
++      if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               return;
+       }
++      /* and that the unpin work is consistent wrt ->pending. */
++      smp_rmb();
++
+       intel_crtc->unpin_work = NULL;
+       if (work->event) {
+@@ -6272,16 +6279,25 @@ void intel_prepare_page_flip(struct drm_
+               to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
+       unsigned long flags;
++      /* NB: An MMIO update of the plane base pointer will also
++       * generate a page-flip completion irq, i.e. every modeset
++       * is also accompanied by a spurious intel_prepare_page_flip().
++       */
+       spin_lock_irqsave(&dev->event_lock, flags);
+-      if (intel_crtc->unpin_work) {
+-              if ((++intel_crtc->unpin_work->pending) > 1)
+-                      DRM_ERROR("Prepared flip multiple times\n");
+-      } else {
+-              DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
+-      }
++      if (intel_crtc->unpin_work)
++              atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
++inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc)
++{
++      /* Ensure that the work item is consistent when activating it ... */
++      smp_wmb();
++      atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING);
++      /* and that it is marked active as soon as the irq could fire. */
++      smp_wmb();
++}
++
+ static int intel_gen2_queue_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+@@ -6315,6 +6331,8 @@ static int intel_gen2_queue_flip(struct
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, 0); /* aux display base address, unused */
++
++      intel_mark_page_flip_active(intel_crtc);
+       intel_ring_advance(ring);
+       return 0;
+@@ -6355,6 +6373,7 @@ static int intel_gen3_queue_flip(struct
+       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, MI_NOOP);
++      intel_mark_page_flip_active(intel_crtc);
+       intel_ring_advance(ring);
+       return 0;
+@@ -6401,6 +6420,8 @@ static int intel_gen4_queue_flip(struct
+       pf = 0;
+       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
+       intel_ring_emit(ring, pf | pipesrc);
++
++      intel_mark_page_flip_active(intel_crtc);
+       intel_ring_advance(ring);
+       return 0;
+@@ -6443,6 +6464,8 @@ static int intel_gen6_queue_flip(struct
+       pf = 0;
+       pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
+       intel_ring_emit(ring, pf | pipesrc);
++
++      intel_mark_page_flip_active(intel_crtc);
+       intel_ring_advance(ring);
+       return 0;
+@@ -6497,6 +6520,8 @@ static int intel_gen7_queue_flip(struct
+       intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
+       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, (MI_NOOP));
++
++      intel_mark_page_flip_active(intel_crtc);
+       intel_ring_advance(ring);
+       return 0;
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -384,7 +384,10 @@ struct intel_unpin_work {
+       struct drm_i915_gem_object *old_fb_obj;
+       struct drm_i915_gem_object *pending_flip_obj;
+       struct drm_pending_vblank_event *event;
+-      int pending;
++      atomic_t pending;
++#define INTEL_FLIP_INACTIVE   0
++#define INTEL_FLIP_PENDING    1
++#define INTEL_FLIP_COMPLETE   2
+       bool enable_stall_check;
+ };
diff --git a/queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch b/queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch
new file mode 100644 (file)
index 0000000..a7ab663
--- /dev/null
@@ -0,0 +1,65 @@
+From b0a2658acb5bf9ca86b4aab011b7106de3af0add Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Tue, 18 Dec 2012 09:37:54 +0100
+Subject: drm/i915: don't disable disconnected outputs
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit b0a2658acb5bf9ca86b4aab011b7106de3af0add upstream.
+
+This piece of neat lore has been ported painstakingly and bug-for-bug
+compatible from the old crtc helper code.
+
+Imo it's utter nonsense.
+
+If you disconnected a cable and before you reconnect it, userspace (or
+the kernel) does an set_crtc call, this will result in that connector
+getting disabled. Which will result in a nice black screen when
+plugging in the cable again.
+
+There's absolutely no reason the kernel does such policy enforcements
+- if userspace tries to set up a mode on something disconnected we
+might fail loudly (since the dp link training fails), but silently
+adjusting the output configuration behind userspace's back is a recipe
+for disaster. Specifically I think that this could explain some of our
+MI_WAIT hangs around suspend, where userspace issues a scanline wait
+on a disable pipe. This mechanisims here could explain how that pipe
+got disabled without userspace noticing.
+
+Note that this fixes a NULL deref at BIOS takeover when the firmware
+sets up a disconnected output in a clone configuration with a
+connected output on the 2nd pipe: When doing the full modeset we don't
+have a mode for the 2nd pipe and OOPS. On the first pipe this doesn't
+matter, since at boot-up the fbdev helpers will set up the choosen
+configuration on that on first. Since this is now the umptenth bug
+around handling this imo brain-dead semantics correctly, I think it's
+time to kill it and see whether there's any userspace out there which
+relies on this.
+
+It also nicely demonstrates that we have a tiny window where DP
+hotplug can still kill the driver.
+
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58396
+Tested-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
+Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
+Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/intel_display.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -7298,10 +7298,6 @@ intel_modeset_stage_output_state(struct
+                       DRM_DEBUG_KMS("encoder changed, full mode switch\n");
+                       config->mode_changed = true;
+               }
+-
+-              /* Disable all disconnected encoders. */
+-              if (connector->base.status == connector_status_disconnected)
+-                      connector->new_encoder = NULL;
+       }
+       /* connector->new_encoder is now updated for all connectors. */
diff --git a/queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch b/queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch
new file mode 100644 (file)
index 0000000..8d65d64
--- /dev/null
@@ -0,0 +1,31 @@
+From 5b42427fc38ecb9056c4e64deaff36d6d6ba1b67 Mon Sep 17 00:00:00 2001
+From: Dave Airlie <airlied@redhat.com>
+Date: Thu, 20 Dec 2012 10:51:09 +1000
+Subject: drm/i915: fix flags in dma buf exporting
+
+From: Dave Airlie <airlied@redhat.com>
+
+commit 5b42427fc38ecb9056c4e64deaff36d6d6ba1b67 upstream.
+
+As pointed out by Seung-Woo Kim this should have been
+passing flags like nouveau/radeon have.
+
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/i915_gem_dmabuf.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
++++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+@@ -226,7 +226,7 @@ struct dma_buf *i915_gem_prime_export(st
+ {
+       struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+-      return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600);
++      return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, flags);
+ }
+ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
diff --git a/queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch b/queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch
new file mode 100644 (file)
index 0000000..6536734
--- /dev/null
@@ -0,0 +1,131 @@
+From b4a98e57fc27854b5938fc8b08b68e5e68b91e1f Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 1 Nov 2012 09:26:26 +0000
+Subject: drm/i915: Flush outstanding unpin tasks before pageflipping
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit b4a98e57fc27854b5938fc8b08b68e5e68b91e1f upstream.
+
+If we accumulate unpin tasks because we are pageflipping faster than the
+system can schedule its workers, we can effectively create a
+pin-leak. The solution taken here is to limit the number of unpin tasks
+we have per-crtc and to flush those outstanding tasks if we accumulate
+too many. This should prevent any jitter in the normal case, and also
+prevent the hang if we should run too fast.
+
+Note: It is important that we switch from the system workqueue to our
+own dev_priv->wq since all work items on that queue are guaranteed to
+only need the dev->struct_mutex and not any modeset resources. For
+otherwise if we have a work item ahead in the queue which needs the
+modeset lock (like the output detect work used by both polling or
+hpd), this work and so the unpin work will never execute since the
+pageflip code already holds that lock. Unfortunately there's no
+lockdep support for this scenario in the workqueue code.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=46991
+Reported-and-tested-by: Tvrtko Ursulin <tvrtko.ursulin@onelan.co.uk>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+[danvet: Added note about workqueu deadlock.]
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56337
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Tested-by: Daniel Gnoutcheff <daniel@gnoutcheff.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/intel_display.c |   22 ++++++++++++++++------
+ drivers/gpu/drm/i915/intel_drv.h     |    4 +++-
+ 2 files changed, 19 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -6187,14 +6187,19 @@ static void intel_unpin_work_fn(struct w
+ {
+       struct intel_unpin_work *work =
+               container_of(__work, struct intel_unpin_work, work);
++      struct drm_device *dev = work->crtc->dev;
+-      mutex_lock(&work->dev->struct_mutex);
++      mutex_lock(&dev->struct_mutex);
+       intel_unpin_fb_obj(work->old_fb_obj);
+       drm_gem_object_unreference(&work->pending_flip_obj->base);
+       drm_gem_object_unreference(&work->old_fb_obj->base);
+-      intel_update_fbc(work->dev);
+-      mutex_unlock(&work->dev->struct_mutex);
++      intel_update_fbc(dev);
++      mutex_unlock(&dev->struct_mutex);
++
++      BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0);
++      atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count);
++
+       kfree(work);
+ }
+@@ -6249,9 +6254,9 @@ static void do_intel_finish_page_flip(st
+       atomic_clear_mask(1 << intel_crtc->plane,
+                         &obj->pending_flip.counter);
+-
+       wake_up(&dev_priv->pending_flip_queue);
+-      schedule_work(&work->work);
++
++      queue_work(dev_priv->wq, &work->work);
+       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
+ }
+@@ -6570,7 +6575,7 @@ static int intel_crtc_page_flip(struct d
+               return -ENOMEM;
+       work->event = event;
+-      work->dev = crtc->dev;
++      work->crtc = crtc;
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       work->old_fb_obj = intel_fb->obj;
+       INIT_WORK(&work->work, intel_unpin_work_fn);
+@@ -6595,6 +6600,9 @@ static int intel_crtc_page_flip(struct d
+       intel_fb = to_intel_framebuffer(fb);
+       obj = intel_fb->obj;
++      if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
++              flush_workqueue(dev_priv->wq);
++
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto cleanup;
+@@ -6613,6 +6621,7 @@ static int intel_crtc_page_flip(struct d
+        * the flip occurs and the object is no longer visible.
+        */
+       atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
++      atomic_inc(&intel_crtc->unpin_work_count);
+       ret = dev_priv->display.queue_flip(dev, crtc, fb, obj);
+       if (ret)
+@@ -6627,6 +6636,7 @@ static int intel_crtc_page_flip(struct d
+       return 0;
+ cleanup_pending:
++      atomic_dec(&intel_crtc->unpin_work_count);
+       atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
+       drm_gem_object_unreference(&work->old_fb_obj->base);
+       drm_gem_object_unreference(&obj->base);
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -198,6 +198,8 @@ struct intel_crtc {
+       struct intel_unpin_work *unpin_work;
+       int fdi_lanes;
++      atomic_t unpin_work_count;
++
+       /* Display surface base address adjustement for pageflips. Note that on
+        * gen4+ this only adjusts up to a tile, offsets within a tile are
+        * handled in the hw itself (with the TILEOFF register). */
+@@ -380,7 +382,7 @@ intel_get_crtc_for_plane(struct drm_devi
+ struct intel_unpin_work {
+       struct work_struct work;
+-      struct drm_device *dev;
++      struct drm_crtc *crtc;
+       struct drm_i915_gem_object *old_fb_obj;
+       struct drm_i915_gem_object *pending_flip_obj;
+       struct drm_pending_vblank_event *event;
diff --git a/queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch b/queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch
new file mode 100644 (file)
index 0000000..4d22253
--- /dev/null
@@ -0,0 +1,42 @@
+From 93be8788e648817d62fda33e2998eb6ca6ebf3a3 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 2 Jan 2013 10:31:22 +0000
+Subject: drm/i915; Only increment the user-pin-count after successfully pinning the bo
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 93be8788e648817d62fda33e2998eb6ca6ebf3a3 upstream.
+
+As along the error path we do not correct the user pin-count for the
+failure, we may end up with userspace believing that it has a pinned
+object at offset 0 (when interrupted by a signal for example).
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/i915_gem.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_gem.c
++++ b/drivers/gpu/drm/i915/i915_gem.c
+@@ -3511,14 +3511,15 @@ i915_gem_pin_ioctl(struct drm_device *de
+               goto out;
+       }
+-      obj->user_pin_count++;
+-      obj->pin_filp = file;
+-      if (obj->user_pin_count == 1) {
++      if (obj->user_pin_count == 0) {
+               ret = i915_gem_object_pin(obj, args->alignment, true, false);
+               if (ret)
+                       goto out;
+       }
++      obj->user_pin_count++;
++      obj->pin_filp = file;
++
+       /* XXX - flush the CPU caches for pinned objects
+        * as the X server doesn't manage domains yet
+        */
diff --git a/queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch b/queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch
new file mode 100644 (file)
index 0000000..c5f482a
--- /dev/null
@@ -0,0 +1,145 @@
+From 93927ca52a55c23e0a6a305e7e9082e8411ac9fa Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Thu, 10 Jan 2013 18:03:00 +0100
+Subject: drm/i915: Revert shrinker changes from "Track unbound pages"
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit 93927ca52a55c23e0a6a305e7e9082e8411ac9fa upstream.
+
+This partially reverts
+
+commit 6c085a728cf000ac1865d66f8c9b52935558b328
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Aug 20 11:40:46 2012 +0200
+
+    drm/i915: Track unbound pages
+
+Closer inspection of that patch revealed a bunch of unrelated changes
+in the shrinker:
+- The shrinker count is now in pages instead of objects.
+- For counting the shrinkable objects the old code only looked at the
+  inactive list, the new code looks at all bounds objects (including
+  pinned ones). That is obviously in addition to the new unbound list.
+- The shrinker cound is no longer scaled with
+  sysctl_vfs_cache_pressure. Note though that with the default tuning
+  value of vfs_cache_pressue = 100 this doesn't affect the shrinker
+  behaviour.
+- When actually shrinking objects, the old code first dropped
+  purgeable objects, then normal (inactive) objects. Only then did it,
+  in a last-ditch effort idle the gpu and evict everything. The new
+  code omits the intermediate step of evicting normal inactive
+  objects.
+
+Safe for the first change, which seems benign, and the shrinker count
+scaling, which is a bit a different story, the endresult of all these
+changes is that the shrinker is _much_ more likely to fall back to the
+last-ditch resort of idling the gpu and evicting everything.  The old
+code could only do that if something else evicted lots of objects
+meanwhile (since without any other changes the nr_to_scan will be
+smaller than the object count).
+
+Reverting the vfs_cache_pressure behaviour itself is a bit bogus: Only
+dentry/inode object caches should scale their shrinker counts with
+vfs_cache_pressure. Originally I've had that change reverted, too. But
+Chris Wilson insisted that it's too bogus and shouldn't again see the
+light of day.
+
+Hence revert all these other changes and restore the old shrinker
+behaviour, with the minor adjustment that we now first scan the
+unbound list, then the inactive list for each object category
+(purgeable or normal).
+
+A similar patch has been tested by a few people affected by the gen4/5
+hangs which started to appear in 3.7, which some people bisected to
+the "drm/i915: Track unbound pages" commit. But just disabling the
+unbound logic alone didn't change things at all.
+
+Note that this patch doesn't fix the referenced bugs, it only hides
+the underlying bug(s) well enough to restore pre-3.7 behaviour. The
+key to achieve that is to massively reduce the likelyhood of going
+into a full gpu stall and evicting everything.
+
+v2: Reword commit message a bit, taking Chris Wilson's comment into
+account.
+
+v3: On Chris Wilson's insistency, do not reinstate the rather bogus
+vfs_cache_pressure change.
+
+Tested-by: Greg KH <gregkh@linuxfoundation.org>
+Tested-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+References: https://bugs.freedesktop.org/show_bug.cgi?id=55984
+References: https://bugs.freedesktop.org/show_bug.cgi?id=57122
+References: https://bugs.freedesktop.org/show_bug.cgi?id=56916
+References: https://bugs.freedesktop.org/show_bug.cgi?id=57136
+Cc: Chris Wilson <chris@chris-wilson.co.uk>
+Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/i915_gem.c |   18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_gem.c
++++ b/drivers/gpu/drm/i915/i915_gem.c
+@@ -1718,7 +1718,8 @@ i915_gem_object_put_pages(struct drm_i91
+ }
+ static long
+-i915_gem_purge(struct drm_i915_private *dev_priv, long target)
++__i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
++                bool purgeable_only)
+ {
+       struct drm_i915_gem_object *obj, *next;
+       long count = 0;
+@@ -1726,7 +1727,7 @@ i915_gem_purge(struct drm_i915_private *
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.unbound_list,
+                                gtt_list) {
+-              if (i915_gem_object_is_purgeable(obj) &&
++              if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
+                   i915_gem_object_put_pages(obj) == 0) {
+                       count += obj->base.size >> PAGE_SHIFT;
+                       if (count >= target)
+@@ -1737,7 +1738,7 @@ i915_gem_purge(struct drm_i915_private *
+       list_for_each_entry_safe(obj, next,
+                                &dev_priv->mm.inactive_list,
+                                mm_list) {
+-              if (i915_gem_object_is_purgeable(obj) &&
++              if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
+                   i915_gem_object_unbind(obj) == 0 &&
+                   i915_gem_object_put_pages(obj) == 0) {
+                       count += obj->base.size >> PAGE_SHIFT;
+@@ -1749,6 +1750,12 @@ i915_gem_purge(struct drm_i915_private *
+       return count;
+ }
++static long
++i915_gem_purge(struct drm_i915_private *dev_priv, long target)
++{
++      return __i915_gem_shrink(dev_priv, target, true);
++}
++
+ static void
+ i915_gem_shrink_all(struct drm_i915_private *dev_priv)
+ {
+@@ -4426,6 +4433,9 @@ i915_gem_inactive_shrink(struct shrinker
+       if (nr_to_scan) {
+               nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
+               if (nr_to_scan > 0)
++                      nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan,
++                                                      false);
++              if (nr_to_scan > 0)
+                       i915_gem_shrink_all(dev_priv);
+       }
+@@ -4433,7 +4443,7 @@ i915_gem_inactive_shrink(struct shrinker
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list)
+               if (obj->pages_pin_count == 0)
+                       cnt += obj->base.size >> PAGE_SHIFT;
+-      list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
++      list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list)
+               if (obj->pin_count == 0 && obj->pages_pin_count == 0)
+                       cnt += obj->base.size >> PAGE_SHIFT;
diff --git a/queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch b/queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch
new file mode 100644 (file)
index 0000000..40086f7
--- /dev/null
@@ -0,0 +1,162 @@
+From 901593f2bf221659a605bdc1dcb11376ea934163 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 19 Dec 2012 16:51:06 +0000
+Subject: drm: Only evict the blocks required to create the requested hole
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 901593f2bf221659a605bdc1dcb11376ea934163 upstream.
+
+Avoid clobbering adjacent blocks if they happen to expire earlier and
+amalgamate together to form the requested hole.
+
+In passing this fixes a regression from
+commit ea7b1dd44867e9cd6bac67e7c9fc3f128b5b255c
+Author: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date:   Fri Feb 18 17:59:12 2011 +0100
+
+    drm: mm: track free areas implicitly
+
+which swaps the end address for size (with a potential overflow) and
+effectively causes the eviction code to clobber almost all earlier
+buffers above the evictee.
+
+v2: Check the original hole not the adjusted as the coloring may confuse
+us when later searching for the overlapping nodes. Also make sure that
+we do apply the range restriction and color adjustment in the same
+order for both scanning, searching and insertion.
+
+v3: Send the version that was actually tested.
+
+Note that this seems to be ducttape of decent quality ot paper over
+some of our unbind related gpu hangs reported since 3.7. It is not
+fully effective though, and certainly doesn't fix the underlying bug.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
+[danvet: Added note plus bugzilla link and tested-by.]
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55984
+Tested-by:  Norbert Preining <preining@logic.at>
+Acked-by: Dave Airlie <airlied@gmail.com
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/drm_mm.c |   45 +++++++++++++++++----------------------------
+ include/drm/drm_mm.h     |    2 +-
+ 2 files changed, 18 insertions(+), 29 deletions(-)
+
+--- a/drivers/gpu/drm/drm_mm.c
++++ b/drivers/gpu/drm/drm_mm.c
+@@ -213,11 +213,13 @@ static void drm_mm_insert_helper_range(s
+       BUG_ON(!hole_node->hole_follows || node->allocated);
+-      if (mm->color_adjust)
+-              mm->color_adjust(hole_node, color, &adj_start, &adj_end);
+-
+       if (adj_start < start)
+               adj_start = start;
++      if (adj_end > end)
++              adj_end = end;
++
++      if (mm->color_adjust)
++              mm->color_adjust(hole_node, color, &adj_start, &adj_end);
+       if (alignment) {
+               unsigned tmp = adj_start % alignment;
+@@ -489,7 +491,7 @@ void drm_mm_init_scan(struct drm_mm *mm,
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+-      mm->scan_hit_size = 0;
++      mm->scan_hit_end = 0;
+       mm->scan_check_range = 0;
+       mm->prev_scanned_node = NULL;
+ }
+@@ -516,7 +518,7 @@ void drm_mm_init_scan_with_range(struct
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+-      mm->scan_hit_size = 0;
++      mm->scan_hit_end = 0;
+       mm->scan_start = start;
+       mm->scan_end = end;
+       mm->scan_check_range = 1;
+@@ -535,8 +537,7 @@ int drm_mm_scan_add_block(struct drm_mm_
+       struct drm_mm *mm = node->mm;
+       struct drm_mm_node *prev_node;
+       unsigned long hole_start, hole_end;
+-      unsigned long adj_start;
+-      unsigned long adj_end;
++      unsigned long adj_start, adj_end;
+       mm->scanned_blocks++;
+@@ -553,14 +554,8 @@ int drm_mm_scan_add_block(struct drm_mm_
+       node->node_list.next = &mm->prev_scanned_node->node_list;
+       mm->prev_scanned_node = node;
+-      hole_start = drm_mm_hole_node_start(prev_node);
+-      hole_end = drm_mm_hole_node_end(prev_node);
+-
+-      adj_start = hole_start;
+-      adj_end = hole_end;
+-
+-      if (mm->color_adjust)
+-              mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end);
++      adj_start = hole_start = drm_mm_hole_node_start(prev_node);
++      adj_end = hole_end = drm_mm_hole_node_end(prev_node);
+       if (mm->scan_check_range) {
+               if (adj_start < mm->scan_start)
+@@ -569,11 +564,14 @@ int drm_mm_scan_add_block(struct drm_mm_
+                       adj_end = mm->scan_end;
+       }
++      if (mm->color_adjust)
++              mm->color_adjust(prev_node, mm->scan_color,
++                               &adj_start, &adj_end);
++
+       if (check_free_hole(adj_start, adj_end,
+                           mm->scan_size, mm->scan_alignment)) {
+               mm->scan_hit_start = hole_start;
+-              mm->scan_hit_size = hole_end;
+-
++              mm->scan_hit_end = hole_end;
+               return 1;
+       }
+@@ -609,19 +607,10 @@ int drm_mm_scan_remove_block(struct drm_
+                              node_list);
+       prev_node->hole_follows = node->scanned_preceeds_hole;
+-      INIT_LIST_HEAD(&node->node_list);
+       list_add(&node->node_list, &prev_node->node_list);
+-      /* Only need to check for containement because start&size for the
+-       * complete resulting free block (not just the desired part) is
+-       * stored. */
+-      if (node->start >= mm->scan_hit_start &&
+-          node->start + node->size
+-                      <= mm->scan_hit_start + mm->scan_hit_size) {
+-              return 1;
+-      }
+-
+-      return 0;
++       return (drm_mm_hole_node_end(node) > mm->scan_hit_start &&
++               node->start < mm->scan_hit_end);
+ }
+ EXPORT_SYMBOL(drm_mm_scan_remove_block);
+--- a/include/drm/drm_mm.h
++++ b/include/drm/drm_mm.h
+@@ -70,7 +70,7 @@ struct drm_mm {
+       unsigned long scan_color;
+       unsigned long scan_size;
+       unsigned long scan_hit_start;
+-      unsigned scan_hit_size;
++      unsigned long scan_hit_end;
+       unsigned scanned_blocks;
+       unsigned long scan_start;
+       unsigned long scan_end;
diff --git a/queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch b/queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch
new file mode 100644 (file)
index 0000000..e3bea46
--- /dev/null
@@ -0,0 +1,100 @@
+From be8a42ae60addd8b6092535c11b42d099d6470ec Mon Sep 17 00:00:00 2001
+From: Seung-Woo Kim <sw0312.kim@samsung.com>
+Date: Thu, 27 Sep 2012 15:30:06 +0900
+Subject: drm/prime: drop reference on imported dma-buf come from gem
+
+From: Seung-Woo Kim <sw0312.kim@samsung.com>
+
+commit be8a42ae60addd8b6092535c11b42d099d6470ec upstream.
+
+Increasing ref counts of both dma-buf and gem for imported dma-buf come from gem
+makes memory leak. release function of dma-buf cannot be called because f_count
+of dma-buf increased by importing gem and gem ref count cannot be decrease
+because of exported dma-buf.
+
+So I add dma_buf_put() for imported gem come from its own gem into each drivers
+having prime_import and prime_export capabilities. With this, only gem ref
+count is increased if importing gem exported from gem of same driver.
+
+Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
+Signed-off-by: Kyungmin.park <kyungmin.park@samsung.com>
+Cc: Inki Dae <inki.dae@samsung.com>
+Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
+Cc: Rob Clark <rob.clark@linaro.org>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/exynos/exynos_drm_dmabuf.c |    5 +++++
+ drivers/gpu/drm/i915/i915_gem_dmabuf.c     |    5 +++++
+ drivers/gpu/drm/nouveau/nouveau_prime.c    |    1 +
+ drivers/gpu/drm/radeon/radeon_prime.c      |    1 +
+ drivers/staging/omapdrm/omap_gem_dmabuf.c  |    5 +++++
+ 5 files changed, 17 insertions(+)
+
+--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
++++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+@@ -210,7 +210,12 @@ struct drm_gem_object *exynos_dmabuf_pri
+               /* is it from our device? */
+               if (obj->dev == drm_dev) {
++                      /*
++                       * Importing dmabuf exported from out own gem increases
++                       * refcount on gem itself instead of f_count of dmabuf.
++                       */
+                       drm_gem_object_reference(obj);
++                      dma_buf_put(dma_buf);
+                       return obj;
+               }
+       }
+--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
++++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+@@ -266,7 +266,12 @@ struct drm_gem_object *i915_gem_prime_im
+               obj = dma_buf->priv;
+               /* is it from our device? */
+               if (obj->base.dev == dev) {
++                      /*
++                       * Importing dmabuf exported from out own gem increases
++                       * refcount on gem itself instead of f_count of dmabuf.
++                       */
+                       drm_gem_object_reference(&obj->base);
++                      dma_buf_put(dma_buf);
+                       return &obj->base;
+               }
+       }
+--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
++++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
+@@ -197,6 +197,7 @@ struct drm_gem_object *nouveau_gem_prime
+               if (nvbo->gem) {
+                       if (nvbo->gem->dev == dev) {
+                               drm_gem_object_reference(nvbo->gem);
++                              dma_buf_put(dma_buf);
+                               return nvbo->gem;
+                       }
+               }
+--- a/drivers/gpu/drm/radeon/radeon_prime.c
++++ b/drivers/gpu/drm/radeon/radeon_prime.c
+@@ -194,6 +194,7 @@ struct drm_gem_object *radeon_gem_prime_
+               bo = dma_buf->priv;
+               if (bo->gem_base.dev == dev) {
+                       drm_gem_object_reference(&bo->gem_base);
++                      dma_buf_put(dma_buf);
+                       return &bo->gem_base;
+               }
+       }
+--- a/drivers/staging/omapdrm/omap_gem_dmabuf.c
++++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c
+@@ -207,7 +207,12 @@ struct drm_gem_object * omap_gem_prime_i
+               obj = buffer->priv;
+               /* is it from our device? */
+               if (obj->dev == dev) {
++                      /*
++                       * Importing dmabuf exported from out own gem increases
++                       * refcount on gem itself instead of f_count of dmabuf.
++                       */
+                       drm_gem_object_reference(obj);
++                      dma_buf_put(buffer);
+                       return obj;
+               }
+       }
diff --git a/queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch b/queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch
new file mode 100644 (file)
index 0000000..e24f8e0
--- /dev/null
@@ -0,0 +1,355 @@
+From 8fb74b9fb2b182d54beee592350d9ea1f325917a Mon Sep 17 00:00:00 2001
+From: Mel Gorman <mgorman@suse.de>
+Date: Fri, 11 Jan 2013 14:32:16 -0800
+Subject: mm: compaction: partially revert capture of suitable high-order page
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit 8fb74b9fb2b182d54beee592350d9ea1f325917a upstream.
+
+Eric Wong reported on 3.7 and 3.8-rc2 that ppoll() got stuck when
+waiting for POLLIN on a local TCP socket.  It was easier to trigger if
+there was disk IO and dirty pages at the same time and he bisected it to
+commit 1fb3f8ca0e92 ("mm: compaction: capture a suitable high-order page
+immediately when it is made available").
+
+The intention of that patch was to improve high-order allocations under
+memory pressure after changes made to reclaim in 3.6 drastically hurt
+THP allocations but the approach was flawed.  For Eric, the problem was
+that page->pfmemalloc was not being cleared for captured pages leading
+to a poor interaction with swap-over-NFS support causing the packets to
+be dropped.  However, I identified a few more problems with the patch
+including the fact that it can increase contention on zone->lock in some
+cases which could result in async direct compaction being aborted early.
+
+In retrospect the capture patch took the wrong approach.  What it should
+have done is mark the pageblock being migrated as MIGRATE_ISOLATE if it
+was allocating for THP and avoided races that way.  While the patch was
+showing to improve allocation success rates at the time, the benefit is
+marginal given the relative complexity and it should be revisited from
+scratch in the context of the other reclaim-related changes that have
+taken place since the patch was first written and tested.  This patch
+partially reverts commit 1fb3f8ca0e92 ("mm: compaction: capture a
+suitable high-order page immediately when it is made available").
+
+Reported-and-tested-by: Eric Wong <normalperson@yhbt.net>
+Tested-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Cc: David Miller <davem@davemloft.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/compaction.h |    4 -
+ include/linux/mm.h         |    1 
+ mm/compaction.c            |   92 ++++++---------------------------------------
+ mm/internal.h              |    1 
+ mm/page_alloc.c            |   35 +++--------------
+ 5 files changed, 23 insertions(+), 110 deletions(-)
+
+--- a/include/linux/compaction.h
++++ b/include/linux/compaction.h
+@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct
+ extern int fragmentation_index(struct zone *zone, unsigned int order);
+ extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *mask,
+-                      bool sync, bool *contended, struct page **page);
++                      bool sync, bool *contended);
+ extern int compact_pgdat(pg_data_t *pgdat, int order);
+ extern void reset_isolation_suitable(pg_data_t *pgdat);
+ extern unsigned long compaction_suitable(struct zone *zone, int order);
+@@ -75,7 +75,7 @@ static inline bool compaction_restarting
+ #else
+ static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *nodemask,
+-                      bool sync, bool *contended, struct page **page)
++                      bool sync, bool *contended)
+ {
+       return COMPACT_CONTINUE;
+ }
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -455,7 +455,6 @@ void put_pages_list(struct list_head *pa
+ void split_page(struct page *page, unsigned int order);
+ int split_free_page(struct page *page);
+-int capture_free_page(struct page *page, int alloc_order, int migratetype);
+ /*
+  * Compound pages have a destructor function.  Provide a
+--- a/mm/compaction.c
++++ b/mm/compaction.c
+@@ -214,60 +214,6 @@ static bool suitable_migration_target(st
+       return false;
+ }
+-static void compact_capture_page(struct compact_control *cc)
+-{
+-      unsigned long flags;
+-      int mtype, mtype_low, mtype_high;
+-
+-      if (!cc->page || *cc->page)
+-              return;
+-
+-      /*
+-       * For MIGRATE_MOVABLE allocations we capture a suitable page ASAP
+-       * regardless of the migratetype of the freelist is is captured from.
+-       * This is fine because the order for a high-order MIGRATE_MOVABLE
+-       * allocation is typically at least a pageblock size and overall
+-       * fragmentation is not impaired. Other allocation types must
+-       * capture pages from their own migratelist because otherwise they
+-       * could pollute other pageblocks like MIGRATE_MOVABLE with
+-       * difficult to move pages and making fragmentation worse overall.
+-       */
+-      if (cc->migratetype == MIGRATE_MOVABLE) {
+-              mtype_low = 0;
+-              mtype_high = MIGRATE_PCPTYPES;
+-      } else {
+-              mtype_low = cc->migratetype;
+-              mtype_high = cc->migratetype + 1;
+-      }
+-
+-      /* Speculatively examine the free lists without zone lock */
+-      for (mtype = mtype_low; mtype < mtype_high; mtype++) {
+-              int order;
+-              for (order = cc->order; order < MAX_ORDER; order++) {
+-                      struct page *page;
+-                      struct free_area *area;
+-                      area = &(cc->zone->free_area[order]);
+-                      if (list_empty(&area->free_list[mtype]))
+-                              continue;
+-
+-                      /* Take the lock and attempt capture of the page */
+-                      if (!compact_trylock_irqsave(&cc->zone->lock, &flags, cc))
+-                              return;
+-                      if (!list_empty(&area->free_list[mtype])) {
+-                              page = list_entry(area->free_list[mtype].next,
+-                                                      struct page, lru);
+-                              if (capture_free_page(page, cc->order, mtype)) {
+-                                      spin_unlock_irqrestore(&cc->zone->lock,
+-                                                                      flags);
+-                                      *cc->page = page;
+-                                      return;
+-                              }
+-                      }
+-                      spin_unlock_irqrestore(&cc->zone->lock, flags);
+-              }
+-      }
+-}
+-
+ /*
+  * Isolate free pages onto a private freelist. Caller must hold zone->lock.
+  * If @strict is true, will abort returning 0 on any invalid PFNs or non-free
+@@ -831,6 +777,7 @@ static isolate_migrate_t isolate_migrate
+ static int compact_finished(struct zone *zone,
+                           struct compact_control *cc)
+ {
++      unsigned int order;
+       unsigned long watermark;
+       if (fatal_signal_pending(current))
+@@ -865,22 +812,16 @@ static int compact_finished(struct zone
+               return COMPACT_CONTINUE;
+       /* Direct compactor: Is a suitable page free? */
+-      if (cc->page) {
+-              /* Was a suitable page captured? */
+-              if (*cc->page)
++      for (order = cc->order; order < MAX_ORDER; order++) {
++              struct free_area *area = &zone->free_area[order];
++
++              /* Job done if page is free of the right migratetype */
++              if (!list_empty(&area->free_list[cc->migratetype]))
++                      return COMPACT_PARTIAL;
++
++              /* Job done if allocation would set block type */
++              if (cc->order >= pageblock_order && area->nr_free)
+                       return COMPACT_PARTIAL;
+-      } else {
+-              unsigned int order;
+-              for (order = cc->order; order < MAX_ORDER; order++) {
+-                      struct free_area *area = &zone->free_area[cc->order];
+-                      /* Job done if page is free of the right migratetype */
+-                      if (!list_empty(&area->free_list[cc->migratetype]))
+-                              return COMPACT_PARTIAL;
+-
+-                      /* Job done if allocation would set block type */
+-                      if (cc->order >= pageblock_order && area->nr_free)
+-                              return COMPACT_PARTIAL;
+-              }
+       }
+       return COMPACT_CONTINUE;
+@@ -1018,9 +959,6 @@ static int compact_zone(struct zone *zon
+                               goto out;
+                       }
+               }
+-
+-              /* Capture a page now if it is a suitable size */
+-              compact_capture_page(cc);
+       }
+ out:
+@@ -1033,8 +971,7 @@ out:
+ static unsigned long compact_zone_order(struct zone *zone,
+                                int order, gfp_t gfp_mask,
+-                               bool sync, bool *contended,
+-                               struct page **page)
++                               bool sync, bool *contended)
+ {
+       unsigned long ret;
+       struct compact_control cc = {
+@@ -1044,7 +981,6 @@ static unsigned long compact_zone_order(
+               .migratetype = allocflags_to_migratetype(gfp_mask),
+               .zone = zone,
+               .sync = sync,
+-              .page = page,
+       };
+       INIT_LIST_HEAD(&cc.freepages);
+       INIT_LIST_HEAD(&cc.migratepages);
+@@ -1074,7 +1010,7 @@ int sysctl_extfrag_threshold = 500;
+  */
+ unsigned long try_to_compact_pages(struct zonelist *zonelist,
+                       int order, gfp_t gfp_mask, nodemask_t *nodemask,
+-                      bool sync, bool *contended, struct page **page)
++                      bool sync, bool *contended)
+ {
+       enum zone_type high_zoneidx = gfp_zone(gfp_mask);
+       int may_enter_fs = gfp_mask & __GFP_FS;
+@@ -1100,7 +1036,7 @@ unsigned long try_to_compact_pages(struc
+               int status;
+               status = compact_zone_order(zone, order, gfp_mask, sync,
+-                                              contended, page);
++                                              contended);
+               rc = max(status, rc);
+               /* If a normal allocation would succeed, stop compacting */
+@@ -1156,7 +1092,6 @@ int compact_pgdat(pg_data_t *pgdat, int
+       struct compact_control cc = {
+               .order = order,
+               .sync = false,
+-              .page = NULL,
+       };
+       return __compact_pgdat(pgdat, &cc);
+@@ -1167,7 +1102,6 @@ static int compact_node(int nid)
+       struct compact_control cc = {
+               .order = -1,
+               .sync = true,
+-              .page = NULL,
+       };
+       return __compact_pgdat(NODE_DATA(nid), &cc);
+--- a/mm/internal.h
++++ b/mm/internal.h
+@@ -130,7 +130,6 @@ struct compact_control {
+       int migratetype;                /* MOVABLE, RECLAIMABLE etc */
+       struct zone *zone;
+       bool contended;                 /* True if a lock was contended */
+-      struct page **page;             /* Page captured of requested size */
+ };
+ unsigned long
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -1376,14 +1376,8 @@ void split_page(struct page *page, unsig
+               set_page_refcounted(page + i);
+ }
+-/*
+- * Similar to the split_page family of functions except that the page
+- * required at the given order and being isolated now to prevent races
+- * with parallel allocators
+- */
+-int capture_free_page(struct page *page, int alloc_order, int migratetype)
++static int __isolate_free_page(struct page *page, unsigned int order)
+ {
+-      unsigned int order;
+       unsigned long watermark;
+       struct zone *zone;
+       int mt;
+@@ -1391,7 +1385,6 @@ int capture_free_page(struct page *page,
+       BUG_ON(!PageBuddy(page));
+       zone = page_zone(page);
+-      order = page_order(page);
+       /* Obey watermarks as if the page was being allocated */
+       watermark = low_wmark_pages(zone) + (1 << order);
+@@ -1405,13 +1398,9 @@ int capture_free_page(struct page *page,
+       mt = get_pageblock_migratetype(page);
+       if (unlikely(mt != MIGRATE_ISOLATE))
+-              __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt);
+-
+-      if (alloc_order != order)
+-              expand(zone, page, alloc_order, order,
+-                      &zone->free_area[order], migratetype);
++              __mod_zone_freepage_state(zone, -(1UL << order), mt);
+-      /* Set the pageblock if the captured page is at least a pageblock */
++      /* Set the pageblock if the isolated page is at least a pageblock */
+       if (order >= pageblock_order - 1) {
+               struct page *endpage = page + (1 << order) - 1;
+               for (; page < endpage; page += pageblock_nr_pages) {
+@@ -1422,7 +1411,7 @@ int capture_free_page(struct page *page,
+               }
+       }
+-      return 1UL << alloc_order;
++      return 1UL << order;
+ }
+ /*
+@@ -1440,10 +1429,9 @@ int split_free_page(struct page *page)
+       unsigned int order;
+       int nr_pages;
+-      BUG_ON(!PageBuddy(page));
+       order = page_order(page);
+-      nr_pages = capture_free_page(page, order, 0);
++      nr_pages = __isolate_free_page(page, order);
+       if (!nr_pages)
+               return 0;
+@@ -2148,8 +2136,6 @@ __alloc_pages_direct_compact(gfp_t gfp_m
+       bool *contended_compaction, bool *deferred_compaction,
+       unsigned long *did_some_progress)
+ {
+-      struct page *page = NULL;
+-
+       if (!order)
+               return NULL;
+@@ -2161,16 +2147,12 @@ __alloc_pages_direct_compact(gfp_t gfp_m
+       current->flags |= PF_MEMALLOC;
+       *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
+                                               nodemask, sync_migration,
+-                                              contended_compaction, &page);
++                                              contended_compaction);
+       current->flags &= ~PF_MEMALLOC;
+-      /* If compaction captured a page, prep and use it */
+-      if (page) {
+-              prep_new_page(page, order, gfp_mask);
+-              goto got_page;
+-      }
+-
+       if (*did_some_progress != COMPACT_SKIPPED) {
++              struct page *page;
++
+               /* Page migration frees to the PCP lists but we want merging */
+               drain_pages(get_cpu());
+               put_cpu();
+@@ -2180,7 +2162,6 @@ __alloc_pages_direct_compact(gfp_t gfp_m
+                               alloc_flags & ~ALLOC_NO_WATERMARKS,
+                               preferred_zone, migratetype);
+               if (page) {
+-got_page:
+                       preferred_zone->compact_blockskip_flush = false;
+                       preferred_zone->compact_considered = 0;
+                       preferred_zone->compact_defer_shift = 0;
index 062d2178058792c4f0709fe0e5411efaecaa0af0..1ad6a1c811bb1766faf52786c076a7c620db3a74 100644 (file)
@@ -77,3 +77,12 @@ drm-radeon-add-connector-table-for-mac-g4-silver.patch
 drm-radeon-properly-handle-ddc-probe-for-dp-bridges.patch
 drm-nouveau-fix-init-with-agpgart-uninorth.patch
 drm-i915-make-the-panel-fitter-work-on-pipes-b-and-c-on-ivb.patch
+mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch
+drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch
+drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch
+drm-i915-don-t-disable-disconnected-outputs.patch
+drm-i915-fix-flags-in-dma-buf-exporting.patch
+drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch
+drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch
+drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch
+drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch