| From 9d0bbc505e364fc11a175cba1bb15bd1c6e6a10a Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> |
| Date: Fri, 11 Oct 2013 19:39:52 +0300 |
| Subject: drm/i915: Improve watermark dirtyness checks |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| Currently hsw_write_vm_values() may write to certain watermark |
| registers needlessly. For instance if only, say, LP3 changes, |
| the current code will again disable all LP1+ watermarks even |
| though only LP3 needs to be reconfigured. |
| |
| Add an easy to read function that will compute the dirtyness of the |
| watermarks, and use that information to further optimize the watermark |
| programming. |
| |
| v2: Disable LP1+ watermarks around changing LP0 watermarks for Paulo |
| |
| Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 49a687c471396d063bb3d3cf04d62568efe7ec5e) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/intel_pm.c | 98 +++++++++++++++++++++++++++++++++-------- |
| 1 file changed, 80 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c |
| index 6d3d5f62dd6b..6d0c3d0e80fd 100644 |
| --- a/drivers/gpu/drm/i915/intel_pm.c |
| +++ b/drivers/gpu/drm/i915/intel_pm.c |
| @@ -2776,6 +2776,66 @@ static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, |
| } |
| } |
| |
| +/* dirty bits used to track which watermarks need changes */ |
| +#define WM_DIRTY_PIPE(pipe) (1 << (pipe)) |
| +#define WM_DIRTY_LINETIME(pipe) (1 << (8 + (pipe))) |
| +#define WM_DIRTY_LP(wm_lp) (1 << (15 + (wm_lp))) |
| +#define WM_DIRTY_LP_ALL (WM_DIRTY_LP(1) | WM_DIRTY_LP(2) | WM_DIRTY_LP(3)) |
| +#define WM_DIRTY_FBC (1 << 24) |
| +#define WM_DIRTY_DDB (1 << 25) |
| + |
| +static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, |
| + const struct hsw_wm_values *old, |
| + const struct hsw_wm_values *new) |
| +{ |
| + unsigned int dirty = 0; |
| + enum pipe pipe; |
| + int wm_lp; |
| + |
| + for_each_pipe(pipe) { |
| + if (old->wm_linetime[pipe] != new->wm_linetime[pipe]) { |
| + dirty |= WM_DIRTY_LINETIME(pipe); |
| + /* Must disable LP1+ watermarks too */ |
| + dirty |= WM_DIRTY_LP_ALL; |
| + } |
| + |
| + if (old->wm_pipe[pipe] != new->wm_pipe[pipe]) { |
| + dirty |= WM_DIRTY_PIPE(pipe); |
| + /* Must disable LP1+ watermarks too */ |
| + dirty |= WM_DIRTY_LP_ALL; |
| + } |
| + } |
| + |
| + if (old->enable_fbc_wm != new->enable_fbc_wm) { |
| + dirty |= WM_DIRTY_FBC; |
| + /* Must disable LP1+ watermarks too */ |
| + dirty |= WM_DIRTY_LP_ALL; |
| + } |
| + |
| + if (old->partitioning != new->partitioning) { |
| + dirty |= WM_DIRTY_DDB; |
| + /* Must disable LP1+ watermarks too */ |
| + dirty |= WM_DIRTY_LP_ALL; |
| + } |
| + |
| + /* LP1+ watermarks already deemed dirty, no need to continue */ |
| + if (dirty & WM_DIRTY_LP_ALL) |
| + return dirty; |
| + |
| + /* Find the lowest numbered LP1+ watermark in need of an update... */ |
| + for (wm_lp = 1; wm_lp <= 3; wm_lp++) { |
| + if (old->wm_lp[wm_lp - 1] != new->wm_lp[wm_lp - 1] || |
| + old->wm_lp_spr[wm_lp - 1] != new->wm_lp_spr[wm_lp - 1]) |
| + break; |
| + } |
| + |
| + /* ...and mark it and all higher numbered LP1+ watermarks as dirty */ |
| + for (; wm_lp <= 3; wm_lp++) |
| + dirty |= WM_DIRTY_LP(wm_lp); |
| + |
| + return dirty; |
| +} |
| + |
| /* |
| * The spec says we shouldn't write when we don't need, because every write |
| * causes WMs to be re-evaluated, expending some power. |
| @@ -2784,6 +2844,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, |
| struct hsw_wm_values *results) |
| { |
| struct hsw_wm_values previous; |
| + unsigned int dirty; |
| uint32_t val; |
| |
| previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); |
| @@ -2804,31 +2865,32 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, |
| |
| previous.enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); |
| |
| - if (memcmp(results, &previous, sizeof(*results)) == 0) |
| + dirty = ilk_compute_wm_dirty(dev_priv->dev, &previous, results); |
| + if (!dirty) |
| return; |
| |
| - if (previous.wm_lp[2] != 0) |
| + if (dirty & WM_DIRTY_LP(3) && previous.wm_lp[2] != 0) |
| I915_WRITE(WM3_LP_ILK, 0); |
| - if (previous.wm_lp[1] != 0) |
| + if (dirty & WM_DIRTY_LP(2) && previous.wm_lp[1] != 0) |
| I915_WRITE(WM2_LP_ILK, 0); |
| - if (previous.wm_lp[0] != 0) |
| + if (dirty & WM_DIRTY_LP(1) && previous.wm_lp[0] != 0) |
| I915_WRITE(WM1_LP_ILK, 0); |
| |
| - if (previous.wm_pipe[0] != results->wm_pipe[0]) |
| + if (dirty & WM_DIRTY_PIPE(PIPE_A)) |
| I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); |
| - if (previous.wm_pipe[1] != results->wm_pipe[1]) |
| + if (dirty & WM_DIRTY_PIPE(PIPE_B)) |
| I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]); |
| - if (previous.wm_pipe[2] != results->wm_pipe[2]) |
| + if (dirty & WM_DIRTY_PIPE(PIPE_C)) |
| I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]); |
| |
| - if (previous.wm_linetime[0] != results->wm_linetime[0]) |
| + if (dirty & WM_DIRTY_LINETIME(PIPE_A)) |
| I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]); |
| - if (previous.wm_linetime[1] != results->wm_linetime[1]) |
| + if (dirty & WM_DIRTY_LINETIME(PIPE_B)) |
| I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]); |
| - if (previous.wm_linetime[2] != results->wm_linetime[2]) |
| + if (dirty & WM_DIRTY_LINETIME(PIPE_C)) |
| I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); |
| |
| - if (previous.partitioning != results->partitioning) { |
| + if (dirty & WM_DIRTY_DDB) { |
| val = I915_READ(WM_MISC); |
| if (results->partitioning == INTEL_DDB_PART_1_2) |
| val &= ~WM_MISC_DATA_PARTITION_5_6; |
| @@ -2837,7 +2899,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, |
| I915_WRITE(WM_MISC, val); |
| } |
| |
| - if (previous.enable_fbc_wm != results->enable_fbc_wm) { |
| + if (dirty & WM_DIRTY_FBC) { |
| val = I915_READ(DISP_ARB_CTL); |
| if (results->enable_fbc_wm) |
| val &= ~DISP_FBC_WM_DIS; |
| @@ -2846,18 +2908,18 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, |
| I915_WRITE(DISP_ARB_CTL, val); |
| } |
| |
| - if (previous.wm_lp_spr[0] != results->wm_lp_spr[0]) |
| + if (dirty & WM_DIRTY_LP(1) && previous.wm_lp_spr[0] != results->wm_lp_spr[0]) |
| I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); |
| - if (previous.wm_lp_spr[1] != results->wm_lp_spr[1]) |
| + if (dirty & WM_DIRTY_LP(2) && previous.wm_lp_spr[1] != results->wm_lp_spr[1]) |
| I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); |
| - if (previous.wm_lp_spr[2] != results->wm_lp_spr[2]) |
| + if (dirty & WM_DIRTY_LP(3) && previous.wm_lp_spr[2] != results->wm_lp_spr[2]) |
| I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); |
| |
| - if (results->wm_lp[0] != 0) |
| + if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) |
| I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); |
| - if (results->wm_lp[1] != 0) |
| + if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0) |
| I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); |
| - if (results->wm_lp[2] != 0) |
| + if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0) |
| I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); |
| |
| dev_priv->wm.hw = *results; |
| -- |
| 1.8.5.rc3 |
| |