]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.8-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Oct 2016 13:47:09 +0000 (09:47 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Oct 2016 13:47:09 +0000 (09:47 -0400)
added patches:
drm-i915-gen9-only-add-the-planes-actually-affected-by-ddb-changes.patch
drm-i915-move-crtc-updating-in-atomic_commit-into-it-s-own-hook.patch
drm-i915-skl-don-t-try-to-update-plane-watermarks-if-they-haven-t-changed.patch
drm-i915-skl-update-ddb-values-atomically-with-wms-plane-attrs.patch
drm-i915-skl-update-plane-watermarks-atomically-during-plane-updates.patch

queue-4.8/drm-i915-gen9-only-add-the-planes-actually-affected-by-ddb-changes.patch [new file with mode: 0644]
queue-4.8/drm-i915-move-crtc-updating-in-atomic_commit-into-it-s-own-hook.patch [new file with mode: 0644]
queue-4.8/drm-i915-skl-don-t-try-to-update-plane-watermarks-if-they-haven-t-changed.patch [new file with mode: 0644]
queue-4.8/drm-i915-skl-update-ddb-values-atomically-with-wms-plane-attrs.patch [new file with mode: 0644]
queue-4.8/drm-i915-skl-update-plane-watermarks-atomically-during-plane-updates.patch [new file with mode: 0644]
queue-4.8/series

diff --git a/queue-4.8/drm-i915-gen9-only-add-the-planes-actually-affected-by-ddb-changes.patch b/queue-4.8/drm-i915-gen9-only-add-the-planes-actually-affected-by-ddb-changes.patch
new file mode 100644 (file)
index 0000000..8fec07d
--- /dev/null
@@ -0,0 +1,92 @@
+From be5c571b2ff3a164d2e14ccc100cb5b2b3d3fb7c Mon Sep 17 00:00:00 2001
+From: Paulo Zanoni <paulo.r.zanoni@intel.com>
+Date: Thu, 29 Sep 2016 16:36:48 -0300
+Subject: drm/i915/gen9: only add the planes actually affected by ddb changes
+
+From: Paulo Zanoni <paulo.r.zanoni@intel.com>
+
+commit be5c571b2ff3a164d2e14ccc100cb5b2b3d3fb7c upstream.
+
+We were previously adding all the planes owned by the CRTC even when
+the ddb partitioning didn't change for them. As a consequence, a lot
+of functions were being called when we were just moving the cursor
+around the screen, such as skylake_update_primary_plane().
+
+This was causing flickering on the primary plane when moving the
+cursor. I'm not 100% sure which operation caused the flickering, but
+we were writing to a lot of registers, so it could be any of these
+writes. With this patch, just moving the mouse won't add the primary
+plane to the commit since it won't trigger a change in DDB
+partitioning.
+
+v2: Use skl_ddb_entry_equal() (Lyude).
+v3: Change Reported-and-bisected-by: to Reported-by: for checkpatch
+
+Fixes: 05a76d3d6ad1 ("drm/i915/skl: Ensure pipes with changed wms get added to the state")
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97888
+Cc: Mike Lothian <mike@fireburn.co.uk>
+Reported-by: Mike Lothian <mike@fireburn.co.uk>
+Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
+Signed-off-by: Lyude <cpaul@redhat.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1475177808-29955-1-git-send-email-paulo.r.zanoni@intel.com
+(cherry picked from commit 7f60e200e254cd53ad1bd74a56bdd23e813ac4b7)
+Signed-off-by: Jani Nikula <jani.nikula@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/intel_pm.c |   37 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 36 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3940,6 +3940,41 @@ pipes_modified(struct drm_atomic_state *
+       return ret;
+ }
++int
++skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
++{
++      struct drm_atomic_state *state = cstate->base.state;
++      struct drm_device *dev = state->dev;
++      struct drm_crtc *crtc = cstate->base.crtc;
++      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++      struct drm_i915_private *dev_priv = to_i915(dev);
++      struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
++      struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
++      struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
++      struct drm_plane_state *plane_state;
++      struct drm_plane *plane;
++      enum pipe pipe = intel_crtc->pipe;
++      int id;
++
++      WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc));
++
++      drm_for_each_plane_mask(plane, dev, crtc->state->plane_mask) {
++              id = skl_wm_plane_id(to_intel_plane(plane));
++
++              if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][id],
++                                      &new_ddb->plane[pipe][id]) &&
++                  skl_ddb_entry_equal(&cur_ddb->y_plane[pipe][id],
++                                      &new_ddb->y_plane[pipe][id]))
++                      continue;
++
++              plane_state = drm_atomic_get_plane_state(state, plane);
++              if (IS_ERR(plane_state))
++                      return PTR_ERR(plane_state);
++      }
++
++      return 0;
++}
++
+ static int
+ skl_compute_ddb(struct drm_atomic_state *state)
+ {
+@@ -4004,7 +4039,7 @@ skl_compute_ddb(struct drm_atomic_state
+               if (ret)
+                       return ret;
+-              ret = drm_atomic_add_affected_planes(state, &intel_crtc->base);
++              ret = skl_ddb_add_affected_planes(cstate);
+               if (ret)
+                       return ret;
+       }
diff --git a/queue-4.8/drm-i915-move-crtc-updating-in-atomic_commit-into-it-s-own-hook.patch b/queue-4.8/drm-i915-move-crtc-updating-in-atomic_commit-into-it-s-own-hook.patch
new file mode 100644 (file)
index 0000000..e4402b0
--- /dev/null
@@ -0,0 +1,162 @@
+From 896e5bb022bce64e29ce2e1b2fc2a7476d311a15 Mon Sep 17 00:00:00 2001
+From: Lyude <cpaul@redhat.com>
+Date: Wed, 24 Aug 2016 07:48:09 +0200
+Subject: drm/i915: Move CRTC updating in atomic_commit into it's own hook
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lyude <cpaul@redhat.com>
+
+commit 896e5bb022bce64e29ce2e1b2fc2a7476d311a15 upstream.
+
+Since we have to write ddb allocations at the same time as we do other
+plane updates, we're going to need to be able to control the order in
+which we execute modesets on each pipe. The easiest way to do this is to
+just factor this section of intel_atomic_commit_tail()
+(intel_atomic_commit() for stable branches) into it's own function, and
+add an appropriate display function hook for it.
+
+Based off of Matt Rope's suggestions
+
+Changes since v1:
+ - Drop pipe_config->base.active check in intel_update_crtcs() since we
+   check that before calling the function
+
+Signed-off-by: Lyude <cpaul@redhat.com>
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+[omitting CC for stable, since this patch will need to be changed for
+such backports first]
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Lyude <cpaul@redhat.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-1-git-send-email-cpaul@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/i915_drv.h      |    2 
+ drivers/gpu/drm/i915/intel_display.c |   74 ++++++++++++++++++++++++-----------
+ 2 files changed, 54 insertions(+), 22 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -631,6 +631,8 @@ struct drm_i915_display_funcs {
+                                 struct intel_crtc_state *crtc_state);
+       void (*crtc_enable)(struct drm_crtc *crtc);
+       void (*crtc_disable)(struct drm_crtc *crtc);
++      void (*update_crtcs)(struct drm_atomic_state *state,
++                           unsigned int *crtc_vblank_mask);
+       void (*audio_codec_enable)(struct drm_connector *connector,
+                                  struct intel_encoder *encoder,
+                                  const struct drm_display_mode *adjusted_mode);
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -13682,6 +13682,52 @@ static bool needs_vblank_wait(struct int
+       return false;
+ }
++static void intel_update_crtc(struct drm_crtc *crtc,
++                            struct drm_atomic_state *state,
++                            struct drm_crtc_state *old_crtc_state,
++                            unsigned int *crtc_vblank_mask)
++{
++      struct drm_device *dev = crtc->dev;
++      struct drm_i915_private *dev_priv = to_i915(dev);
++      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++      struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->state);
++      bool modeset = needs_modeset(crtc->state);
++
++      if (modeset) {
++              update_scanline_offset(intel_crtc);
++              dev_priv->display.crtc_enable(crtc);
++      } else {
++              intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
++      }
++
++      if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
++              intel_fbc_enable(
++                  intel_crtc, pipe_config,
++                  to_intel_plane_state(crtc->primary->state));
++      }
++
++      drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
++
++      if (needs_vblank_wait(pipe_config))
++              *crtc_vblank_mask |= drm_crtc_mask(crtc);
++}
++
++static void intel_update_crtcs(struct drm_atomic_state *state,
++                             unsigned int *crtc_vblank_mask)
++{
++      struct drm_crtc *crtc;
++      struct drm_crtc_state *old_crtc_state;
++      int i;
++
++      for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
++              if (!crtc->state->active)
++                      continue;
++
++              intel_update_crtc(crtc, state, old_crtc_state,
++                                crtc_vblank_mask);
++      }
++}
++
+ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+ {
+       struct drm_device *dev = state->dev;
+@@ -13780,17 +13826,9 @@ static void intel_atomic_commit_tail(str
+               intel_modeset_verify_disabled(dev);
+       }
+-      /* Now enable the clocks, plane, pipe, and connectors that we set up. */
++      /* Complete the events for pipes that have now been disabled */
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+-              struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               bool modeset = needs_modeset(crtc->state);
+-              struct intel_crtc_state *pipe_config =
+-                      to_intel_crtc_state(crtc->state);
+-
+-              if (modeset && crtc->state->active) {
+-                      update_scanline_offset(to_intel_crtc(crtc));
+-                      dev_priv->display.crtc_enable(crtc);
+-              }
+               /* Complete events for now disable pipes here. */
+               if (modeset && !crtc->state->active && crtc->state->event) {
+@@ -13800,21 +13838,11 @@ static void intel_atomic_commit_tail(str
+                       crtc->state->event = NULL;
+               }
+-
+-              if (!modeset)
+-                      intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
+-
+-              if (crtc->state->active &&
+-                  drm_atomic_get_existing_plane_state(state, crtc->primary))
+-                      intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
+-
+-              if (crtc->state->active)
+-                      drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+-
+-              if (pipe_config->base.active && needs_vblank_wait(pipe_config))
+-                      crtc_vblank_mask |= 1 << i;
+       }
++      /* Now enable the clocks, plane, pipe, and connectors that we set up. */
++      dev_priv->display.update_crtcs(state, &crtc_vblank_mask);
++
+       /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
+        * already, but still need the state for the delayed optimization. To
+        * fix this:
+@@ -15275,6 +15303,8 @@ void intel_init_display_hooks(struct drm
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
+       }
++      dev_priv->display.update_crtcs = intel_update_crtcs;
++
+       /* Returns the core display clock speed */
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+               dev_priv->display.get_display_clock_speed =
diff --git a/queue-4.8/drm-i915-skl-don-t-try-to-update-plane-watermarks-if-they-haven-t-changed.patch b/queue-4.8/drm-i915-skl-don-t-try-to-update-plane-watermarks-if-they-haven-t-changed.patch
new file mode 100644 (file)
index 0000000..4f468af
--- /dev/null
@@ -0,0 +1,79 @@
+From ccebc23b57c313229526dc76383ce82f5e0b9001 Mon Sep 17 00:00:00 2001
+From: Lyude <cpaul@redhat.com>
+Date: Mon, 29 Aug 2016 12:31:27 -0400
+Subject: drm/i915/skl: Don't try to update plane watermarks if they haven't changed
+
+From: Lyude <cpaul@redhat.com>
+
+commit ccebc23b57c313229526dc76383ce82f5e0b9001 upstream.
+
+i915 sometimes needs to disable planes in the middle of an atomic
+commit, and then reenable them later in the same commit. Because of
+this, we can't make the assumption that the state of the plane actually
+changed. Since the state of the plane hasn't actually changed, neither
+have it's watermarks. And if the watermarks hasn't changed then we
+haven't populated skl_results with anything, which means we'll end up
+zeroing out a plane's watermarks in the middle of the atomic commit
+without restoring them later.
+
+Simple reproduction recipe:
+ - Get a SKL laptop, launch any kind of X session
+ - Get two extra monitors
+ - Keep hotplugging both displays (so that the display configuration
+   jumps from 1 active pipe to 3 active pipes and back)
+ - Eventually underrun
+
+Changes since v1:
+ - Fix incorrect use of "it's"
+Changes since v2:
+ - Add reproduction recipe
+
+Signed-off-by: Lyude <cpaul@redhat.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Fixes: 62e0fb880123 ("drm/i915/skl: Update plane watermarks atomically during plane updates")
+Signed-off-by: Lyude <cpaul@redhat.com>
+Testcase: kms_plane
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1472488288-27280-1-git-send-email-cpaul@redhat.com
+Cc: drm-intel-fixes@lists.freedesktop.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/gpu/drm/i915/intel_display.c |    7 ++++++-
+ drivers/gpu/drm/i915/intel_sprite.c  |    8 ++++++++
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -3068,7 +3068,12 @@ static void skylake_disable_primary_plan
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+-      skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
++      /*
++       * We only populate skl_results on watermark updates, and if the
++       * plane's visiblity isn't actually changing neither is its watermarks.
++       */
++      if (!to_intel_plane_state(crtc->primary->state)->visible)
++              skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
+       I915_WRITE(PLANE_CTL(pipe, 0), 0);
+       I915_WRITE(PLANE_SURF(pipe, 0), 0);
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -314,6 +314,14 @@ skl_disable_plane(struct drm_plane *dpla
+       const int pipe = intel_plane->pipe;
+       const int plane = intel_plane->plane + 1;
++      /*
++       * We only populate skl_results on watermark updates, and if the
++       * plane's visiblity isn't actually changing neither is its watermarks.
++       */
++      if (!to_intel_plane_state(dplane->state)->visible)
++              skl_write_plane_wm(to_intel_crtc(crtc),
++                                 &dev_priv->wm.skl_results, plane);
++
+       I915_WRITE(PLANE_CTL(pipe, plane), 0);
+       I915_WRITE(PLANE_SURF(pipe, plane), 0);
diff --git a/queue-4.8/drm-i915-skl-update-ddb-values-atomically-with-wms-plane-attrs.patch b/queue-4.8/drm-i915-skl-update-ddb-values-atomically-with-wms-plane-attrs.patch
new file mode 100644 (file)
index 0000000..492d656
--- /dev/null
@@ -0,0 +1,479 @@
+From 27082493e9c6371b05370a619ab9d2877c5f4726 Mon Sep 17 00:00:00 2001
+From: Lyude <cpaul@redhat.com>
+Date: Wed, 24 Aug 2016 07:48:10 +0200
+Subject: drm/i915/skl: Update DDB values atomically with wms/plane attrs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lyude <cpaul@redhat.com>
+
+commit 27082493e9c6371b05370a619ab9d2877c5f4726 upstream.
+
+Now that we can hook into update_crtcs and control the order in which we
+update CRTCs at each modeset, we can finish the final step of fixing
+Skylake's watermark handling by performing DDB updates at the same time
+as plane updates and watermark updates.
+
+The first major change in this patch is skl_update_crtcs(), which
+handles ensuring that we order each CRTC update in our atomic commits
+properly so that they honor the DDB flush order.
+
+The second major change in this patch is the order in which we flush the
+pipes. While the previous order may have worked, it can't be used in
+this approach since it no longer will do the right thing. For example,
+using the old ddb flush order:
+
+We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
+allocation looks like this:
+
+|   A   |   B   |xxxxxxx|
+
+Since we're performing the ddb updates after performing any CRTC
+disablements in intel_atomic_commit_tail(), the space to the right of
+pipe B is unallocated.
+
+1. Flush pipes with new allocation contained into old space. None
+   apply, so we skip this
+2. Flush pipes having their allocation reduced, but overlapping with a
+   previous allocation. None apply, so we also skip this
+3. Flush pipes that got more space allocated. This applies to A and B,
+   giving us the following update order: A, B
+
+This is wrong, since updating pipe A first will cause it to overlap with
+B and potentially burst into flames. Our new order (see the code
+comments for details) would update the pipes in the proper order: B, A.
+
+As well, we calculate the order for each DDB update during the check
+phase, and reference it later in the commit phase when we hit
+skl_update_crtcs().
+
+This long overdue patch fixes the rest of the underruns on Skylake.
+
+Changes since v1:
+ - Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
+Changes since v2:
+ - Use the method for updating CRTCs that Ville suggested
+ - In skl_update_wm(), only copy the watermarks for the crtc that was
+   passed to us
+Changes since v3:
+ - Small comment fix in skl_ddb_allocation_overlaps()
+Changes since v4:
+ - Remove the second loop in intel_update_crtcs() and use Ville's
+   suggestion for updating the ddb allocations in the right order
+ - Get rid of the second loop and just use the ddb state as it updates
+   to determine what order to update everything in (thanks for the
+   suggestion Ville)
+ - Simplify skl_ddb_allocation_overlaps()
+ - Split actual overlap checking into it's own helper
+
+Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
+Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
+[omitting CC for stable, since this patch will need to be changed for
+such backports first]
+
+Testcase: kms_cursor_legacy
+Testcase: plane-all-modeset-transition
+Signed-off-by: Lyude <cpaul@redhat.com>
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+Cc: Matt Roper <matthew.d.roper@intel.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/intel_display.c |   93 ++++++++++++++--
+ drivers/gpu/drm/i915/intel_drv.h     |    7 +
+ drivers/gpu/drm/i915/intel_pm.c      |  200 +++++++----------------------------
+ 3 files changed, 132 insertions(+), 168 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -12967,16 +12967,23 @@ static void verify_wm_state(struct drm_c
+                         hw_entry->start, hw_entry->end);
+       }
+-      /* cursor */
+-      hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
+-      sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
+-
+-      if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
+-              DRM_ERROR("mismatch in DDB state pipe %c cursor "
+-                        "(expected (%u,%u), found (%u,%u))\n",
+-                        pipe_name(pipe),
+-                        sw_entry->start, sw_entry->end,
+-                        hw_entry->start, hw_entry->end);
++      /*
++       * cursor
++       * If the cursor plane isn't active, we may not have updated it's ddb
++       * allocation. In that case since the ddb allocation will be updated
++       * once the plane becomes visible, we can skip this check
++       */
++      if (intel_crtc->cursor_addr) {
++              hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
++              sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
++
++              if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
++                      DRM_ERROR("mismatch in DDB state pipe %c cursor "
++                                "(expected (%u,%u), found (%u,%u))\n",
++                                pipe_name(pipe),
++                                sw_entry->start, sw_entry->end,
++                                hw_entry->start, hw_entry->end);
++              }
+       }
+ }
+@@ -13728,6 +13735,65 @@ static void intel_update_crtcs(struct dr
+       }
+ }
++static void skl_update_crtcs(struct drm_atomic_state *state,
++                           unsigned int *crtc_vblank_mask)
++{
++      struct drm_device *dev = state->dev;
++      struct drm_i915_private *dev_priv = to_i915(dev);
++      struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
++      struct drm_crtc *crtc;
++      struct drm_crtc_state *old_crtc_state;
++      struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
++      struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
++      unsigned int updated = 0;
++      bool progress;
++      enum pipe pipe;
++
++      /*
++       * Whenever the number of active pipes changes, we need to make sure we
++       * update the pipes in the right order so that their ddb allocations
++       * never overlap with eachother inbetween CRTC updates. Otherwise we'll
++       * cause pipe underruns and other bad stuff.
++       */
++      do {
++              int i;
++              progress = false;
++
++              for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
++                      bool vbl_wait = false;
++                      unsigned int cmask = drm_crtc_mask(crtc);
++                      pipe = to_intel_crtc(crtc)->pipe;
++
++                      if (updated & cmask || !crtc->state->active)
++                              continue;
++                      if (skl_ddb_allocation_overlaps(state, cur_ddb, new_ddb,
++                                                      pipe))
++                              continue;
++
++                      updated |= cmask;
++
++                      /*
++                       * If this is an already active pipe, it's DDB changed,
++                       * and this isn't the last pipe that needs updating
++                       * then we need to wait for a vblank to pass for the
++                       * new ddb allocation to take effect.
++                       */
++                      if (!skl_ddb_allocation_equals(cur_ddb, new_ddb, pipe) &&
++                          !crtc->state->active_changed &&
++                          intel_state->wm_results.dirty_pipes != updated)
++                              vbl_wait = true;
++
++                      intel_update_crtc(crtc, state, old_crtc_state,
++                                        crtc_vblank_mask);
++
++                      if (vbl_wait)
++                              intel_wait_for_vblank(dev, pipe);
++
++                      progress = true;
++              }
++      } while (progress);
++}
++
+ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+ {
+       struct drm_device *dev = state->dev;
+@@ -15303,8 +15369,6 @@ void intel_init_display_hooks(struct drm
+               dev_priv->display.crtc_disable = i9xx_crtc_disable;
+       }
+-      dev_priv->display.update_crtcs = intel_update_crtcs;
+-
+       /* Returns the core display clock speed */
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+               dev_priv->display.get_display_clock_speed =
+@@ -15394,6 +15458,11 @@ void intel_init_display_hooks(struct drm
+                       skl_modeset_calc_cdclk;
+       }
++      if (dev_priv->info.gen >= 9)
++              dev_priv->display.update_crtcs = skl_update_crtcs;
++      else
++              dev_priv->display.update_crtcs = intel_update_crtcs;
++
+       switch (INTEL_INFO(dev_priv)->gen) {
+       case 2:
+               dev_priv->display.queue_flip = intel_gen2_queue_flip;
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -1720,6 +1720,13 @@ void skl_ddb_get_hw_state(struct drm_i91
+ bool skl_can_enable_sagv(struct drm_atomic_state *state);
+ int skl_enable_sagv(struct drm_i915_private *dev_priv);
+ int skl_disable_sagv(struct drm_i915_private *dev_priv);
++bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
++                             const struct skl_ddb_allocation *new,
++                             enum pipe pipe);
++bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
++                               const struct skl_ddb_allocation *old,
++                               const struct skl_ddb_allocation *new,
++                               enum pipe pipe);
+ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+                        const struct skl_wm_values *wm);
+ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3843,6 +3843,11 @@ void skl_write_plane_wm(struct intel_crt
+                          wm->plane[pipe][plane][level]);
+       }
+       I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
++
++      skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane),
++                          &wm->ddb.plane[pipe][plane]);
++      skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane),
++                          &wm->ddb.y_plane[pipe][plane]);
+ }
+ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+@@ -3859,170 +3864,46 @@ void skl_write_cursor_wm(struct intel_cr
+                          wm->plane[pipe][PLANE_CURSOR][level]);
+       }
+       I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
+-}
+-
+-static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+-                              const struct skl_wm_values *new)
+-{
+-      struct drm_device *dev = &dev_priv->drm;
+-      struct intel_crtc *crtc;
+-
+-      for_each_intel_crtc(dev, crtc) {
+-              int i;
+-              enum pipe pipe = crtc->pipe;
+-
+-              if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
+-                      continue;
+-              if (!crtc->active)
+-                      continue;
+-
+-              for (i = 0; i < intel_num_planes(crtc); i++) {
+-                      skl_ddb_entry_write(dev_priv,
+-                                          PLANE_BUF_CFG(pipe, i),
+-                                          &new->ddb.plane[pipe][i]);
+-                      skl_ddb_entry_write(dev_priv,
+-                                          PLANE_NV12_BUF_CFG(pipe, i),
+-                                          &new->ddb.y_plane[pipe][i]);
+-              }
+-              skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
+-                                  &new->ddb.plane[pipe][PLANE_CURSOR]);
+-      }
++      skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
++                          &wm->ddb.plane[pipe][PLANE_CURSOR]);
+ }
+-/*
+- * When setting up a new DDB allocation arrangement, we need to correctly
+- * sequence the times at which the new allocations for the pipes are taken into
+- * account or we'll have pipes fetching from space previously allocated to
+- * another pipe.
+- *
+- * Roughly the sequence looks like:
+- *  1. re-allocate the pipe(s) with the allocation being reduced and not
+- *     overlapping with a previous light-up pipe (another way to put it is:
+- *     pipes with their new allocation strickly included into their old ones).
+- *  2. re-allocate the other pipes that get their allocation reduced
+- *  3. allocate the pipes having their allocation increased
+- *
+- * Steps 1. and 2. are here to take care of the following case:
+- * - Initially DDB looks like this:
+- *     |   B    |   C    |
+- * - enable pipe A.
+- * - pipe B has a reduced DDB allocation that overlaps with the old pipe C
+- *   allocation
+- *     |  A  |  B  |  C  |
+- *
+- * We need to sequence the re-allocation: C, B, A (and not B, C, A).
+- */
+-
+-static void
+-skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
++bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
++                             const struct skl_ddb_allocation *new,
++                             enum pipe pipe)
+ {
+-      int plane;
+-
+-      DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
+-
+-      for_each_plane(dev_priv, pipe, plane) {
+-              I915_WRITE(PLANE_SURF(pipe, plane),
+-                         I915_READ(PLANE_SURF(pipe, plane)));
+-      }
+-      I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe)));
++      return new->pipe[pipe].start == old->pipe[pipe].start &&
++             new->pipe[pipe].end == old->pipe[pipe].end;
+ }
+-static bool
+-skl_ddb_allocation_included(const struct skl_ddb_allocation *old,
+-                          const struct skl_ddb_allocation *new,
+-                          enum pipe pipe)
++static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
++                                         const struct skl_ddb_entry *b)
+ {
+-      uint16_t old_size, new_size;
+-
+-      old_size = skl_ddb_entry_size(&old->pipe[pipe]);
+-      new_size = skl_ddb_entry_size(&new->pipe[pipe]);
+-
+-      return old_size != new_size &&
+-             new->pipe[pipe].start >= old->pipe[pipe].start &&
+-             new->pipe[pipe].end <= old->pipe[pipe].end;
++      return a->start < b->end && b->start < a->end;
+ }
+-static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
+-                              struct skl_wm_values *new_values)
++bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
++                               const struct skl_ddb_allocation *old,
++                               const struct skl_ddb_allocation *new,
++                               enum pipe pipe)
+ {
+-      struct drm_device *dev = &dev_priv->drm;
+-      struct skl_ddb_allocation *cur_ddb, *new_ddb;
+-      bool reallocated[I915_MAX_PIPES] = {};
+-      struct intel_crtc *crtc;
+-      enum pipe pipe;
+-
+-      new_ddb = &new_values->ddb;
+-      cur_ddb = &dev_priv->wm.skl_hw.ddb;
+-
+-      /*
+-       * First pass: flush the pipes with the new allocation contained into
+-       * the old space.
+-       *
+-       * We'll wait for the vblank on those pipes to ensure we can safely
+-       * re-allocate the freed space without this pipe fetching from it.
+-       */
+-      for_each_intel_crtc(dev, crtc) {
+-              if (!crtc->active)
+-                      continue;
+-
+-              pipe = crtc->pipe;
+-
+-              if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe))
+-                      continue;
+-
+-              skl_wm_flush_pipe(dev_priv, pipe, 1);
+-              intel_wait_for_vblank(dev, pipe);
+-
+-              reallocated[pipe] = true;
+-      }
+-
+-
+-      /*
+-       * Second pass: flush the pipes that are having their allocation
+-       * reduced, but overlapping with a previous allocation.
+-       *
+-       * Here as well we need to wait for the vblank to make sure the freed
+-       * space is not used anymore.
+-       */
+-      for_each_intel_crtc(dev, crtc) {
+-              if (!crtc->active)
+-                      continue;
++      struct drm_device *dev = state->dev;
++      struct intel_crtc *intel_crtc;
++      enum pipe otherp;
+-              pipe = crtc->pipe;
++      for_each_intel_crtc(dev, intel_crtc) {
++              otherp = intel_crtc->pipe;
+-              if (reallocated[pipe])
++              if (otherp == pipe)
+                       continue;
+-              if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) <
+-                  skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
+-                      skl_wm_flush_pipe(dev_priv, pipe, 2);
+-                      intel_wait_for_vblank(dev, pipe);
+-                      reallocated[pipe] = true;
+-              }
++              if (skl_ddb_entries_overlap(&new->pipe[pipe],
++                                          &old->pipe[otherp]))
++                      return true;
+       }
+-      /*
+-       * Third pass: flush the pipes that got more space allocated.
+-       *
+-       * We don't need to actively wait for the update here, next vblank
+-       * will just get more DDB space with the correct WM values.
+-       */
+-      for_each_intel_crtc(dev, crtc) {
+-              if (!crtc->active)
+-                      continue;
+-
+-              pipe = crtc->pipe;
+-
+-              /*
+-               * At this point, only the pipes more space than before are
+-               * left to re-allocate.
+-               */
+-              if (reallocated[pipe])
+-                      continue;
+-
+-              skl_wm_flush_pipe(dev_priv, pipe, 3);
+-      }
++      return false;
+ }
+ static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
+@@ -4224,7 +4105,7 @@ static void skl_update_wm(struct drm_crt
+       struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+       struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
+-      int pipe;
++      enum pipe pipe = intel_crtc->pipe;
+       if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
+               return;
+@@ -4233,15 +4114,22 @@ static void skl_update_wm(struct drm_crt
+       mutex_lock(&dev_priv->wm.wm_mutex);
+-      skl_write_wm_values(dev_priv, results);
+-      skl_flush_wm_values(dev_priv, results);
+-
+       /*
+-       * Store the new configuration (but only for the pipes that have
+-       * changed; the other values weren't recomputed).
++       * If this pipe isn't active already, we're going to be enabling it
++       * very soon. Since it's safe to update a pipe's ddb allocation while
++       * the pipe's shut off, just do so here. Already active pipes will have
++       * their watermarks updated once we update their planes.
+        */
+-      for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
+-              skl_copy_wm_for_pipe(hw_vals, results, pipe);
++      if (crtc->state->active_changed) {
++              int plane;
++
++              for (plane = 0; plane < intel_num_planes(intel_crtc); plane++)
++                      skl_write_plane_wm(intel_crtc, results, plane);
++
++              skl_write_cursor_wm(intel_crtc, results);
++      }
++
++      skl_copy_wm_for_pipe(hw_vals, results, pipe);
+       mutex_unlock(&dev_priv->wm.wm_mutex);
+ }
diff --git a/queue-4.8/drm-i915-skl-update-plane-watermarks-atomically-during-plane-updates.patch b/queue-4.8/drm-i915-skl-update-plane-watermarks-atomically-during-plane-updates.patch
new file mode 100644 (file)
index 0000000..d9798c4
--- /dev/null
@@ -0,0 +1,335 @@
+From 62e0fb880123c98793e5c3ba8355501b0305e92e Mon Sep 17 00:00:00 2001
+From: Lyude <cpaul@redhat.com>
+Date: Mon, 22 Aug 2016 12:50:08 -0400
+Subject: drm/i915/skl: Update plane watermarks atomically during plane updates
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lyude <cpaul@redhat.com>
+
+commit 62e0fb880123c98793e5c3ba8355501b0305e92e upstream.
+
+Thanks to Ville for suggesting this as a potential solution to pipe
+underruns on Skylake.
+
+On Skylake all of the registers for configuring planes, including the
+registers for configuring their watermarks, are double buffered. New
+values written to them won't take effect until said registers are
+"armed", which is done by writing to the PLANE_SURF (or in the case of
+cursor planes, the CURBASE register) register.
+
+With this in mind, up until now we've been updating watermarks on skl
+like this:
+
+  non-modeset {
+   - calculate (during atomic check phase)
+   - finish_atomic_commit:
+     - intel_pre_plane_update:
+        - intel_update_watermarks()
+     - {vblank happens; new watermarks + old plane values => underrun }
+     - drm_atomic_helper_commit_planes_on_crtc:
+        - start vblank evasion
+        - write new plane registers
+        - end vblank evasion
+  }
+
+  or
+
+  modeset {
+   - calculate (during atomic check phase)
+   - finish_atomic_commit:
+     - crtc_enable:
+        - intel_update_watermarks()
+     - {vblank happens; new watermarks + old plane values => underrun }
+     - drm_atomic_helper_commit_planes_on_crtc:
+        - start vblank evasion
+        - write new plane registers
+        - end vblank evasion
+  }
+
+Now we update watermarks atomically like this:
+
+  non-modeset {
+   - calculate (during atomic check phase)
+   - finish_atomic_commit:
+     - intel_pre_plane_update:
+        - intel_update_watermarks() (wm values aren't written yet)
+     - drm_atomic_helper_commit_planes_on_crtc:
+        - start vblank evasion
+        - write new plane registers
+        - write new wm values
+        - end vblank evasion
+  }
+
+  modeset {
+   - calculate (during atomic check phase)
+   - finish_atomic_commit:
+     - crtc_enable:
+        - intel_update_watermarks() (actual wm values aren't written
+          yet)
+     - drm_atomic_helper_commit_planes_on_crtc:
+        - start vblank evasion
+        - write new plane registers
+       - write new wm values
+        - end vblank evasion
+  }
+
+So this patch moves all of the watermark writes into the right place;
+inside of the vblank evasion where we update all of the registers for
+each plane. While this patch doesn't fix everything, it does allow us to
+update the watermark values in the way the hardware expects us to.
+
+Changes since original patch series:
+ - Remove mutex_lock/mutex_unlock since they don't do anything and we're
+   not touching global state
+ - Move skl_write_cursor_wm/skl_write_plane_wm functions into
+   intel_pm.c, make externally visible
+ - Add skl_write_plane_wm calls to skl_update_plane
+ - Fix conditional for for loop in skl_write_plane_wm (level < max_level
+   should be level <= max_level)
+ - Make diagram in commit more accurate to what's actually happening
+ - Add Fixes:
+
+Changes since v1:
+ - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
+   then just Skylake
+ - Update description to make it clear this patch doesn't fix everything
+ - Check if pipes were actually changed before writing watermarks
+
+Changes since v2:
+ - Write PIPE_WM_LINETIME during vblank evasion
+
+Changes since v3:
+ - Rebase against new SAGV patch changes
+
+Changes since v4:
+ - Add a parameter to choose what skl_wm_values struct to use when
+   writing new plane watermarks
+
+Changes since v5:
+ - Remove cursor ddb entry write in skl_write_cursor_wm(), defer until
+   patch 6
+ - Write WM_LINETIME in intel_begin_crtc_commit()
+
+Changes since v6:
+ - Remove redundant dirty_pipes check in skl_write_plane_wm (we check
+   this in all places where we call this function, and it was supposed
+   to have been removed earlier anyway)
+ - In i9xx_update_cursor(), use dev_priv->info.gen >= 9 instead of
+   IS_GEN9(dev_priv). We do this everywhere else and I'd imagine this
+   needs to be done for gen10 as well
+
+Changes since v7:
+ - Fix rebase fail (unused variable obj)
+ - Make struct skl_wm_values *wm const
+ - Fix indenting
+ - Use INTEL_GEN() instead of dev_priv->info.gen
+
+Changes since v8:
+ - Don't forget calls to skl_write_plane_wm() when disabling planes
+ - Use INTEL_GEN(), not INTEL_INFO()->gen in intel_begin_crtc_commit()
+
+Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
+Signed-off-by: Lyude <cpaul@redhat.com>
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Cc: stable@vger.kernel.org
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
+Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/gpu/drm/i915/intel_display.c |   21 +++++++++++++-
+ drivers/gpu/drm/i915/intel_drv.h     |    5 +++
+ drivers/gpu/drm/i915/intel_pm.c      |   50 +++++++++++++++++++++++------------
+ drivers/gpu/drm/i915/intel_sprite.c  |    6 ++++
+ 4 files changed, 64 insertions(+), 18 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -2980,6 +2980,7 @@ static void skylake_update_primary_plane
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
++      const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+       int pipe = intel_crtc->pipe;
+       u32 plane_ctl, stride_div, stride;
+       u32 tile_height, plane_offset, plane_size;
+@@ -3031,6 +3032,9 @@ static void skylake_update_primary_plane
+       intel_crtc->adjusted_x = x_offset;
+       intel_crtc->adjusted_y = y_offset;
++      if (wm->dirty_pipes & drm_crtc_mask(&intel_crtc->base))
++              skl_write_plane_wm(intel_crtc, wm, 0);
++
+       I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
+       I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
+       I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
+@@ -3061,7 +3065,10 @@ static void skylake_disable_primary_plan
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+-      int pipe = to_intel_crtc(crtc)->pipe;
++      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++      int pipe = intel_crtc->pipe;
++
++      skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
+       I915_WRITE(PLANE_CTL(pipe, 0), 0);
+       I915_WRITE(PLANE_SURF(pipe, 0), 0);
+@@ -10306,9 +10313,13 @@ static void i9xx_update_cursor(struct dr
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++      const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+       int pipe = intel_crtc->pipe;
+       uint32_t cntl = 0;
++      if (INTEL_GEN(dev_priv) >= 9 && wm->dirty_pipes & drm_crtc_mask(crtc))
++              skl_write_cursor_wm(intel_crtc, wm);
++
+       if (plane_state && plane_state->visible) {
+               cntl = MCURSOR_GAMMA_ENABLE;
+               switch (plane_state->base.crtc_w) {
+@@ -14221,10 +14232,12 @@ static void intel_begin_crtc_commit(stru
+                                   struct drm_crtc_state *old_crtc_state)
+ {
+       struct drm_device *dev = crtc->dev;
++      struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *old_intel_state =
+               to_intel_crtc_state(old_crtc_state);
+       bool modeset = needs_modeset(crtc->state);
++      enum pipe pipe = intel_crtc->pipe;
+       /* Perform vblank evasion around commit operation */
+       intel_pipe_update_start(intel_crtc);
+@@ -14239,8 +14252,12 @@ static void intel_begin_crtc_commit(stru
+       if (to_intel_crtc_state(crtc->state)->update_pipe)
+               intel_update_pipe_config(intel_crtc, old_intel_state);
+-      else if (INTEL_INFO(dev)->gen >= 9)
++      else if (INTEL_GEN(dev_priv) >= 9) {
+               skl_detach_scalers(intel_crtc);
++
++              I915_WRITE(PIPE_WM_LINETIME(pipe),
++                         dev_priv->wm.skl_hw.wm_linetime[pipe]);
++      }
+ }
+ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -1720,6 +1720,11 @@ void skl_ddb_get_hw_state(struct drm_i91
+ bool skl_can_enable_sagv(struct drm_atomic_state *state);
+ int skl_enable_sagv(struct drm_i915_private *dev_priv);
+ int skl_disable_sagv(struct drm_i915_private *dev_priv);
++void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
++                       const struct skl_wm_values *wm);
++void skl_write_plane_wm(struct intel_crtc *intel_crtc,
++                      const struct skl_wm_values *wm,
++                      int plane);
+ uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
+ bool ilk_disable_lp_wm(struct drm_device *dev);
+ int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3828,6 +3828,39 @@ static void skl_ddb_entry_write(struct d
+               I915_WRITE(reg, 0);
+ }
++void skl_write_plane_wm(struct intel_crtc *intel_crtc,
++                      const struct skl_wm_values *wm,
++                      int plane)
++{
++      struct drm_crtc *crtc = &intel_crtc->base;
++      struct drm_device *dev = crtc->dev;
++      struct drm_i915_private *dev_priv = to_i915(dev);
++      int level, max_level = ilk_wm_max_level(dev);
++      enum pipe pipe = intel_crtc->pipe;
++
++      for (level = 0; level <= max_level; level++) {
++              I915_WRITE(PLANE_WM(pipe, plane, level),
++                         wm->plane[pipe][plane][level]);
++      }
++      I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
++}
++
++void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
++                       const struct skl_wm_values *wm)
++{
++      struct drm_crtc *crtc = &intel_crtc->base;
++      struct drm_device *dev = crtc->dev;
++      struct drm_i915_private *dev_priv = to_i915(dev);
++      int level, max_level = ilk_wm_max_level(dev);
++      enum pipe pipe = intel_crtc->pipe;
++
++      for (level = 0; level <= max_level; level++) {
++              I915_WRITE(CUR_WM(pipe, level),
++                         wm->plane[pipe][PLANE_CURSOR][level]);
++      }
++      I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
++}
++
+ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+                               const struct skl_wm_values *new)
+ {
+@@ -3835,7 +3868,7 @@ static void skl_write_wm_values(struct d
+       struct intel_crtc *crtc;
+       for_each_intel_crtc(dev, crtc) {
+-              int i, level, max_level = ilk_wm_max_level(dev);
++              int i;
+               enum pipe pipe = crtc->pipe;
+               if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
+@@ -3843,21 +3876,6 @@ static void skl_write_wm_values(struct d
+               if (!crtc->active)
+                       continue;
+-              I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
+-
+-              for (level = 0; level <= max_level; level++) {
+-                      for (i = 0; i < intel_num_planes(crtc); i++)
+-                              I915_WRITE(PLANE_WM(pipe, i, level),
+-                                         new->plane[pipe][i][level]);
+-                      I915_WRITE(CUR_WM(pipe, level),
+-                                 new->plane[pipe][PLANE_CURSOR][level]);
+-              }
+-              for (i = 0; i < intel_num_planes(crtc); i++)
+-                      I915_WRITE(PLANE_WM_TRANS(pipe, i),
+-                                 new->plane_trans[pipe][i]);
+-              I915_WRITE(CUR_WM_TRANS(pipe),
+-                         new->plane_trans[pipe][PLANE_CURSOR]);
+-
+               for (i = 0; i < intel_num_planes(crtc); i++) {
+                       skl_ddb_entry_write(dev_priv,
+                                           PLANE_BUF_CFG(pipe, i),
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -203,6 +203,9 @@ skl_update_plane(struct drm_plane *drm_p
+       struct intel_plane *intel_plane = to_intel_plane(drm_plane);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
++      const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
++      struct drm_crtc *crtc = crtc_state->base.crtc;
++      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       const int pipe = intel_plane->pipe;
+       const int plane = intel_plane->plane + 1;
+       u32 plane_ctl, stride_div, stride;
+@@ -238,6 +241,9 @@ skl_update_plane(struct drm_plane *drm_p
+       crtc_w--;
+       crtc_h--;
++      if (wm->dirty_pipes & drm_crtc_mask(crtc))
++              skl_write_plane_wm(intel_crtc, wm, plane);
++
+       if (key->flags) {
+               I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
+               I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
index a43c650eee2f5c4a01a590fff14cc4664134f003..8612ba30f739be93773aca339b07d3bcaa154fe9 100644 (file)
@@ -16,3 +16,8 @@ drm-vmwgfx-limit-the-user-space-command-buffer-size.patch
 drm-fsl-dcu-fix-endian-issue-when-using-clk_register_divider.patch
 drm-amd-powerplay-fix-mclk-not-switching-back-after-multi-head-was-disabled.patch
 hid-add-quirk-for-akai-midimix.patch
+drm-i915-skl-update-plane-watermarks-atomically-during-plane-updates.patch
+drm-i915-move-crtc-updating-in-atomic_commit-into-it-s-own-hook.patch
+drm-i915-skl-update-ddb-values-atomically-with-wms-plane-attrs.patch
+drm-i915-skl-don-t-try-to-update-plane-watermarks-if-they-haven-t-changed.patch
+drm-i915-gen9-only-add-the-planes-actually-affected-by-ddb-changes.patch