2013/10/11 <ville.syrjala@xxxxxxxxxxxxxxx>: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > 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 Reviewed-by: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > 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 bed96fb..c3e5c0b 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.1.5 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Paulo Zanoni _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx