Commit ac930bab authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915/bw: Untangle dbuf bw from the sagv/mem bw stuff



Currently intel_bw.c contains basically three completely independent
parts:
- SAGV/memory bandwidth handling
- DBuf bandwidth handling
- "Maximum pipe read bandwidth" calculation, which is some kind
  of internal per-pipe bandwidth limit.

Carve out the DBuf bandwdith handling into a separate file since
there is no actual dependency between it and the rest of intel_bw.c.

Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20251013201236.30084-2-ville.syrjala@linux.intel.com


Reviewed-by: default avatarMika Kahola <mika.kahola@intel.com>
parent 27e21516
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -242,6 +242,7 @@ i915-y += \
	display/intel_crtc.o \
	display/intel_crtc_state_dump.o \
	display/intel_cursor.o \
	display/intel_dbuf_bw.o \
	display/intel_display.o \
	display/intel_display_conversion.o \
	display/intel_display_driver.o \
+0 −191
Original line number Diff line number Diff line
@@ -3,16 +3,12 @@
 * Copyright © 2019 Intel Corporation
 */

#include <drm/drm_atomic_state_helper.h>

#include "soc/intel_dram.h"

#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_utils.h"
#include "intel_atomic.h"
#include "intel_bw.h"
#include "intel_cdclk.h"
#include "intel_crtc.h"
#include "intel_display_core.h"
#include "intel_display_regs.h"
@@ -22,14 +18,8 @@
#include "intel_uncore.h"
#include "skl_watermark.h"

struct intel_dbuf_bw {
	unsigned int max_bw[I915_MAX_DBUF_SLICES];
	u8 active_planes[I915_MAX_DBUF_SLICES];
};

struct intel_bw_state {
	struct intel_global_state base;
	struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES];

	/*
	 * Contains a bit mask, used to determine, whether correspondent
@@ -1264,184 +1254,6 @@ static int intel_bw_check_qgv_points(struct intel_display *display,
					   old_bw_state, new_bw_state);
}

static bool intel_dbuf_bw_changed(struct intel_display *display,
				  const struct intel_dbuf_bw *old_dbuf_bw,
				  const struct intel_dbuf_bw *new_dbuf_bw)
{
	enum dbuf_slice slice;

	for_each_dbuf_slice(display, slice) {
		if (old_dbuf_bw->max_bw[slice] != new_dbuf_bw->max_bw[slice] ||
		    old_dbuf_bw->active_planes[slice] != new_dbuf_bw->active_planes[slice])
			return true;
	}

	return false;
}

static bool intel_bw_state_changed(struct intel_display *display,
				   const struct intel_bw_state *old_bw_state,
				   const struct intel_bw_state *new_bw_state)
{
	enum pipe pipe;

	for_each_pipe(display, pipe) {
		const struct intel_dbuf_bw *old_dbuf_bw =
			&old_bw_state->dbuf_bw[pipe];
		const struct intel_dbuf_bw *new_dbuf_bw =
			&new_bw_state->dbuf_bw[pipe];

		if (intel_dbuf_bw_changed(display, old_dbuf_bw, new_dbuf_bw))
			return true;
	}

	return false;
}

static void skl_plane_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
				   struct intel_crtc *crtc,
				   enum plane_id plane_id,
				   const struct skl_ddb_entry *ddb,
				   unsigned int data_rate)
{
	struct intel_display *display = to_intel_display(crtc);
	unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(display, ddb);
	enum dbuf_slice slice;

	/*
	 * The arbiter can only really guarantee an
	 * equal share of the total bw to each plane.
	 */
	for_each_dbuf_slice_in_mask(display, slice, dbuf_mask) {
		dbuf_bw->max_bw[slice] = max(dbuf_bw->max_bw[slice], data_rate);
		dbuf_bw->active_planes[slice] |= BIT(plane_id);
	}
}

static void skl_crtc_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
				  const struct intel_crtc_state *crtc_state)
{
	struct intel_display *display = to_intel_display(crtc_state);
	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
	enum plane_id plane_id;

	memset(dbuf_bw, 0, sizeof(*dbuf_bw));

	if (!crtc_state->hw.active)
		return;

	for_each_plane_id_on_crtc(crtc, plane_id) {
		/*
		 * We assume cursors are small enough
		 * to not cause bandwidth problems.
		 */
		if (plane_id == PLANE_CURSOR)
			continue;

		skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
				       &crtc_state->wm.skl.plane_ddb[plane_id],
				       crtc_state->data_rate[plane_id]);

		if (DISPLAY_VER(display) < 11)
			skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
					       &crtc_state->wm.skl.plane_ddb_y[plane_id],
					       crtc_state->data_rate[plane_id]);
	}
}

/* "Maximum Data Buffer Bandwidth" */
static int
intel_bw_dbuf_min_cdclk(struct intel_display *display,
			const struct intel_bw_state *bw_state)
{
	unsigned int total_max_bw = 0;
	enum dbuf_slice slice;

	for_each_dbuf_slice(display, slice) {
		int num_active_planes = 0;
		unsigned int max_bw = 0;
		enum pipe pipe;

		/*
		 * The arbiter can only really guarantee an
		 * equal share of the total bw to each plane.
		 */
		for_each_pipe(display, pipe) {
			const struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[pipe];

			max_bw = max(dbuf_bw->max_bw[slice], max_bw);
			num_active_planes += hweight8(dbuf_bw->active_planes[slice]);
		}
		max_bw *= num_active_planes;

		total_max_bw = max(total_max_bw, max_bw);
	}

	return DIV_ROUND_UP(total_max_bw, 64);
}

int intel_bw_min_cdclk(struct intel_display *display,
		       const struct intel_bw_state *bw_state)
{
	int min_cdclk;

	min_cdclk = intel_bw_dbuf_min_cdclk(display, bw_state);

	return min_cdclk;
}

int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
			    bool *need_cdclk_calc)
{
	struct intel_display *display = to_intel_display(state);
	struct intel_bw_state *new_bw_state = NULL;
	const struct intel_bw_state *old_bw_state = NULL;
	const struct intel_crtc_state *old_crtc_state;
	const struct intel_crtc_state *new_crtc_state;
	struct intel_crtc *crtc;
	int ret, i;

	if (DISPLAY_VER(display) < 9)
		return 0;

	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
					    new_crtc_state, i) {
		struct intel_dbuf_bw old_dbuf_bw, new_dbuf_bw;

		skl_crtc_calc_dbuf_bw(&old_dbuf_bw, old_crtc_state);
		skl_crtc_calc_dbuf_bw(&new_dbuf_bw, new_crtc_state);

		if (!intel_dbuf_bw_changed(display, &old_dbuf_bw, &new_dbuf_bw))
			continue;

		new_bw_state = intel_atomic_get_bw_state(state);
		if (IS_ERR(new_bw_state))
			return PTR_ERR(new_bw_state);

		old_bw_state = intel_atomic_get_old_bw_state(state);

		new_bw_state->dbuf_bw[crtc->pipe] = new_dbuf_bw;
	}

	if (!old_bw_state)
		return 0;

	if (intel_bw_state_changed(display, old_bw_state, new_bw_state)) {
		int ret = intel_atomic_lock_global_state(&new_bw_state->base);
		if (ret)
			return ret;
	}

	ret = intel_cdclk_update_bw_min_cdclk(state,
					      intel_bw_min_cdclk(display, old_bw_state),
					      intel_bw_min_cdclk(display, new_bw_state),
					      need_cdclk_calc);
	if (ret)
		return ret;

	return 0;
}

static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *changed)
{
	struct intel_display *display = to_intel_display(state);
@@ -1647,8 +1459,6 @@ void intel_bw_update_hw_state(struct intel_display *display)
		if (DISPLAY_VER(display) >= 11)
			intel_bw_crtc_update(bw_state, crtc_state);

		skl_crtc_calc_dbuf_bw(&bw_state->dbuf_bw[pipe], crtc_state);

		/* initially SAGV has been forced off */
		bw_state->pipe_sagv_reject |= BIT(pipe);
	}
@@ -1666,7 +1476,6 @@ void intel_bw_crtc_disable_noatomic(struct intel_crtc *crtc)

	bw_state->data_rate[pipe] = 0;
	bw_state->num_active_planes[pipe] = 0;
	memset(&bw_state->dbuf_bw[pipe], 0, sizeof(bw_state->dbuf_bw[pipe]));
}

static struct intel_global_state *
+0 −4
Original line number Diff line number Diff line
@@ -30,10 +30,6 @@ void intel_bw_init_hw(struct intel_display *display);
int intel_bw_init(struct intel_display *display);
int intel_bw_atomic_check(struct intel_atomic_state *state);
int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state);
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
			    bool *need_cdclk_calc);
int intel_bw_min_cdclk(struct intel_display *display,
		       const struct intel_bw_state *bw_state);
void intel_bw_update_hw_state(struct intel_display *display);
void intel_bw_crtc_disable_noatomic(struct intel_crtc *crtc);

+14 −18
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "intel_bw.h"
#include "intel_cdclk.h"
#include "intel_crtc.h"
#include "intel_dbuf_bw.h"
#include "intel_de.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
@@ -133,8 +134,8 @@ struct intel_cdclk_state {
	 */
	struct intel_cdclk_config actual;

	/* minimum acceptable cdclk to satisfy bandwidth requirements */
	int bw_min_cdclk;
	/* minimum acceptable cdclk to satisfy DBUF bandwidth requirements */
	int dbuf_bw_min_cdclk;
	/* minimum acceptable cdclk for each pipe */
	int min_cdclk[I915_MAX_PIPES];
	/* minimum acceptable voltage level for each pipe */
@@ -2895,7 +2896,7 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state,
	return 0;
}

int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
					 int old_min_cdclk, int new_min_cdclk,
					 bool *need_cdclk_calc)
{
@@ -2914,7 +2915,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
	if (IS_ERR(cdclk_state))
		return PTR_ERR(cdclk_state);

	old_min_cdclk = cdclk_state->bw_min_cdclk;
	old_min_cdclk = cdclk_state->dbuf_bw_min_cdclk;

	if (new_min_cdclk == old_min_cdclk)
		return 0;
@@ -2922,7 +2923,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
	if (!allow_cdclk_decrease && new_min_cdclk < old_min_cdclk)
		return 0;

	cdclk_state->bw_min_cdclk = new_min_cdclk;
	cdclk_state->dbuf_bw_min_cdclk = new_min_cdclk;

	ret = intel_atomic_lock_global_state(&cdclk_state->base);
	if (ret)
@@ -2931,7 +2932,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
	*need_cdclk_calc = true;

	drm_dbg_kms(display->drm,
		    "bandwidth min cdclk: %d kHz -> %d kHz\n",
		    "dbuf bandwidth min cdclk: %d kHz -> %d kHz\n",
		    old_min_cdclk, new_min_cdclk);

	return 0;
@@ -2954,7 +2955,7 @@ static int intel_compute_min_cdclk(struct intel_atomic_state *state)
	int min_cdclk;

	min_cdclk = cdclk_state->force_min_cdclk;
	min_cdclk = max(min_cdclk, cdclk_state->bw_min_cdclk);
	min_cdclk = max(min_cdclk, cdclk_state->dbuf_bw_min_cdclk);
	for_each_pipe(display, pipe)
		min_cdclk = max(min_cdclk, cdclk_state->min_cdclk[pipe]);

@@ -3480,7 +3481,7 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state)
	if (ret)
		return ret;

	ret = intel_bw_calc_min_cdclk(state, &need_cdclk_calc);
	ret = intel_dbuf_bw_calc_min_cdclk(state, &need_cdclk_calc);
	if (ret)
		return ret;

@@ -3507,8 +3508,8 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state)

void intel_cdclk_update_hw_state(struct intel_display *display)
{
	const struct intel_bw_state *bw_state =
		to_intel_bw_state(display->bw.obj.state);
	const struct intel_dbuf_bw_state *dbuf_bw_state =
		to_intel_dbuf_bw_state(display->dbuf_bw.obj.state);
	struct intel_cdclk_state *cdclk_state =
		to_intel_cdclk_state(display->cdclk.obj.state);
	struct intel_crtc *crtc;
@@ -3530,7 +3531,7 @@ void intel_cdclk_update_hw_state(struct intel_display *display)
		cdclk_state->min_voltage_level[pipe] = crtc_state->min_voltage_level;
	}

	cdclk_state->bw_min_cdclk = intel_bw_min_cdclk(display, bw_state);
	cdclk_state->dbuf_bw_min_cdclk = intel_dbuf_bw_min_cdclk(display, dbuf_bw_state);
}

void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc)
@@ -4024,11 +4025,6 @@ int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe
	return cdclk_state->min_cdclk[pipe];
}

int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state)
{
	return cdclk_state->bw_min_cdclk;
}

bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state)
{
	const struct intel_cdclk_state *new_cdclk_state, *old_cdclk_state;
+3 −4
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ struct intel_cdclk_state *
intel_atomic_get_cdclk_state(struct intel_atomic_state *state);
void intel_cdclk_update_hw_state(struct intel_display *display);
void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc);
int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
					 int old_min_cdclk, int new_min_cdclk,
					 bool *need_cdclk_calc);

@@ -65,7 +65,6 @@ int intel_cdclk_logical(const struct intel_cdclk_state *cdclk_state);
int intel_cdclk_actual(const struct intel_cdclk_state *cdclk_state);
int intel_cdclk_actual_voltage_level(const struct intel_cdclk_state *cdclk_state);
int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe pipe);
int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state);
bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state);
void intel_cdclk_force_min_cdclk(struct intel_cdclk_state *cdclk_state, int force_min_cdclk);
void intel_cdclk_read_hw(struct intel_display *display);
Loading