[Intel-gfx] [PATCH] drm/i915/skl: distribute DDB based on panel resolution

Chris Wilson chris at chris-wilson.co.uk
Mon Jul 30 15:38:15 UTC 2018


Quoting Mahesh Kumar (2018-07-30 15:12:02)
> We distribute DDB equally among all pipes irrespective of display
> buffer requirement of each pipe. This leads to a situation where high
> resolution y-tiled display can not be enabled with 2 low resolution
> displays.
> 
> Main contributing factor for DDB requirement is width of the display.
> This patch make changes to distribute ddb based on display width.
> So display with higher width will get bigger chunk of DDB.
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107113
> Cc: raviraj.p.sitaram at intel.com
> Signed-off-by: Mahesh Kumar <mahesh1.kumar at intel.com>
> ---
>  drivers/gpu/drm/i915/intel_pm.c | 55 +++++++++++++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 7312ecb73415..e092f0deb93d 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3814,8 +3814,14 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
>         struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
>         struct drm_i915_private *dev_priv = to_i915(dev);
>         struct drm_crtc *for_crtc = cstate->base.crtc;
> +       enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe;
> +       const struct drm_crtc_state *crtc_state;
> +       const struct drm_crtc *crtc;
> +       u32 pipe_width[I915_MAX_PIPES] = {0};
> +       u32 total_width = 0, width_before_pipe = 0;
>         unsigned int pipe_size, ddb_size;
> -       int nth_active_pipe;
> +       u16 ddb_size_before_pipe;
> +       u32 i;
>  
>         if (WARN_ON(!state) || !cstate->base.active) {
>                 alloc->start = 0;
> @@ -3833,14 +3839,14 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
>                                       *num_active, ddb);
>  
>         /*
> -        * If the state doesn't change the active CRTC's, then there's
> -        * no need to recalculate; the existing pipe allocation limits
> -        * should remain unchanged.  Note that we're safe from racing
> -        * commits since any racing commit that changes the active CRTC
> -        * list would need to grab _all_ crtc locks, including the one
> -        * we currently hold.
> +        * If the state doesn't change the active CRTC's or there is no
> +        * modeset request, then there's no need to recalculate;
> +        * the existing pipe allocation limits should remain unchanged.
> +        * Note that we're safe from racing commits since any racing commit
> +        * that changes the active CRTC list or do modeset would need to
> +        * grab _all_ crtc locks, including the one we currently hold.
>          */
> -       if (!intel_state->active_pipe_changes) {
> +       if (!intel_state->active_pipe_changes && !intel_state->modeset) {
>                 /*
>                  * alloc may be cleared by clear_intel_crtc_state,
>                  * copy from old state to be sure
> @@ -3849,10 +3855,33 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
>                 return;
>         }
>  
> -       nth_active_pipe = hweight32(intel_state->active_crtcs &
> -                                   (drm_crtc_mask(for_crtc) - 1));
> -       pipe_size = ddb_size / hweight32(intel_state->active_crtcs);
> -       alloc->start = nth_active_pipe * ddb_size / *num_active;
> +       /*
> +        * Watermark/ddb requirement highly depends upon width of the
> +        * framebuffer, So instead of allocating DDB equally among pipes
> +        * distribute DDB based on resolution/width of the display.
> +        */
> +       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +               const struct drm_display_mode *adjusted_mode;
> +               int hdisplay, vdisplay;
> +               enum pipe pipe;
> +
> +               if (!crtc_state->enable)
> +                       continue;
> +
> +               pipe = to_intel_crtc(crtc)->pipe;
> +               adjusted_mode = &crtc_state->adjusted_mode;
> +               drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay);
> +               pipe_width[pipe] = hdisplay;
> +               total_width += pipe_width[pipe];
> +
> +               if (pipe < for_pipe)
> +                       width_before_pipe += pipe_width[pipe];
> +       }
> +
> +       ddb_size_before_pipe = div_u64(ddb_size * width_before_pipe,
> +                                      total_width);

ddb_size is unsigned int (u32)
width_before_pipe is u32
ddb_size_before_pipe is u16

That mismash of types is itself perplexing, but u32*u16 is only u32, you
need to cast it to u64 to avoid the overflow: i.e.
	div_u64(mul_u32_u32(ddb_size, width_before_pipe),
	        total_width);

But ddb_size_before_pipe obviously need to be the same type as ddb_size,
and if u16 is good enough, then you do not need a 64b divide!

> +       pipe_size = div_u64(ddb_size * pipe_width[for_pipe], total_width);

So why did you store all pipe_width?

And are not all the previous pipes stored in their respective cstate? So
alloc->start = &previous_cstate->wm.skl.ddb->end;

Looking at the earlier results seems far more robust.
-Chris


More information about the Intel-gfx mailing list