From 0cd161e9472f2eb4be3436670c6db2dd0e3851e4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 13 Mar 2025 16:08:35 +0200 Subject: [PATCH 01/16] drm/i915: Use a nicer way to lookup the memory region in BIOS FB takeover MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Use intel_memory_region_by_type() to find the appropriate memory region for the BIOS FB takeover. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250313140838.29742-8-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- .../drm/i915/display/intel_plane_initial.c | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index cf7d1a5ab524..5f75ef4ba3b1 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -52,6 +52,17 @@ intel_reuse_initial_plane_obj(struct intel_crtc *this, return false; } +static enum intel_memory_type +initial_plane_memory_type(struct drm_i915_private *i915) +{ + if (IS_DGFX(i915)) + return INTEL_MEMORY_LOCAL; + else if (HAS_LMEMBAR_SMEM_STOLEN(i915)) + return INTEL_MEMORY_STOLEN_LOCAL; + else + return INTEL_MEMORY_STOLEN_SYSTEM; +} + static bool initial_plane_phys_lmem(struct intel_display *display, struct intel_initial_plane_config *plane_config) @@ -59,6 +70,7 @@ initial_plane_phys_lmem(struct intel_display *display, struct drm_i915_private *i915 = to_i915(display->drm); struct i915_ggtt *ggtt = to_gt(i915)->ggtt; struct intel_memory_region *mem; + enum intel_memory_type mem_type; bool is_present, is_local; dma_addr_t dma_addr; u32 base; @@ -79,13 +91,12 @@ initial_plane_phys_lmem(struct intel_display *display, return false; } - if (IS_DGFX(i915)) - mem = i915->mm.regions[INTEL_REGION_LMEM_0]; - else - mem = i915->mm.stolen_region; + mem_type = initial_plane_memory_type(i915); + mem = intel_memory_region_by_type(i915, mem_type); if (!mem) { drm_dbg_kms(display->drm, - "Initial plane memory region not initialized\n"); + "Initial plane memory region (type %s) not initialized\n", + intel_memory_type_str(mem_type)); return false; } @@ -117,6 +128,7 @@ initial_plane_phys_smem(struct intel_display *display, struct drm_i915_private *i915 = to_i915(display->drm); struct i915_ggtt *ggtt = to_gt(i915)->ggtt; struct intel_memory_region *mem; + enum intel_memory_type mem_type; bool is_present, is_local; dma_addr_t dma_addr; u32 base; @@ -137,10 +149,12 @@ initial_plane_phys_smem(struct intel_display *display, return false; } - mem = i915->mm.stolen_region; + mem_type = initial_plane_memory_type(i915); + mem = intel_memory_region_by_type(i915, mem_type); if (!mem) { drm_dbg_kms(display->drm, - "Initial plane memory region not initialized\n"); + "Initial plane memory region (type %s) not initialized\n", + intel_memory_type_str(mem_type)); return false; } -- 2.51.0 From a47720c545065aef972fba78c50bf1bdc6f89d02 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 13 Mar 2025 16:08:36 +0200 Subject: [PATCH 02/16] drm/i915: Lookup the memory region first in the BIOS FB takeover MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When doing the BIOS FB takeover let's look up the appropriate memory region first. If it doesn't exist there's not much point in doing the PTE read/etc either. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250313140838.29742-9-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- .../drm/i915/display/intel_plane_initial.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 5f75ef4ba3b1..d522da7000ff 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -75,6 +75,15 @@ initial_plane_phys_lmem(struct intel_display *display, dma_addr_t dma_addr; u32 base; + mem_type = initial_plane_memory_type(i915); + mem = intel_memory_region_by_type(i915, mem_type); + if (!mem) { + drm_dbg_kms(display->drm, + "Initial plane memory region (type %s) not initialized\n", + intel_memory_type_str(mem_type)); + return false; + } + base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local); @@ -91,15 +100,6 @@ initial_plane_phys_lmem(struct intel_display *display, return false; } - mem_type = initial_plane_memory_type(i915); - mem = intel_memory_region_by_type(i915, mem_type); - if (!mem) { - drm_dbg_kms(display->drm, - "Initial plane memory region (type %s) not initialized\n", - intel_memory_type_str(mem_type)); - return false; - } - /* * On lmem we don't currently expect this to * ever be placed in the stolen portion. @@ -133,6 +133,15 @@ initial_plane_phys_smem(struct intel_display *display, dma_addr_t dma_addr; u32 base; + mem_type = initial_plane_memory_type(i915); + mem = intel_memory_region_by_type(i915, mem_type); + if (!mem) { + drm_dbg_kms(display->drm, + "Initial plane memory region (type %s) not initialized\n", + intel_memory_type_str(mem_type)); + return false; + } + base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local); @@ -149,15 +158,6 @@ initial_plane_phys_smem(struct intel_display *display, return false; } - mem_type = initial_plane_memory_type(i915); - mem = intel_memory_region_by_type(i915, mem_type); - if (!mem) { - drm_dbg_kms(display->drm, - "Initial plane memory region (type %s) not initialized\n", - intel_memory_type_str(mem_type)); - return false; - } - if (dma_addr < mem->region.start || dma_addr > mem->region.end) { drm_err(display->drm, "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n", -- 2.51.0 From 9d293478474f0a7101b678967bf3b3ae88d35696 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 13 Mar 2025 16:08:37 +0200 Subject: [PATCH 03/16] drm/i915: Use intel_memory_region_type_is_local() in the BIOS FB takeover MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Replace the hardcoded PTE vs. memory region is_local checks in the BIOS FB takeover with intel_memory_region_type_is_local(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250313140838.29742-10-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- drivers/gpu/drm/i915/display/intel_plane_initial.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index d522da7000ff..6abe17be0add 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -94,9 +94,10 @@ initial_plane_phys_lmem(struct intel_display *display, return false; } - if (!is_local) { + if (intel_memory_type_is_local(mem->type) != is_local) { drm_err(display->drm, - "Initial plane FB PTE not LMEM\n"); + "Initial plane FB PTE unsuitable for %s\n", + mem->region.name); return false; } @@ -152,9 +153,10 @@ initial_plane_phys_smem(struct intel_display *display, return false; } - if (is_local) { + if (intel_memory_type_is_local(mem->type) != is_local) { drm_err(display->drm, - "Initial plane FB PTE LMEM\n"); + "Initial plane FB PTE unsuitable for %s\n", + mem->region.name); return false; } -- 2.51.0 From 544813fb8cbcd8b53ddb6d7dafec6673be91ee2f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 13 Mar 2025 16:08:38 +0200 Subject: [PATCH 04/16] drm/i915: Eliminate the initial_plane_phys_{smem,lmem}() duplication MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit initial_plane_phys_lmem() and initial_plane_phys_smem() are now identical. Remove one of them. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250313140838.29742-11-ville.syrjala@linux.intel.com Reviewed-by: Jouni Högander --- .../drm/i915/display/intel_plane_initial.c | 75 +------------------ 1 file changed, 2 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 6abe17be0add..b0c4892775ce 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -64,67 +64,8 @@ initial_plane_memory_type(struct drm_i915_private *i915) } static bool -initial_plane_phys_lmem(struct intel_display *display, - struct intel_initial_plane_config *plane_config) -{ - struct drm_i915_private *i915 = to_i915(display->drm); - struct i915_ggtt *ggtt = to_gt(i915)->ggtt; - struct intel_memory_region *mem; - enum intel_memory_type mem_type; - bool is_present, is_local; - dma_addr_t dma_addr; - u32 base; - - mem_type = initial_plane_memory_type(i915); - mem = intel_memory_region_by_type(i915, mem_type); - if (!mem) { - drm_dbg_kms(display->drm, - "Initial plane memory region (type %s) not initialized\n", - intel_memory_type_str(mem_type)); - return false; - } - - base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); - - dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local); - - if (!is_present) { - drm_err(display->drm, - "Initial plane FB PTE not present\n"); - return false; - } - - if (intel_memory_type_is_local(mem->type) != is_local) { - drm_err(display->drm, - "Initial plane FB PTE unsuitable for %s\n", - mem->region.name); - return false; - } - - /* - * On lmem we don't currently expect this to - * ever be placed in the stolen portion. - */ - if (dma_addr < mem->region.start || dma_addr > mem->region.end) { - drm_err(display->drm, - "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n", - &dma_addr, mem->region.name, &mem->region.start, &mem->region.end); - return false; - } - - drm_dbg(display->drm, - "Using dma_addr=%pa, based on initial plane programming\n", - &dma_addr); - - plane_config->phys_base = dma_addr - mem->region.start; - plane_config->mem = mem; - - return true; -} - -static bool -initial_plane_phys_smem(struct intel_display *display, - struct intel_initial_plane_config *plane_config) +initial_plane_phys(struct intel_display *display, + struct intel_initial_plane_config *plane_config) { struct drm_i915_private *i915 = to_i915(display->drm); struct i915_ggtt *ggtt = to_gt(i915)->ggtt; @@ -177,18 +118,6 @@ initial_plane_phys_smem(struct intel_display *display, return true; } -static bool -initial_plane_phys(struct intel_display *display, - struct intel_initial_plane_config *plane_config) -{ - struct drm_i915_private *i915 = to_i915(display->drm); - - if (IS_DGFX(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915)) - return initial_plane_phys_lmem(display, plane_config); - else - return initial_plane_phys_smem(display, plane_config); -} - static struct i915_vma * initial_plane_vma(struct intel_display *display, struct intel_initial_plane_config *plane_config) -- 2.51.0 From d354d52c55c6ccebcc4f4148820139f319a4065f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jouni=20H=C3=B6gander?= Date: Mon, 31 Mar 2025 12:07:47 +0300 Subject: [PATCH 05/16] drm/i915/psr: Prevent DP Panel Replay as well when CRC is enable MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit We are seeing timeouts in opening CRC fd when testing on setup where DP Panel Replay can be enabled. Fix these by checking if CRC is enabled for DP Panel Replay as well. Signed-off-by: Jouni Högander Reviewed-by: Jani Nikula Link: https://lore.kernel.org/r/20250331090747.2964028-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 55414fa55b12..eef48c014112 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1595,6 +1595,12 @@ _panel_replay_compute_config(struct intel_dp *intel_dp, return false; } + if (crtc_state->crc_enabled) { + drm_dbg_kms(display->drm, + "Panel Replay not enabled because it would inhibit pipe CRC calculation\n"); + return false; + } + if (!intel_dp_is_edp(intel_dp)) return true; @@ -1625,12 +1631,6 @@ _panel_replay_compute_config(struct intel_dp *intel_dp, if (!alpm_config_valid(intel_dp, crtc_state, true)) return false; - if (crtc_state->crc_enabled) { - drm_dbg_kms(display->drm, - "Panel Replay not enabled because it would inhibit pipe CRC calculation\n"); - return false; - } - return true; } -- 2.51.0 From 38188a7f575dacba1120a59fd5d62c7f3313c0fa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 6 Mar 2025 23:07:40 +0200 Subject: [PATCH 06/16] drm/i915/dp: Reject HBR3 when sink doesn't support TPS4 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit According to the DP spec TPS4 is mandatory for HBR3. We have however seen some broken eDP sinks that violate this and declare support for HBR3 without TPS4 support. At least in the case of the icl Dell XPS 13 7390 this results in an unstable output. Reject HBR3 when TPS4 supports is unavailable on the sink. v2: Leave breadcrumbs in dmesg to avoid head scratching (Jani) Cc: stable@vger.kernel.org Cc: Jani Nikula Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5969 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250306210740.11886-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 49 +++++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f21f9b441fc2..7b95d62730e6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -172,10 +172,28 @@ int intel_dp_link_symbol_clock(int rate) static int max_dprx_rate(struct intel_dp *intel_dp) { + struct intel_display *display = to_intel_display(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int max_rate; + if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) - return drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel); + max_rate = drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel); + else + max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); - return drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); + /* + * Some broken eDP sinks illegally declare support for + * HBR3 without TPS4, and are unable to produce a stable + * output. Reject HBR3 when TPS4 is not available. + */ + if (max_rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { + drm_dbg_kms(display->drm, + "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", + encoder->base.base.id, encoder->base.name); + max_rate = 540000; + } + + return max_rate; } static int max_dprx_lane_count(struct intel_dp *intel_dp) @@ -4170,6 +4188,9 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp) static void intel_edp_set_sink_rates(struct intel_dp *intel_dp) { + struct intel_display *display = to_intel_display(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + intel_dp->num_sink_rates = 0; if (intel_dp->edp_dpcd[0] >= DP_EDP_14) { @@ -4180,10 +4201,7 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) sink_rates, sizeof(sink_rates)); for (i = 0; i < ARRAY_SIZE(sink_rates); i++) { - int val = le16_to_cpu(sink_rates[i]); - - if (val == 0) - break; + int rate; /* Value read multiplied by 200kHz gives the per-lane * link rate in kHz. The source rates are, however, @@ -4191,7 +4209,24 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) * back to symbols is * (val * 200kHz)*(8/10 ch. encoding)*(1/8 bit to Byte) */ - intel_dp->sink_rates[i] = (val * 200) / 10; + rate = le16_to_cpu(sink_rates[i]) * 200 / 10; + + if (rate == 0) + break; + + /* + * Some broken eDP sinks illegally declare support for + * HBR3 without TPS4, and are unable to produce a stable + * output. Reject HBR3 when TPS4 is not available. + */ + if (rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { + drm_dbg_kms(display->drm, + "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", + encoder->base.base.id, encoder->base.name); + break; + } + + intel_dp->sink_rates[i] = rate; } intel_dp->num_sink_rates = i; } -- 2.51.0 From 1aa4031257e6f8a3ff436a165863f40905dd3968 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:31 +0200 Subject: [PATCH 07/16] drm/i915: Drop the cached per-pipe min_cdclk[] from bw state MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit intel_bw_crtc_min_cdclk() only depends on the pipe data rate, which we already have stashed in bw_state->data_rate[]. So stashing the resulting min_cdclk[] as well is redundant. Get rid of it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 17 ++++++++--------- drivers/gpu/drm/i915/display/intel_bw.h | 1 - 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index bb81efec08a0..15c2377193f7 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -825,14 +825,13 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_ } /* "Maximum Pipe Read Bandwidth" */ -static int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state) +static int intel_bw_crtc_min_cdclk(struct intel_display *display, + unsigned int data_rate) { - struct intel_display *display = to_intel_display(crtc_state); - if (DISPLAY_VER(display) < 12) return 0; - return DIV_ROUND_UP_ULL(mul_u32_u32(intel_bw_crtc_data_rate(crtc_state), 10), 512); + return DIV_ROUND_UP_ULL(mul_u32_u32(data_rate, 10), 512); } static unsigned int intel_bw_num_active_planes(struct intel_display *display, @@ -1170,7 +1169,8 @@ static bool intel_bw_state_changed(struct intel_display *display, return true; } - if (old_bw_state->min_cdclk[pipe] != new_bw_state->min_cdclk[pipe]) + if (intel_bw_crtc_min_cdclk(display, old_bw_state->data_rate[pipe]) != + intel_bw_crtc_min_cdclk(display, new_bw_state->data_rate[pipe])) return true; } @@ -1271,7 +1271,9 @@ int intel_bw_min_cdclk(struct intel_display *display, min_cdclk = intel_bw_dbuf_min_cdclk(display, bw_state); for_each_pipe(display, pipe) - min_cdclk = max(min_cdclk, bw_state->min_cdclk[pipe]); + min_cdclk = max(min_cdclk, + intel_bw_crtc_min_cdclk(display, + bw_state->data_rate[pipe])); return min_cdclk; } @@ -1299,9 +1301,6 @@ int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, old_bw_state = intel_atomic_get_old_bw_state(state); skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state); - - new_bw_state->min_cdclk[crtc->pipe] = - intel_bw_crtc_min_cdclk(crtc_state); } if (!old_bw_state) diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index c18126c83d2e..3e4397c85774 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -54,7 +54,6 @@ struct intel_bw_state { */ bool force_check_qgv; - int min_cdclk[I915_MAX_PIPES]; unsigned int data_rate[I915_MAX_PIPES]; u8 num_active_planes[I915_MAX_PIPES]; }; -- 2.51.0 From 92512d4827f140fcdd8ae86639858f05c8f21ecc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:32 +0200 Subject: [PATCH 08/16] drm/i915: s/intel_crtc_bw/intel_dbuf_bw/ MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Rename the intel_crtc_bw struct to intel_dbuf_bw to better reflect what it does. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 15c2377193f7..b34db55f5a7e 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1157,15 +1157,15 @@ static bool intel_bw_state_changed(struct intel_display *display, enum pipe pipe; for_each_pipe(display, pipe) { - const struct intel_dbuf_bw *old_crtc_bw = + const struct intel_dbuf_bw *old_dbuf_bw = &old_bw_state->dbuf_bw[pipe]; - const struct intel_dbuf_bw *new_crtc_bw = + const struct intel_dbuf_bw *new_dbuf_bw = &new_bw_state->dbuf_bw[pipe]; enum dbuf_slice slice; for_each_dbuf_slice(display, slice) { - if (old_crtc_bw->max_bw[slice] != new_crtc_bw->max_bw[slice] || - old_crtc_bw->active_planes[slice] != new_crtc_bw->active_planes[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; } @@ -1185,7 +1185,7 @@ static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, { struct intel_display *display = to_intel_display(crtc); struct drm_i915_private *i915 = to_i915(display->drm); - struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe]; + struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[crtc->pipe]; unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb); enum dbuf_slice slice; @@ -1194,8 +1194,8 @@ static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, * equal share of the total bw to each plane. */ for_each_dbuf_slice_in_mask(display, slice, dbuf_mask) { - crtc_bw->max_bw[slice] = max(crtc_bw->max_bw[slice], data_rate); - crtc_bw->active_planes[slice] |= BIT(plane_id); + dbuf_bw->max_bw[slice] = max(dbuf_bw->max_bw[slice], data_rate); + dbuf_bw->active_planes[slice] |= BIT(plane_id); } } @@ -1204,10 +1204,10 @@ static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state, { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe]; + struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[crtc->pipe]; enum plane_id plane_id; - memset(crtc_bw, 0, sizeof(*crtc_bw)); + memset(dbuf_bw, 0, sizeof(*dbuf_bw)); if (!crtc_state->hw.active) return; @@ -1249,10 +1249,10 @@ intel_bw_dbuf_min_cdclk(struct intel_display *display, * equal share of the total bw to each plane. */ for_each_pipe(display, pipe) { - const struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[pipe]; + const struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[pipe]; - max_bw = max(crtc_bw->max_bw[slice], max_bw); - num_active_planes += hweight8(crtc_bw->active_planes[slice]); + max_bw = max(dbuf_bw->max_bw[slice], max_bw); + num_active_planes += hweight8(dbuf_bw->active_planes[slice]); } max_bw *= num_active_planes; -- 2.51.0 From 8261fbacd9bb523ddebc3bee624f36c7d8d0b8d8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:33 +0200 Subject: [PATCH 09/16] drm/i915: Extract intel_dbuf_bw_changed() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Extract the struct intel_dbuf_bw comparison into a small helper. We'll get more users later. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index b34db55f5a7e..898ddaf7e76b 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1150,6 +1150,21 @@ 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) @@ -1161,13 +1176,9 @@ static bool intel_bw_state_changed(struct intel_display *display, &old_bw_state->dbuf_bw[pipe]; const struct intel_dbuf_bw *new_dbuf_bw = &new_bw_state->dbuf_bw[pipe]; - 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; - } + if (intel_dbuf_bw_changed(display, old_dbuf_bw, new_dbuf_bw)) + return true; if (intel_bw_crtc_min_cdclk(display, old_bw_state->data_rate[pipe]) != intel_bw_crtc_min_cdclk(display, new_bw_state->data_rate[pipe])) -- 2.51.0 From 18e6866615698f9dd714e47353022bd597a90a57 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:34 +0200 Subject: [PATCH 10/16] drm/i915: Pass intel_dbuf_bw to skl_*_calc_dbuf_bw() explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Make skl_*_calc_dbuf_bw() a bit lower level passing in the to be mutated dbuf_bw struct in explicitly. This will allow more reuse later. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 898ddaf7e76b..67d088da1f38 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1188,7 +1188,7 @@ static bool intel_bw_state_changed(struct intel_display *display, return false; } -static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, +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, @@ -1196,7 +1196,6 @@ static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, { struct intel_display *display = to_intel_display(crtc); struct drm_i915_private *i915 = to_i915(display->drm); - struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[crtc->pipe]; unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb); enum dbuf_slice slice; @@ -1210,12 +1209,11 @@ static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, } } -static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state, +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); - struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[crtc->pipe]; enum plane_id plane_id; memset(dbuf_bw, 0, sizeof(*dbuf_bw)); @@ -1231,12 +1229,12 @@ static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state, if (plane_id == PLANE_CURSOR) continue; - skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id, + 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(bw_state, crtc, plane_id, + 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]); } @@ -1311,7 +1309,8 @@ int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, old_bw_state = intel_atomic_get_old_bw_state(state); - skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state); + skl_crtc_calc_dbuf_bw(&new_bw_state->dbuf_bw[crtc->pipe], + crtc_state); } if (!old_bw_state) -- 2.51.0 From 074c31271a1d9ec74c5a1965589671337be11d0f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:35 +0200 Subject: [PATCH 11/16] drm/i915: Avoid triggering unwanted cdclk changes due to dbuf bandwidth changes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Currently intel_bw_calc_min_cdclk() always adds the bw_state to the atomic state. Not only does it result in potentially redundant work later, it's also currently causing unwanted cdclk changes during driver load. Check if the dbuf bw is actually changing before we decide to pull in the bw state. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 67d088da1f38..19b516084fac 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1294,7 +1294,8 @@ int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, struct intel_bw_state *new_bw_state = NULL; const struct intel_bw_state *old_bw_state = NULL; const struct intel_cdclk_state *cdclk_state; - const struct intel_crtc_state *crtc_state; + const struct intel_crtc_state *old_crtc_state; + const struct intel_crtc_state *new_crtc_state; int old_min_cdclk, new_min_cdclk; struct intel_crtc *crtc; int i; @@ -1302,15 +1303,23 @@ int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, if (DISPLAY_VER(display) < 9) return 0; - for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { + 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); - skl_crtc_calc_dbuf_bw(&new_bw_state->dbuf_bw[crtc->pipe], - crtc_state); + new_bw_state->dbuf_bw[crtc->pipe] = new_dbuf_bw; } if (!old_bw_state) -- 2.51.0 From 0029d2f739383fcd3269d5ac34d5290c15ac8213 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:36 +0200 Subject: [PATCH 12/16] drm/i915: Do more bw readout MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Update a bunch of bw related stuff during readout: - bw_state->dbuf_bw possible now that the wm readout has given us access to the plane ddb data - cdclk_state->bw_min_cdclk Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 3 +++ drivers/gpu/drm/i915/display/intel_cdclk.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 19b516084fac..69f3de0bba6a 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1495,6 +1495,8 @@ 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); } } @@ -1510,6 +1512,7 @@ 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 * diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 984fd9f98c9f..ea2fbee2d62f 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -3341,6 +3341,8 @@ int intel_modeset_calc_cdclk(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); struct intel_cdclk_state *cdclk_state = to_intel_cdclk_state(display->cdclk.obj.state); struct intel_crtc *crtc; @@ -3358,6 +3360,8 @@ void intel_cdclk_update_hw_state(struct intel_display *display) cdclk_state->min_cdclk[pipe] = intel_crtc_compute_min_cdclk(crtc_state); cdclk_state->min_voltage_level[pipe] = crtc_state->min_voltage_level; } + + cdclk_state->bw_min_cdclk = intel_bw_min_cdclk(display, bw_state); } void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc) -- 2.51.0 From da1c27e4aef40b9c9710647ac3f8c4144711c1fa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:37 +0200 Subject: [PATCH 13/16] drm/i915: Flag even inactive crtcs as "inherited" MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit I want to use the crtc_state->inherited flag to clean up some of the early SAGV handling. To make that work nicely I need to flag even the inactive crtcs as "inherited". Since we can't expect user space to perform any real commits on inactive crtcs we'll clear the flag already during initial_commit(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-8-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 3 +++ .../drm/i915/display/intel_modeset_setup.c | 22 +++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c540e2cae1f0..d448ee4f4a10 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8100,6 +8100,9 @@ retry: goto out; } + if (!crtc_state->hw.active) + crtc_state->inherited = false; + if (crtc_state->hw.active) { struct intel_encoder *encoder; diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index 3cc915739677..2dc641da0c3b 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -821,18 +821,18 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915) to_intel_crtc_state(crtc->base.state); struct intel_plane *plane; - if (crtc_state->hw.active) { - /* - * The initial mode needs to be set in order to keep - * the atomic core happy. It wants a valid mode if the - * crtc's enabled, so we do the above call. - * - * But we don't set all the derived state fully, hence - * set a flag to indicate that a full recalculation is - * needed on the next commit. - */ - crtc_state->inherited = true; + /* + * The initial mode needs to be set in order to keep + * the atomic core happy. It wants a valid mode if the + * crtc's enabled, so we do the above call. + * + * But we don't set all the derived state fully, hence + * set a flag to indicate that a full recalculation is + * needed on the next commit. + */ + crtc_state->inherited = true; + if (crtc_state->hw.active) { intel_crtc_update_active_timings(crtc_state, crtc_state->vrr.enable); -- 2.51.0 From 67ad5b9babdc99c352e9cc244ca3d7dffa5daf97 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:38 +0200 Subject: [PATCH 14/16] drm/i915: Drop force_check_qgv MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Remove the force_check_qgv flag and just fill the pipe_sagv_reject bitmask properly during readout. This will cause the initial commit to re-enable SAGV if possible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-9-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 12 ++++++------ drivers/gpu/drm/i915/display/intel_bw.h | 6 ------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 69f3de0bba6a..47de106c608f 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1435,9 +1435,8 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) new_bw_state = intel_atomic_get_new_bw_state(state); if (new_bw_state && - (intel_can_enable_sagv(i915, old_bw_state) != - intel_can_enable_sagv(i915, new_bw_state) || - new_bw_state->force_check_qgv)) + intel_can_enable_sagv(i915, old_bw_state) != + intel_can_enable_sagv(i915, new_bw_state)) changed = true; /* @@ -1451,8 +1450,6 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) if (ret) return ret; - new_bw_state->force_check_qgv = false; - return 0; } @@ -1466,7 +1463,6 @@ static void intel_bw_crtc_update(struct intel_bw_state *bw_state, intel_bw_crtc_data_rate(crtc_state); bw_state->num_active_planes[crtc->pipe] = intel_bw_crtc_num_active_planes(crtc_state); - bw_state->force_check_qgv = true; drm_dbg_kms(display->drm, "pipe %c data rate %u num active planes %u\n", pipe_name(crtc->pipe), @@ -1484,6 +1480,7 @@ void intel_bw_update_hw_state(struct intel_display *display) return; bw_state->active_pipes = 0; + bw_state->pipe_sagv_reject = 0; for_each_intel_crtc(display->drm, crtc) { const struct intel_crtc_state *crtc_state = @@ -1497,6 +1494,9 @@ void intel_bw_update_hw_state(struct intel_display *display) 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); } } diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index 3e4397c85774..4a6a033f11e4 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -48,12 +48,6 @@ struct intel_bw_state { */ u16 qgv_points_mask; - /* - * Flag to force the QGV comparison in atomic check right after the - * hw state readout - */ - bool force_check_qgv; - unsigned int data_rate[I915_MAX_PIPES]; u8 num_active_planes[I915_MAX_PIPES]; }; -- 2.51.0 From dacbfc5e9ee94a9c064bfbd0f03fa3880a5fa0c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:39 +0200 Subject: [PATCH 15/16] drm/i915: Extract intel_bw_modeset_checks() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Pull the new_bw_state->active_pipes computation out from intel_compute_sagv_mask() and move it into the intel_bw.c (which is arguably the correct place for it). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-10-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 29 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_bw.h | 1 + drivers/gpu/drm/i915/display/intel_display.c | 6 ++++ drivers/gpu/drm/i915/display/skl_watermark.c | 9 ------ 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 47de106c608f..dcf2b711b83a 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1414,6 +1414,35 @@ static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *chan return 0; } +int intel_bw_modeset_checks(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_bw_state *old_bw_state; + struct intel_bw_state *new_bw_state; + + if (DISPLAY_VER(display) < 9) + return 0; + + 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->active_pipes = + intel_calc_active_pipes(state, old_bw_state->active_pipes); + + if (new_bw_state->active_pipes != old_bw_state->active_pipes) { + int ret; + + ret = intel_atomic_lock_global_state(&new_bw_state->base); + if (ret) + return ret; + } + + return 0; +} + int intel_bw_atomic_check(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index 4a6a033f11e4..ac435674c3ed 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -66,6 +66,7 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state); void intel_bw_init_hw(struct intel_display *display); int intel_bw_init(struct intel_display *display); +int intel_bw_modeset_checks(struct intel_atomic_state *state); int intel_bw_atomic_check(struct intel_atomic_state *state); int icl_pcode_restrict_qgv_points(struct intel_display *display, u32 points_mask); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d448ee4f4a10..2a58a1a16cdf 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6443,6 +6443,12 @@ int intel_atomic_check(struct drm_device *dev, if (ret) goto fail; + if (any_ms) { + ret = intel_bw_modeset_checks(state); + if (ret) + goto fail; + } + ret = intel_compute_global_watermarks(state); if (ret) goto fail; diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index a6af5e4ba4d4..1da1bfeadd9c 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -501,15 +501,6 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) if (!new_bw_state) return 0; - new_bw_state->active_pipes = - intel_calc_active_pipes(state, old_bw_state->active_pipes); - - if (new_bw_state->active_pipes != old_bw_state->active_pipes) { - ret = intel_atomic_lock_global_state(&new_bw_state->base); - if (ret) - return ret; - } - if (intel_can_enable_sagv(i915, new_bw_state) != intel_can_enable_sagv(i915, old_bw_state)) { ret = intel_atomic_serialize_global_state(&new_bw_state->base); -- 2.51.0 From 014ea4d39c09c85b4120111927ce22b31fd0ceea Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Mar 2025 18:25:40 +0200 Subject: [PATCH 16/16] drm/i915: Extract intel_bw_check_sagv_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Move the bw_state->pipe_sagv_reject computation into intel_bw.c where it belongs. Previously we had a complicated dance between watermarks and sagv which required this to be computed earlier, but that was changed in commit 5e8146251f7b ("extract intel_bw_check_sagv_mask()") which allows the whole thing to be cleaned up quite a bit. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250326162544.3642-11-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bw.c | 40 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_bw.h | 1 + drivers/gpu/drm/i915/display/skl_watermark.c | 31 ++------------- drivers/gpu/drm/i915/display/skl_watermark.h | 1 + 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index dcf2b711b83a..0553e902727e 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -1443,6 +1443,46 @@ int intel_bw_modeset_checks(struct intel_atomic_state *state) return 0; } +int intel_bw_check_sagv_mask(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + struct drm_i915_private *i915 = to_i915(display->drm); + const struct intel_crtc_state *new_crtc_state; + const struct intel_bw_state *old_bw_state = NULL; + struct intel_bw_state *new_bw_state = NULL; + struct intel_crtc *crtc; + int ret, i; + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + 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); + + if (intel_crtc_can_enable_sagv(new_crtc_state)) + new_bw_state->pipe_sagv_reject &= ~BIT(crtc->pipe); + else + new_bw_state->pipe_sagv_reject |= BIT(crtc->pipe); + } + + if (!new_bw_state) + return 0; + + if (intel_can_enable_sagv(i915, new_bw_state) != + intel_can_enable_sagv(i915, old_bw_state)) { + ret = intel_atomic_serialize_global_state(&new_bw_state->base); + if (ret) + return ret; + } else if (new_bw_state->pipe_sagv_reject != old_bw_state->pipe_sagv_reject) { + ret = intel_atomic_lock_global_state(&new_bw_state->base); + if (ret) + return ret; + } + + return 0; +} + int intel_bw_atomic_check(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index ac435674c3ed..ee1d437340f3 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -67,6 +67,7 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state); void intel_bw_init_hw(struct intel_display *display); int intel_bw_init(struct intel_display *display); int intel_bw_modeset_checks(struct intel_atomic_state *state); +int intel_bw_check_sagv_mask(struct intel_atomic_state *state); int intel_bw_atomic_check(struct intel_atomic_state *state); int icl_pcode_restrict_qgv_points(struct intel_display *display, u32 points_mask); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 1da1bfeadd9c..747b2b5c31bd 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -426,7 +426,7 @@ static bool tgl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) return true; } -static bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) +bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); @@ -457,20 +457,12 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) int ret; struct intel_crtc *crtc; struct intel_crtc_state *new_crtc_state; - struct intel_bw_state *new_bw_state = NULL; - const struct intel_bw_state *old_bw_state = NULL; int i; for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal; - 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); - /* * We store use_sagv_wm in the crtc state rather than relying on * that bw state since we have no convenient way to get at the @@ -491,26 +483,11 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) pipe_wm->use_sagv_wm = !HAS_HW_SAGV_WM(display) && DISPLAY_VER(i915) >= 12 && intel_crtc_can_enable_sagv(new_crtc_state); - - if (intel_crtc_can_enable_sagv(new_crtc_state)) - new_bw_state->pipe_sagv_reject &= ~BIT(crtc->pipe); - else - new_bw_state->pipe_sagv_reject |= BIT(crtc->pipe); } - if (!new_bw_state) - return 0; - - if (intel_can_enable_sagv(i915, new_bw_state) != - intel_can_enable_sagv(i915, old_bw_state)) { - ret = intel_atomic_serialize_global_state(&new_bw_state->base); - if (ret) - return ret; - } else if (new_bw_state->pipe_sagv_reject != old_bw_state->pipe_sagv_reject) { - ret = intel_atomic_lock_global_state(&new_bw_state->base); - if (ret) - return ret; - } + ret = intel_bw_check_sagv_mask(state); + if (ret) + return ret; return 0; } diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index d9cff6c54310..7e8107f808b6 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -27,6 +27,7 @@ u8 intel_enabled_dbuf_slices_mask(struct intel_display *display); void intel_sagv_pre_plane_update(struct intel_atomic_state *state); void intel_sagv_post_plane_update(struct intel_atomic_state *state); +bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state); bool intel_can_enable_sagv(struct drm_i915_private *i915, const struct intel_bw_state *bw_state); bool intel_has_sagv(struct drm_i915_private *i915); -- 2.51.0