[Intel-gfx] [PATCH v5 24/25] drm/i915/dp_mst: Improve BW sharing between MST streams
Lisovskiy, Stanislav
stanislav.lisovskiy at intel.com
Mon Sep 25 07:42:15 UTC 2023
On Tue, Sep 19, 2023 at 01:52:11PM +0300, Imre Deak wrote:
> At the moment modesetting a stream CRTC will fail if the stream's BW
> along with the current BW of all the other streams on the same MST link
> is above the total BW of the MST link. Make the BW sharing more dynamic
> by trying to reduce the link bpp of one or more streams on the MST link
> in this case.
>
> When selecting a stream to reduce the BW for, take into account which
> link segment in the MST topology ran out of BW and which streams go
> through this link segment. For instance with A,B,C streams in the same
> MST topology A and B may share the BW of a link segment downstream of a
> branch device, stream C not downstream of the branch device, hence not
> affecting this BW. If this link segment's BW runs out one or both of
> stream A/B's BW will be reduced until their total BW is within limits.
>
> While reducing the link bpp for a given stream DSC may need to be
> enabled for it, which requires FEC on the whole MST link. Check for this
> condition and recompute the state for all streams taking the FEC
> overhead into account (on 8b/10b links).
>
> v2:
> - Rebase on s/min_bpp_pipes/min_bpp_reached_pipes/ change.
>
> Signed-off-by: Imre Deak <imre.deak at intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_display.c | 5 +-
> drivers/gpu/drm/i915/display/intel_dp.c | 13 +-
> drivers/gpu/drm/i915/display/intel_dp.h | 2 +
> drivers/gpu/drm/i915/display/intel_dp_mst.c | 129 +++++++++++++++++++
> drivers/gpu/drm/i915/display/intel_dp_mst.h | 3 +
> drivers/gpu/drm/i915/display/intel_link_bw.c | 15 ++-
> drivers/gpu/drm/i915/display/intel_link_bw.h | 1 +
> 7 files changed, 159 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 8af22cf9a49de..565a6f20ffbfd 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -4629,6 +4629,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
> if (ret)
> return ret;
>
> + crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe);
> 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)) {
> @@ -6435,10 +6436,6 @@ int intel_atomic_check(struct drm_device *dev,
> goto fail;
> }
>
> - ret = drm_dp_mst_atomic_check(&state->base);
> - if (ret)
> - goto fail;
> -
> ret = intel_atomic_check_planes(state);
> if (ret)
> goto fail;
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 3d2ede31aa4e8..9b5070d8c8984 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1369,8 +1369,8 @@ static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp,
> return false;
> }
>
> -static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
> - const struct intel_crtc_state *pipe_config)
> +bool intel_dp_supports_fec(struct intel_dp *intel_dp,
> + const struct intel_crtc_state *pipe_config)
> {
> return intel_dp_source_supports_fec(intel_dp, pipe_config) &&
> drm_dp_sink_supports_fec(intel_dp->fec_capable);
> @@ -2111,8 +2111,9 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
> &pipe_config->hw.adjusted_mode;
> int ret;
>
> - pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) &&
> - intel_dp_supports_fec(intel_dp, pipe_config);
> + pipe_config->fec_enable = pipe_config->fec_enable ||
> + (!intel_dp_is_edp(intel_dp) &&
> + intel_dp_supports_fec(intel_dp, pipe_config));
>
> if (!intel_dp_supports_dsc(intel_dp, pipe_config))
> return -EINVAL;
> @@ -2308,6 +2309,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
> bool dsc_needed;
> int ret = 0;
>
> + if (pipe_config->fec_enable &&
> + !intel_dp_supports_fec(intel_dp, pipe_config))
> + return -EINVAL;
I wonder, could we just check that, when
we are actually setting fec_enable to true, then
we wouldn't have to care about this here.
Otherwise, with this clarified
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>
> +
> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> adjusted_mode->crtc_clock))
> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> index 2cf3681bac64a..612105a303419 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -135,6 +135,8 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
> return ~((1 << lane_count) - 1) & 0xf;
> }
>
> +bool intel_dp_supports_fec(struct intel_dp *intel_dp,
> + const struct intel_crtc_state *pipe_config);
> u32 intel_dp_mode_to_fec_clock(u32 mode_clock);
> u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 pipe_bpp);
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index 9681708acaa1a..ce69122fb4e54 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -43,6 +43,7 @@
> #include "intel_dpio_phy.h"
> #include "intel_hdcp.h"
> #include "intel_hotplug.h"
> +#include "intel_link_bw.h"
> #include "intel_vdsc.h"
> #include "skl_scaler.h"
>
> @@ -373,6 +374,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> bool dsc_needed;
> int ret = 0;
>
> + if (pipe_config->fec_enable &&
> + !intel_dp_supports_fec(intel_dp, pipe_config))
> + return -EINVAL;
> +
> if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> return -EINVAL;
>
> @@ -492,6 +497,130 @@ intel_dp_mst_transcoder_mask(struct intel_atomic_state *state,
> return transcoders;
> }
>
> +static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state,
> + struct drm_dp_mst_topology_mgr *mst_mgr,
> + struct drm_dp_mst_port *parent_port)
> +{
> + const struct intel_digital_connector_state *conn_state;
> + struct intel_connector *connector;
> + u8 mask = 0;
> + int i;
> +
> + for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
> + if (!conn_state->base.crtc)
> + continue;
> +
> + if (&connector->mst_port->mst_mgr != mst_mgr)
> + continue;
> +
> + if (connector->port != parent_port &&
> + !drm_dp_mst_port_downstream_of_parent(mst_mgr,
> + connector->port,
> + parent_port))
> + continue;
> +
> + mask |= BIT(to_intel_crtc(conn_state->base.crtc)->pipe);
> + }
> +
> + return mask;
> +}
> +
> +static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state,
> + struct drm_dp_mst_topology_mgr *mst_mgr,
> + struct intel_link_bw_limits *limits)
> +{
> + struct drm_i915_private *i915 = to_i915(state->base.dev);
> + struct intel_crtc *crtc;
> + u8 mst_pipe_mask;
> + u8 fec_pipe_mask = 0;
> + int ret;
> +
> + mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL);
> +
> + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, mst_pipe_mask) {
> + struct intel_crtc_state *crtc_state =
> + intel_atomic_get_new_crtc_state(state, crtc);
> +
> + /* Atomic connector check should've added all the MST CRTCs. */
> + if (drm_WARN_ON(&i915->drm, !crtc_state))
> + return -EINVAL;
> +
> + if (crtc_state->fec_enable)
> + fec_pipe_mask |= BIT(crtc->pipe);
> + }
> +
> + if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask)
> + return 0;
> +
> + limits->force_fec_pipes |= mst_pipe_mask;
> +
> + ret = intel_modeset_pipes_in_mask_early(state, "MST FEC",
> + mst_pipe_mask);
> +
> + return ret ? : -EAGAIN;
> +}
> +
> +static int intel_dp_mst_check_bw(struct intel_atomic_state *state,
> + struct drm_dp_mst_topology_mgr *mst_mgr,
> + struct drm_dp_mst_topology_state *mst_state,
> + struct intel_link_bw_limits *limits)
> +{
> + struct drm_dp_mst_port *mst_port;
> + u8 mst_port_pipes;
> + int ret;
> +
> + ret = drm_dp_mst_atomic_check_mgr(&state->base, mst_mgr, mst_state, &mst_port);
> + if (ret != -ENOSPC)
> + return ret;
> +
> + mst_port_pipes = get_pipes_downstream_of_mst_port(state, mst_mgr, mst_port);
> +
> + ret = intel_link_bw_reduce_bpp(state, limits,
> + mst_port_pipes, "MST link BW");
> +
> + return ret ? : -EAGAIN;
> +}
> +
> +/**
> + * intel_dp_mst_atomic_check_link - check all modeset MST link configuration
> + * @state: intel atomic state
> + * @limits: link BW limits
> + *
> + * Check the link configuration for all modeset MST 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_dp_mst_atomic_check_link(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits)
> +{
> + struct drm_dp_mst_topology_mgr *mgr;
> + struct drm_dp_mst_topology_state *mst_state;
> + int ret;
> + int i;
> +
> + for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) {
> + ret = intel_dp_mst_check_fec_change(state, mgr, limits);
> + if (ret)
> + return ret;
> +
> + ret = intel_dp_mst_check_bw(state, mgr, mst_state,
> + limits);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder,
> struct intel_crtc_state *crtc_state,
> struct drm_connector_state *conn_state)
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h
> index f1815bb722672..4e836b9ac6061 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h
> @@ -13,6 +13,7 @@ struct intel_crtc;
> struct intel_crtc_state;
> struct intel_digital_port;
> struct intel_dp;
> +struct intel_link_bw_limits;
>
> int intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_id);
> void intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port);
> @@ -22,5 +23,7 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state);
> bool intel_dp_mst_source_support(struct intel_dp *intel_dp);
> int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state,
> struct intel_crtc *crtc);
> +int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state,
> + struct intel_link_bw_limits *limits);
>
> #endif /* __INTEL_DP_MST_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c
> index 9d95e4a8478f7..85ceae2a5aaf1 100644
> --- a/drivers/gpu/drm/i915/display/intel_link_bw.c
> +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c
> @@ -22,6 +22,7 @@ void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_
> {
> enum pipe pipe;
>
> + limits->force_fec_pipes = 0;
> limits->min_bpp_reached_pipes = 0;
> for_each_pipe(i915, pipe)
> limits->max_bpp_x16[pipe] = INT_MAX;
> @@ -168,6 +169,10 @@ static int check_all_link_config(struct intel_atomic_state *state,
> {
> int ret;
>
> + ret = intel_dp_mst_atomic_check_link(state, limits);
> + if (ret)
> + return ret;
> +
> ret = intel_fdi_atomic_check_link(state, limits);
> if (ret)
> return ret;
> @@ -183,6 +188,12 @@ assert_link_limit_change_valid(struct drm_i915_private *i915,
> bool bpps_changed = false;
> enum pipe pipe;
>
> + /* FEC can't be forced off after it was forced on. */
> + if (drm_WARN_ON(&i915->drm,
> + (old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=
> + old_limits->force_fec_pipes))
> + return false;
> +
> for_each_pipe(i915, pipe) {
> /* The bpp limit can only decrease. */
> if (drm_WARN_ON(&i915->drm,
> @@ -197,7 +208,9 @@ assert_link_limit_change_valid(struct drm_i915_private *i915,
>
> /* At least one limit must change. */
> if (drm_WARN_ON(&i915->drm,
> - !bpps_changed))
> + !bpps_changed &&
> + new_limits->force_fec_pipes ==
> + old_limits->force_fec_pipes))
> return false;
>
> return true;
> diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h
> index 0f666c9712f3c..33b9a338beeb6 100644
> --- a/drivers/gpu/drm/i915/display/intel_link_bw.h
> +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h
> @@ -16,6 +16,7 @@ struct intel_atomic_state;
> struct intel_crtc_state;
>
> struct intel_link_bw_limits {
> + u8 force_fec_pipes;
> u8 min_bpp_reached_pipes;
> /* in 1/16 bpp units */
> int max_bpp_x16[I915_MAX_PIPES];
> --
> 2.37.2
>
More information about the Intel-gfx
mailing list