From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Imre Deak <imre.deak@intel.com>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH v2 08/22] drm/i915/fdi: Improve FDI BW sharing between pipe B and C
Date: Mon, 11 Sep 2023 21:59:34 +0300 [thread overview]
Message-ID: <ZP9jltWAdNY7LJpM@intel.com> (raw)
In-Reply-To: <20230824080517.693621-9-imre.deak@intel.com>
On Thu, Aug 24, 2023 at 11:05:03AM +0300, Imre Deak wrote:
> At the moment modesetting pipe C on IVB will fail if pipe B uses 4 FDI
> lanes. Make the BW sharing more dynamic by trying to reduce pipe B's
> link bpp in this case, until pipe B uses only up to 2 FDI lanes.
>
> For this instead of the encoder compute config retry loop - which
> reduced link bpp only for the encoder's pipe - check the overall BW
> limits after all CRTC states have been computed and if the check fails
> reduce the maximum link bpp for a selected pipe (for FDI pipe B or C as
> required) and recompute all the CRTC states. Retry this sequence until
> either the overall BW limit check passes, or further bpp reduction is
> not possible (because all pipes/encoders sharing the link BW reached
> their minimum link bpp).
>
> This change also prepares for an upcoming patch resolving BW limits in
> a similar way on MST links as well.
>
> v2:
> - Rename intel_crtc_state::max_link_bpp to max_link_bpp_x16 and
> intel_link_bw_limits::max_bpp to max_bpp_x16. (Jani)
> - Increase back pipe B's link bpp if earlier it was limited due to
> pipe C and pipe C gets later disabled.
> - Don't assume that a CRTC is already in the atomic state, while
> reducing its link bpp.
> - Add DocBook description to intel_fdi_atomic_check_link().
>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
> drivers/gpu/drm/i915/display/g4x_hdmi.c | 5 +-
> drivers/gpu/drm/i915/display/intel_atomic.c | 207 ++++++++++++++++++
> drivers/gpu/drm/i915/display/intel_atomic.h | 8 +
> drivers/gpu/drm/i915/display/intel_crt.c | 7 +
> drivers/gpu/drm/i915/display/intel_crtc.c | 1 +
> drivers/gpu/drm/i915/display/intel_display.c | 44 ++--
> drivers/gpu/drm/i915/display/intel_display.h | 4 +
> .../drm/i915/display/intel_display_types.h | 9 +-
> drivers/gpu/drm/i915/display/intel_dp.c | 3 +-
> drivers/gpu/drm/i915/display/intel_fdi.c | 137 ++++++++++--
> drivers/gpu/drm/i915/display/intel_fdi.h | 5 +
> drivers/gpu/drm/i915/display/intel_lvds.c | 9 +-
> drivers/gpu/drm/i915/display/intel_sdvo.c | 9 +-
> 13 files changed, 404 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
> index 634b14116d9dd..ebbceddc13259 100644
> --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
> +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
> @@ -133,8 +133,11 @@ static int g4x_hdmi_compute_config(struct intel_encoder *encoder,
> struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> struct drm_i915_private *i915 = to_i915(encoder->base.dev);
>
> - if (HAS_PCH_SPLIT(i915))
> + if (HAS_PCH_SPLIT(i915)) {
> crtc_state->has_pch_encoder = true;
> + if (!intel_atomic_compute_pipe_bpp(crtc_state))
> + return -EINVAL;
> + }
>
> if (IS_G4X(i915))
> crtc_state->has_hdmi_sink = g4x_compute_has_hdmi_sink(state, crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
> index 7cf51dd8c0567..ee4cbf80ddb55 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.c
Not convinced we should put anything there. I think I mostly managed to
move a bunch or semi-random stuff out now, so all it more or less has is
the struct intel_atomic_state alloc/free stuff.
You have intel_atomic_check() in intel_display.c and the lower level
intel_atomic_check_config() is also there, but now the middle man
intel_atomic_check_config_and_link() ended up in intel_atomic.c for
whatever reason. I'd just shove all of it into intel_display.c.
The patch is also rather massive. Can we try to chunk it up to
eg. something like:
1) add the new infrastructure
2) convert the fdi retry stuff to use the new infrastructure
3) add intel_fdi_add_affected_crtcs() (which seems more or less
independent from the rest of the fdi conversion?)
?
> @@ -38,6 +38,7 @@
> #include "intel_atomic.h"
> #include "intel_cdclk.h"
> #include "intel_display_types.h"
> +#include "intel_fdi.h"
> #include "intel_global_state.h"
> #include "intel_hdcp.h"
> #include "intel_psr.h"
> @@ -358,3 +359,209 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
>
> return to_intel_crtc_state(crtc_state);
> }
> +
> +/**
> + * intel_atomic_compute_pipe_bpp - compute pipe bpp limited by max link bpp
> + * @crtc_state: the crtc state
> + *
> + * Compute the pipe bpp limited by the CRTC's maximum link bpp. Encoders can
> + * call this function during state computation in the simple case where the
> + * link bpp will always match the pipe bpp. This is the case for all non-DP
> + * encoders, while DP encoders will use a link bpp lower than pipe bpp in case
> + * of DSC compression.
> + *
> + * Returns %true in case of success, %false if pipe bpp would need to be
> + * reduced below its valid range.
> + */
> +bool intel_atomic_compute_pipe_bpp(struct intel_crtc_state *crtc_state)
> +{
> + int pipe_bpp = min(crtc_state->pipe_bpp,
> + to_bpp_int(crtc_state->max_link_bpp_x16));
> +
> + pipe_bpp = rounddown(pipe_bpp, 2 * 3);
> +
> + if (pipe_bpp < 6 * 3)
> + return false;
> +
> + crtc_state->pipe_bpp = pipe_bpp;
> +
> + return true;
> +}
> +
> +/**
> + * intel_atomic_reduce_link_bpp - reduce maximum link bpp for a selected pipe
> + * @state: atomic state
> + * @limits: link BW limits
> + * @pipe_mask: mask of pipes to select from
> + * @reason: explanation of why bpp reduction is needed
> + *
> + * Select the pipe from @pipe_mask with the biggest link bpp value and set the
> + * maximum of link bpp in @limits below this value. Modeset the selected pipe,
> + * so that its state will get recomputed.
> + *
> + * This function can be called to resolve a link's BW overallocation by reducing
> + * the link bpp of one pipe on the link and hence reducing the total link BW.
> + *
> + * Returns
> + * - 0 in case of success
> + * - %-EINVAL if no pipe can further reduce its link bpp
> + * - Other negative error, if modesetting the selected pipe failed
> + */
> +int intel_atomic_reduce_link_bpp(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits,
> + u8 pipe_mask,
> + const char *reason)
> +{
> + struct drm_i915_private *i915 = to_i915(state->base.dev);
> + enum pipe max_bpp_pipe = INVALID_PIPE;
> + struct intel_crtc *crtc;
> + int max_bpp = 0;
> +
> + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {
> + struct intel_crtc_state *crtc_state;
> + int pipe_bpp;
> +
> + if (limits->min_bpp_pipes & BIT(crtc->pipe))
> + continue;
> +
> + crtc_state = intel_atomic_get_crtc_state(&state->base,
> + crtc);
> + if (IS_ERR(crtc_state))
> + return PTR_ERR(crtc_state);
> +
> + if (crtc_state->dsc.compression_enable)
> + pipe_bpp = crtc_state->dsc.compressed_bpp;
> + else
> + pipe_bpp = crtc_state->pipe_bpp;
> +
> + if (pipe_bpp > max_bpp) {
> + max_bpp = pipe_bpp;
> + max_bpp_pipe = crtc->pipe;
> + }
> + }
> +
> + if (max_bpp_pipe == INVALID_PIPE)
> + return -EINVAL;
> +
> + limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1;
> +
> + return intel_modeset_pipes_in_mask(state, reason,
> + BIT(max_bpp_pipe), false);
> +}
> +
> +static int intel_atomic_check_link(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits)
> +{
> + int ret;
> +
> + ret = intel_fdi_atomic_check_link(state, limits);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static bool
> +assert_link_limit_change_valid(struct drm_i915_private *i915,
> + const struct intel_link_bw_limits *old_limits,
> + const struct intel_link_bw_limits *new_limits)
> +{
> + bool bpps_changed = false;
> + enum pipe pipe;
> +
> + for_each_pipe(i915, pipe) {
> + /* The bpp limit can only decrease. */
> + if (drm_WARN_ON(&i915->drm,
> + new_limits->max_bpp_x16[pipe] >
> + old_limits->max_bpp_x16[pipe]))
> + return false;
> +
> + if (new_limits->max_bpp_x16[pipe] <
> + old_limits->max_bpp_x16[pipe])
> + bpps_changed = true;
> + }
> +
> + if (drm_WARN_ON(&i915->drm,
> + !bpps_changed))
> + return false;
> +
> + return true;
> +}
> +
> +static bool
> +reset_link_bpp_limit_to_min(struct intel_atomic_state *state,
> + const struct intel_link_bw_limits *old_limits,
> + struct intel_link_bw_limits *new_limits,
> + enum pipe failed_pipe)
> +{
> + if (failed_pipe == INVALID_PIPE)
> + return false;
> +
> + if (new_limits->min_bpp_pipes & BIT(failed_pipe))
> + return false;
> +
> + if (new_limits->max_bpp_x16[failed_pipe] ==
> + old_limits->max_bpp_x16[failed_pipe])
> + return false;
> +
> + new_limits->max_bpp_x16[failed_pipe] =
> + old_limits->max_bpp_x16[failed_pipe];
> + new_limits->min_bpp_pipes |= BIT(failed_pipe);
> +
> + return true;
> +}
> +
> +/**
> + * intel_atomic_check_config_and_link - compute CRTC configs, resolving any BW limits
> + * @state: atomic state
> + *
> + * Compute the configuration of all CRTCs in @state and resolve any BW
> + * limitations on links shared by these CRTCs.
> + *
> + * Return 0 in case of success, or a negative error code otherwise.
> + */
> +int intel_atomic_check_config_and_link(struct intel_atomic_state *state)
> +{
> + struct drm_i915_private *i915 = to_i915(state->base.dev);
> + struct intel_link_bw_limits new_limits = {};
> + struct intel_link_bw_limits old_limits;
> + enum pipe pipe;
> + int ret;
> +
> + for_each_pipe(i915, pipe)
> + new_limits.max_bpp_x16[pipe] = INT_MAX;
> +
> + old_limits = new_limits;
> +
> + while (true) {
> + enum pipe failed_pipe;
> +
> + ret = intel_atomic_check_config(state, &new_limits,
> + &failed_pipe);
> + if (ret) {
> + if (ret == -EINVAL &&
> + reset_link_bpp_limit_to_min(state,
> + &old_limits,
> + &new_limits,
> + failed_pipe))
> + continue;
> +
> + break;
> + }
> +
> + old_limits = new_limits;
> +
> + ret = intel_atomic_check_link(state, &new_limits);
> + if (ret != -EAGAIN)
> + break;
> +
> + if (!assert_link_limit_change_valid(i915,
> + &old_limits,
> + &new_limits)) {
> + ret = -EINVAL;
> + break;
> + }
> + }
> +
> + return ret;
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h
> index e506f6a873447..bbf3595d52c41 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.h
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.h
> @@ -20,6 +20,7 @@ struct intel_atomic_state;
> struct intel_connector;
> struct intel_crtc;
> struct intel_crtc_state;
> +struct intel_link_bw_limits;
>
> int intel_digital_connector_atomic_get_property(struct drm_connector *connector,
> const struct drm_connector_state *state,
> @@ -52,4 +53,11 @@ struct intel_crtc_state *
> intel_atomic_get_crtc_state(struct drm_atomic_state *state,
> struct intel_crtc *crtc);
>
> +int intel_atomic_reduce_link_bpp(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits,
> + u8 pipe_mask,
> + const char *reason);
> +bool intel_atomic_compute_pipe_bpp(struct intel_crtc_state *crtc_state);
> +int intel_atomic_check_config_and_link(struct intel_atomic_state *state);
> +
> #endif /* __INTEL_ATOMIC_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
> index f66340b4caf0f..3322080a574e8 100644
> --- a/drivers/gpu/drm/i915/display/intel_crt.c
> +++ b/drivers/gpu/drm/i915/display/intel_crt.c
> @@ -36,6 +36,7 @@
> #include "i915_drv.h"
> #include "i915_irq.h"
> #include "i915_reg.h"
> +#include "intel_atomic.h"
> #include "intel_connector.h"
> #include "intel_crt.h"
> #include "intel_crtc.h"
> @@ -413,6 +414,9 @@ static int pch_crt_compute_config(struct intel_encoder *encoder,
> return -EINVAL;
>
> pipe_config->has_pch_encoder = true;
> + if (!intel_atomic_compute_pipe_bpp(pipe_config))
> + return -EINVAL;
> +
> pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
>
> return 0;
> @@ -435,6 +439,9 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder,
> return -EINVAL;
>
> pipe_config->has_pch_encoder = true;
> + if (!intel_atomic_compute_pipe_bpp(pipe_config))
> + return -EINVAL;
> +
> pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
>
> /* LPT FDI RX only supports 8bpc. */
> diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
> index 182c6dd64f47c..1eda6a9f19aa8 100644
> --- a/drivers/gpu/drm/i915/display/intel_crtc.c
> +++ b/drivers/gpu/drm/i915/display/intel_crtc.c
> @@ -175,6 +175,7 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
> crtc_state->hsw_workaround_pipe = INVALID_PIPE;
> crtc_state->scaler_state.scaler_id = -1;
> crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
> + crtc_state->max_link_bpp_x16 = INT_MAX;
> }
>
> static struct intel_crtc *intel_crtc_alloc(void)
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index dbf109a2e738f..32778bd01bb05 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -4641,7 +4641,8 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
>
> static int
> intel_modeset_pipe_config(struct intel_atomic_state *state,
> - struct intel_crtc *crtc)
> + struct intel_crtc *crtc,
> + const struct intel_link_bw_limits *limits)
> {
> struct drm_i915_private *i915 = to_i915(crtc->base.dev);
> struct intel_crtc_state *crtc_state =
> @@ -4650,7 +4651,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
> struct drm_connector_state *connector_state;
> int pipe_src_w, pipe_src_h;
> int base_bpp, ret, i;
> - bool retry = true;
>
> crtc_state->cpu_transcoder = (enum transcoder) crtc->pipe;
>
> @@ -4673,6 +4673,17 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
> if (ret)
> return ret;
>
> + crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe];
> +
> + if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) {
> + drm_dbg_kms(&i915->drm,
> + "[CRTC:%d:%s] Link bpp limited to %d.%04d\n",
> + crtc->base.base.id, crtc->base.name,
> + to_bpp_int(crtc_state->max_link_bpp_x16),
> + to_bpp_frac_dec(crtc_state->max_link_bpp_x16));
> + crtc_state->bw_constrained = true;
> + }
> +
> base_bpp = crtc_state->pipe_bpp;
>
> /*
> @@ -4714,7 +4725,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
> crtc_state->output_types |= BIT(encoder->type);
> }
>
> -encoder_retry:
> /* Ensure the port clock defaults are reset when retrying. */
> crtc_state->port_clock = 0;
> crtc_state->pixel_multiplier = 1;
> @@ -4754,17 +4764,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
> ret = intel_crtc_compute_config(state, crtc);
> if (ret == -EDEADLK)
> return ret;
> - if (ret == -EAGAIN) {
> - if (drm_WARN(&i915->drm, !retry,
> - "[CRTC:%d:%s] loop in pipe configuration computation\n",
> - crtc->base.base.id, crtc->base.name))
> - return -EINVAL;
> -
> - drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] bw constrained, retrying\n",
> - crtc->base.base.id, crtc->base.name);
> - retry = false;
> - goto encoder_retry;
> - }
> if (ret < 0) {
> drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] config failure: %d\n",
> crtc->base.base.id, crtc->base.name, ret);
> @@ -6206,7 +6205,9 @@ static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state)
> return 0;
> }
>
> -static int intel_atomic_check_config(struct intel_atomic_state *state)
> +int intel_atomic_check_config(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits,
> + enum pipe *failed_pipe)
> {
> struct drm_i915_private *i915 = to_i915(state->base.dev);
> struct intel_crtc_state *new_crtc_state;
> @@ -6214,10 +6215,16 @@ static int intel_atomic_check_config(struct intel_atomic_state *state)
> int ret;
> int i;
>
> + *failed_pipe = INVALID_PIPE;
> +
> ret = intel_bigjoiner_add_affected_crtcs(state);
> if (ret)
> return ret;
>
> + ret = intel_fdi_add_affected_crtcs(state);
> + if (ret)
> + return ret;
> +
> for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
> if (!intel_crtc_needs_modeset(new_crtc_state)) {
> if (intel_crtc_is_bigjoiner_slave(new_crtc_state))
> @@ -6239,7 +6246,7 @@ static int intel_atomic_check_config(struct intel_atomic_state *state)
> if (!new_crtc_state->hw.enable)
> continue;
>
> - ret = intel_modeset_pipe_config(state, crtc);
> + ret = intel_modeset_pipe_config(state, crtc, limits);
> if (ret)
> break;
>
> @@ -6248,6 +6255,9 @@ static int intel_atomic_check_config(struct intel_atomic_state *state)
> break;
> }
>
> + if (ret)
> + *failed_pipe = crtc->pipe;
> +
> return ret;
> }
>
> @@ -6295,7 +6305,7 @@ int intel_atomic_check(struct drm_device *dev,
> return ret;
> }
>
> - ret = intel_atomic_check_config(state);
> + ret = intel_atomic_check_config_and_link(state);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index d9a54610d9d5e..2e0535739bd70 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -55,6 +55,7 @@ struct intel_digital_port;
> struct intel_dp;
> struct intel_encoder;
> struct intel_initial_plane_config;
> +struct intel_link_bw_limits;
> struct intel_link_m_n;
> struct intel_plane;
> struct intel_plane_state;
> @@ -391,6 +392,9 @@ enum phy_fia {
> (new_connector_state) = to_intel_digital_connector_state((__state)->base.connectors[__i].new_state), 1))
>
> int intel_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
> +int intel_atomic_check_config(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits,
> + enum pipe *failed_pipe);
> int intel_atomic_add_affected_planes(struct intel_atomic_state *state,
> struct intel_crtc *crtc);
> u8 intel_calc_active_pipes(struct intel_atomic_state *state,
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index b143085b399eb..6f4f46658df22 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -66,6 +66,12 @@ struct intel_tc_port;
> * Display related stuff
> */
>
> +struct intel_link_bw_limits {
> + u8 min_bpp_pipes;
> + /* in 1/16 bpp units */
> + int max_bpp_x16[I915_MAX_PIPES];
> +};
> +
> /* these are outputs from the chip - integrated only
> external chips are via DVO or SDVO output */
> enum intel_output_type {
> @@ -1189,7 +1195,8 @@ struct intel_crtc_state {
> u32 ctrl, div;
> } dsi_pll;
>
> - int pipe_bpp;
> + int max_link_bpp_x16; /* in 1/16 bpp units */
> + int pipe_bpp; /* in 1 bpp units */
> struct intel_link_m_n dp_m_n;
>
> /* m2_n2 for eDP downclock */
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 6637bd4768bf7..48f005932ad8b 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2218,7 +2218,8 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
> const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
> int max_link_bpp_x16;
>
> - max_link_bpp_x16 = to_bpp_x16(limits->pipe.max_bpp);
> + max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16,
> + to_bpp_x16(limits->pipe.max_bpp));
>
> if (!dsc) {
> max_link_bpp_x16 = rounddown(max_link_bpp_x16, to_bpp_x16(2 * 3));
> diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
> index e12b46a84fa11..123ba67f68791 100644
> --- a/drivers/gpu/drm/i915/display/intel_fdi.c
> +++ b/drivers/gpu/drm/i915/display/intel_fdi.c
> @@ -119,6 +119,59 @@ void intel_fdi_link_train(struct intel_crtc *crtc,
> dev_priv->display.funcs.fdi->fdi_link_train(crtc, crtc_state);
> }
>
> +/**
> + * intel_fdi_add_affected_crtcs - add CRTCs on FDI affected by other modeset CRTCs
> + * @state: intel atomic state
> + *
> + * Add a CRTC using FDI to @state if changing another CRTC's FDI BW usage is
> + * known to affect the available FDI BW for the former CRTC. In practice this
> + * means adding CRTC B on IVYBRIDGE if its use of FDI lanes is limited (by
> + * CRTC C) and CRTC C is getting disabled.
> + *
> + * Returns 0 in case of success, or a negative error code otherwise.
> + */
> +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state)
> +{
> + struct drm_i915_private *i915 = to_i915(state->base.dev);
> + struct intel_crtc_state *old_crtc_state;
> + struct intel_crtc_state *new_crtc_state;
> + struct intel_crtc *crtc;
> +
> + if (!IS_IVYBRIDGE(i915))
> + return 0;
> +
> + crtc = intel_crtc_for_pipe(i915, PIPE_C);
> + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
> +
> + if (!new_crtc_state)
> + return 0;
> +
> + old_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
> +
> + if (!old_crtc_state->fdi_lanes)
> + return 0;
> +
> + if (!intel_crtc_needs_modeset(new_crtc_state))
> + return 0;
> +
> + if (new_crtc_state->uapi.enable)
> + return 0;
> +
> + crtc = intel_crtc_for_pipe(i915, PIPE_B);
> + new_crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
> +
> + if (IS_ERR(new_crtc_state))
> + return PTR_ERR(old_crtc_state);
> +
> + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
> + if (!old_crtc_state->fdi_lanes)
> + return 0;
> +
> + return intel_modeset_pipes_in_mask(state,
> + "FDI link BW decrease on pipe C",
> + BIT(PIPE_B), false);
> +}
> +
> /* units of 100MHz */
> static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
> {
> @@ -129,13 +182,16 @@ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
> }
>
> static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
> - struct intel_crtc_state *pipe_config)
> + struct intel_crtc_state *pipe_config,
> + enum pipe *pipe_to_reduce)
> {
> struct drm_i915_private *dev_priv = to_i915(dev);
> struct drm_atomic_state *state = pipe_config->uapi.state;
> struct intel_crtc *other_crtc;
> struct intel_crtc_state *other_crtc_state;
>
> + *pipe_to_reduce = pipe;
> +
> drm_dbg_kms(&dev_priv->drm,
> "checking fdi config on pipe %c, lanes %i\n",
> pipe_name(pipe), pipe_config->fdi_lanes);
> @@ -198,6 +254,9 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
> if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
> drm_dbg_kms(&dev_priv->drm,
> "fdi link B uses too many lanes to enable link C\n");
> +
> + *pipe_to_reduce = PIPE_B;
> +
> return -EINVAL;
> }
> return 0;
> @@ -238,10 +297,8 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc,
> struct drm_device *dev = crtc->base.dev;
> struct drm_i915_private *i915 = to_i915(dev);
> const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
> - int lane, link_bw, fdi_dotclock, ret;
> - bool needs_recompute = false;
> + int lane, link_bw, fdi_dotclock;
>
> -retry:
> /* FDI is a binary signal running at ~2.7GHz, encoding
> * each output octet as 10 bits. The actual frequency
> * is stored as a divider into a 100MHz clock, and the
> @@ -261,25 +318,69 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc,
> intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
> link_bw, &pipe_config->fdi_m_n, false);
>
> - ret = ilk_check_fdi_lanes(dev, crtc->pipe, pipe_config);
> - if (ret == -EDEADLK)
> + return 0;
> +}
> +
> +static int intel_fdi_atomic_check_bw(struct intel_atomic_state *state,
> + struct intel_crtc *crtc,
> + struct intel_crtc_state *pipe_config,
> + struct intel_link_bw_limits *limits)
> +{
> + struct drm_i915_private *i915 = to_i915(crtc->base.dev);
> + enum pipe pipe_to_reduce;
> + int ret;
> +
> + ret = ilk_check_fdi_lanes(&i915->drm, crtc->pipe, pipe_config,
> + &pipe_to_reduce);
> + if (ret != -EINVAL)
> return ret;
>
> - if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
> - pipe_config->pipe_bpp -= 2*3;
> - drm_dbg_kms(&i915->drm,
> - "fdi link bw constraint, reducing pipe bpp to %i\n",
> - pipe_config->pipe_bpp);
> - needs_recompute = true;
> - pipe_config->bw_constrained = true;
> + ret = intel_atomic_reduce_link_bpp(state, limits,
> + BIT(pipe_to_reduce),
> + "FDI link BW");
>
> - goto retry;
> - }
> + return ret ? : -EAGAIN;
> +}
>
> - if (needs_recompute)
> - return -EAGAIN;
> +/**
> + * intel_fdi_atomic_check_link - check all modeset FDI link configuration
> + * @state: intel atomic state
> + * @limits: link BW limits
> + *
> + * Check the link configuration for all modeset FDI outputs. If the
> + * configuration is invalid @limits will be updated if possible to
> + * reduce the total BW, after which the configuration for all CRTCs in
> + * @state must be recomputed with the updated @limits.
> + *
> + * Returns:
> + * - 0 if the confugration is valid
> + * - %-EAGAIN, if the configuration is invalid and @limits got updated
> + * with fallback values with which the configuration of all CRTCs
> + * in @state must be recomputed
> + * - Other negative error, if the configuration is invalid without a
> + * fallback possibility, or the check failed for another reason
> + */
> +int intel_fdi_atomic_check_link(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits)
> +{
> + struct intel_crtc *crtc;
> + struct intel_crtc_state *crtc_state;
> + int i;
> +
> + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
> + int ret;
>
> - return ret;
> + if (!crtc_state->has_pch_encoder ||
> + !intel_crtc_needs_modeset(crtc_state) ||
> + !crtc_state->hw.enable)
> + continue;
> +
> + ret = intel_fdi_atomic_check_bw(state, crtc, crtc_state, limits);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> }
>
> static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable)
> diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h
> index 1cdb86172702f..eb02b967bb440 100644
> --- a/drivers/gpu/drm/i915/display/intel_fdi.h
> +++ b/drivers/gpu/drm/i915/display/intel_fdi.h
> @@ -8,14 +8,19 @@
>
> enum pipe;
> struct drm_i915_private;
> +struct intel_atomic_state;
> struct intel_crtc;
> struct intel_crtc_state;
> struct intel_encoder;
> +struct intel_link_bw_limits;
>
> +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state);
> int intel_fdi_link_freq(struct drm_i915_private *i915,
> const struct intel_crtc_state *pipe_config);
> int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
> struct intel_crtc_state *pipe_config);
> +int intel_fdi_atomic_check_link(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits);
> void intel_fdi_normal_train(struct intel_crtc *crtc);
> void ilk_fdi_disable(struct intel_crtc *crtc);
> void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
> index 3ace56979b70e..08dcc2d10a2c1 100644
> --- a/drivers/gpu/drm/i915/display/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/display/intel_lvds.c
> @@ -425,6 +425,12 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder,
> return -EINVAL;
> }
>
> + if (HAS_PCH_SPLIT(i915)) {
> + crtc_state->has_pch_encoder = true;
> + if (!intel_atomic_compute_pipe_bpp(crtc_state))
> + return -EINVAL;
> + }
> +
> if (lvds_encoder->a3_power == LVDS_A3_POWER_UP)
> lvds_bpp = 8*3;
> else
> @@ -453,9 +459,6 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder,
> if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> return -EINVAL;
>
> - if (HAS_PCH_SPLIT(i915))
> - crtc_state->has_pch_encoder = true;
> -
> ret = intel_panel_fitting(crtc_state, conn_state);
> if (ret)
> return ret;
> diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
> index 7d25a64698e2f..1c6330151f4d6 100644
> --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> @@ -1352,14 +1352,17 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
> struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
> struct drm_display_mode *mode = &pipe_config->hw.mode;
>
> + if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) {
> + pipe_config->has_pch_encoder = true;
> + if (!intel_atomic_compute_pipe_bpp(pipe_config))
> + return -EINVAL;
> + }
> +
> DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
> pipe_config->pipe_bpp = 8*3;
> pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
> pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
>
> - if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
> - pipe_config->has_pch_encoder = true;
> -
> /*
> * We need to construct preferred input timings based on our
> * output timings. To do that, we have to set the output
> --
> 2.37.2
--
Ville Syrjälä
Intel
next prev parent reply other threads:[~2023-09-11 18:59 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-24 8:04 [Intel-gfx] [PATCH v2 00/22] drm/i915: Improve BW management on shared display links Imre Deak
2023-08-24 8:04 ` [Intel-gfx] [PATCH v2 01/22] drm/i915/dp: Factor out helpers to compute the link limits Imre Deak
2023-09-04 3:19 ` Ville Syrjälä
2023-09-04 10:25 ` Imre Deak
2023-08-24 8:04 ` [Intel-gfx] [PATCH v2 02/22] drm/i915/dp: Track the pipe and link bpp limits separately Imre Deak
2023-09-14 9:33 ` Luca Coelho
2023-09-14 9:55 ` Imre Deak
2023-09-14 10:51 ` Luca Coelho
2023-09-14 11:08 ` Imre Deak
2023-09-14 12:08 ` Luca Coelho
2023-08-24 8:04 ` [Intel-gfx] [PATCH v2 03/22] drm/i915/dp: Skip computing a non-DSC link config if DSC is needed Imre Deak
2023-09-04 3:24 ` Ville Syrjälä
2023-08-24 8:04 ` [Intel-gfx] [PATCH v2 04/22] drm/i915/dp: Update the link bpp limits for DSC mode Imre Deak
2023-09-04 3:48 ` Ville Syrjälä
2023-09-04 11:08 ` Imre Deak
2023-09-05 5:25 ` Ville Syrjälä
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 05/22] drm/i915/dp: Limit the output link bpp in " Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 06/22] drm/i915: Add helper to modeset a set of pipes Imre Deak
2023-09-08 19:25 ` Ville Syrjälä
2023-09-08 20:08 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 07/22] drm/i915: Factor out a helper to check/compute all the CRTC states Imre Deak
2023-09-08 19:31 ` Ville Syrjälä
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 08/22] drm/i915/fdi: Improve FDI BW sharing between pipe B and C Imre Deak
2023-09-11 18:59 ` Ville Syrjälä [this message]
2023-09-11 20:42 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 09/22] drm/dp_mst: Fix fractional bpp scaling in drm_dp_calc_pbn_mode() Imre Deak
2023-08-24 8:05 ` Imre Deak
2023-08-30 21:27 ` [Intel-gfx] " Lyude Paul
2023-08-30 21:27 ` Lyude Paul
2023-09-04 2:53 ` [Intel-gfx] " Ville Syrjälä
2023-09-04 10:22 ` Imre Deak
2023-09-06 10:45 ` Ville Syrjälä
2023-09-06 11:14 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 10/22] drm/dp_mst: Add a way to calculate PBN values with FEC overhead Imre Deak
2023-08-24 8:05 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 11/22] drm/dp_mst: Add helper to determine if an MST port is downstream of another port Imre Deak
2023-08-24 8:05 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 12/22] drm/dp_mst: Factor out a helper to check the atomic state of a topology manager Imre Deak
2023-08-24 8:05 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 13/22] drm/dp_mst: Swap the order of checking root vs. non-root port BW limitations Imre Deak
2023-08-24 8:05 ` Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 14/22] drm/i915/dp_mst: Fix PBN calculation with FEC overhead Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 15/22] drm/i915/dp_mst: Add atomic state for all streams on pre-tgl platforms Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 16/22] drm/i915/dp_mst: Program the DSC PPS SDP for each stream Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 17/22] drm/i915/dp: Make sure the DSC PPS SDP is disabled whenever DSC is disabled Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 18/22] drm/i915/dp_mst: Enable DSC decompression if any stream needs this Imre Deak
2023-08-24 9:31 ` Lisovskiy, Stanislav
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 19/22] drm/i915/dp_mst: Add missing DSC compression disabling Imre Deak
2023-08-24 9:44 ` Lisovskiy, Stanislav
2023-08-24 10:37 ` Imre Deak
2023-09-11 12:29 ` Lisovskiy, Stanislav
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 20/22] drm/i915/dp_mst: Allow DSC only for sink ports of the first branch device Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 21/22] drm/i915/dp_mst: Improve BW sharing between MST streams Imre Deak
2023-08-24 8:05 ` [Intel-gfx] [PATCH v2 22/22] drm/i915/dp_mst: Check BW limitations only after all streams are computed Imre Deak
2023-09-25 7:46 ` Lisovskiy, Stanislav
2023-08-24 9:54 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Improve BW management on shared display links (rev2) Patchwork
2023-08-24 9:54 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2023-08-24 10:07 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2023-08-24 17:54 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
2023-09-04 7:14 ` [Intel-gfx] ✗ Fi.CI.BUILD: failure for drm/i915: Improve BW management on shared display links (rev3) Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZP9jltWAdNY7LJpM@intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=imre.deak@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.