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

drm/i915/flipq: Implement flip queue based commit path



Support commits via the flip queue (as opposed to DSB or MMIO).

As it's somewhat unknown if we can actually use it is currently
gated behind the new use_flipq modparam, which defaults to disabled.

The implementation has a bunch of limitations that would need
real though to solve:
- disabled when PSR is used
- disabled when VRR is used
- color management updates not performed via the flip queue

v2: Don't use flip queue if there is no dmc
v3: Use intel_flipq_supported()
v3: Configure PKG_C_LATENCY appropriately
    Ignore INT_VECTOR if there is a real PIPEDMC interrupt
    (nothing in the hw appears to clear INT_VECTOR)
v4: Leave added_wake_time=0 when flip queue isn't used, to
    avoid needleslly increasing pkg_c_latency on lnl/ptl due
    to Wa_22020432604. This is a bit racy though...
    Use IS_DISPLAY_VER()

Reviewed-by: default avatarUma Shankar <uma.shankar@intel.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250624170049.27284-6-ville.syrjala@linux.intel.com
parent 470022b5
Loading
Loading
Loading
Loading
+35 −9
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@
#include "intel_fbc.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
#include "intel_flipq.h"
#include "intel_frontbuffer.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
@@ -6619,7 +6620,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state,
		intel_atomic_get_new_crtc_state(state, crtc);
	bool modeset = intel_crtc_needs_modeset(new_crtc_state);

	drm_WARN_ON(display->drm, new_crtc_state->use_dsb);
	drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq);

	/*
	 * During modesets pipe configuration was programmed as the
@@ -6649,7 +6650,7 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state,
		intel_atomic_get_new_crtc_state(state, crtc);
	bool modeset = intel_crtc_needs_modeset(new_crtc_state);

	drm_WARN_ON(display->drm, new_crtc_state->use_dsb);
	drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq);

	/*
	 * Disable the scaler(s) after the plane(s) so that we don't
@@ -6738,10 +6739,10 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state,

	if (!modeset &&
	    intel_crtc_needs_color_update(new_crtc_state) &&
	    !new_crtc_state->use_dsb)
	    !new_crtc_state->use_dsb && !new_crtc_state->use_flipq)
		intel_color_commit_noarm(NULL, new_crtc_state);

	if (!new_crtc_state->use_dsb)
	if (!new_crtc_state->use_dsb && !new_crtc_state->use_flipq)
		intel_crtc_planes_update_noarm(NULL, state, crtc);
}

@@ -6753,7 +6754,14 @@ static void intel_update_crtc(struct intel_atomic_state *state,
	struct intel_crtc_state *new_crtc_state =
		intel_atomic_get_new_crtc_state(state, crtc);

	if (new_crtc_state->use_dsb) {
	if (new_crtc_state->use_flipq) {
		intel_flipq_enable(new_crtc_state);

		intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->flipq_event);

		intel_flipq_add(crtc, INTEL_FLIPQ_PLANE_1, 0, INTEL_DSB_0,
				new_crtc_state->dsb_commit);
	} else if (new_crtc_state->use_dsb) {
		intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->dsb_event);

		intel_dsb_commit(new_crtc_state->dsb_commit);
@@ -7191,7 +7199,17 @@ static void intel_atomic_dsb_prepare(struct intel_atomic_state *state,
		return;

	/* FIXME deal with everything */
	new_crtc_state->use_flipq =
		intel_flipq_supported(display) &&
		!new_crtc_state->do_async_flip &&
		!new_crtc_state->vrr.enable &&
		!new_crtc_state->has_psr &&
		!intel_crtc_needs_modeset(new_crtc_state) &&
		!intel_crtc_needs_fastset(new_crtc_state) &&
		!intel_crtc_needs_color_update(new_crtc_state);

	new_crtc_state->use_dsb =
		!new_crtc_state->use_flipq &&
		!new_crtc_state->do_async_flip &&
		(DISPLAY_VER(display) >= 20 || !new_crtc_state->has_psr) &&
		!intel_crtc_needs_modeset(new_crtc_state) &&
@@ -7207,7 +7225,9 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
	struct intel_crtc_state *new_crtc_state =
		intel_atomic_get_new_crtc_state(state, crtc);

	if (!new_crtc_state->use_dsb && !new_crtc_state->dsb_color)
	if (!new_crtc_state->use_flipq &&
	    !new_crtc_state->use_dsb &&
	    !new_crtc_state->dsb_color)
		return;

	/*
@@ -7216,14 +7236,16 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
	 * Double that for pipe stuff and other overhead.
	 */
	new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0,
						       new_crtc_state->use_dsb ? 1024 : 16);
						       new_crtc_state->use_dsb ||
						       new_crtc_state->use_flipq ? 1024 : 16);
	if (!new_crtc_state->dsb_commit) {
		new_crtc_state->use_flipq = false;
		new_crtc_state->use_dsb = false;
		intel_color_cleanup_commit(new_crtc_state);
		return;
	}

	if (new_crtc_state->use_dsb) {
	if (new_crtc_state->use_flipq || new_crtc_state->use_dsb) {
		if (intel_crtc_needs_color_update(new_crtc_state))
			intel_color_commit_noarm(new_crtc_state->dsb_commit,
						 new_crtc_state);
@@ -7238,6 +7260,7 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
		intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit,
						     state, crtc);

		if (new_crtc_state->use_dsb)
			intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit);

		if (intel_crtc_needs_color_update(new_crtc_state))
@@ -7417,6 +7440,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)

		if (!state->base.legacy_cursor_update && !new_crtc_state->use_dsb)
			intel_vrr_check_push_sent(NULL, new_crtc_state);

		if (new_crtc_state->use_flipq)
			intel_flipq_disable(new_crtc_state);
	}

	/*
+3 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ intel_display_param_named_unsafe(enable_dpt, bool, 0400,
intel_display_param_named_unsafe(enable_dsb, bool, 0400,
	"Enable display state buffer (DSB) (default: true)");

intel_display_param_named_unsafe(enable_flipq, bool, 0400,
	"Enable DMC flip queue (default: false)");

intel_display_param_named_unsafe(enable_sagv, bool, 0400,
	"Enable system agent voltage/frequency scaling (SAGV) (default: true)");

+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct drm_printer;
	param(int, enable_dc, -1, 0400) \
	param(bool, enable_dpt, true, 0400) \
	param(bool, enable_dsb, true, 0600) \
	param(bool, enable_flipq, false, 0600) \
	param(bool, enable_sagv, true, 0600) \
	param(int, disable_power_well, -1, 0400) \
	param(bool, enable_ips, true, 0600) \
+3 −0
Original line number Diff line number Diff line
@@ -1305,6 +1305,7 @@ struct intel_crtc_state {
	/* For DSB based pipe updates */
	struct intel_dsb *dsb_color, *dsb_commit;
	bool use_dsb;
	bool use_flipq;

	u32 psr2_man_track_ctl;

@@ -1412,6 +1413,8 @@ struct intel_crtc {
	struct drm_pending_vblank_event *flip_done_event;
	/* armed event for DSB based updates */
	struct drm_pending_vblank_event *dsb_event;
	/* armed event for flip queue based updates */
	struct drm_pending_vblank_event *flipq_event;

	/* Access to these should be protected by display->irq.lock. */
	bool cpu_fifo_underrun_disabled;
+22 −4
Original line number Diff line number Diff line
@@ -501,7 +501,8 @@ static u32 pipedmc_interrupt_mask(struct intel_display *display)
	 * triggering it during the first DC state transition. Figure
	 * out what is going on...
	 */
	return PIPEDMC_GTT_FAULT |
	return PIPEDMC_FLIPQ_PROG_DONE |
		PIPEDMC_GTT_FAULT |
		PIPEDMC_ATS_FAULT;
}

@@ -1608,12 +1609,29 @@ void intel_dmc_debugfs_register(struct intel_display *display)
void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe)
{
	struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
	u32 tmp;
	u32 tmp = 0, int_vector;

	if (DISPLAY_VER(display) >= 20) {
		tmp = intel_de_read(display, PIPEDMC_INTERRUPT(pipe));
		intel_de_write(display, PIPEDMC_INTERRUPT(pipe), tmp);

		if (tmp & PIPEDMC_FLIPQ_PROG_DONE) {
			spin_lock(&display->drm->event_lock);

			if (crtc->flipq_event) {
				/*
				 * Update vblank counter/timestamp in case it
				 * hasn't been done yet for this frame.
				 */
				drm_crtc_accurate_vblank_count(&crtc->base);

				drm_crtc_send_vblank_event(&crtc->base, crtc->flipq_event);
				crtc->flipq_event = NULL;
			}

			spin_unlock(&display->drm->event_lock);
		}

		if (tmp & PIPEDMC_ATS_FAULT)
			drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC ATS fault\n",
					    crtc->base.base.id, crtc->base.name);
@@ -1625,8 +1643,8 @@ void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe)
				crtc->base.base.id, crtc->base.name);
	}

	tmp = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK;
	if (tmp)
	int_vector = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK;
	if (tmp == 0 && int_vector != 0)
		drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n",
			crtc->base.base.id, crtc->base.name, tmp);
}
Loading