]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/flipq: Implement flip queue based commit path
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 24 Jun 2025 17:00:45 +0000 (20:00 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 27 Jun 2025 12:55:36 +0000 (15:55 +0300)
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: Uma Shankar <uma.shankar@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250624170049.27284-6-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display_params.c
drivers/gpu/drm/i915/display/intel_display_params.h
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dmc.c
drivers/gpu/drm/i915/display/intel_flipq.c
drivers/gpu/drm/i915/display/intel_flipq.h
drivers/gpu/drm/i915/display/skl_watermark.c

index a687d315d2050d93aa1adfb271b9f8662e355e32..42780d7d8eed170d8227952d6c6a8cc430d61405 100644 (file)
@@ -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,7 +7260,8 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
                intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit,
                                                     state, crtc);
 
-               intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit);
+               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))
                        intel_color_commit_arm(new_crtc_state->dsb_commit,
@@ -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);
        }
 
        /*
index c4f1ab43fc0c864a97226e216b9178749749049a..75316247ee8a858168732a2dadbbb9cf090d759f 100644 (file)
@@ -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)");
 
index 5317138e6044bfc2e929bb7ac7603470a86c9798..784e6bae86154fd15d65efb08286f65a048f2fff 100644 (file)
@@ -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) \
index 9e355d781e5c7c1985bcf038746e068218ec494c..ce45261c4a8f4299293dd9dc485e63139d29063a 100644 (file)
@@ -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;
index b8fe9a089bf20a3275b7bf48c2facd490c170038..af9eb67718ea06bdd6a2ba64c57f937d6e57cb6e 100644 (file)
@@ -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);
 }
index 92324d207c2471aa06b091a93428c0b062ae8e95..9dbe0104c9ef63ad2ec062dfac0b1fda622490ad 100644 (file)
@@ -112,6 +112,9 @@ static void intel_flipq_crtc_init(struct intel_crtc *crtc)
 
 bool intel_flipq_supported(struct intel_display *display)
 {
+       if (!display->params.enable_flipq)
+               return false;
+
        if (!display->dmc.dmc)
                return false;
 
@@ -140,7 +143,7 @@ static int cdclk_factor(struct intel_display *display)
                return 280;
 }
 
-static int intel_flipq_exec_time_us(struct intel_display *display)
+int intel_flipq_exec_time_us(struct intel_display *display)
 {
        return intel_dsb_exec_time_us() +
                DIV_ROUND_UP(display->cdclk.hw.cdclk * cdclk_factor(display), 540000) +
index 64d3c2a5bb7b845b63a5986f0b3f337d77e31932..195ff0dd83f52b38528f25a481548bb1baa08472 100644 (file)
@@ -28,5 +28,6 @@ void intel_flipq_add(struct intel_crtc *crtc,
                     unsigned int pts,
                     enum intel_dsb_id dsb_id,
                     struct intel_dsb *dsb);
+int intel_flipq_exec_time_us(struct intel_display *display);
 
 #endif /* __INTEL_FLIPQ_H__ */
index 9ab9e2ed1089d79ccbaa6fcd781ca0784167cc50..222c069fdadb5f1fd6a6b8f5c805ce415d475eaf 100644 (file)
@@ -26,6 +26,7 @@
 #include "intel_display_types.h"
 #include "intel_fb.h"
 #include "intel_fixed.h"
+#include "intel_flipq.h"
 #include "intel_pcode.h"
 #include "intel_plane.h"
 #include "intel_wm.h"
@@ -2897,11 +2898,15 @@ intel_program_dpkgc_latency(struct intel_atomic_state *state)
 
        latency = skl_watermark_max_latency(display, 1);
 
+       /* FIXME runtime changes to enable_flipq are racy */
+       if (display->params.enable_flipq)
+               added_wake_time = intel_flipq_exec_time_us(display);
+
        /*
         * Wa_22020432604
         * "PKG_C_LATENCY Added Wake Time field is not working"
         */
-       if (latency && (DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30)) {
+       if (latency && IS_DISPLAY_VER(display, 20, 30)) {
                latency += added_wake_time;
                added_wake_time = 0;
        }