On Wed, Oct 23, 2019 at 12:08:03PM +0300, Stanislav Lisovskiy wrote: > Currently intel_can_enable_sagv function contains > a mix of workarounds for different platforms > some of them are not valid for gens >= 11 already, > so lets split it into separate functions. > > v2: > - Rework watermark calculation algorithm to > attempt to calculate Level 0 watermark > with added sagv block time latency and > check if it fits in DBuf in order to > determine if SAGV can be enabled already > at this stage, just as BSpec 49325 states. > if that fails rollback to usual Level 0 > latency and disable SAGV. > - Remove unneeded tabs(James Ausmus) > > v3: Rebased the patch > > Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@xxxxxxxxx> > Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxx> > Cc: James Ausmus <james.ausmus@xxxxxxxxx> > --- > .../drm/i915/display/intel_display_types.h | 8 + > drivers/gpu/drm/i915/intel_pm.c | 228 +++++++++++++++++- > 2 files changed, 228 insertions(+), 8 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h > index 8358152e403e..f09c80c96470 100644 > --- a/drivers/gpu/drm/i915/display/intel_display_types.h > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h > @@ -490,6 +490,13 @@ struct intel_atomic_state { > */ > u8 active_pipe_changes; > > + /* > + * For Gen12 only after calculating watermarks with > + * additional latency, we can determine if SAGV can be enabled > + * or not for that particular configuration. > + */ > + bool gen12_can_sagv; > + > u8 active_pipes; > /* minimum acceptable cdclk for each pipe */ > int min_cdclk[I915_MAX_PIPES]; > @@ -642,6 +649,7 @@ struct skl_plane_wm { > struct skl_wm_level wm[8]; > struct skl_wm_level uv_wm[8]; > struct skl_wm_level trans_wm; > + struct skl_wm_level sagv_wm_l0; > bool is_planar; > }; > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c > index 362234449087..c0419e4d83de 100644 > --- a/drivers/gpu/drm/i915/intel_pm.c > +++ b/drivers/gpu/drm/i915/intel_pm.c > @@ -3751,7 +3751,7 @@ intel_disable_sagv(struct drm_i915_private *dev_priv) > return 0; > } > > -bool intel_can_enable_sagv(struct intel_atomic_state *state) > +bool skl_can_enable_sagv(struct intel_atomic_state *state) > { > struct drm_device *dev = state->base.dev; > struct drm_i915_private *dev_priv = to_i915(dev); > @@ -3817,6 +3817,75 @@ bool intel_can_enable_sagv(struct intel_atomic_state *state) > return true; > } > > +bool icl_can_enable_sagv(struct intel_atomic_state *state) > +{ > + struct drm_device *dev = state->base.dev; > + struct drm_i915_private *dev_priv = to_i915(dev); > + struct intel_crtc *crtc; > + struct intel_crtc_state *new_crtc_state; > + int level, latency; > + int i; > + int plane_id; > + > + if (!intel_has_sagv(dev_priv)) > + return false; > + > + /* > + * If there are no active CRTCs, no additional checks need be performed > + */ > + if (hweight8(state->active_pipes) == 0) > + return true; > + > + for_each_new_intel_crtc_in_state(state, crtc, > + new_crtc_state, i) { > + > + if (crtc->base.state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) > + return false; > + > + if (!new_crtc_state->base.enable) > + continue; > + > + for_each_plane_id_on_crtc(crtc, plane_id) { > + struct skl_plane_wm *wm = > + &new_crtc_state->wm.skl.optimal.planes[plane_id]; > + > + /* Skip this plane if it's not enabled */ > + if (!wm->wm[0].plane_en) > + continue; > + > + /* Find the highest enabled wm level for this plane */ > + for (level = ilk_wm_max_level(dev_priv); > + !wm->wm[level].plane_en; --level) > + { } > + > + latency = dev_priv->wm.skl_latency[level]; > + > + /* > + * If any of the planes on this pipe don't enable wm levels that > + * incur memory latencies higher than sagv_block_time_us we > + * can't enable SAGV. > + */ > + if (latency < dev_priv->sagv_block_time_us) > + return false; > + } > + } > + > + return true; > +} > + > +bool intel_can_enable_sagv(struct intel_atomic_state *state) > +{ > + struct drm_device *dev = state->base.dev; > + struct drm_i915_private *dev_priv = to_i915(dev); > + > + if (INTEL_GEN(dev_priv) >= 12) > + return state->gen12_can_sagv; This loses the interlaced mode check that the skl and icl functions have, which is still needed for TGL > + else if (INTEL_GEN(dev_priv) == 11) > + return icl_can_enable_sagv(state); > + > + return skl_can_enable_sagv(state); > +} > + > static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, > const struct intel_crtc_state *crtc_state, > const u64 total_data_rate, > @@ -3936,6 +4005,7 @@ static int skl_compute_wm_params(const struct intel_crtc_state *crtc_state, > int color_plane); > static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, > int level, > + u32 latency, > const struct skl_wm_params *wp, > const struct skl_wm_level *result_prev, > struct skl_wm_level *result /* out */); > @@ -3958,7 +4028,8 @@ skl_cursor_allocation(const struct intel_crtc_state *crtc_state, > WARN_ON(ret); > > for (level = 0; level <= max_level; level++) { > - skl_compute_plane_wm(crtc_state, level, &wp, &wm, &wm); > + u32 latency = dev_priv->wm.skl_latency[level]; > + skl_compute_plane_wm(crtc_state, level, latency, &wp, &wm, &wm); > if (wm.min_ddb_alloc == U16_MAX) > break; > > @@ -4310,6 +4381,73 @@ icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state, > return total_data_rate; > } > > +static int > +tgl_check_pipe_fits_sagv_wm(struct intel_crtc_state *crtc_state, > + struct skl_ddb_allocation *ddb /* out */) > +{ > + struct drm_crtc *crtc = crtc_state->base.crtc; > + struct drm_i915_private *dev_priv = to_i915(crtc->dev); > + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > + struct skl_ddb_entry *alloc = &crtc_state->wm.skl.ddb; > + u16 alloc_size; > + u16 total[I915_MAX_PLANES] = {}; > + u64 total_data_rate; > + enum plane_id plane_id; > + int num_active; > + u64 plane_data_rate[I915_MAX_PLANES] = {}; > + u64 uv_plane_data_rate[I915_MAX_PLANES] = {}; > + u32 blocks; > + > + if (INTEL_GEN(dev_priv) >= 11) > + total_data_rate = > + icl_get_total_relative_data_rate(crtc_state, > + plane_data_rate); This function is already only called on gen12+ - could drop the if check, and the entire else block. > + else > + total_data_rate = > + skl_get_total_relative_data_rate(crtc_state, > + plane_data_rate, > + uv_plane_data_rate); > + > + > + skl_ddb_get_pipe_allocation_limits(dev_priv, crtc_state, total_data_rate, > + ddb, alloc, &num_active); > + alloc_size = skl_ddb_entry_size(alloc); > + if (alloc_size == 0) > + return -ENOSPC; > + > + /* Allocate fixed number of blocks for cursor. */ > + total[PLANE_CURSOR] = skl_cursor_allocation(crtc_state, num_active); > + alloc_size -= total[PLANE_CURSOR]; > + crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR].start = > + alloc->end - total[PLANE_CURSOR]; > + crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end; > + > + /* > + * Do check if we can fit L0 + sagv_block_time and > + * disable SAGV if we can't. > + */ > + blocks = 0; > + for_each_plane_id_on_crtc(intel_crtc, plane_id) { > + const struct skl_plane_wm *wm = > + &crtc_state->wm.skl.optimal.planes[plane_id]; > + > + if (plane_id == PLANE_CURSOR) { > + if (WARN_ON(wm->sagv_wm_l0.min_ddb_alloc > > + total[PLANE_CURSOR])) { > + blocks = U32_MAX; > + break; > + } > + continue; > + } > + > + blocks += wm->sagv_wm_l0.min_ddb_alloc; > + if (blocks > alloc_size) { > + return -ENOSPC; > + } > + } > + return 0; > +} > + > static int > skl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state, > struct skl_ddb_allocation *ddb /* out */) > @@ -4739,12 +4877,12 @@ static bool skl_wm_has_lines(struct drm_i915_private *dev_priv, int level) > > static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, > int level, > + u32 latency, > const struct skl_wm_params *wp, > const struct skl_wm_level *result_prev, > struct skl_wm_level *result /* out */) > { > struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); > - u32 latency = dev_priv->wm.skl_latency[level]; > uint_fixed_16_16_t method1, method2; > uint_fixed_16_16_t selected_result; > u32 res_blocks, res_lines, min_ddb_alloc = 0; > @@ -4865,19 +5003,45 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, > static void > skl_compute_wm_levels(const struct intel_crtc_state *crtc_state, > const struct skl_wm_params *wm_params, > - struct skl_wm_level *levels) > + struct skl_plane_wm *plane_wm, > + bool yuv) > { > struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); > int level, max_level = ilk_wm_max_level(dev_priv); > + /* > + * Check which kind of plane is it and based on that calculate > + * correspondent WM levels. > + */ > + struct skl_wm_level *levels = yuv ? plane_wm->uv_wm : plane_wm->wm; > struct skl_wm_level *result_prev = &levels[0]; > > for (level = 0; level <= max_level; level++) { > struct skl_wm_level *result = &levels[level]; > + u32 latency = dev_priv->wm.skl_latency[level]; > > - skl_compute_plane_wm(crtc_state, level, wm_params, > - result_prev, result); > + skl_compute_plane_wm(crtc_state, level, latency, > + wm_params, result_prev, result); > > result_prev = result; > + if (level == 0) { > + /* > + * For Gen12 if it is an L0 we need to also > + * consider sagv_block_time when calculating > + * L0 watermark - we will need that when making > + * a decision whether enable SAGV or not. > + * For older gens we agreed to copy L0 value for > + * compatibility. > + */ > + if ((INTEL_GEN(dev_priv) >= 12)) { > + latency += dev_priv->sagv_block_time_us; > + skl_compute_plane_wm(crtc_state, level, latency, > + wm_params, result_prev, > + &plane_wm->sagv_wm_l0); > + } > + else > + memcpy(&plane_wm->sagv_wm_l0, &levels[0], > + sizeof(struct skl_wm_level)); > + } > } > } > > @@ -4971,7 +5135,7 @@ static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, > if (ret) > return ret; > > - skl_compute_wm_levels(crtc_state, &wm_params, wm->wm); > + skl_compute_wm_levels(crtc_state, &wm_params, wm, false); > skl_compute_transition_wm(crtc_state, &wm_params, wm); > > return 0; > @@ -4993,7 +5157,7 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, > if (ret) > return ret; > > - skl_compute_wm_levels(crtc_state, &wm_params, wm->uv_wm); > + skl_compute_wm_levels(crtc_state, &wm_params, wm, true); > > return 0; > } > @@ -5544,10 +5708,13 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, > static int > skl_compute_wm(struct intel_atomic_state *state) > { > + struct drm_device *dev = state->base.dev; > + const struct drm_i915_private *dev_priv = to_i915(dev); > struct intel_crtc *crtc; > struct intel_crtc_state *new_crtc_state; > struct intel_crtc_state *old_crtc_state; > struct skl_ddb_values *results = &state->wm_results; > + struct skl_ddb_allocation *ddb = &state->wm_results.ddb; > int ret, i; > > /* Clear all dirty flags */ > @@ -5557,6 +5724,8 @@ skl_compute_wm(struct intel_atomic_state *state) > if (ret) > return ret; > > + state->gen12_can_sagv = false; > + > /* > * Calculate WM's for all pipes that are part of this transaction. > * Note that skl_ddb_add_affected_pipes may have added more CRTC's that > @@ -5579,6 +5748,49 @@ skl_compute_wm(struct intel_atomic_state *state) > results->dirty_pipes |= BIT(crtc->pipe); > } > > + if (INTEL_GEN(dev_priv) < 12) > + goto compute_ddb; I understand why you are goto'ing to avoid the extra indent below - can the block between here and compute_ddb just be extracted to a separate function instead? -James > + > + /* > + * Lets assume we can tolerate SAGV for now, > + * until watermark calculations prove the opposite > + * if any of the pipe planes in the state will > + * fail the requirements it will be assigned to false > + * in skl_compute_ddb. > + */ > + state->gen12_can_sagv = true; > + > + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, > + new_crtc_state, i) { > + ret = tgl_check_pipe_fits_sagv_wm(new_crtc_state, ddb); > + if (ret) { > + state->gen12_can_sagv = false; > + break; > + } > + } > + > + if (state->gen12_can_sagv) { > + /* > + * If we determined that we can actually enable SAGV, then > + * actually use those levels tgl_check_pipe_fits_sagv_wm > + * has already taken care of checking if L0 + sagv block time > + * fits into ddb. > + */ > + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, > + new_crtc_state, i) { > + struct intel_plane *plane; > + for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { > + enum plane_id plane_id = plane->id; > + struct skl_plane_wm *plane_wm = \ > + &new_crtc_state->wm.skl.optimal.planes[plane_id]; > + struct skl_wm_level *sagv_wm0 = &plane_wm->sagv_wm_l0; > + struct skl_wm_level *l0_wm0 = &plane_wm->wm[0]; > + memcpy(l0_wm0, sagv_wm0, sizeof(struct skl_wm_level)); > + } > + } > + } > + > +compute_ddb: > ret = skl_compute_ddb(state); > if (ret) > return ret; > -- > 2.17.1 > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx