Commit 8ca0b875 authored by Imre Deak's avatar Imre Deak
Browse files

drm/i915: Add helpers for BW management on shared display links



At the moment a modeset fails if the config computation of a pipe can't
fit its required BW to the available link BW even though the limitation
may be resolved by reducing the BW requirement of other pipes.

To improve the above this patch adds helper functions checking the
overall BW limits after all CRTC states have been computed. If the check
fails the maximum link bpp for a selected pipe will be reduced and all
the CRTC states will be recomputed 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).

Atm, the MST encoder allocates twice the required BW for YUV420 format
streams. A follow-up patchset will fix that, add a code comment about
this.

This change prepares for upcoming patches enabling the above BW
management on FDI and MST links.

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)
v3:
- Add the helper functions in a separate patch. (Ville)
- Add the functions to intel_link_bw.c instead of intel_atomic.c (Ville)
- Return -ENOSPC instead of -EINVAL to userspace in case of a link BW
  limit failure.
v4:
- Make intel_atomic_check_config() static.
v5: (Ville)
- Rename intel_link_bw_limits::min_bpp_pipes to min_bpp_reached_pipes
  and intel_link_bw_reset_pipe_limit_to_min() to
  intel_link_bw_set_min_bpp_for_pipe().
- Rename pipe_bpp to link_bpp in intel_link_bw_reduce_bpp().
- Add FIXME: comment about MST encoder's YUV420 BW allocation and
  tracking the link bpp limit accordingly.
v6:
- Move intel_link_bw_compute_pipe_bpp() to intel_fdi.c (Ville)
- WARN_ON(BIT(pipe) & min_bpp_reached_pipes) in
  intel_link_bw_set_bpp_limit_for_pipe(). (Ville)
- Rename intel_link_bw_set_min_bpp_for_pipe() to
  intel_link_bw_set_bpp_limit_for_pipe() and
  intel_link_bw_limits::min_bpp_reached_pipes to
  bpp_limit_reached_pipes. (Ville)
- Remove unused header includes.

Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230921195159.2646027-10-imre.deak@intel.com
parent 1050e4c2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -268,6 +268,7 @@ i915-y += \
	display/intel_hotplug.o \
	display/intel_hotplug_irq.o \
	display/intel_hti.o \
	display/intel_link_bw.o \
	display/intel_load_detect.o \
	display/intel_lpe_audio.o \
	display/intel_modeset_lock.o \
+1 −0
Original line number Diff line number Diff line
@@ -176,6 +176,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)
+61 −4
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@
#include "intel_frontbuffer.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
#include "intel_link_bw.h"
#include "intel_lvds.h"
#include "intel_lvds_regs.h"
#include "intel_modeset_setup.h"
@@ -4644,7 +4645,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 =
@@ -4676,6 +4678,15 @@ 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 " BPP_X16_FMT "\n",
			    crtc->base.base.id, crtc->base.name,
			    BPP_X16_ARGS(crtc_state->max_link_bpp_x16));
	}

	base_bpp = crtc_state->pipe_bpp;

	/*
@@ -6283,7 +6294,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)
static 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;
@@ -6291,6 +6304,8 @@ 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;
@@ -6316,7 +6331,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;

@@ -6325,9 +6340,51 @@ static int intel_atomic_check_config(struct intel_atomic_state *state)
			break;
	}

	if (ret)
		*failed_pipe = crtc->pipe;

	return ret;
}

static 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;
	int ret;

	intel_link_bw_init_limits(i915, &new_limits);
	old_limits = new_limits;

	while (true) {
		enum pipe failed_pipe;

		ret = intel_atomic_check_config(state, &new_limits,
						&failed_pipe);
		if (ret) {
			/*
			 * The bpp limit for a pipe is below the minimum it supports, set the
			 * limit to the minimum and recalculate the config.
			 */
			if (ret == -EINVAL &&
			    intel_link_bw_set_bpp_limit_for_pipe(state,
								 &old_limits,
								 &new_limits,
								 failed_pipe))
				continue;

			break;
		}

		old_limits = new_limits;

		ret = intel_link_bw_atomic_check(state, &new_limits);
		if (ret != -EAGAIN)
			break;
	}

	return ret;
}
/**
 * intel_atomic_check - validate state object
 * @dev: drm device
@@ -6372,7 +6429,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;

+2 −1
Original line number Diff line number Diff line
@@ -1191,7 +1191,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 */
+4 −0
Original line number Diff line number Diff line
@@ -157,6 +157,10 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
	int slots = -EINVAL;
	int link_bpp;

	/*
	 * FIXME: allocate the BW according to link_bpp, which in the case of
	 * YUV420 is only half of the pipe bpp value.
	 */
	slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state,
						     to_bpp_int(limits->link.max_bpp_x16),
						     to_bpp_int(limits->link.min_bpp_x16),
Loading