From ce079f6d87ccd7129675c48067dd49329a123ce6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 15 Sep 2021 12:59:46 +0200 Subject: [PATCH 001/554] drm/i915: Add mmap lock around vma_lookup() in the mman selftest. Add mmap_read_lock/unlock around vma_lookup(). The core code requires this for lookups. Since we only check if the return value is NULL, we can immediately unlock. This fixes the following splat in the selftes: i915: Running i915_gem_mman_live_selftests/igt_mmap ------------[ cut here ]------------ WARNING: CPU: 3 PID: 5654 at include/linux/mmap_lock.h:164 find_vma+0x4e/0xb0 Modules linked in: i915(+) vgem fuse snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio mei_hdcp x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_intel_dspcfg snd_hda_codec snd_hwdep e1000e snd_hda_core ptp snd_pcm ttm mei_me pps_core i2c_i801 prime_numbers i2c_smbus mei [last unloaded: i915] CPU: 3 PID: 5654 Comm: i915_selftest Tainted: G U 5.15.0-rc1-CI-Trybot_7984+ #1 Hardware name: Micro-Star International Co., Ltd. MS-7B54/Z370M MORTAR (MS-7B54), BIOS 1.00 10/31/2017 RIP: 0010:find_vma+0x4e/0xb0 Code: de 48 89 ef e8 d3 94 fe ff 48 85 c0 74 34 48 83 c4 08 5b 5d c3 48 8d bf 28 01 00 00 be ff ff ff ff e8 d6 46 8b 00 85 c0 75 c8 <0f> 0b 48 8b 85 b8 00 00 00 48 85 c0 75 c6 48 89 ef e8 12 26 87 00 RSP: 0018:ffffc900013df980 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 00007f9df2b80000 RCX: 0000000000000000 RDX: 0000000000000001 RSI: ffffffff822e314c RDI: ffffffff8233c83f RBP: ffff88811bafc840 R08: ffff888107d0ddb8 R09: 00000000fffffffe R10: 0000000000000001 R11: 00000000ffbae7ba R12: 0000000000000000 R13: 0000000000000000 R14: ffff88812a710000 R15: ffff888114fa42c0 FS: 00007f9def9d4c00(0000) GS:ffff888266580000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f799627fe50 CR3: 000000011bbc2006 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __igt_mmap+0xe0/0x490 [i915] igt_mmap+0xd2/0x160 [i915] ? __trace_bprintk+0x6e/0x80 __i915_subtests.cold.7+0x42/0x92 [i915] ? i915_perf_selftests+0x20/0x20 [i915] ? __i915_nop_setup+0x10/0x10 [i915] __run_selftests.part.3+0x10d/0x172 [i915] i915_live_selftests.cold.5+0x1f/0x47 [i915] i915_pci_probe+0x93/0x1d0 [i915] Signed-off-by: Maarten Lankhorst Closes: https://gitlab.freedesktop.org/drm/intel/issues/4129 Link: https://patchwork.freedesktop.org/patch/msgid/20210915105946.394412-1-maarten.lankhorst@linux.intel.com Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index a2c34e5a1c54..6d30cdfa80f3 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -903,7 +903,9 @@ static int __igt_mmap(struct drm_i915_private *i915, pr_debug("igt_mmap(%s, %d) @ %lx\n", obj->mm.region->name, type, addr); + mmap_read_lock(current->mm); area = vma_lookup(current->mm, addr); + mmap_read_unlock(current->mm); if (!area) { pr_err("%s: Did not create a vm_area_struct for the mmap\n", obj->mm.region->name); From dc34ca9231f2631e635a4737242bc0f7fe5c4a45 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 3 Sep 2021 16:28:37 +0200 Subject: [PATCH 002/554] drm/i915: Mark GPU wedging on driver unregister unrecoverable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPU wedged flag now set on driver unregister to prevent from further using the GPU can be then cleared unintentionally when calling __intel_gt_unset_wedged() still before the flag is finally marked unrecoverable. We need to have it marked unrecoverable earlier. Implement that by replacing a call to intel_gt_set_wedged() in intel_gt_driver_unregister() with intel_gt_set_wedged_on_fini(). With the above in place, intel_gt_set_wedged_on_fini() is now called twice on driver remove, second time from __intel_gt_disable(). This seems harmless, while dropping intel_gt_set_wedged_on_fini() from __intel_gt_disable() proved to break some driver probe error unwind paths as well as mock selftest exit path. Signed-off-by: Janusz Krzysztofik Cc: Michał Winiarski Reviewed-by: Michał Winiarski Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210903142837.216978-1-janusz.krzysztofik@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 2aeaae036a6f..55e87aff51d2 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -752,7 +752,7 @@ void intel_gt_driver_unregister(struct intel_gt *gt) * all in-flight requests so that we can quickly unbind the active * resources. */ - intel_gt_set_wedged(gt); + intel_gt_set_wedged_on_fini(gt); /* Scrub all HW state upon release */ with_intel_runtime_pm(gt->uncore->rpm, wakeref) From e0ccf1d6f1ef46456ff6d3744afb6a105a516817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:27 +0300 Subject: [PATCH 003/554] drm/i915: Extract intel_dp_need_bigjoiner() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suck the "do we need bigjoiner?" checks into a helper instead of duplicating them in two differentt places. v2: s/use/need/ (Jani) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2db606ad59a2..3e7236b07773 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -805,6 +805,17 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, return MODE_OK; } +static bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp, + int hdisplay, int clock) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + if (!intel_dp_can_bigjoiner(intel_dp)) + return false; + + return clock > i915->max_dotclk_freq || hdisplay > 5120; +} + static enum drm_mode_status intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -840,8 +851,7 @@ intel_dp_mode_valid(struct drm_connector *connector, if (mode->clock < 10000) return MODE_CLOCK_LOW; - if ((target_clock > max_dotclk || mode->hdisplay > 5120) && - intel_dp_can_bigjoiner(intel_dp)) { + if (intel_dp_need_bigjoiner(intel_dp, mode->hdisplay, target_clock)) { bigjoiner = true; max_dotclk *= 2; } @@ -1457,9 +1467,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, limits.max_lane_count, limits.max_rate, limits.max_bpp, adjusted_mode->crtc_clock); - if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq || - adjusted_mode->crtc_hdisplay > 5120) && - intel_dp_can_bigjoiner(intel_dp)) + if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, + adjusted_mode->crtc_clock)) pipe_config->bigjoiner = true; /* From 555ec52127f9f09cae798ae66c82d017144743f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:28 +0300 Subject: [PATCH 004/554] drm/i915: Flatten hsw_crtc_compute_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hsw_crtc_compute_clock() has become spaghetti. Flatten it a bit to make it at least semi-legible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 210f91f4a576..ace9157a1c30 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -937,16 +937,18 @@ static int hsw_crtc_compute_clock(struct intel_crtc_state *crtc_state) struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); - if (IS_DG2(dev_priv)) { + if (IS_DG2(dev_priv)) return intel_mpllb_calc_state(crtc_state, encoder); - } else if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) || - DISPLAY_VER(dev_priv) >= 11) { - if (!intel_reserve_shared_dplls(state, crtc, encoder)) { - drm_dbg_kms(&dev_priv->drm, - "failed to find PLL for pipe %c\n", - pipe_name(crtc->pipe)); - return -EINVAL; - } + + if (DISPLAY_VER(dev_priv) < 11 && + intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) + return 0; + + if (!intel_reserve_shared_dplls(state, crtc, encoder)) { + drm_dbg_kms(&dev_priv->drm, + "failed to find PLL for pipe %c\n", + pipe_name(crtc->pipe)); + return -EINVAL; } return 0; From 8c66081b0b32a5fca6791ee09ccf0e6ef35acce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:29 +0300 Subject: [PATCH 005/554] drm/i915: s/pipe/transcoder/ when dealing with PIPECONF/TRANSCONF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PIPECONF becamse TRANSCONF when HSW introduced the EDP transcoder. Bigjoiner is making life even more confusing by introducing a N:1 relationship between pipes and transcoders. In that case we only enable/configure the transcoder corresponding to the master pipe. Let's do some renames to make it clear we're dealing with the transcoder rather than pipe when it comes to PIPECONF/TRANSCONF. I decided to leave the _cpu_ part out from the function/macro names since the PCH transcoder related stuff already has a _pch_ in their name. So shouldn't be possible to confuse them. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/g4x_dp.c | 4 +-- drivers/gpu/drm/i915/display/intel_crt.c | 4 +-- drivers/gpu/drm/i915/display/intel_ddi.c | 4 +-- drivers/gpu/drm/i915/display/intel_display.c | 28 ++++++++++---------- drivers/gpu/drm/i915/display/intel_display.h | 12 ++++----- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 +-- drivers/gpu/drm/i915/display/intel_dpll.c | 12 ++++----- drivers/gpu/drm/i915/display/intel_fdi.c | 2 +- drivers/gpu/drm/i915/display/intel_tv.c | 2 +- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 9577f6843f79..8e0620ae2ed1 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -211,7 +211,7 @@ static void ilk_edp_pll_on(struct intel_dp *intel_dp, struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + assert_transcoder_disabled(dev_priv, pipe_config->cpu_transcoder); assert_dp_port_disabled(intel_dp); assert_edp_pll_disabled(dev_priv); @@ -251,7 +251,7 @@ static void ilk_edp_pll_off(struct intel_dp *intel_dp, struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - assert_pipe_disabled(dev_priv, old_crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, old_crtc_state->cpu_transcoder); assert_dp_port_disabled(intel_dp); assert_edp_pll_enabled(dev_priv); diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 408f82b0dc7d..1c161eeed82f 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -251,7 +251,7 @@ static void hsw_post_disable_crt(struct intel_atomic_state *state, intel_crtc_vblank_off(old_crtc_state); - intel_disable_pipe(old_crtc_state); + intel_disable_transcoder(old_crtc_state); intel_ddi_disable_transcoder_func(old_crtc_state); @@ -314,7 +314,7 @@ static void hsw_enable_crt(struct intel_atomic_state *state, intel_ddi_enable_transcoder_func(encoder, crtc_state); - intel_enable_pipe(crtc_state); + intel_enable_transcoder(crtc_state); lpt_pch_enable(crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 23ef291f7b30..c7e12b09106f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2867,7 +2867,7 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state, if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST)) { intel_crtc_vblank_off(old_crtc_state); - intel_disable_pipe(old_crtc_state); + intel_disable_transcoder(old_crtc_state); intel_vrr_disable(old_crtc_state); @@ -3138,7 +3138,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_vrr_enable(encoder, crtc_state); - intel_enable_pipe(crtc_state); + intel_enable_transcoder(crtc_state); intel_crtc_vblank_on(crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a7ca38613f89..bc59fba02386 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -120,7 +120,7 @@ static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_sta const struct intel_link_m_n *m2_n2); static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state); static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state); -static void hsw_set_pipeconf(const struct intel_crtc_state *crtc_state); +static void hsw_set_transconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state); static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, @@ -448,8 +448,8 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) pipe_name(pipe)); } -void assert_pipe(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder, bool state) +void assert_transcoder(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder, bool state) { bool cur_state; enum intel_display_power_domain power_domain; @@ -766,7 +766,7 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc) return crtc->pipe; } -void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state) +void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -827,7 +827,7 @@ void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state) intel_wait_for_pipe_scanline_moving(crtc); } -void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state) +void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -2905,7 +2905,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, if (dev_priv->display.initial_watermarks) dev_priv->display.initial_watermarks(state, crtc); - intel_enable_pipe(new_crtc_state); + intel_enable_transcoder(new_crtc_state); if (new_crtc_state->has_pch_encoder) ilk_pch_enable(state, new_crtc_state); @@ -3084,7 +3084,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, } if (!transcoder_is_dsi(cpu_transcoder)) - hsw_set_pipeconf(new_crtc_state); + hsw_set_transconf(new_crtc_state); crtc->active = true; @@ -3179,7 +3179,7 @@ static void ilk_crtc_disable(struct intel_atomic_state *state, intel_crtc_vblank_off(old_crtc_state); - intel_disable_pipe(old_crtc_state); + intel_disable_transcoder(old_crtc_state); ilk_pfit_disable(old_crtc_state); @@ -3241,7 +3241,7 @@ static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state) */ drm_WARN_ON(&dev_priv->drm, intel_de_read(dev_priv, PFIT_CONTROL) & PFIT_ENABLE); - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); intel_de_write(dev_priv, PFIT_PGM_RATIOS, crtc_state->gmch_pfit.pgm_ratios); @@ -3533,7 +3533,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, intel_disable_primary_plane(new_crtc_state); dev_priv->display.initial_watermarks(state, crtc); - intel_enable_pipe(new_crtc_state); + intel_enable_transcoder(new_crtc_state); intel_crtc_vblank_on(new_crtc_state); @@ -3579,7 +3579,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, dev_priv->display.initial_watermarks(state, crtc); else intel_update_watermarks(crtc); - intel_enable_pipe(new_crtc_state); + intel_enable_transcoder(new_crtc_state); intel_crtc_vblank_on(new_crtc_state); @@ -3598,7 +3598,7 @@ static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state) if (!old_crtc_state->gmch_pfit.control) return; - assert_pipe_disabled(dev_priv, old_crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, old_crtc_state->cpu_transcoder); drm_dbg_kms(&dev_priv->drm, "disabling pfit, current: 0x%08x\n", intel_de_read(dev_priv, PFIT_CONTROL)); @@ -3624,7 +3624,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, intel_crtc_vblank_off(old_crtc_state); - intel_disable_pipe(old_crtc_state); + intel_disable_transcoder(old_crtc_state); i9xx_pfit_disable(old_crtc_state); @@ -5194,7 +5194,7 @@ static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state) intel_de_posting_read(dev_priv, PIPECONF(pipe)); } -static void hsw_set_pipeconf(const struct intel_crtc_state *crtc_state) +static void hsw_set_transconf(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 4719ffc97fce..d425ee77aad7 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -531,8 +531,8 @@ enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port); bool is_trans_port_sync_mode(const struct intel_crtc_state *state); void intel_plane_destroy(struct drm_plane *plane); -void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state); -void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state); +void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state); +void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); @@ -657,10 +657,10 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_fdi_rx_pll_enabled(d, p) assert_fdi_rx_pll(d, p, true) #define assert_fdi_rx_pll_disabled(d, p) assert_fdi_rx_pll(d, p, false) -void assert_pipe(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder, bool state); -#define assert_pipe_enabled(d, t) assert_pipe(d, t, true) -#define assert_pipe_disabled(d, t) assert_pipe(d, t, false) +void assert_transcoder(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder, bool state); +#define assert_transcoder_enabled(d, t) assert_transcoder(d, t, true) +#define assert_transcoder_disabled(d, t) assert_transcoder(d, t, false) /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index d104441344c0..f7a0470b1f1c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -405,7 +405,7 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, intel_crtc_vblank_off(old_crtc_state); - intel_disable_pipe(old_crtc_state); + intel_disable_transcoder(old_crtc_state); drm_dp_update_payload_part2(&intel_dp->mst_mgr); @@ -566,7 +566,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), 0, FECSTALL_DIS_DPTSTREAM_DPTTG); - intel_enable_pipe(pipe_config); + intel_enable_transcoder(pipe_config); intel_crtc_vblank_on(pipe_config); diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index ace9157a1c30..487d8721ecf8 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1402,7 +1402,7 @@ void i9xx_enable_pll(const struct intel_crtc_state *crtc_state) enum pipe pipe = crtc->pipe; int i; - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); /* PLL is protected by panel, make sure we can write it */ if (i9xx_has_pps(dev_priv)) @@ -1582,7 +1582,7 @@ void vlv_enable_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); /* PLL is protected by panel, make sure we can write it */ assert_panel_unlocked(dev_priv, pipe); @@ -1734,7 +1734,7 @@ void chv_enable_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); /* PLL is protected by panel, make sure we can write it */ assert_panel_unlocked(dev_priv, pipe); @@ -1818,7 +1818,7 @@ void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) u32 val; /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + assert_transcoder_disabled(dev_priv, (enum transcoder)pipe); val = DPLL_INTEGRATED_REF_CLK_VLV | DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; @@ -1835,7 +1835,7 @@ void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) u32 val; /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + assert_transcoder_disabled(dev_priv, (enum transcoder)pipe); val = DPLL_SSC_REF_CLK_CHV | DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; @@ -1866,7 +1866,7 @@ void i9xx_disable_pll(const struct intel_crtc_state *crtc_state) return; /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); intel_de_write(dev_priv, DPLL(pipe), DPLL_VGA_MODE_DIS); intel_de_posting_read(dev_priv, DPLL(pipe)); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index fc09b781f15f..96ff12ad0873 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -281,7 +281,7 @@ static void ilk_fdi_link_train(struct intel_crtc *crtc, intel_de_read(dev_priv, PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); /* FDI needs bits from pipe first */ - assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder); + assert_transcoder_enabled(dev_priv, crtc_state->cpu_transcoder); /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index d02f09f7e750..88a398df9621 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1529,7 +1529,7 @@ static void intel_tv_pre_enable(struct intel_atomic_state *state, intel_de_write(dev_priv, TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + assert_transcoder_disabled(dev_priv, pipe_config->cpu_transcoder); /* Filter ctl must be set before TV_WIN_SIZE */ tv_filter_ctl = TV_AUTO_SCALE; From c98e3d15b5820778ea7f9d93531ffb1c91c0108f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:30 +0300 Subject: [PATCH 006/554] drm/i915: Introduce with_intel_display_power_if_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the _if_enabled() counterpart to with_intel_display_power(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_power.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index 978531841fa3..0612e4b6e3c8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -410,6 +410,10 @@ void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, for ((wf) = intel_display_power_get((i915), (domain)); (wf); \ intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0) +#define with_intel_display_power_if_enabled(i915, domain, wf) \ + for ((wf) = intel_display_power_get_if_enabled((i915), (domain)); (wf); \ + intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0) + void chv_phy_powergate_lanes(struct intel_encoder *encoder, bool override, unsigned int mask); bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, From 32f6734c724335a4f03b83a1a39f189d66ad5d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:31 +0300 Subject: [PATCH 007/554] drm/i915: Adjust intel_dsc_power_domain() calling convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the crtc+cpu_transcoder rather than the crtc state to intel_dsc_power_domain(). This should allow us to reuse it during readout as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-8-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 6 +- drivers/gpu/drm/i915/display/intel_vdsc.c | 77 ++++++++++---------- drivers/gpu/drm/i915/display/intel_vdsc.h | 6 +- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index bc59fba02386..3163a7213741 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3426,16 +3426,16 @@ static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; struct drm_encoder *encoder; enum pipe pipe = crtc->pipe; u64 mask; - enum transcoder transcoder = crtc_state->cpu_transcoder; if (!crtc_state->hw.active) return 0; mask = BIT_ULL(POWER_DOMAIN_PIPE(pipe)); - mask |= BIT_ULL(POWER_DOMAIN_TRANSCODER(transcoder)); + mask |= BIT_ULL(POWER_DOMAIN_TRANSCODER(cpu_transcoder)); if (crtc_state->pch_pfit.enabled || crtc_state->pch_pfit.force_thru) mask |= BIT_ULL(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); @@ -3454,7 +3454,7 @@ static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state) mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE); if (crtc_state->dsc.compression_enable) - mask |= BIT_ULL(intel_dsc_power_domain(crtc_state)); + mask |= BIT_ULL(intel_dsc_power_domain(crtc, cpu_transcoder)); return mask; } diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index df3286aa6999..2275f99ce9d7 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -357,11 +357,9 @@ bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state) return false; } -static bool is_pipe_dsc(const struct intel_crtc_state *crtc_state) +static bool is_pipe_dsc(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { - const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_i915_private *i915 = to_i915(crtc->base.dev); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); if (DISPLAY_VER(i915) >= 12) return true; @@ -547,9 +545,8 @@ int intel_dsc_compute_params(struct intel_encoder *encoder, } enum intel_display_power_domain -intel_dsc_power_domain(const struct intel_crtc_state *crtc_state) +intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; @@ -566,7 +563,7 @@ intel_dsc_power_domain(const struct intel_crtc_state *crtc_state) */ if (DISPLAY_VER(i915) == 12 && !IS_ROCKETLAKE(i915) && pipe == PIPE_A) return POWER_DOMAIN_TRANSCODER_VDSC_PW2; - else if (is_pipe_dsc(crtc_state)) + else if (is_pipe_dsc(crtc, cpu_transcoder)) return POWER_DOMAIN_PIPE(pipe); else return POWER_DOMAIN_TRANSCODER_VDSC_PW2; @@ -577,6 +574,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; u32 pps_val = 0; u32 rc_buf_thresh_dword[4]; @@ -601,7 +599,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) if (vdsc_cfg->vbr_enable) pps_val |= DSC_VBR_ENABLE; drm_info(&dev_priv->drm, "PPS0 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_0, pps_val); /* @@ -625,7 +623,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val = 0; pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel); drm_info(&dev_priv->drm, "PPS1 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_1, pps_val); /* @@ -650,7 +648,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) | DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances); drm_info(&dev_priv->drm, "PPS2 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_2, pps_val); /* @@ -675,7 +673,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) | DSC_SLICE_WIDTH(vdsc_cfg->slice_width); drm_info(&dev_priv->drm, "PPS3 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_3, pps_val); /* @@ -700,7 +698,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) | DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay); drm_info(&dev_priv->drm, "PPS4 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_4, pps_val); /* @@ -725,7 +723,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) | DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval); drm_info(&dev_priv->drm, "PPS5 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_5, pps_val); /* @@ -752,7 +750,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) | DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp); drm_info(&dev_priv->drm, "PPS6 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_6, pps_val); /* @@ -777,7 +775,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) | DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset); drm_info(&dev_priv->drm, "PPS7 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_7, pps_val); /* @@ -802,7 +800,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) | DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset); drm_info(&dev_priv->drm, "PPS8 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_8, pps_val); /* @@ -827,7 +825,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) pps_val |= DSC_RC_MODEL_SIZE(vdsc_cfg->rc_model_size) | DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST); drm_info(&dev_priv->drm, "PPS9 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_9, pps_val); /* @@ -854,7 +852,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) | DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST); drm_info(&dev_priv->drm, "PPS10 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_10, pps_val); /* @@ -882,7 +880,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height / vdsc_cfg->slice_height); drm_info(&dev_priv->drm, "PPS16 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_16, pps_val); /* @@ -911,7 +909,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) drm_info(&dev_priv->drm, " RC_BUF_THRESH%d = 0x%08x\n", i, rc_buf_thresh_dword[i / 4]); } - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]); intel_de_write(dev_priv, DSCA_RC_BUF_THRESH_0_UDW, @@ -968,7 +966,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) drm_info(&dev_priv->drm, " RC_RANGE_PARAM_%d = 0x%08x\n", i, rc_range_params_dword[i / 2]); } - if (!is_pipe_dsc(crtc_state)) { + if (!is_pipe_dsc(crtc, cpu_transcoder)) { intel_de_write(dev_priv, DSCA_RC_RANGE_PARAMETERS_0, rc_range_params_dword[0]); intel_de_write(dev_priv, DSCA_RC_RANGE_PARAMETERS_0_UDW, @@ -1095,18 +1093,16 @@ static void intel_dsc_dp_pps_write(struct intel_encoder *encoder, sizeof(dp_dsc_pps_sdp)); } -static i915_reg_t dss_ctl1_reg(const struct intel_crtc_state *crtc_state) +static i915_reg_t dss_ctl1_reg(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - - return is_pipe_dsc(crtc_state) ? ICL_PIPE_DSS_CTL1(pipe) : DSS_CTL1; + return is_pipe_dsc(crtc, cpu_transcoder) ? + ICL_PIPE_DSS_CTL1(crtc->pipe) : DSS_CTL1; } -static i915_reg_t dss_ctl2_reg(const struct intel_crtc_state *crtc_state) +static i915_reg_t dss_ctl2_reg(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - - return is_pipe_dsc(crtc_state) ? ICL_PIPE_DSS_CTL2(pipe) : DSS_CTL2; + return is_pipe_dsc(crtc, cpu_transcoder) ? + ICL_PIPE_DSS_CTL2(crtc->pipe) : DSS_CTL2; } static struct intel_crtc * @@ -1142,7 +1138,7 @@ void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state) else dss_ctl1_val |= UNCOMPRESSED_JOINER_MASTER; - intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val); + intel_de_write(dev_priv, dss_ctl1_reg(crtc, crtc_state->cpu_transcoder), dss_ctl1_val); } } @@ -1176,8 +1172,8 @@ void intel_dsc_enable(struct intel_encoder *encoder, if (!crtc_state->bigjoiner_slave) dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE; } - intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val); - intel_de_write(dev_priv, dss_ctl2_reg(crtc_state), dss_ctl2_val); + intel_de_write(dev_priv, dss_ctl1_reg(crtc, crtc_state->cpu_transcoder), dss_ctl1_val); + intel_de_write(dev_priv, dss_ctl2_reg(crtc, crtc_state->cpu_transcoder), dss_ctl2_val); } void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) @@ -1188,8 +1184,8 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) /* Disable only if either of them is enabled */ if (old_crtc_state->dsc.compression_enable || old_crtc_state->bigjoiner) { - intel_de_write(dev_priv, dss_ctl1_reg(old_crtc_state), 0); - intel_de_write(dev_priv, dss_ctl2_reg(old_crtc_state), 0); + intel_de_write(dev_priv, dss_ctl1_reg(crtc, old_crtc_state->cpu_transcoder), 0); + intel_de_write(dev_priv, dss_ctl2_reg(crtc, old_crtc_state->cpu_transcoder), 0); } } @@ -1199,7 +1195,7 @@ void intel_uncompressed_joiner_get_config(struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 dss_ctl1; - dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state)); + dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc, crtc_state->cpu_transcoder)); if (dss_ctl1 & UNCOMPRESSED_JOINER_MASTER) { crtc_state->bigjoiner = true; crtc_state->bigjoiner_linked_crtc = intel_dsc_get_bigjoiner_secondary(crtc); @@ -1214,9 +1210,10 @@ void intel_uncompressed_joiner_get_config(struct intel_crtc_state *crtc_state) void intel_dsc_get_config(struct intel_crtc_state *crtc_state) { - struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; enum intel_display_power_domain power_domain; intel_wakeref_t wakeref; @@ -1225,14 +1222,14 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state) if (!intel_dsc_source_support(crtc_state)) return; - power_domain = intel_dsc_power_domain(crtc_state); + power_domain = intel_dsc_power_domain(crtc, cpu_transcoder); wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); if (!wakeref) return; - dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state)); - dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg(crtc_state)); + dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc, cpu_transcoder)); + dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg(crtc, cpu_transcoder)); crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE; if (!crtc_state->dsc.compression_enable) @@ -1256,7 +1253,7 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state) /* FIXME: add more state readout as needed */ /* PPS1 */ - if (!is_pipe_dsc(crtc_state)) + if (!is_pipe_dsc(crtc, cpu_transcoder)) val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1); else val = intel_de_read(dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h index dfb1fd38deb4..0c5d80a572da 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc.h @@ -8,8 +8,10 @@ #include -struct intel_encoder; +enum transcoder; +struct intel_crtc; struct intel_crtc_state; +struct intel_encoder; bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state); void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state); @@ -21,7 +23,7 @@ int intel_dsc_compute_params(struct intel_encoder *encoder, void intel_uncompressed_joiner_get_config(struct intel_crtc_state *crtc_state); void intel_dsc_get_config(struct intel_crtc_state *crtc_state); enum intel_display_power_domain -intel_dsc_power_domain(const struct intel_crtc_state *crtc_state); +intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder); struct intel_crtc *intel_dsc_get_bigjoiner_secondary(const struct intel_crtc *primary_crtc); #endif /* __INTEL_VDSC_H__ */ From 262d88baad8d8a7c13124fb9807db399b3e595f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:32 +0300 Subject: [PATCH 008/554] drm/i915: Extract hsw_panel_transcoders() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the "panel transcoder" bitmask into a helper. We'll have a couple of uses for this later. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-9-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3163a7213741..f6c0c595f631 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5599,21 +5599,27 @@ out: return ret; } +static u8 hsw_panel_transcoders(struct drm_i915_private *i915) +{ + u8 panel_transcoder_mask = BIT(TRANSCODER_EDP); + + if (DISPLAY_VER(i915) >= 11) + panel_transcoder_mask |= BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1); + + return panel_transcoder_mask; +} + static bool hsw_get_transcoder_state(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config, struct intel_display_power_domain_set *power_domain_set) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - unsigned long panel_transcoder_mask = BIT(TRANSCODER_EDP); + u8 panel_transcoder_mask = hsw_panel_transcoders(dev_priv); unsigned long enabled_panel_transcoders = 0; enum transcoder panel_transcoder; u32 tmp; - if (DISPLAY_VER(dev_priv) >= 11) - panel_transcoder_mask |= - BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1); - /* * The pipe->transcoder mapping is fixed with the exception of the eDP * and DSI transcoders handled below. From f6d66fc8cf5f673ea76407be84dc17dbb3eda108 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Tue, 14 Sep 2021 15:07:44 -0700 Subject: [PATCH 009/554] drm/i915: Update memory bandwidth parameters Earlier while calculating derated bw we would use 90% of the calculated bw. Starting ADL-P we use a non standard derating. Updating the formulae to reflect the same. Bspec: 64631 v2: Use the new derating value only for ADL-P(MattR) Fixes: 4d32fe2f14a7 ("drm/i915/adl_p: Update memory bandwidth parameters") Cc: Matt Roper Signed-off-by: Radhakrishna Sripada Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210914220744.16042-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/display/intel_bw.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index e91e0e0191fb..4b94256d7319 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -222,31 +222,42 @@ static int icl_sagv_max_dclk(const struct intel_qgv_info *qi) struct intel_sa_info { u16 displayrtids; - u8 deburst, deprogbwlimit; + u8 deburst, deprogbwlimit, derating; }; static const struct intel_sa_info icl_sa_info = { .deburst = 8, .deprogbwlimit = 25, /* GB/s */ .displayrtids = 128, + .derating = 10, }; static const struct intel_sa_info tgl_sa_info = { .deburst = 16, .deprogbwlimit = 34, /* GB/s */ .displayrtids = 256, + .derating = 10, }; static const struct intel_sa_info rkl_sa_info = { .deburst = 16, .deprogbwlimit = 20, /* GB/s */ .displayrtids = 128, + .derating = 10, }; static const struct intel_sa_info adls_sa_info = { .deburst = 16, .deprogbwlimit = 38, /* GB/s */ .displayrtids = 256, + .derating = 10, +}; + +static const struct intel_sa_info adlp_sa_info = { + .deburst = 16, + .deprogbwlimit = 38, /* GB/s */ + .displayrtids = 256, + .derating = 20, }; static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa) @@ -302,7 +313,7 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel bw = icl_calc_bw(sp->dclk, clpchgroup * 32 * num_channels, ct); bi->deratedbw[j] = min(maxdebw, - bw * 9 / 10); /* 90% */ + bw * (100 - sa->derating) / 100); drm_dbg_kms(&dev_priv->drm, "BW%d / QGV %d: num_planes=%d deratedbw=%u\n", @@ -400,7 +411,9 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv) if (IS_DG2(dev_priv)) dg2_get_bw_info(dev_priv); - else if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) + else if (IS_ALDERLAKE_P(dev_priv)) + icl_get_bw_info(dev_priv, &adlp_sa_info); + else if (IS_ALDERLAKE_S(dev_priv)) icl_get_bw_info(dev_priv, &adls_sa_info); else if (IS_ROCKETLAKE(dev_priv)) icl_get_bw_info(dev_priv, &rkl_sa_info); From 48b0961269546716c3232748bf37e64e49fb866c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 30 Aug 2021 14:09:48 +0200 Subject: [PATCH 010/554] drm/i915: Move __i915_gem_free_object to ttm_bo_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we implement delayed destroy, we may have a second call to the delete_mem_notify() handler, while free_object() only should be called once. Move it to bo->destroy(), to ensure it's only called once. This fixes some weird memory corruption issues with delayed destroy when async eviction is used. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20210830121006.2978297-2-maarten.lankhorst@linux.intel.com Fixes: 213d50927763 ("drm/i915/ttm: Introduce a TTM i915 gem object backend") Cc: Thomas Hellström Reviewed-by: Thomas Hellström --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 3225fda1f0f6..1e9fb126cb7b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -356,11 +356,8 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); - if (likely(obj)) { - /* This releases all gem object bindings to the backend. */ + if (likely(obj)) i915_ttm_free_cached_io_st(obj); - __i915_gem_free_object(obj); - } } static struct intel_memory_region * @@ -886,8 +883,12 @@ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); + /* This releases all gem object bindings to the backend. */ + __i915_gem_free_object(obj); + i915_gem_object_release_memory_region(obj); mutex_destroy(&obj->ttm.get_io_page.lock); + if (obj->ttm.created) call_rcu(&obj->rcu, __i915_gem_free_object_rcu); } From 064b877dff4252ced91a1c8b1f129073f2991f6e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 9 Aug 2021 12:48:05 -0700 Subject: [PATCH 011/554] drm/i915: Free all DMC payloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Free all the DMC payloads, not just DMC_MAIN. unreferenced object 0xffff88ff32d4d800 (size 1024): comm "kworker/1:5", pid 701, jiffies 4294904239 (age 109.736s) hex dump (first 32 bytes): 40 40 00 0c 03 00 00 00 00 00 00 00 00 00 00 00 @@.............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000ba9d0d95>] dmc_load_work_fn+0x34d/0x510 [i915] [<000000001049fcab>] process_one_work+0x261/0x550 [<00000000eeb995ac>] worker_thread+0x49/0x3c0 [<0000000021031dc3>] kthread+0x10b/0x140 [<000000004a0f69ee>] ret_from_fork+0x1f/0x30 unreferenced object 0xffff88ff0bde4000 (size 1024): comm "kworker/0:3", pid 708, jiffies 4294904469 (age 108.816s) hex dump (first 32 bytes): 40 40 00 0c 01 00 00 00 00 00 00 00 00 00 00 00 @@.............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000ba9d0d95>] dmc_load_work_fn+0x34d/0x510 [i915] [<000000001049fcab>] process_one_work+0x261/0x550 [<00000000eeb995ac>] worker_thread+0x49/0x3c0 [<0000000021031dc3>] kthread+0x10b/0x140 [<000000004a0f69ee>] ret_from_fork+0x1f/0x30 Fixes: 3d5928a168a9 ("drm/i915/xelpd: Pipe A DMC plugging") Cc: Anusha Srivatsa Cc: José Roberto de Souza Signed-off-by: Chris Wilson Signed-off-by: Lucas De Marchi Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210809194805.3793060-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 3c3c6cb5c0df..b3c8e1c450ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -805,11 +805,14 @@ void intel_dmc_ucode_resume(struct drm_i915_private *dev_priv) */ void intel_dmc_ucode_fini(struct drm_i915_private *dev_priv) { + int id; + if (!HAS_DMC(dev_priv)) return; intel_dmc_ucode_suspend(dev_priv); drm_WARN_ON(&dev_priv->drm, dev_priv->dmc.wakeref); - kfree(dev_priv->dmc.dmc_info[DMC_FW_MAIN].payload); + for (id = 0; id < DMC_FW_MAX; id++) + kfree(dev_priv->dmc.dmc_info[id].payload); } From 259d71992e57c637aa0a5d3f4f7b9f689c186191 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Tue, 14 Sep 2021 14:57:32 -0700 Subject: [PATCH 012/554] drm/i915/dmc: Update to DMC v2.12 The release notes mentions that this version- 1. Fix for unblock indication to punit. 2. Robustness fix for DC6/6v abort scenarios. Cc: Imre Deak > Signed-off-by: Anusha Srivatsa Reviewed-by: Imre Deak Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20210914215732.67135-2-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b3c8e1c450ef..b0268552b286 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -45,8 +45,8 @@ #define GEN12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE -#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 10) -#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 10) +#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 12) +#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 12) MODULE_FIRMWARE(ADLP_DMC_PATH); #define ADLS_DMC_PATH DMC_PATH(adls, 2, 01) From 72fe6ca84f080a01218d9208e2fa8ce8baaec548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 14 Sep 2021 14:25:03 -0700 Subject: [PATCH 013/554] drm/i915/display/adlp: Fix PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the SU_REGION_START begins at 0, the SU_REGION_END should be number of lines - 1. BSpec: 50424 Reviewed-by: Gwan-gyeong Mun Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210914212507.177511-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 3f6fb7d67f84..36816abb3bcc 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1501,7 +1501,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, if (IS_ALDERLAKE_P(dev_priv)) { val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1); - val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2); + val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1); } else { drm_WARN_ON(crtc_state->uapi.crtc->dev, clip->y1 % 4 || clip->y2 % 4); From ce0eacbbd922b91ce28523b167ef848d0f76f908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 14 Sep 2021 14:25:04 -0700 Subject: [PATCH 014/554] drm/i915/display: Wait at least 2 frames before selective update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BSpec states that the minimum number of frames before selective update is 2, so making sure this minimum limit is fulfilled. BSpec: 50422 Reviewed-by: Gwan-gyeong Mun Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210914212507.177511-2-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 36816abb3bcc..567c7ceef8db 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -510,7 +510,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) val |= EDP_Y_COORDINATE_ENABLE; - val |= EDP_PSR2_FRAME_BEFORE_SU(intel_dp->psr.sink_sync_latency + 1); + val |= EDP_PSR2_FRAME_BEFORE_SU(max_t(u8, intel_dp->psr.sink_sync_latency + 1, 2)); val |= intel_psr2_get_tp_time(intel_dp); /* Wa_22012278275:adl-p */ From 1f3a11c341ab211d6ba55ef3d58026b7b5319945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 14 Sep 2021 14:25:05 -0700 Subject: [PATCH 015/554] drm/i915/display: Workaround cursor left overs with PSR2 selective fetch enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure why but when moving the cursor fast it causes some artifacts of the cursor to be left in the cursor path, adding some pixels above the cursor to the damaged area fixes the issue, so leaving this as a workaround until proper fix is found. This is reproducile on TGL and ADL-P. Cc: Gwan-gyeong Mun Reviewed-by: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210914212507.177511-3-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 567c7ceef8db..f8fa30e50e70 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1543,6 +1543,28 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c drm_warn(&dev_priv->drm, "Missing PSR2 sel fetch alignment with DSC\n"); } +/* + * FIXME: Not sure why but when moving the cursor fast it causes some artifacts + * of the cursor to be left in the cursor path, adding some pixels above the + * cursor to the damaged area fixes the issue. + */ +static void cursor_area_workaround(const struct intel_plane_state *new_plane_state, + struct drm_rect *damaged_area, + struct drm_rect *pipe_clip) +{ + const struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); + int height; + + if (plane->id != PLANE_CURSOR) + return; + + height = drm_rect_height(&new_plane_state->uapi.dst) / 2; + damaged_area->y1 -= height; + damaged_area->y1 = max(damaged_area->y1, 0); + + clip_area_update(pipe_clip, damaged_area); +} + int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -1611,6 +1633,9 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.y2 = new_plane_state->uapi.dst.y2; clip_area_update(&pipe_clip, &damaged_area); } + + cursor_area_workaround(new_plane_state, &damaged_area, + &pipe_clip); continue; } else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha || (!num_clips && From af7ea1e22afc7ce7773b2e4562df4370c8c711ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 14 Sep 2021 14:25:06 -0700 Subject: [PATCH 016/554] drm/i915/display/psr: Use drm damage helpers to calculate plane damaged area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_atomic_helper_damage_iter_init() + drm_atomic_for_each_plane_damage() returns the full plane area in case no damaged area was set by userspace or it was discarted by driver. This is important to fix the rendering of userspace applications that does frontbuffer rendering and notify driver about dirty areas but do not set any dirty clips. With this we don't need to worry about to check and mark the whole area as damaged in page flips. Another important change here is the move of drm_atomic_add_affected_planes() call, it needs to called late otherwise the area of all the planes would be added to pipe_clip and not saving power. Cc: Daniel Vetter Cc: Gwan-gyeong Mun Reviewed-by: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210914212507.177511-4-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 37 +++++++++--------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index f8fa30e50e70..5a1535e11e6b 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -22,6 +22,7 @@ */ #include +#include #include "display/intel_dp.h" @@ -1578,10 +1579,6 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (!crtc_state->enable_psr2_sel_fetch) return 0; - ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); - if (ret) - return ret; - /* * Calculate minimal selective fetch area of each plane and calculate * the pipe damaged area. @@ -1591,8 +1588,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { struct drm_rect src, damaged_area = { .y1 = -1 }; - struct drm_mode_rect *damaged_clips; - u32 num_clips, j; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc) continue; @@ -1612,8 +1609,6 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, break; } - num_clips = drm_plane_get_damage_clips_count(&new_plane_state->uapi); - /* * If visibility or plane moved, mark the whole plane area as * damaged as it needs to be complete redraw in the new and old @@ -1637,14 +1632,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, cursor_area_workaround(new_plane_state, &damaged_area, &pipe_clip); continue; - } else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha || - (!num_clips && - new_plane_state->uapi.fb != old_plane_state->uapi.fb)) { - /* - * If the plane don't have damaged areas but the - * framebuffer changed or alpha changed, mark the whole - * plane area as damaged. - */ + } else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha) { + /* If alpha changed mark the whole plane area as damaged */ damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; clip_area_update(&pipe_clip, &damaged_area); @@ -1652,15 +1641,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, } drm_rect_fp_to_int(&src, &new_plane_state->uapi.src); - damaged_clips = drm_plane_get_damage_clips(&new_plane_state->uapi); - for (j = 0; j < num_clips; j++) { - struct drm_rect clip; - - clip.x1 = damaged_clips[j].x1; - clip.y1 = damaged_clips[j].y1; - clip.x2 = damaged_clips[j].x2; - clip.y2 = damaged_clips[j].y2; + drm_atomic_helper_damage_iter_init(&iter, + &old_plane_state->uapi, + &new_plane_state->uapi); + drm_atomic_for_each_plane_damage(&iter, &clip) { if (drm_rect_intersect(&clip, &src)) clip_area_update(&damaged_area, &clip); } @@ -1676,6 +1661,10 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (full_update) goto skip_sel_fetch_set_loop; + ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); + if (ret) + return ret; + intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip); /* From 641dd82ffa9daad38f630d9f4a36e4875fd4e0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 14 Sep 2021 14:25:07 -0700 Subject: [PATCH 017/554] drm/i915/display/adlp: Add new PSR2 workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wa_16014451276 fixes the starting coordinate for PSR2 selective updates. CHICKEN_TRANS definition of the workaround bit has a wrong name based on workaround definition and HSD. Wa_14014971508 allows the screen to continue to be updated when coming back from DC5/DC6 and SF_SINGLE_FULL_FRAME bit is not kept set in PSR2_MAN_TRK_CTL. Wa_16012604467 fixes underruns when exiting PSR2 when it is in one of its internal states. Wa_14014971508 is still in pending status in BSpec but by the time this is reviewed and ready to be merged it will be finalized. v2: - renamed register to ADLP_1_BASED_X_GRANULARITY - added comment about all ADL-P supported panels being 1 based X granularity BSpec: 54369 BSpec: 50054 Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210914212507.177511-5-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 27 +++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 5a1535e11e6b..c1894b056d6c 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1087,6 +1087,16 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp) intel_de_write(dev_priv, reg, chicken); } + /* + * Wa_16014451276:adlp + * All supported adlp panels have 1-based X granularity, this may + * cause issues if non-supported panels are used. + */ + if (IS_ALDERLAKE_P(dev_priv) && + intel_dp->psr.psr2_enabled) + intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), 0, + ADLP_1_BASED_X_GRANULARITY); + /* * Per Spec: Avoid continuous PSR exit by masking MEMUP and HPD also * mask LPSP to avoid dependency on other drivers that might block @@ -1132,6 +1142,11 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp) TRANS_SET_CONTEXT_LATENCY(intel_dp->psr.transcoder), TRANS_SET_CONTEXT_LATENCY_MASK, TRANS_SET_CONTEXT_LATENCY_VALUE(1)); + + /* Wa_16012604467:adlp */ + if (IS_ALDERLAKE_P(dev_priv) && intel_dp->psr.psr2_enabled) + intel_de_rmw(dev_priv, CLKGATE_DIS_MISC, 0, + CLKGATE_DIS_MISC_DMASC_GATING_DIS); } static bool psr_interrupt_error_check(struct intel_dp *intel_dp) @@ -1321,6 +1336,11 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) TRANS_SET_CONTEXT_LATENCY(intel_dp->psr.transcoder), TRANS_SET_CONTEXT_LATENCY_MASK, 0); + /* Wa_16012604467:adlp */ + if (IS_ALDERLAKE_P(dev_priv) && intel_dp->psr.psr2_enabled) + intel_de_rmw(dev_priv, CLKGATE_DIS_MISC, + CLKGATE_DIS_MISC_DMASC_GATING_DIS, 0); + intel_snps_phy_update_psr_power_state(dev_priv, phy, false); /* Disable PSR on Sink */ @@ -1489,8 +1509,13 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, u32 val = PSR2_MAN_TRK_CTL_ENABLE; if (full_update) { + /* + * Wa_14014971508:adlp + * SINGLE_FULL_FRAME bit is not hold in register so can not be + * restored by DMC, so using CONTINUOS_FULL_FRAME to mimic that + */ if (IS_ALDERLAKE_P(dev_priv)) - val |= ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; + val |= ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME; else val |= PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bd63760207b0..67351ed5ab5b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8205,6 +8205,7 @@ enum { #define VSC_DATA_SEL_SOFTWARE_CONTROL REG_BIT(25) /* GLK */ #define FECSTALL_DIS_DPTSTREAM_DPTTG REG_BIT(23) #define DDI_TRAINING_OVERRIDE_ENABLE REG_BIT(19) +#define ADLP_1_BASED_X_GRANULARITY REG_BIT(18) #define DDI_TRAINING_OVERRIDE_VALUE REG_BIT(18) #define DDIE_TRAINING_OVERRIDE_ENABLE REG_BIT(17) /* CHICKEN_TRANS_A only */ #define DDIE_TRAINING_OVERRIDE_VALUE REG_BIT(16) /* CHICKEN_TRANS_A only */ @@ -12759,4 +12760,7 @@ enum skl_power_gate { #define CLKREQ_POLICY _MMIO(0x101038) #define CLKREQ_POLICY_MEM_UP_OVRD REG_BIT(1) +#define CLKGATE_DIS_MISC _MMIO(0x46534) +#define CLKGATE_DIS_MISC_DMASC_GATING_DIS REG_BIT(21) + #endif /* _I915_REG_H_ */ From 022f324c9934cc9e603923121f108eb8623a986c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 17 Sep 2021 19:57:51 -0700 Subject: [PATCH 018/554] drm/i915: rename debugfs_gt files We shouldn't be using debugfs_ namespace for this functionality. Rename debugfs_gt.[ch] to intel_gt_debugfs.[ch] and then make functions, defines and structs follow suit. While at it and since we are renaming the header, sort the includes alphabetically. Signed-off-by: Lucas De Marchi Acked-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210918025754.1254705-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/gt/debugfs_engines.c | 6 +++--- drivers/gpu/drm/i915/gt/debugfs_gt_pm.c | 14 +++++++------- drivers/gpu/drm/i915/gt/intel_gt.c | 6 +++--- .../gt/{debugfs_gt.c => intel_gt_debugfs.c} | 8 ++++---- .../gt/{debugfs_gt.h => intel_gt_debugfs.h} | 14 +++++++------- drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c | 10 +++++----- drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c | 18 +++++++++--------- .../gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c | 8 ++++---- drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.c | 6 +++--- drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c | 6 +++--- 11 files changed, 49 insertions(+), 49 deletions(-) rename drivers/gpu/drm/i915/gt/{debugfs_gt.c => intel_gt_debugfs.c} (87%) rename drivers/gpu/drm/i915/gt/{debugfs_gt.h => intel_gt_debugfs.h} (71%) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 335ba9f43d8f..7eab4edae2b6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -79,7 +79,6 @@ i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ gt/debugfs_engines.o \ - gt/debugfs_gt.o \ gt/debugfs_gt_pm.o \ gt/gen2_engine_cs.o \ gt/gen6_engine_cs.o \ @@ -100,6 +99,7 @@ gt-y += \ gt/intel_gt.o \ gt/intel_gt_buffer_pool.o \ gt/intel_gt_clock_utils.o \ + gt/intel_gt_debugfs.o \ gt/intel_gt_irq.o \ gt/intel_gt_pm.o \ gt/intel_gt_pm_irq.o \ diff --git a/drivers/gpu/drm/i915/gt/debugfs_engines.c b/drivers/gpu/drm/i915/gt/debugfs_engines.c index 5e3725e62241..2980dac5b171 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_engines.c +++ b/drivers/gpu/drm/i915/gt/debugfs_engines.c @@ -7,9 +7,9 @@ #include #include "debugfs_engines.h" -#include "debugfs_gt.h" #include "i915_drv.h" /* for_each_engine! */ #include "intel_engine.h" +#include "intel_gt_debugfs.h" static int engines_show(struct seq_file *m, void *data) { @@ -24,11 +24,11 @@ static int engines_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(engines); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(engines); void debugfs_engines_register(struct intel_gt *gt, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "engines", &engines_fops }, }; diff --git a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c b/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c index f6733f279890..9222cf68c56c 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c @@ -6,11 +6,11 @@ #include -#include "debugfs_gt.h" #include "debugfs_gt_pm.h" #include "i915_drv.h" #include "intel_gt.h" #include "intel_gt_clock_utils.h" +#include "intel_gt_debugfs.h" #include "intel_gt_pm.h" #include "intel_llc.h" #include "intel_rc6.h" @@ -36,7 +36,7 @@ static int fw_domains_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(fw_domains); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(fw_domains); static void print_rc6_res(struct seq_file *m, const char *title, @@ -238,7 +238,7 @@ static int drpc_show(struct seq_file *m, void *unused) return err; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(drpc); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(drpc); static int frequency_show(struct seq_file *m, void *unused) { @@ -480,7 +480,7 @@ static int frequency_show(struct seq_file *m, void *unused) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(frequency); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(frequency); static int llc_show(struct seq_file *m, void *data) { @@ -533,7 +533,7 @@ static bool llc_eval(void *data) return HAS_LLC(gt->i915); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(llc); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(llc); static const char *rps_power_to_str(unsigned int power) { @@ -612,11 +612,11 @@ static bool rps_eval(void *data) return HAS_RPS(gt->i915); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(rps_boost); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rps_boost); void debugfs_gt_pm_register(struct intel_gt *gt, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "drpc", &drpc_fops, NULL }, { "frequency", &frequency_fops, NULL }, { "forcewake", &fw_domains_fops, NULL }, diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 55e87aff51d2..985922c03297 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -3,7 +3,7 @@ * Copyright © 2019 Intel Corporation */ -#include "debugfs_gt.h" +#include "intel_gt_debugfs.h" #include "gem/i915_gem_lmem.h" #include "i915_drv.h" @@ -15,11 +15,11 @@ #include "intel_gt_requests.h" #include "intel_migrate.h" #include "intel_mocs.h" +#include "intel_pm.h" #include "intel_rc6.h" #include "intel_renderstate.h" #include "intel_rps.h" #include "intel_uncore.h" -#include "intel_pm.h" #include "shmem_utils.h" void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915) @@ -434,7 +434,7 @@ void intel_gt_driver_register(struct intel_gt *gt) { intel_rps_driver_register(>->rps); - debugfs_gt_register(gt); + intel_gt_debugfs_register(gt); } static int intel_gt_init_scratch(struct intel_gt *gt, unsigned int size) diff --git a/drivers/gpu/drm/i915/gt/debugfs_gt.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c similarity index 87% rename from drivers/gpu/drm/i915/gt/debugfs_gt.c rename to drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index 591eb60785db..b19648008265 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -6,13 +6,13 @@ #include #include "debugfs_engines.h" -#include "debugfs_gt.h" #include "debugfs_gt_pm.h" +#include "i915_drv.h" +#include "intel_gt_debugfs.h" #include "intel_sseu_debugfs.h" #include "uc/intel_uc_debugfs.h" -#include "i915_drv.h" -void debugfs_gt_register(struct intel_gt *gt) +void intel_gt_debugfs_register(struct intel_gt *gt) { struct dentry *root; @@ -31,7 +31,7 @@ void debugfs_gt_register(struct intel_gt *gt) } void intel_gt_debugfs_register_files(struct dentry *root, - const struct debugfs_gt_file *files, + const struct intel_gt_debugfs_file *files, unsigned long count, void *data) { while (count--) { diff --git a/drivers/gpu/drm/i915/gt/debugfs_gt.h b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h similarity index 71% rename from drivers/gpu/drm/i915/gt/debugfs_gt.h rename to drivers/gpu/drm/i915/gt/intel_gt_debugfs.h index f77540f727e9..8b6fca09897c 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h @@ -3,14 +3,14 @@ * Copyright © 2019 Intel Corporation */ -#ifndef DEBUGFS_GT_H -#define DEBUGFS_GT_H +#ifndef INTEL_GT_DEBUGFS_H +#define INTEL_GT_DEBUGFS_H #include struct intel_gt; -#define DEFINE_GT_DEBUGFS_ATTRIBUTE(__name) \ +#define DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(__name) \ static int __name ## _open(struct inode *inode, struct file *file) \ { \ return single_open(file, __name ## _show, inode->i_private); \ @@ -23,16 +23,16 @@ static const struct file_operations __name ## _fops = { \ .release = single_release, \ } -void debugfs_gt_register(struct intel_gt *gt); +void intel_gt_debugfs_register(struct intel_gt *gt); -struct debugfs_gt_file { +struct intel_gt_debugfs_file { const char *name; const struct file_operations *fops; bool (*eval)(void *data); }; void intel_gt_debugfs_register_files(struct dentry *root, - const struct debugfs_gt_file *files, + const struct intel_gt_debugfs_file *files, unsigned long count, void *data); -#endif /* DEBUGFS_GT_H */ +#endif /* INTEL_GT_DEBUGFS_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c b/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c index 1ba8b7da9d37..8bb3a91dad82 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c @@ -4,9 +4,9 @@ * Copyright © 2020 Intel Corporation */ -#include "debugfs_gt.h" -#include "intel_sseu_debugfs.h" #include "i915_drv.h" +#include "intel_gt_debugfs.h" +#include "intel_sseu_debugfs.h" static void sseu_copy_subslices(const struct sseu_dev_info *sseu, int slice, u8 *to_mask) @@ -282,7 +282,7 @@ static int sseu_status_show(struct seq_file *m, void *unused) return intel_sseu_status(m, gt); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(sseu_status); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status); static int rcs_topology_show(struct seq_file *m, void *unused) { @@ -293,11 +293,11 @@ static int rcs_topology_show(struct seq_file *m, void *unused) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(rcs_topology); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rcs_topology); void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "sseu_status", &sseu_status_fops, NULL }, { "rcs_topology", &rcs_topology_fops, NULL }, }; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c index 887c8c8f35db..25f09a420561 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c @@ -5,14 +5,14 @@ #include -#include "gt/debugfs_gt.h" +#include "gt/intel_gt_debugfs.h" +#include "gt/uc/intel_guc_ads.h" +#include "gt/uc/intel_guc_ct.h" +#include "gt/uc/intel_guc_slpc.h" +#include "gt/uc/intel_guc_submission.h" #include "intel_guc.h" #include "intel_guc_debugfs.h" #include "intel_guc_log_debugfs.h" -#include "gt/uc/intel_guc_ct.h" -#include "gt/uc/intel_guc_ads.h" -#include "gt/uc/intel_guc_submission.h" -#include "gt/uc/intel_guc_slpc.h" static int guc_info_show(struct seq_file *m, void *data) { @@ -35,7 +35,7 @@ static int guc_info_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(guc_info); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(guc_info); static int guc_registered_contexts_show(struct seq_file *m, void *data) { @@ -49,7 +49,7 @@ static int guc_registered_contexts_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(guc_registered_contexts); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(guc_registered_contexts); static int guc_slpc_info_show(struct seq_file *m, void *unused) { @@ -62,7 +62,7 @@ static int guc_slpc_info_show(struct seq_file *m, void *unused) return intel_guc_slpc_print_info(slpc, &p); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(guc_slpc_info); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(guc_slpc_info); static bool intel_eval_slpc_support(void *data) { @@ -73,7 +73,7 @@ static bool intel_eval_slpc_support(void *data) void intel_guc_debugfs_register(struct intel_guc *guc, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "guc_info", &guc_info_fops, NULL }, { "guc_registered_contexts", &guc_registered_contexts_fops, NULL }, { "guc_slpc_info", &guc_slpc_info_fops, &intel_eval_slpc_support}, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c index 64e0b86bf258..46026c2c1722 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c @@ -6,7 +6,7 @@ #include #include -#include "gt/debugfs_gt.h" +#include "gt/intel_gt_debugfs.h" #include "intel_guc.h" #include "intel_guc_log.h" #include "intel_guc_log_debugfs.h" @@ -17,7 +17,7 @@ static int guc_log_dump_show(struct seq_file *m, void *data) return intel_guc_log_dump(m->private, &p, false); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(guc_log_dump); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(guc_log_dump); static int guc_load_err_log_dump_show(struct seq_file *m, void *data) { @@ -25,7 +25,7 @@ static int guc_load_err_log_dump_show(struct seq_file *m, void *data) return intel_guc_log_dump(m->private, &p, true); } -DEFINE_GT_DEBUGFS_ATTRIBUTE(guc_load_err_log_dump); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(guc_load_err_log_dump); static int guc_log_level_get(void *data, u64 *val) { @@ -109,7 +109,7 @@ static const struct file_operations guc_log_relay_fops = { void intel_guc_log_debugfs_register(struct intel_guc_log *log, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "guc_log_dump", &guc_log_dump_fops, NULL }, { "guc_load_err_log_dump", &guc_load_err_log_dump_fops, NULL }, { "guc_log_level", &guc_log_level_fops, NULL }, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.c index 5733c15fd123..15998963b863 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.c @@ -5,7 +5,7 @@ #include -#include "gt/debugfs_gt.h" +#include "gt/intel_gt_debugfs.h" #include "intel_huc.h" #include "intel_huc_debugfs.h" @@ -21,11 +21,11 @@ static int huc_info_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(huc_info); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(huc_info); void intel_huc_debugfs_register(struct intel_huc *huc, struct dentry *root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "huc_info", &huc_info_fops, NULL }, }; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c index 089d98662f46..c2f7924295e7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c @@ -6,7 +6,7 @@ #include #include -#include "gt/debugfs_gt.h" +#include "gt/intel_gt_debugfs.h" #include "intel_guc_debugfs.h" #include "intel_huc_debugfs.h" #include "intel_uc.h" @@ -32,11 +32,11 @@ static int uc_usage_show(struct seq_file *m, void *data) return 0; } -DEFINE_GT_DEBUGFS_ATTRIBUTE(uc_usage); +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(uc_usage); void intel_uc_debugfs_register(struct intel_uc *uc, struct dentry *gt_root) { - static const struct debugfs_gt_file files[] = { + static const struct intel_gt_debugfs_file files[] = { { "usage", &uc_usage_fops, NULL }, }; struct dentry *root; From 00142bce94dc31a5d8ecfd0238114354dd07ac6e Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 17 Sep 2021 19:57:52 -0700 Subject: [PATCH 019/554] drm/i915: rename debugfs_engines files We shouldn't be using debugfs_ namespace for this functionality. Rename debugfs_engines.[ch] to intel_gt_engines_debugfs.[ch] and then make functions, defines and structs follow suit. Signed-off-by: Lucas De Marchi Acked-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210918025754.1254705-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/gt/debugfs_engines.h | 14 -------------- drivers/gpu/drm/i915/gt/intel_gt_debugfs.c | 4 ++-- ...ebugfs_engines.c => intel_gt_engines_debugfs.c} | 4 ++-- drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.h | 14 ++++++++++++++ 5 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 drivers/gpu/drm/i915/gt/debugfs_engines.h rename drivers/gpu/drm/i915/gt/{debugfs_engines.c => intel_gt_engines_debugfs.c} (85%) create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7eab4edae2b6..3c68909d9066 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -78,7 +78,6 @@ i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ - gt/debugfs_engines.o \ gt/debugfs_gt_pm.o \ gt/gen2_engine_cs.o \ gt/gen6_engine_cs.o \ @@ -100,6 +99,7 @@ gt-y += \ gt/intel_gt_buffer_pool.o \ gt/intel_gt_clock_utils.o \ gt/intel_gt_debugfs.o \ + gt/intel_gt_engines_debugfs.o \ gt/intel_gt_irq.o \ gt/intel_gt_pm.o \ gt/intel_gt_pm_irq.o \ diff --git a/drivers/gpu/drm/i915/gt/debugfs_engines.h b/drivers/gpu/drm/i915/gt/debugfs_engines.h deleted file mode 100644 index f69257eaa1cc..000000000000 --- a/drivers/gpu/drm/i915/gt/debugfs_engines.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2019 Intel Corporation - */ - -#ifndef DEBUGFS_ENGINES_H -#define DEBUGFS_ENGINES_H - -struct intel_gt; -struct dentry; - -void debugfs_engines_register(struct intel_gt *gt, struct dentry *root); - -#endif /* DEBUGFS_ENGINES_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index b19648008265..3c77c2965e19 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -5,10 +5,10 @@ #include -#include "debugfs_engines.h" #include "debugfs_gt_pm.h" #include "i915_drv.h" #include "intel_gt_debugfs.h" +#include "intel_gt_engines_debugfs.h" #include "intel_sseu_debugfs.h" #include "uc/intel_uc_debugfs.h" @@ -23,7 +23,7 @@ void intel_gt_debugfs_register(struct intel_gt *gt) if (IS_ERR(root)) return; - debugfs_engines_register(gt, root); + intel_gt_engines_debugfs_register(gt, root); debugfs_gt_pm_register(gt, root); intel_sseu_debugfs_register(gt, root); diff --git a/drivers/gpu/drm/i915/gt/debugfs_engines.c b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c similarity index 85% rename from drivers/gpu/drm/i915/gt/debugfs_engines.c rename to drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c index 2980dac5b171..8f9b874fdc9c 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_engines.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c @@ -6,10 +6,10 @@ #include -#include "debugfs_engines.h" #include "i915_drv.h" /* for_each_engine! */ #include "intel_engine.h" #include "intel_gt_debugfs.h" +#include "intel_gt_engines_debugfs.h" static int engines_show(struct seq_file *m, void *data) { @@ -26,7 +26,7 @@ static int engines_show(struct seq_file *m, void *data) } DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(engines); -void debugfs_engines_register(struct intel_gt *gt, struct dentry *root) +void intel_gt_engines_debugfs_register(struct intel_gt *gt, struct dentry *root) { static const struct intel_gt_debugfs_file files[] = { { "engines", &engines_fops }, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.h b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.h new file mode 100644 index 000000000000..dda113452da9 --- /dev/null +++ b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2019 Intel Corporation + */ + +#ifndef INTEL_GT_ENGINES_DEBUGFS_H +#define INTEL_GT_ENGINES_DEBUGFS_H + +struct intel_gt; +struct dentry; + +void intel_gt_engines_debugfs_register(struct intel_gt *gt, struct dentry *root); + +#endif /* INTEL_GT_ENGINES_DEBUGFS_H */ From 23f6a829a67cd40ecd1b90dede33b8395f105f81 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 17 Sep 2021 19:57:53 -0700 Subject: [PATCH 020/554] drm/i915: rename debugfs_gt_pm files We shouldn't be using debugfs_ namespace for this functionality. Rename debugfs_gt_pm.[ch] to intel_gt_pm_debugfs.[ch] and then make functions, defines and structs follow suit. Signed-off-by: Lucas De Marchi Acked-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210918025754.1254705-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/gt/debugfs_gt_pm.h | 14 -------------- drivers/gpu/drm/i915/gt/intel_gt_debugfs.c | 4 ++-- .../gt/{debugfs_gt_pm.c => intel_gt_pm_debugfs.c} | 4 ++-- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h | 14 ++++++++++++++ 5 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 drivers/gpu/drm/i915/gt/debugfs_gt_pm.h rename drivers/gpu/drm/i915/gt/{debugfs_gt_pm.c => intel_gt_pm_debugfs.c} (99%) create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3c68909d9066..0823ea80fdc6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -78,7 +78,6 @@ i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ - gt/debugfs_gt_pm.o \ gt/gen2_engine_cs.o \ gt/gen6_engine_cs.o \ gt/gen6_ppgtt.o \ @@ -102,6 +101,7 @@ gt-y += \ gt/intel_gt_engines_debugfs.o \ gt/intel_gt_irq.o \ gt/intel_gt_pm.o \ + gt/intel_gt_pm_debugfs.o \ gt/intel_gt_pm_irq.o \ gt/intel_gt_requests.o \ gt/intel_gtt.o \ diff --git a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.h b/drivers/gpu/drm/i915/gt/debugfs_gt_pm.h deleted file mode 100644 index 4cf5f5c9da7d..000000000000 --- a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2019 Intel Corporation - */ - -#ifndef DEBUGFS_GT_PM_H -#define DEBUGFS_GT_PM_H - -struct intel_gt; -struct dentry; - -void debugfs_gt_pm_register(struct intel_gt *gt, struct dentry *root); - -#endif /* DEBUGFS_GT_PM_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index 3c77c2965e19..03fb4aefbf90 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -5,10 +5,10 @@ #include -#include "debugfs_gt_pm.h" #include "i915_drv.h" #include "intel_gt_debugfs.h" #include "intel_gt_engines_debugfs.h" +#include "intel_gt_pm_debugfs.h" #include "intel_sseu_debugfs.h" #include "uc/intel_uc_debugfs.h" @@ -24,7 +24,7 @@ void intel_gt_debugfs_register(struct intel_gt *gt) return; intel_gt_engines_debugfs_register(gt, root); - debugfs_gt_pm_register(gt, root); + intel_gt_pm_debugfs_register(gt, root); intel_sseu_debugfs_register(gt, root); intel_uc_debugfs_register(>->uc, root); diff --git a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c similarity index 99% rename from drivers/gpu/drm/i915/gt/debugfs_gt_pm.c rename to drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 9222cf68c56c..250467108eda 100644 --- a/drivers/gpu/drm/i915/gt/debugfs_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -6,12 +6,12 @@ #include -#include "debugfs_gt_pm.h" #include "i915_drv.h" #include "intel_gt.h" #include "intel_gt_clock_utils.h" #include "intel_gt_debugfs.h" #include "intel_gt_pm.h" +#include "intel_gt_pm_debugfs.h" #include "intel_llc.h" #include "intel_rc6.h" #include "intel_rps.h" @@ -614,7 +614,7 @@ static bool rps_eval(void *data) DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rps_boost); -void debugfs_gt_pm_register(struct intel_gt *gt, struct dentry *root) +void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) { static const struct intel_gt_debugfs_file files[] = { { "drpc", &drpc_fops, NULL }, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h new file mode 100644 index 000000000000..b5c6a00cfa04 --- /dev/null +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2019 Intel Corporation + */ + +#ifndef INTEL_GT_PM_DEBUGFS_H +#define INTEL_GT_PM_DEBUGFS_H + +struct intel_gt; +struct dentry; + +void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root); + +#endif /* INTEL_GT_PM_DEBUGFS_H */ From d0c560316d6fc7a2189bbb7acba929e81beabd01 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 17 Sep 2021 19:57:54 -0700 Subject: [PATCH 021/554] drm/i915: deduplicate frequency dump on debugfs Although commit 9dd4b065446a ("drm/i915/gt: Move pm debug files into a gt aware debugfs") says it was moving debug files to gt/, the i915_frequency_info file was left behind and its implementation copied into drivers/gpu/drm/i915/gt/debugfs_gt_pm.c. Over time we had several patches having to change both places to keep them in sync (and some patches failing to do so). The initial idea was to remove i915_frequency_info, but there are user space tools using it. From a quick code search there are other scripts and test tools besides igt, so it's not simply updating igt to get rid of the older file. Here we export a function using drm_printer as parameter and make both show() implementations to call this same function. Aside from a few variable name differences, for i915_frequency_info this brings a few lines that were not previously printed: RP UP EI, RP UP THRESHOLD, RP DOWN THRESHOLD and RP DOWN EI. These came in as part of commit 9c878557b1eb ("drm/i915/gt: Use the RPM config register to determine clk frequencies"), which didn't change both places. Signed-off-by: Lucas De Marchi Acked-by: Jani Nikula Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210918025754.1254705-4-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 127 +++++----- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h | 2 + drivers/gpu/drm/i915/i915_debugfs.c | 231 +----------------- 3 files changed, 76 insertions(+), 284 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 250467108eda..5f84ad602642 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -240,9 +240,8 @@ static int drpc_show(struct seq_file *m, void *unused) } DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(drpc); -static int frequency_show(struct seq_file *m, void *unused) +void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p) { - struct intel_gt *gt = m->private; struct drm_i915_private *i915 = gt->i915; struct intel_uncore *uncore = gt->uncore; struct intel_rps *rps = >->rps; @@ -254,21 +253,21 @@ static int frequency_show(struct seq_file *m, void *unused) u16 rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); u16 rgvstat = intel_uncore_read16(uncore, MEMSTAT_ILK); - seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); - seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); - seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> + drm_printf(p, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); + drm_printf(p, "Requested VID: %d\n", rgvswctl & 0x3f); + drm_printf(p, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> MEMSTAT_VID_SHIFT); - seq_printf(m, "Current P-state: %d\n", + drm_printf(p, "Current P-state: %d\n", (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { u32 rpmodectl, freq_sts; rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL); - seq_printf(m, "Video Turbo Mode: %s\n", + drm_printf(p, "Video Turbo Mode: %s\n", yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); - seq_printf(m, "HW control enabled: %s\n", + drm_printf(p, "HW control enabled: %s\n", yesno(rpmodectl & GEN6_RP_ENABLE)); - seq_printf(m, "SW control enabled: %s\n", + drm_printf(p, "SW control enabled: %s\n", yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); @@ -276,25 +275,25 @@ static int frequency_show(struct seq_file *m, void *unused) freq_sts = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); vlv_punit_put(i915); - seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); - seq_printf(m, "DDR freq: %d MHz\n", i915->mem_freq); + drm_printf(p, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); + drm_printf(p, "DDR freq: %d MHz\n", i915->mem_freq); - seq_printf(m, "actual GPU freq: %d MHz\n", + drm_printf(p, "actual GPU freq: %d MHz\n", intel_gpu_freq(rps, (freq_sts >> 8) & 0xff)); - seq_printf(m, "current GPU freq: %d MHz\n", + drm_printf(p, "current GPU freq: %d MHz\n", intel_gpu_freq(rps, rps->cur_freq)); - seq_printf(m, "max GPU freq: %d MHz\n", + drm_printf(p, "max GPU freq: %d MHz\n", intel_gpu_freq(rps, rps->max_freq)); - seq_printf(m, "min GPU freq: %d MHz\n", + drm_printf(p, "min GPU freq: %d MHz\n", intel_gpu_freq(rps, rps->min_freq)); - seq_printf(m, "idle GPU freq: %d MHz\n", + drm_printf(p, "idle GPU freq: %d MHz\n", intel_gpu_freq(rps, rps->idle_freq)); - seq_printf(m, "efficient (RPe) frequency: %d MHz\n", + drm_printf(p, "efficient (RPe) frequency: %d MHz\n", intel_gpu_freq(rps, rps->efficient_freq)); } else if (GRAPHICS_VER(i915) >= 6) { u32 rp_state_limits; @@ -374,109 +373,117 @@ static int frequency_show(struct seq_file *m, void *unused) } pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK); - seq_printf(m, "Video Turbo Mode: %s\n", + drm_printf(p, "Video Turbo Mode: %s\n", yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); - seq_printf(m, "HW control enabled: %s\n", + drm_printf(p, "HW control enabled: %s\n", yesno(rpmodectl & GEN6_RP_ENABLE)); - seq_printf(m, "SW control enabled: %s\n", + drm_printf(p, "SW control enabled: %s\n", yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); - seq_printf(m, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", + drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", pm_ier, pm_imr, pm_mask); if (GRAPHICS_VER(i915) <= 10) - seq_printf(m, "PM ISR=0x%08x IIR=0x%08x\n", + drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n", pm_isr, pm_iir); - seq_printf(m, "pm_intrmsk_mbz: 0x%08x\n", + drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n", rps->pm_intrmsk_mbz); - seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - seq_printf(m, "Render p-state ratio: %d\n", + drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); + drm_printf(p, "Render p-state ratio: %d\n", (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8); - seq_printf(m, "Render p-state VID: %d\n", + drm_printf(p, "Render p-state VID: %d\n", gt_perf_status & 0xff); - seq_printf(m, "Render p-state limit: %d\n", + drm_printf(p, "Render p-state limit: %d\n", rp_state_limits & 0xff); - seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); - seq_printf(m, "RPMODECTL: 0x%08x\n", rpmodectl); - seq_printf(m, "RPINCLIMIT: 0x%08x\n", rpinclimit); - seq_printf(m, "RPDECLIMIT: 0x%08x\n", rpdeclimit); - seq_printf(m, "RPNSWREQ: %dMHz\n", reqf); - seq_printf(m, "CAGF: %dMHz\n", cagf); - seq_printf(m, "RP CUR UP EI: %d (%lldns)\n", + drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat); + drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl); + drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit); + drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit); + drm_printf(p, "RPNSWREQ: %dMHz\n", reqf); + drm_printf(p, "CAGF: %dMHz\n", cagf); + drm_printf(p, "RP CUR UP EI: %d (%lldns)\n", rpcurupei, intel_gt_pm_interval_to_ns(gt, rpcurupei)); - seq_printf(m, "RP CUR UP: %d (%lldns)\n", + drm_printf(p, "RP CUR UP: %d (%lldns)\n", rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup)); - seq_printf(m, "RP PREV UP: %d (%lldns)\n", + drm_printf(p, "RP PREV UP: %d (%lldns)\n", rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup)); - seq_printf(m, "Up threshold: %d%%\n", + drm_printf(p, "Up threshold: %d%%\n", rps->power.up_threshold); - seq_printf(m, "RP UP EI: %d (%lldns)\n", + drm_printf(p, "RP UP EI: %d (%lldns)\n", rpupei, intel_gt_pm_interval_to_ns(gt, rpupei)); - seq_printf(m, "RP UP THRESHOLD: %d (%lldns)\n", + drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n", rpupt, intel_gt_pm_interval_to_ns(gt, rpupt)); - seq_printf(m, "RP CUR DOWN EI: %d (%lldns)\n", + drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n", rpcurdownei, intel_gt_pm_interval_to_ns(gt, rpcurdownei)); - seq_printf(m, "RP CUR DOWN: %d (%lldns)\n", + drm_printf(p, "RP CUR DOWN: %d (%lldns)\n", rpcurdown, intel_gt_pm_interval_to_ns(gt, rpcurdown)); - seq_printf(m, "RP PREV DOWN: %d (%lldns)\n", + drm_printf(p, "RP PREV DOWN: %d (%lldns)\n", rpprevdown, intel_gt_pm_interval_to_ns(gt, rpprevdown)); - seq_printf(m, "Down threshold: %d%%\n", + drm_printf(p, "Down threshold: %d%%\n", rps->power.down_threshold); - seq_printf(m, "RP DOWN EI: %d (%lldns)\n", + drm_printf(p, "RP DOWN EI: %d (%lldns)\n", rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei)); - seq_printf(m, "RP DOWN THRESHOLD: %d (%lldns)\n", + drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n", rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt)); max_freq = (IS_GEN9_LP(i915) ? rp_state_cap >> 0 : rp_state_cap >> 16) & 0xff; max_freq *= (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", + drm_printf(p, "Lowest (RPN) frequency: %dMHz\n", intel_gpu_freq(rps, max_freq)); max_freq = (rp_state_cap & 0xff00) >> 8; max_freq *= (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", + drm_printf(p, "Nominal (RP1) frequency: %dMHz\n", intel_gpu_freq(rps, max_freq)); max_freq = (IS_GEN9_LP(i915) ? rp_state_cap >> 16 : rp_state_cap >> 0) & 0xff; max_freq *= (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", + drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(rps, max_freq)); - seq_printf(m, "Max overclocked frequency: %dMHz\n", + drm_printf(p, "Max overclocked frequency: %dMHz\n", intel_gpu_freq(rps, rps->max_freq)); - seq_printf(m, "Current freq: %d MHz\n", + drm_printf(p, "Current freq: %d MHz\n", intel_gpu_freq(rps, rps->cur_freq)); - seq_printf(m, "Actual freq: %d MHz\n", cagf); - seq_printf(m, "Idle freq: %d MHz\n", + drm_printf(p, "Actual freq: %d MHz\n", cagf); + drm_printf(p, "Idle freq: %d MHz\n", intel_gpu_freq(rps, rps->idle_freq)); - seq_printf(m, "Min freq: %d MHz\n", + drm_printf(p, "Min freq: %d MHz\n", intel_gpu_freq(rps, rps->min_freq)); - seq_printf(m, "Boost freq: %d MHz\n", + drm_printf(p, "Boost freq: %d MHz\n", intel_gpu_freq(rps, rps->boost_freq)); - seq_printf(m, "Max freq: %d MHz\n", + drm_printf(p, "Max freq: %d MHz\n", intel_gpu_freq(rps, rps->max_freq)); - seq_printf(m, + drm_printf(p, "efficient (RPe) frequency: %d MHz\n", intel_gpu_freq(rps, rps->efficient_freq)); } else { - seq_puts(m, "no P-state info available\n"); + drm_puts(p, "no P-state info available\n"); } - seq_printf(m, "Current CD clock frequency: %d kHz\n", i915->cdclk.hw.cdclk); - seq_printf(m, "Max CD clock frequency: %d kHz\n", i915->max_cdclk_freq); - seq_printf(m, "Max pixel clock frequency: %d kHz\n", i915->max_dotclk_freq); + drm_printf(p, "Current CD clock frequency: %d kHz\n", i915->cdclk.hw.cdclk); + drm_printf(p, "Max CD clock frequency: %d kHz\n", i915->max_cdclk_freq); + drm_printf(p, "Max pixel clock frequency: %d kHz\n", i915->max_dotclk_freq); intel_runtime_pm_put(uncore->rpm, wakeref); +} + +static int frequency_show(struct seq_file *m, void *unused) +{ + struct intel_gt *gt = m->private; + struct drm_printer p = drm_seq_file_printer(m); + + intel_gt_pm_frequency_dump(gt, &p); return 0; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h index b5c6a00cfa04..2b824289582b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h @@ -8,7 +8,9 @@ struct intel_gt; struct dentry; +struct drm_printer; void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root); +void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *m); #endif /* INTEL_GT_PM_DEBUGFS_H */ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 04351a851586..9f2cfcf7aa6a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -32,13 +32,14 @@ #include #include "gem/i915_gem_context.h" +#include "gt/intel_gt.h" #include "gt/intel_gt_buffer_pool.h" #include "gt/intel_gt_clock_utils.h" -#include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" +#include "gt/intel_gt_pm_debugfs.h" #include "gt/intel_gt_requests.h" -#include "gt/intel_reset.h" #include "gt/intel_rc6.h" +#include "gt/intel_reset.h" #include "gt/intel_rps.h" #include "gt/intel_sseu_debugfs.h" @@ -354,230 +355,12 @@ static const struct file_operations i915_error_state_fops = { static int i915_frequency_info(struct seq_file *m, void *unused) { - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct intel_uncore *uncore = &dev_priv->uncore; - struct intel_rps *rps = &dev_priv->gt.rps; - intel_wakeref_t wakeref; + struct drm_i915_private *i915 = node_to_i915(m->private); + struct intel_gt *gt = &i915->gt; + struct drm_printer p = drm_seq_file_printer(m); - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + intel_gt_pm_frequency_dump(gt, &p); - if (GRAPHICS_VER(dev_priv) == 5) { - u16 rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); - u16 rgvstat = intel_uncore_read16(uncore, MEMSTAT_ILK); - - seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); - seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); - seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> - MEMSTAT_VID_SHIFT); - seq_printf(m, "Current P-state: %d\n", - (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - u32 rpmodectl, freq_sts; - - rpmodectl = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CONTROL); - seq_printf(m, "Video Turbo Mode: %s\n", - yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); - seq_printf(m, "HW control enabled: %s\n", - yesno(rpmodectl & GEN6_RP_ENABLE)); - seq_printf(m, "SW control enabled: %s\n", - yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == - GEN6_RP_MEDIA_SW_MODE)); - - vlv_punit_get(dev_priv); - freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - vlv_punit_put(dev_priv); - - seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); - seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); - - seq_printf(m, "actual GPU freq: %d MHz\n", - intel_gpu_freq(rps, (freq_sts >> 8) & 0xff)); - - seq_printf(m, "current GPU freq: %d MHz\n", - intel_gpu_freq(rps, rps->cur_freq)); - - seq_printf(m, "max GPU freq: %d MHz\n", - intel_gpu_freq(rps, rps->max_freq)); - - seq_printf(m, "min GPU freq: %d MHz\n", - intel_gpu_freq(rps, rps->min_freq)); - - seq_printf(m, "idle GPU freq: %d MHz\n", - intel_gpu_freq(rps, rps->idle_freq)); - - seq_printf(m, - "efficient (RPe) frequency: %d MHz\n", - intel_gpu_freq(rps, rps->efficient_freq)); - } else if (GRAPHICS_VER(dev_priv) >= 6) { - u32 rp_state_limits; - u32 gt_perf_status; - u32 rp_state_cap; - u32 rpmodectl, rpinclimit, rpdeclimit; - u32 rpstat, cagf, reqf; - u32 rpupei, rpcurup, rpprevup; - u32 rpdownei, rpcurdown, rpprevdown; - u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask; - int max_freq; - - rp_state_limits = intel_uncore_read(&dev_priv->uncore, GEN6_RP_STATE_LIMITS); - rp_state_cap = intel_rps_read_state_cap(rps); - if (IS_GEN9_LP(dev_priv)) - gt_perf_status = intel_uncore_read(&dev_priv->uncore, BXT_GT_PERF_STATUS); - else - gt_perf_status = intel_uncore_read(&dev_priv->uncore, GEN6_GT_PERF_STATUS); - - /* RPSTAT1 is in the GT power well */ - intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL); - - reqf = intel_uncore_read(&dev_priv->uncore, GEN6_RPNSWREQ); - if (GRAPHICS_VER(dev_priv) >= 9) - reqf >>= 23; - else { - reqf &= ~GEN6_TURBO_DISABLE; - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - reqf >>= 24; - else - reqf >>= 25; - } - reqf = intel_gpu_freq(rps, reqf); - - rpmodectl = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CONTROL); - rpinclimit = intel_uncore_read(&dev_priv->uncore, GEN6_RP_UP_THRESHOLD); - rpdeclimit = intel_uncore_read(&dev_priv->uncore, GEN6_RP_DOWN_THRESHOLD); - - rpstat = intel_uncore_read(&dev_priv->uncore, GEN6_RPSTAT1); - rpupei = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK; - rpcurup = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK; - rpprevup = intel_uncore_read(&dev_priv->uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK; - rpdownei = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK; - rpcurdown = intel_uncore_read(&dev_priv->uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK; - rpprevdown = intel_uncore_read(&dev_priv->uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK; - cagf = intel_rps_read_actual_frequency(rps); - - intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL); - - if (GRAPHICS_VER(dev_priv) >= 11) { - pm_ier = intel_uncore_read(&dev_priv->uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE); - pm_imr = intel_uncore_read(&dev_priv->uncore, GEN11_GPM_WGBOXPERF_INTR_MASK); - /* - * The equivalent to the PM ISR & IIR cannot be read - * without affecting the current state of the system - */ - pm_isr = 0; - pm_iir = 0; - } else if (GRAPHICS_VER(dev_priv) >= 8) { - pm_ier = intel_uncore_read(&dev_priv->uncore, GEN8_GT_IER(2)); - pm_imr = intel_uncore_read(&dev_priv->uncore, GEN8_GT_IMR(2)); - pm_isr = intel_uncore_read(&dev_priv->uncore, GEN8_GT_ISR(2)); - pm_iir = intel_uncore_read(&dev_priv->uncore, GEN8_GT_IIR(2)); - } else { - pm_ier = intel_uncore_read(&dev_priv->uncore, GEN6_PMIER); - pm_imr = intel_uncore_read(&dev_priv->uncore, GEN6_PMIMR); - pm_isr = intel_uncore_read(&dev_priv->uncore, GEN6_PMISR); - pm_iir = intel_uncore_read(&dev_priv->uncore, GEN6_PMIIR); - } - pm_mask = intel_uncore_read(&dev_priv->uncore, GEN6_PMINTRMSK); - - seq_printf(m, "Video Turbo Mode: %s\n", - yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); - seq_printf(m, "HW control enabled: %s\n", - yesno(rpmodectl & GEN6_RP_ENABLE)); - seq_printf(m, "SW control enabled: %s\n", - yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == - GEN6_RP_MEDIA_SW_MODE)); - - seq_printf(m, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", - pm_ier, pm_imr, pm_mask); - if (GRAPHICS_VER(dev_priv) <= 10) - seq_printf(m, "PM ISR=0x%08x IIR=0x%08x\n", - pm_isr, pm_iir); - seq_printf(m, "pm_intrmsk_mbz: 0x%08x\n", - rps->pm_intrmsk_mbz); - seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - seq_printf(m, "Render p-state ratio: %d\n", - (gt_perf_status & (GRAPHICS_VER(dev_priv) >= 9 ? 0x1ff00 : 0xff00)) >> 8); - seq_printf(m, "Render p-state VID: %d\n", - gt_perf_status & 0xff); - seq_printf(m, "Render p-state limit: %d\n", - rp_state_limits & 0xff); - seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); - seq_printf(m, "RPMODECTL: 0x%08x\n", rpmodectl); - seq_printf(m, "RPINCLIMIT: 0x%08x\n", rpinclimit); - seq_printf(m, "RPDECLIMIT: 0x%08x\n", rpdeclimit); - seq_printf(m, "RPNSWREQ: %dMHz\n", reqf); - seq_printf(m, "CAGF: %dMHz\n", cagf); - seq_printf(m, "RP CUR UP EI: %d (%lldns)\n", - rpupei, - intel_gt_pm_interval_to_ns(&dev_priv->gt, rpupei)); - seq_printf(m, "RP CUR UP: %d (%lldun)\n", - rpcurup, - intel_gt_pm_interval_to_ns(&dev_priv->gt, rpcurup)); - seq_printf(m, "RP PREV UP: %d (%lldns)\n", - rpprevup, - intel_gt_pm_interval_to_ns(&dev_priv->gt, rpprevup)); - seq_printf(m, "Up threshold: %d%%\n", - rps->power.up_threshold); - - seq_printf(m, "RP CUR DOWN EI: %d (%lldns)\n", - rpdownei, - intel_gt_pm_interval_to_ns(&dev_priv->gt, - rpdownei)); - seq_printf(m, "RP CUR DOWN: %d (%lldns)\n", - rpcurdown, - intel_gt_pm_interval_to_ns(&dev_priv->gt, - rpcurdown)); - seq_printf(m, "RP PREV DOWN: %d (%lldns)\n", - rpprevdown, - intel_gt_pm_interval_to_ns(&dev_priv->gt, - rpprevdown)); - seq_printf(m, "Down threshold: %d%%\n", - rps->power.down_threshold); - - max_freq = (IS_GEN9_LP(dev_priv) ? rp_state_cap >> 0 : - rp_state_cap >> 16) & 0xff; - max_freq *= (IS_GEN9_BC(dev_priv) || - GRAPHICS_VER(dev_priv) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", - intel_gpu_freq(rps, max_freq)); - - max_freq = (rp_state_cap & 0xff00) >> 8; - max_freq *= (IS_GEN9_BC(dev_priv) || - GRAPHICS_VER(dev_priv) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", - intel_gpu_freq(rps, max_freq)); - - max_freq = (IS_GEN9_LP(dev_priv) ? rp_state_cap >> 16 : - rp_state_cap >> 0) & 0xff; - max_freq *= (IS_GEN9_BC(dev_priv) || - GRAPHICS_VER(dev_priv) >= 11 ? GEN9_FREQ_SCALER : 1); - seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", - intel_gpu_freq(rps, max_freq)); - seq_printf(m, "Max overclocked frequency: %dMHz\n", - intel_gpu_freq(rps, rps->max_freq)); - - seq_printf(m, "Current freq: %d MHz\n", - intel_gpu_freq(rps, rps->cur_freq)); - seq_printf(m, "Actual freq: %d MHz\n", cagf); - seq_printf(m, "Idle freq: %d MHz\n", - intel_gpu_freq(rps, rps->idle_freq)); - seq_printf(m, "Min freq: %d MHz\n", - intel_gpu_freq(rps, rps->min_freq)); - seq_printf(m, "Boost freq: %d MHz\n", - intel_gpu_freq(rps, rps->boost_freq)); - seq_printf(m, "Max freq: %d MHz\n", - intel_gpu_freq(rps, rps->max_freq)); - seq_printf(m, - "efficient (RPe) frequency: %d MHz\n", - intel_gpu_freq(rps, rps->efficient_freq)); - } else { - seq_puts(m, "no P-state info available\n"); - } - - seq_printf(m, "Current CD clock frequency: %d kHz\n", dev_priv->cdclk.hw.cdclk); - seq_printf(m, "Max CD clock frequency: %d kHz\n", dev_priv->max_cdclk_freq); - seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq); - - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); return 0; } From d0a652493abd86180ad0cc0ed44427831d37fabe Mon Sep 17 00:00:00 2001 From: Venkata Sandeep Dhanalakota Date: Fri, 17 Sep 2021 10:08:45 -0700 Subject: [PATCH 022/554] drm/i915: Make wa list per-gt Support for multiple GT's within a single i915 device will be arriving soon. Since each GT may have its own fusing and require different workarounds, we need to make the GT workaround functions and multicast steering setup per-gt. Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Signed-off-by: Venkata Sandeep Dhanalakota Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210917170845.836358-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 3 + drivers/gpu/drm/i915/gt/intel_gt_types.h | 2 + drivers/gpu/drm/i915/gt/intel_workarounds.c | 141 +++++++++--------- drivers/gpu/drm/i915/gt/intel_workarounds.h | 2 +- .../gpu/drm/i915/gt/selftest_workarounds.c | 2 +- drivers/gpu/drm/i915/i915_drv.c | 2 - drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/i915_gem.c | 2 - 8 files changed, 81 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 985922c03297..0c99424bf810 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -660,6 +660,8 @@ int intel_gt_init(struct intel_gt *gt) if (err) return err; + intel_gt_init_workarounds(gt); + /* * This is just a security blanket to placate dragons. * On some systems, we very sporadically observe that the first TLBs @@ -767,6 +769,7 @@ void intel_gt_driver_release(struct intel_gt *gt) if (vm) /* FIXME being called twice on error paths :( */ i915_vm_put(vm); + intel_wa_list_free(>->wa_list); intel_gt_pm_fini(gt); intel_gt_fini_scratch(gt); intel_gt_fini_buffer_pool(gt); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 6fdcde64c180..ce127cae9e49 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -72,6 +72,8 @@ struct intel_gt { struct intel_uc uc; + struct i915_wa_list wa_list; + struct intel_gt_timelines { spinlock_t lock; /* protects active_list */ struct list_head active_list; diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index c314d4917b6b..e1f362530889 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -804,7 +804,7 @@ int intel_engine_emit_ctx_wa(struct i915_request *rq) } static void -gen4_gt_workarounds_init(struct drm_i915_private *i915, +gen4_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { /* WaDisable_RenderCache_OperationalFlush:gen4,ilk */ @@ -812,29 +812,29 @@ gen4_gt_workarounds_init(struct drm_i915_private *i915, } static void -g4x_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +g4x_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen4_gt_workarounds_init(i915, wal); + gen4_gt_workarounds_init(gt, wal); /* WaDisableRenderCachePipelinedFlush:g4x,ilk */ wa_masked_en(wal, CACHE_MODE_0, CM0_PIPELINED_RENDER_FLUSH_DISABLE); } static void -ilk_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +ilk_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - g4x_gt_workarounds_init(i915, wal); + g4x_gt_workarounds_init(gt, wal); wa_masked_en(wal, _3D_CHICKEN2, _3D_CHICKEN2_WM_READ_PIPELINED); } static void -snb_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +snb_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { } static void -ivb_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +ivb_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */ wa_masked_dis(wal, @@ -850,7 +850,7 @@ ivb_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -vlv_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +vlv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { /* WaForceL3Serialization:vlv */ wa_write_clr(wal, GEN7_L3SQCREG4, L3SQ_URB_READ_CAM_MATCH_DISABLE); @@ -863,7 +863,7 @@ vlv_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -hsw_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +hsw_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { /* L3 caching of data atomics doesn't work -- disable it. */ wa_write(wal, HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE); @@ -878,8 +878,10 @@ hsw_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -gen9_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +gen9_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { + struct drm_i915_private *i915 = gt->i915; + /* WaDisableKillLogic:bxt,skl,kbl */ if (!IS_COFFEELAKE(i915) && !IS_COMETLAKE(i915)) wa_write_or(wal, @@ -904,9 +906,9 @@ gen9_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal } static void -skl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +skl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen9_gt_workarounds_init(i915, wal); + gen9_gt_workarounds_init(gt, wal); /* WaDisableGafsUnitClkGating:skl */ wa_write_or(wal, @@ -914,19 +916,19 @@ skl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); /* WaInPlaceDecompressionHang:skl */ - if (IS_SKL_GT_STEP(i915, STEP_A0, STEP_H0)) + if (IS_SKL_GT_STEP(gt->i915, STEP_A0, STEP_H0)) wa_write_or(wal, GEN9_GAMT_ECO_REG_RW_IA, GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } static void -kbl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +kbl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen9_gt_workarounds_init(i915, wal); + gen9_gt_workarounds_init(gt, wal); /* WaDisableDynamicCreditSharing:kbl */ - if (IS_KBL_GT_STEP(i915, 0, STEP_C0)) + if (IS_KBL_GT_STEP(gt->i915, 0, STEP_C0)) wa_write_or(wal, GAMT_CHKN_BIT_REG, GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING); @@ -943,15 +945,15 @@ kbl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -glk_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +glk_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen9_gt_workarounds_init(i915, wal); + gen9_gt_workarounds_init(gt, wal); } static void -cfl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +cfl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen9_gt_workarounds_init(i915, wal); + gen9_gt_workarounds_init(gt, wal); /* WaDisableGafsUnitClkGating:cfl */ wa_write_or(wal, @@ -976,21 +978,21 @@ static void __set_mcr_steering(struct i915_wa_list *wal, wa_write_clr_set(wal, steering_reg, mcr_mask, mcr); } -static void __add_mcr_wa(struct drm_i915_private *i915, struct i915_wa_list *wal, +static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal, unsigned int slice, unsigned int subslice) { - drm_dbg(&i915->drm, "MCR slice=0x%x, subslice=0x%x\n", slice, subslice); + drm_dbg(>->i915->drm, "MCR slice=0x%x, subslice=0x%x\n", slice, subslice); __set_mcr_steering(wal, GEN8_MCR_SELECTOR, slice, subslice); } static void -icl_wa_init_mcr(struct drm_i915_private *i915, struct i915_wa_list *wal) +icl_wa_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) { - const struct sseu_dev_info *sseu = &i915->gt.info.sseu; + const struct sseu_dev_info *sseu = >->info.sseu; unsigned int slice, subslice; - GEM_BUG_ON(GRAPHICS_VER(i915) < 11); + GEM_BUG_ON(GRAPHICS_VER(gt->i915) < 11); GEM_BUG_ON(hweight8(sseu->slice_mask) > 1); slice = 0; @@ -1010,16 +1012,15 @@ icl_wa_init_mcr(struct drm_i915_private *i915, struct i915_wa_list *wal) * then we can just rely on the default steering and won't need to * worry about explicitly re-steering L3BANK reads later. */ - if (i915->gt.info.l3bank_mask & BIT(subslice)) - i915->gt.steering_table[L3BANK] = NULL; + if (gt->info.l3bank_mask & BIT(subslice)) + gt->steering_table[L3BANK] = NULL; - __add_mcr_wa(i915, wal, slice, subslice); + __add_mcr_wa(gt, wal, slice, subslice); } static void xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) { - struct drm_i915_private *i915 = gt->i915; const struct sseu_dev_info *sseu = >->info.sseu; unsigned long slice, subslice = 0, slice_mask = 0; u64 dss_mask = 0; @@ -1083,7 +1084,7 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) WARN_ON(subslice > GEN_DSS_PER_GSLICE); WARN_ON(dss_mask >> (slice * GEN_DSS_PER_GSLICE) == 0); - __add_mcr_wa(i915, wal, slice, subslice); + __add_mcr_wa(gt, wal, slice, subslice); /* * SQIDI ranges are special because they use different steering @@ -1099,9 +1100,11 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) } static void -icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - icl_wa_init_mcr(i915, wal); + struct drm_i915_private *i915 = gt->i915; + + icl_wa_init_mcr(gt, wal); /* WaModifyGamTlbPartitioning:icl */ wa_write_clr_set(wal, @@ -1152,10 +1155,9 @@ icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) * the engine-specific workaround list. */ static void -wa_14011060649(struct drm_i915_private *i915, struct i915_wa_list *wal) +wa_14011060649(struct intel_gt *gt, struct i915_wa_list *wal) { struct intel_engine_cs *engine; - struct intel_gt *gt = &i915->gt; int id; for_each_engine(engine, gt, id) { @@ -1169,22 +1171,23 @@ wa_14011060649(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -gen12_gt_workarounds_init(struct drm_i915_private *i915, - struct i915_wa_list *wal) +gen12_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - icl_wa_init_mcr(i915, wal); + icl_wa_init_mcr(gt, wal); /* Wa_14011060649:tgl,rkl,dg1,adl-s,adl-p */ - wa_14011060649(i915, wal); + wa_14011060649(gt, wal); /* Wa_14011059788:tgl,rkl,adl-s,dg1,adl-p */ wa_write_or(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE); } static void -tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +tgl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen12_gt_workarounds_init(i915, wal); + struct drm_i915_private *i915 = gt->i915; + + gen12_gt_workarounds_init(gt, wal); /* Wa_1409420604:tgl */ if (IS_TGL_UY_GT_STEP(i915, STEP_A0, STEP_B0)) @@ -1205,9 +1208,11 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -dg1_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +dg1_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - gen12_gt_workarounds_init(i915, wal); + struct drm_i915_private *i915 = gt->i915; + + gen12_gt_workarounds_init(gt, wal); /* Wa_1607087056:dg1 */ if (IS_DG1_GT_STEP(i915, STEP_A0, STEP_B0)) @@ -1229,60 +1234,62 @@ dg1_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -xehpsdv_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - xehp_init_mcr(&i915->gt, wal); + xehp_init_mcr(gt, wal); } static void -gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal) +gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) { + struct drm_i915_private *i915 = gt->i915; + if (IS_XEHPSDV(i915)) - xehpsdv_gt_workarounds_init(i915, wal); + xehpsdv_gt_workarounds_init(gt, wal); else if (IS_DG1(i915)) - dg1_gt_workarounds_init(i915, wal); + dg1_gt_workarounds_init(gt, wal); else if (IS_TIGERLAKE(i915)) - tgl_gt_workarounds_init(i915, wal); + tgl_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) == 12) - gen12_gt_workarounds_init(i915, wal); + gen12_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) == 11) - icl_gt_workarounds_init(i915, wal); + icl_gt_workarounds_init(gt, wal); else if (IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) - cfl_gt_workarounds_init(i915, wal); + cfl_gt_workarounds_init(gt, wal); else if (IS_GEMINILAKE(i915)) - glk_gt_workarounds_init(i915, wal); + glk_gt_workarounds_init(gt, wal); else if (IS_KABYLAKE(i915)) - kbl_gt_workarounds_init(i915, wal); + kbl_gt_workarounds_init(gt, wal); else if (IS_BROXTON(i915)) - gen9_gt_workarounds_init(i915, wal); + gen9_gt_workarounds_init(gt, wal); else if (IS_SKYLAKE(i915)) - skl_gt_workarounds_init(i915, wal); + skl_gt_workarounds_init(gt, wal); else if (IS_HASWELL(i915)) - hsw_gt_workarounds_init(i915, wal); + hsw_gt_workarounds_init(gt, wal); else if (IS_VALLEYVIEW(i915)) - vlv_gt_workarounds_init(i915, wal); + vlv_gt_workarounds_init(gt, wal); else if (IS_IVYBRIDGE(i915)) - ivb_gt_workarounds_init(i915, wal); + ivb_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) == 6) - snb_gt_workarounds_init(i915, wal); + snb_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) == 5) - ilk_gt_workarounds_init(i915, wal); + ilk_gt_workarounds_init(gt, wal); else if (IS_G4X(i915)) - g4x_gt_workarounds_init(i915, wal); + g4x_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) == 4) - gen4_gt_workarounds_init(i915, wal); + gen4_gt_workarounds_init(gt, wal); else if (GRAPHICS_VER(i915) <= 8) ; else MISSING_CASE(GRAPHICS_VER(i915)); } -void intel_gt_init_workarounds(struct drm_i915_private *i915) +void intel_gt_init_workarounds(struct intel_gt *gt) { - struct i915_wa_list *wal = &i915->gt_wa_list; + struct i915_wa_list *wal = >->wa_list; wa_init_start(wal, "GT", "global"); - gt_init_workarounds(i915, wal); + gt_init_workarounds(gt, wal); wa_init_finish(wal); } @@ -1353,7 +1360,7 @@ wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal) void intel_gt_apply_workarounds(struct intel_gt *gt) { - wa_list_apply(gt, >->i915->gt_wa_list); + wa_list_apply(gt, >->wa_list); } static bool wa_list_verify(struct intel_gt *gt, @@ -1385,7 +1392,7 @@ static bool wa_list_verify(struct intel_gt *gt, bool intel_gt_verify_workarounds(struct intel_gt *gt, const char *from) { - return wa_list_verify(gt, >->i915->gt_wa_list, from); + return wa_list_verify(gt, >->wa_list, from); } __maybe_unused diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.h b/drivers/gpu/drm/i915/gt/intel_workarounds.h index 15abb68b6c00..9beaab77c7f0 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.h +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.h @@ -24,7 +24,7 @@ static inline void intel_wa_list_free(struct i915_wa_list *wal) void intel_engine_init_ctx_wa(struct intel_engine_cs *engine); int intel_engine_emit_ctx_wa(struct i915_request *rq); -void intel_gt_init_workarounds(struct drm_i915_private *i915); +void intel_gt_init_workarounds(struct intel_gt *gt); void intel_gt_apply_workarounds(struct intel_gt *gt); bool intel_gt_verify_workarounds(struct intel_gt *gt, const char *from); diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c index e623ac45f4aa..962e91ba3be4 100644 --- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c +++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c @@ -66,7 +66,7 @@ reference_lists_init(struct intel_gt *gt, struct wa_lists *lists) memset(lists, 0, sizeof(*lists)); wa_init_start(&lists->gt_wa_list, "GT_REF", "global"); - gt_init_workarounds(gt->i915, &lists->gt_wa_list); + gt_init_workarounds(gt, &lists->gt_wa_list); wa_init_finish(&lists->gt_wa_list); for_each_engine(engine, gt, id) { diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 59fb4c710c8c..3cf61bead2f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -588,8 +588,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) pci_set_master(pdev); - intel_gt_init_workarounds(dev_priv); - /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there * according to the published specs. It doesn't appear to function diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74fd70385273..93d13aba6a85 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1022,8 +1022,6 @@ struct drm_i915_private { */ u8 active_pipes; - struct i915_wa_list gt_wa_list; - struct i915_frontbuffer_tracking fb_tracking; struct intel_atomic_helper { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 590efc8b0265..981e383d1a5d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1139,8 +1139,6 @@ void i915_gem_driver_release(struct drm_i915_private *dev_priv) { intel_gt_driver_release(&dev_priv->gt); - intel_wa_list_free(&dev_priv->gt_wa_list); - intel_uc_cleanup_firmwares(&dev_priv->gt.uc); i915_gem_drain_freed_objects(dev_priv); From 53718bff8f4054bd2ad4e4799ebf2ecbeed453d5 Mon Sep 17 00:00:00 2001 From: Ayaz A Siddiqui Date: Thu, 16 Sep 2021 11:57:36 +0530 Subject: [PATCH 023/554] drm/i915/gt: Add "intel_" as prefix in set_mocs_index() Adding missing "intel_" prefix in set_mocs_index(). Fixes: b62aa57e3c78 ("drm/i915/gt: Add support of mocs propagation") Cc: Matt Roper Signed-off-by: Ayaz A Siddiqui Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210916062736.1733587-1-ayaz.siddiqui@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- drivers/gpu/drm/i915/gt/intel_mocs.c | 2 +- drivers/gpu/drm/i915/gt/intel_mocs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 0c99424bf810..5753c5943ed9 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -684,7 +684,7 @@ int intel_gt_init(struct intel_gt *gt) goto err_pm; } - set_mocs_index(gt); + intel_set_mocs_index(gt); err = intel_engines_init(gt); if (err) diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index e4b97cd14cf9..15f9ada28a7a 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -616,7 +616,7 @@ static u32 global_mocs_offset(void) return i915_mmio_reg_offset(GEN12_GLOBAL_MOCS(0)); } -void set_mocs_index(struct intel_gt *gt) +void intel_set_mocs_index(struct intel_gt *gt) { struct drm_i915_mocs_table table; diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.h b/drivers/gpu/drm/i915/gt/intel_mocs.h index 8a09d64b115f..76db827210c0 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.h +++ b/drivers/gpu/drm/i915/gt/intel_mocs.h @@ -36,6 +36,6 @@ struct intel_gt; void intel_mocs_init(struct intel_gt *gt); void intel_mocs_init_engine(struct intel_engine_cs *engine); -void set_mocs_index(struct intel_gt *gt); +void intel_set_mocs_index(struct intel_gt *gt); #endif From 054ce0bce22eeb714c6cc3808869a326d0611792 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:53 +0300 Subject: [PATCH 024/554] drm/dp: add DP 2.0 UHBR link rate and bw code conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bw code equals link_rate / 0.27 Gbps only for 8b/10b link rates. Handle DP 2.0 UHBR rates as special cases, though this is not pretty. Cc: dri-devel@lists.freedesktop.org Reviewed-by: Ville Syrjälä Acked-by: Maxime Ripard Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/cab4edda8834d6b4db610fabb5e1f1f18ae33c2c.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 6d0f2c447f3b..9b2a2961fca8 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -207,15 +207,33 @@ EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay); u8 drm_dp_link_rate_to_bw_code(int link_rate) { - /* Spec says link_bw = link_rate / 0.27Gbps */ - return link_rate / 27000; + switch (link_rate) { + case 1000000: + return DP_LINK_BW_10; + case 1350000: + return DP_LINK_BW_13_5; + case 2000000: + return DP_LINK_BW_20; + default: + /* Spec says link_bw = link_rate / 0.27Gbps */ + return link_rate / 27000; + } } EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); int drm_dp_bw_code_to_link_rate(u8 link_bw) { - /* Spec says link_rate = link_bw * 0.27Gbps */ - return link_bw * 27000; + switch (link_bw) { + case DP_LINK_BW_10: + return 1000000; + case DP_LINK_BW_13_5: + return 1350000; + case DP_LINK_BW_20: + return 2000000; + default: + /* Spec says link_rate = link_bw * 0.27Gbps */ + return link_bw * 27000; + } } EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); From fc8a2b1e0f91368872424e9e3a8473344c350299 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:54 +0300 Subject: [PATCH 025/554] drm/dp: use more of the extended receiver cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the use of extended receiver cap at 0x2200 to cover MAIN_LINK_CHANNEL_CODING_CAP in 0x2206, in case an implementation hides the DP 2.0 128b/132b channel encoding cap. v2: Extend to DP_RECEIVER_CAP_SIZE (Ville) Cc: Lyude Paul Cc: dri-devel@lists.freedesktop.org Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Lyude Paul Acked-by: Maxime Ripard Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/649051cb896821147feee91aab1f2abc523c1353.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 9b2a2961fca8..2e74b02ed96b 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -608,7 +608,7 @@ static u8 drm_dp_downstream_port_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux, u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - u8 dpcd_ext[6]; + u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; int ret; /* From 762520e310258aa69add29261cef106fddf8f915 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:55 +0300 Subject: [PATCH 026/554] drm/dp: add LTTPR DP 2.0 DPCD addresses DP 2.0 brings some new DPCD addresses for PHY repeaters. Cc: dri-devel@lists.freedesktop.org Reviewed-by: Manasi Navare Acked-by: Maxime Ripard Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/def17e2329722f22c35807be26b35590ccb93bfd.1631191763.git.jani.nikula@intel.com --- include/drm/drm_dp_helper.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 1d5b3dbb6e56..f3a61341011d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1319,6 +1319,10 @@ struct drm_panel; #define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ #define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ #define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ +#define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER 0xf0006 /* 2.0 */ +# define DP_PHY_REPEATER_128B132B_SUPPORTED (1 << 0) +/* See DP_128B132B_SUPPORTED_LINK_RATES for values */ +#define DP_PHY_REPEATER_128B132B_RATES 0xf0007 /* 2.0 */ enum drm_dp_phy { DP_PHY_DPRX, From c78b4a85721f3905ba9baeac4e0bb99a36211d9b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:56 +0300 Subject: [PATCH 027/554] drm/dp: add helper for extracting adjust 128b/132b TX FFE preset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP 2.0 128b/132b channel coding uses TX FFE presets instead of vswing and pre-emphasis. Cc: dri-devel@lists.freedesktop.org Reviewed-by: Ville Syrjälä Acked-by: Maxime Ripard Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/4ba129c51aeb01a5f210de7026abe704a554a178.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 14 ++++++++++++++ include/drm/drm_dp_helper.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 2e74b02ed96b..4d0d1e8e51fa 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -130,6 +130,20 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); +/* DP 2.0 128b/132b */ +u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_TX_FFE_PRESET_LANE1_SHIFT : + DP_ADJUST_TX_FFE_PRESET_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return (l >> s) & 0xf; +} +EXPORT_SYMBOL(drm_dp_get_adjust_tx_ffe_preset); + u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], unsigned int lane) { diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index f3a61341011d..3ee0b3ffb8a5 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1494,6 +1494,8 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); +u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], unsigned int lane); From 7bb97db8d32983b3525912a219f11c5140f282e7 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:57 +0300 Subject: [PATCH 028/554] drm/i915/dg2: add DG2+ TRANS_DDI_FUNC_CTL DP 2.0 128b/132b mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, the DP 2.0 128b/132b DDI mode selection in the register conflicts with FDI. Since we have to deal with both meanings in the same code, for different platforms, clarify the macro name so we don't forget. Bspec: 50493 Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/260e4da302d47ae50122eb8d517be6ac3ccb15f2.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +++--- drivers/gpu/drm/i915/i915_reg.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c7e12b09106f..cb8f303265a7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -489,7 +489,7 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, if (crtc_state->hdmi_high_tmds_clock_ratio) temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE; } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) { - temp |= TRANS_DDI_MODE_SELECT_FDI; + temp |= TRANS_DDI_MODE_SELECT_FDI_OR_128B132B; temp |= (crtc_state->fdi_lanes - 1) << 1; } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) { temp |= TRANS_DDI_MODE_SELECT_DP_MST; @@ -679,7 +679,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ret = false; break; - case TRANS_DDI_MODE_SELECT_FDI: + case TRANS_DDI_MODE_SELECT_FDI_OR_128B132B: ret = type == DRM_MODE_CONNECTOR_VGA; break; @@ -3558,7 +3558,7 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI); pipe_config->lane_count = 4; break; - case TRANS_DDI_MODE_SELECT_FDI: + case TRANS_DDI_MODE_SELECT_FDI_OR_128B132B: pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG); break; case TRANS_DDI_MODE_SELECT_DP_SST: diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 67351ed5ab5b..61d29068925c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -10173,7 +10173,7 @@ enum skl_power_gate { #define TRANS_DDI_MODE_SELECT_DVI (1 << 24) #define TRANS_DDI_MODE_SELECT_DP_SST (2 << 24) #define TRANS_DDI_MODE_SELECT_DP_MST (3 << 24) -#define TRANS_DDI_MODE_SELECT_FDI (4 << 24) +#define TRANS_DDI_MODE_SELECT_FDI_OR_128B132B (4 << 24) #define TRANS_DDI_BPC_MASK (7 << 20) #define TRANS_DDI_BPC_8 (0 << 20) #define TRANS_DDI_BPC_10 (1 << 20) From 4e718a0e4053249c0ff5df60f8f3799fce1a1981 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:58 +0300 Subject: [PATCH 029/554] drm/i915/dp: add helper for checking for UHBR link rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helpful abstraction to avoid duplication. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/fe9a222ad900da797c989de9f7fa13928d2c9861.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_dp.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3e7236b07773..7559911c140a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -115,6 +115,12 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) static void intel_dp_unset_edid(struct intel_dp *intel_dp); static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); +/* Is link rate UHBR and thus 128b/132b? */ +bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->port_clock >= 1000000; +} + /* update sink rates from dpcd */ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index a28fff286c21..94b568704b22 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -58,6 +58,7 @@ int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); bool intel_dp_is_edp(struct intel_dp *intel_dp); +bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd); From 078397bbad2d70cef41771322801b73b39daddb3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:51:59 +0300 Subject: [PATCH 030/554] drm/i915/dp: use 128b/132b TPS2 for UHBR+ link rates 128b/132b channel encoding has separate TPS1 and TPS2, although the DPCD register values coincide with 8b/10b TPS1 and TPS2 values. Use 128b/132b TPS2 for channel equalization. v2: Use intel_dp_is_uhbr Reviewed-by: Manasi Navare # v1 Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/723b29223dc570c8b63c3c6fe5fb772d9db06c0d.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 508a514c5e37..36b35239da83 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -602,9 +602,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, } /* - * Pick training pattern for channel equalization. Training pattern 4 for HBR3 - * or for 1.4 devices that support it, training Pattern 3 for HBR2 - * or 1.2 devices that support it, Training Pattern 2 otherwise. + * Pick Training Pattern Sequence (TPS) for channel equalization. 128b/132b TPS2 + * for UHBR+, TPS4 for HBR3 or for 1.4 devices that support it, TPS3 for HBR2 or + * 1.2 devices that support it, TPS2 otherwise. */ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -612,6 +612,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, { bool source_tps3, sink_tps3, source_tps4, sink_tps4; + /* UHBR+ use separate 128b/132b TPS2 */ + if (intel_dp_is_uhbr(crtc_state)) + return DP_TRAINING_PATTERN_2; + /* * Intel platforms that support HBR3 also support TPS4. It is mandatory * for all downstream devices that support HBR3. There are no known eDP From 6114f71b3953407148158476b81c5eb082ef142b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:52:00 +0300 Subject: [PATCH 031/554] drm/i915/dp: select 128b/132b channel encoding for UHBR rates UHBR rates and 128b/132b channel encoding go hand in hand. v2: Fix check for >= UHBR rates using intel_dp_is_uhbr() (Ville) Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/b4ffd0187b306c0abaa08b89ed35c993ad8145c7.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 36b35239da83..4f116cd32846 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -495,7 +495,8 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp, &rate_select, 1); link_config[0] = crtc_state->vrr.enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0; - link_config[1] = DP_SET_ANSI_8B10B; + link_config[1] = intel_dp_is_uhbr(crtc_state) ? + DP_SET_ANSI_128B132B : DP_SET_ANSI_8B10B; drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); intel_dp->DP |= DP_PORT_EN; From 79ac2b1bc9b9a1bc17b52263d940be075aa55982 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:52:01 +0300 Subject: [PATCH 032/554] drm/i915/dg2: configure TRANS_DP2_CTL for DP 2.0 Set the DP 2.0 128b/132b channel encoding for UHBR rates. v2: Fix UHBR port clock check, use intel_dp_is_uhbr() Bspec: 54128 Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/c88b08d80a96d1229ae941b296590633be4d8711.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cb8f303265a7..91ee32ffba97 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -408,6 +408,20 @@ static u32 bdw_trans_port_sync_master_select(enum transcoder master_transcoder) return master_transcoder + 1; } +static void +intel_ddi_config_transcoder_dp2(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 val = 0; + + if (intel_dp_is_uhbr(crtc_state)) + val = TRANS_DP2_128B132B_CHANNEL_CODING; + + intel_de_write(i915, TRANS_DP2_CTL(cpu_transcoder), val); +} + /* * Returns the TRANS_DDI_FUNC_CTL value based on CRTC state. * @@ -2376,7 +2390,8 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, */ intel_ddi_enable_pipe_clock(encoder, crtc_state); - /* 5.b Not relevant to i915 for now */ + /* 5.b Configure transcoder for DP 2.0 128b/132b */ + intel_ddi_config_transcoder_dp2(encoder, crtc_state); /* * 5.c Configure TRANS_DDI_FUNC_CTL DDI Select, DDI Mode Select & MST From 1d713917248080b1fe2289677f8a92ad1293b1a5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:52:02 +0300 Subject: [PATCH 033/554] drm/i915/dp: add HAS_DP20 macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's abstract the DP 2.0 feature. Initially just DG2. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/3746e700641bc17eff270569387fe869707d92ed.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a8129153d1db..b9fd54f24f95 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1641,6 +1641,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_IPS(dev_priv) (IS_HSW_ULT(dev_priv) || IS_BROADWELL(dev_priv)) #define HAS_DP_MST(dev_priv) (INTEL_INFO(dev_priv)->display.has_dp_mst) +#define HAS_DP20(dev_priv) (IS_DG2(dev_priv)) #define HAS_CDCLK_CRAWL(dev_priv) (INTEL_INFO(dev_priv)->display.has_cdclk_crawl) #define HAS_DDI(dev_priv) (INTEL_INFO(dev_priv)->display.has_ddi) From 652135940ee20e2aaa4c628d13b3fb2b53770cab Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:52:03 +0300 Subject: [PATCH 034/554] drm/i915/dg2: use 128b/132b transcoder DDI mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 128b/132b has a separate transcoder DDI mode, which also requires the MST transport select to be set. Note that we'll use DP MST also for single-stream 128b/132b. Having the FDI and 128b/132b modes share the register mode value complicates things a bit. v2: - Use HAS_DP20 abstraction for 128b/132b mode (Ville) - Use intel_dp_is_uhbr() helper Bspec: 50493 Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/279bfbd979e0256fae13a5231e07e2f4fb665c07.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 27 ++++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 91ee32ffba97..bba0ab99836b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -506,7 +506,10 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, temp |= TRANS_DDI_MODE_SELECT_FDI_OR_128B132B; temp |= (crtc_state->fdi_lanes - 1) << 1; } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) { - temp |= TRANS_DDI_MODE_SELECT_DP_MST; + if (intel_dp_is_uhbr(crtc_state)) + temp |= TRANS_DDI_MODE_SELECT_FDI_OR_128B132B; + else + temp |= TRANS_DDI_MODE_SELECT_DP_MST; temp |= DDI_PORT_WIDTH(crtc_state->lane_count); if (DISPLAY_VER(dev_priv) >= 12) { @@ -694,7 +697,12 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) break; case TRANS_DDI_MODE_SELECT_FDI_OR_128B132B: - ret = type == DRM_MODE_CONNECTOR_VGA; + if (HAS_DP20(dev_priv)) + /* 128b/132b */ + ret = false; + else + /* FDI */ + ret = type == DRM_MODE_CONNECTOR_VGA; break; default: @@ -781,8 +789,9 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder, if ((tmp & port_mask) != ddi_select) continue; - if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == - TRANS_DDI_MODE_SELECT_DP_MST) + if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST || + (HAS_DP20(dev_priv) && + (tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_FDI_OR_128B132B)) mst_pipe_mask |= BIT(p); *pipe_mask |= BIT(p); @@ -3573,9 +3582,6 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI); pipe_config->lane_count = 4; break; - case TRANS_DDI_MODE_SELECT_FDI_OR_128B132B: - pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG); - break; case TRANS_DDI_MODE_SELECT_DP_SST: if (encoder->type == INTEL_OUTPUT_EDP) pipe_config->output_types |= BIT(INTEL_OUTPUT_EDP); @@ -3604,6 +3610,13 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, pipe_config->infoframes.enable |= intel_hdmi_infoframes_enabled(encoder, pipe_config); break; + case TRANS_DDI_MODE_SELECT_FDI_OR_128B132B: + if (!HAS_DP20(dev_priv)) { + /* FDI */ + pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG); + break; + } + fallthrough; /* 128b/132b */ case TRANS_DDI_MODE_SELECT_DP_MST: pipe_config->output_types |= BIT(INTEL_OUTPUT_DP_MST); pipe_config->lane_count = From e01163e82b708535ae1bfca67730516578b237be Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 9 Sep 2021 15:52:04 +0300 Subject: [PATCH 035/554] drm/i915/dg2: configure TRANS_DP2_VFREQ{HIGH,LOW} for 128b/132b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a new register pair for 128b/132b mode where you need to set the pixel clock in Hz. v2: Fix UHBR rate check, use intel_dp_is_uhbr() helper Bspec: 54128 Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/a2902cc188973f022f282f2a77e693afdecefb5a.1631191763.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index f7a0470b1f1c..fd0a31bc3dcd 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -550,6 +550,17 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, clear_act_sent(encoder, pipe_config); + if (intel_dp_is_uhbr(pipe_config)) { + const struct drm_display_mode *adjusted_mode = + &pipe_config->hw.adjusted_mode; + u64 crtc_clock_hz = KHz(adjusted_mode->crtc_clock); + + intel_de_write(dev_priv, TRANS_DP2_VFREQHIGH(pipe_config->cpu_transcoder), + TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz >> 24)); + intel_de_write(dev_priv, TRANS_DP2_VFREQLOW(pipe_config->cpu_transcoder), + TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz & 0xffffff)); + } + intel_ddi_enable_transcoder_func(encoder, pipe_config); intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(trans), 0, From ea97e44f83e25cb63c70293d71ab625a23f8a0cc Mon Sep 17 00:00:00 2001 From: Venkata Sandeep Dhanalakota Date: Thu, 16 Sep 2021 09:28:15 -0700 Subject: [PATCH 036/554] drm/i915: Do not define vma on stack Defining vma on stack can cause stack overflow, if vma gets populated with new fields. v2: (Daniel Vetter) - Add kerneldoc for new field Cc: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Signed-off-by: Venkata Sandeep Dhanalakota Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-2-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 18 +++++++++--------- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h | 9 +++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 3a16d08608a5..f632dbd32b42 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -413,20 +413,20 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw) { struct drm_i915_gem_object *obj = uc_fw->obj; struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt; - struct i915_vma dummy = { - .node.start = uc_fw_ggtt_offset(uc_fw), - .node.size = obj->base.size, - .pages = obj->mm.pages, - .vm = &ggtt->vm, - }; + struct i915_vma *dummy = &uc_fw->dummy; + + dummy->node.start = uc_fw_ggtt_offset(uc_fw); + dummy->node.size = obj->base.size; + dummy->pages = obj->mm.pages; + dummy->vm = &ggtt->vm; GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); - GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size); + GEM_BUG_ON(dummy->node.size > ggtt->uc_fw.size); /* uc_fw->obj cache domains were not controlled across suspend */ - drm_clflush_sg(dummy.pages); + drm_clflush_sg(dummy->pages); - ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0); + ggtt->vm.insert_entries(&ggtt->vm, dummy, I915_CACHE_NONE, 0); } static void uc_fw_unbind_ggtt(struct intel_uc_fw *uc_fw) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h index 99bb1fe1af66..1e00bf65639e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h @@ -10,6 +10,7 @@ #include "intel_uc_fw_abi.h" #include "intel_device_info.h" #include "i915_gem.h" +#include "i915_vma.h" struct drm_printer; struct drm_i915_private; @@ -75,6 +76,14 @@ struct intel_uc_fw { bool user_overridden; size_t size; struct drm_i915_gem_object *obj; + /** + * @dummy: A vma used in binding the uc fw to ggtt. We can't define this + * vma on the stack as it can lead to a stack overflow, so we define it + * here. Safe to have 1 copy per uc fw because the binding is single + * threaded as it done during driver load (inherently single threaded) + * or during a GT reset (mutex guarantees single threaded). + */ + struct i915_vma dummy; /* * The firmware build process will generate a version header file with major and From 7acbbc7cf4851b42b723098aa5699e8fca634e4a Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 16 Sep 2021 09:28:16 -0700 Subject: [PATCH 037/554] drm/i915/guc: put all guc objects in lmem when available The firmware binary has to be loaded from lmem and the recommendation is to put all other objects in there as well. Note that we don't fall back to system memory if the allocation in lmem fails because all objects are allocated during driver load and if we have issues with lmem at that point something is seriously wrong with the system, so no point in trying to handle it. Cc: Matthew Auld Cc: Abdiel Janulgue Cc: Michal Wajdeczko Cc: Vinay Belgaumkar Cc: Radoslaw Szwichtenberg Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-3-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 26 ++++++++ drivers/gpu/drm/i915/gem/i915_gem_lmem.h | 4 ++ drivers/gpu/drm/i915/gt/uc/intel_guc.c | 9 ++- drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c | 13 ++-- drivers/gpu/drm/i915/gt/uc/intel_huc.c | 14 ++++- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 75 +++++++++++++++++++++-- 6 files changed, 128 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c index eb345305dc52..034226c5d4d0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c @@ -103,6 +103,32 @@ __i915_gem_object_create_lmem_with_ps(struct drm_i915_private *i915, size, page_size, flags); } +struct drm_i915_gem_object * +i915_gem_object_create_lmem_from_data(struct drm_i915_private *i915, + const void *data, size_t size) +{ + struct drm_i915_gem_object *obj; + void *map; + + obj = i915_gem_object_create_lmem(i915, + round_up(size, PAGE_SIZE), + I915_BO_ALLOC_CONTIGUOUS); + if (IS_ERR(obj)) + return obj; + + map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); + if (IS_ERR(map)) { + i915_gem_object_put(obj); + return map; + } + + memcpy(map, data, size); + + i915_gem_object_unpin_map(obj); + + return obj; +} + struct drm_i915_gem_object * i915_gem_object_create_lmem(struct drm_i915_private *i915, resource_size_t size, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h index 4ee81fc66302..1b88ea13435c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.h @@ -23,6 +23,10 @@ bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj); bool __i915_gem_object_is_lmem(struct drm_i915_gem_object *obj); +struct drm_i915_gem_object * +i915_gem_object_create_lmem_from_data(struct drm_i915_private *i915, + const void *data, size_t size); + struct drm_i915_gem_object * __i915_gem_object_create_lmem_with_ps(struct drm_i915_private *i915, resource_size_t size, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index fbfcae727d7f..8ffb689066f6 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -3,6 +3,7 @@ * Copyright © 2014-2019 Intel Corporation */ +#include "gem/i915_gem_lmem.h" #include "gt/intel_gt.h" #include "gt/intel_gt_irq.h" #include "gt/intel_gt_pm_irq.h" @@ -647,7 +648,13 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) u64 flags; int ret; - obj = i915_gem_object_create_shmem(gt->i915, size); + if (HAS_LMEM(gt->i915)) + obj = i915_gem_object_create_lmem(gt->i915, size, + I915_BO_ALLOC_CPU_CLEAR | + I915_BO_ALLOC_CONTIGUOUS); + else + obj = i915_gem_object_create_shmem(gt->i915, size); + if (IS_ERR(obj)) return ERR_CAST(obj); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index 76fe766ad1bc..196424be0998 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -41,18 +41,21 @@ static void guc_prepare_xfer(struct intel_uncore *uncore) } /* Copy RSA signature from the fw image to HW for verification */ -static void guc_xfer_rsa(struct intel_uc_fw *guc_fw, - struct intel_uncore *uncore) +static int guc_xfer_rsa(struct intel_uc_fw *guc_fw, + struct intel_uncore *uncore) { u32 rsa[UOS_RSA_SCRATCH_COUNT]; size_t copied; int i; copied = intel_uc_fw_copy_rsa(guc_fw, rsa, sizeof(rsa)); - GEM_BUG_ON(copied < sizeof(rsa)); + if (copied < sizeof(rsa)) + return -ENOMEM; for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++) intel_uncore_write(uncore, UOS_RSA_SCRATCH(i), rsa[i]); + + return 0; } /* @@ -141,7 +144,9 @@ int intel_guc_fw_upload(struct intel_guc *guc) * by the DMA engine in one operation, whereas the RSA signature is * loaded via MMIO. */ - guc_xfer_rsa(&guc->fw, uncore); + ret = guc_xfer_rsa(&guc->fw, uncore); + if (ret) + goto out; /* * Current uCode expects the code to be loaded at 8k; locations below diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index fc5387b410a2..ff4b6869b80b 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -87,17 +87,25 @@ static int intel_huc_rsa_data_create(struct intel_huc *huc) vma->obj, true)); if (IS_ERR(vaddr)) { i915_vma_unpin_and_release(&vma, 0); - return PTR_ERR(vaddr); + err = PTR_ERR(vaddr); + goto unpin_out; } copied = intel_uc_fw_copy_rsa(&huc->fw, vaddr, vma->size); - GEM_BUG_ON(copied < huc->fw.rsa_size); - i915_gem_object_unpin_map(vma->obj); + if (copied < huc->fw.rsa_size) { + err = -ENOMEM; + goto unpin_out; + } + huc->rsa_data = vma; return 0; + +unpin_out: + i915_vma_unpin_and_release(&vma, 0); + return err; } static void intel_huc_rsa_data_destroy(struct intel_huc *huc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index f632dbd32b42..f8cb00ffb506 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -7,6 +7,7 @@ #include #include +#include "gem/i915_gem_lmem.h" #include "intel_uc_fw.h" #include "intel_uc_fw_abi.h" #include "i915_drv.h" @@ -370,7 +371,11 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) uc_fw->private_data_size = css->private_data_size; - obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); + if (HAS_LMEM(i915)) + obj = i915_gem_object_create_lmem_from_data(i915, fw->data, fw->size); + else + obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); + if (IS_ERR(obj)) { err = PTR_ERR(obj); goto fail; @@ -414,6 +419,7 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw) struct drm_i915_gem_object *obj = uc_fw->obj; struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt; struct i915_vma *dummy = &uc_fw->dummy; + u32 pte_flags = 0; dummy->node.start = uc_fw_ggtt_offset(uc_fw); dummy->node.size = obj->base.size; @@ -424,9 +430,13 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw) GEM_BUG_ON(dummy->node.size > ggtt->uc_fw.size); /* uc_fw->obj cache domains were not controlled across suspend */ - drm_clflush_sg(dummy->pages); + if (i915_gem_object_has_struct_page(obj)) + drm_clflush_sg(dummy->pages); - ggtt->vm.insert_entries(&ggtt->vm, dummy, I915_CACHE_NONE, 0); + if (i915_gem_object_is_lmem(obj)) + pte_flags |= PTE_LM; + + ggtt->vm.insert_entries(&ggtt->vm, dummy, I915_CACHE_NONE, pte_flags); } static void uc_fw_unbind_ggtt(struct intel_uc_fw *uc_fw) @@ -585,13 +595,68 @@ void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw) */ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len) { - struct sg_table *pages = uc_fw->obj->mm.pages; + struct intel_memory_region *mr = uc_fw->obj->mm.region; u32 size = min_t(u32, uc_fw->rsa_size, max_len); u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size; + struct sgt_iter iter; + size_t count = 0; + int idx; + /* Called during reset handling, must be atomic [no fs_reclaim] */ GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw)); - return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset); + idx = offset >> PAGE_SHIFT; + offset = offset_in_page(offset); + if (i915_gem_object_has_struct_page(uc_fw->obj)) { + struct page *page; + + for_each_sgt_page(page, iter, uc_fw->obj->mm.pages) { + u32 len = min_t(u32, size, PAGE_SIZE - offset); + void *vaddr; + + if (idx > 0) { + idx--; + continue; + } + + vaddr = kmap_atomic(page); + memcpy(dst, vaddr + offset, len); + kunmap_atomic(vaddr); + + offset = 0; + dst += len; + size -= len; + count += len; + if (!size) + break; + } + } else { + dma_addr_t addr; + + for_each_sgt_daddr(addr, iter, uc_fw->obj->mm.pages) { + u32 len = min_t(u32, size, PAGE_SIZE - offset); + void __iomem *vaddr; + + if (idx > 0) { + idx--; + continue; + } + + vaddr = io_mapping_map_atomic_wc(&mr->iomap, + addr - mr->region.start); + memcpy_fromio(dst, vaddr + offset, len); + io_mapping_unmap_atomic(vaddr); + + offset = 0; + dst += len; + size -= len; + count += len; + if (!size) + break; + } + } + + return count; } /** From 87ba15d6b67abb72986b10b3c163faf0ad4c6a32 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 16 Sep 2021 09:28:17 -0700 Subject: [PATCH 038/554] drm/i915/guc: Add DG1 GuC / HuC firmware defs Add DG1 GuC / HuC firmware defs Signed-off-by: Matthew Brost Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-4-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index f8cb00ffb506..a685d563df72 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -51,6 +51,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \ fw_def(ALDERLAKE_P, 0, guc_def(adlp, 62, 0, 3), huc_def(tgl, 7, 9, 3)) \ fw_def(ALDERLAKE_S, 0, guc_def(tgl, 62, 0, 0), huc_def(tgl, 7, 9, 3)) \ + fw_def(DG1, 0, guc_def(dg1, 62, 0, 0), huc_def(dg1, 7, 9, 3)) \ fw_def(ROCKETLAKE, 0, guc_def(tgl, 62, 0, 0), huc_def(tgl, 7, 9, 3)) \ fw_def(TIGERLAKE, 0, guc_def(tgl, 62, 0, 0), huc_def(tgl, 7, 9, 3)) \ fw_def(JASPERLAKE, 0, guc_def(ehl, 62, 0, 0), huc_def(ehl, 9, 0, 0)) \ From 9175ffff5ea9f2b9e956f7458d3fa38eec8f6ec8 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 16 Sep 2021 09:28:18 -0700 Subject: [PATCH 039/554] drm/i915/guc: Enable GuC submission by default on DG1 Enable GuC submission by default on DG1 Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-5-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index 86c318516e14..2fef3b0bbe95 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -35,7 +35,7 @@ static void uc_expand_default_options(struct intel_uc *uc) } /* Intermediate platforms are HuC authentication only */ - if (IS_DG1(i915) || IS_ALDERLAKE_S(i915)) { + if (IS_ALDERLAKE_S(i915)) { i915->params.enable_guc = ENABLE_GUC_LOAD_HUC; return; } From 91160c8398243228dce619330fee600b4ad3a0f2 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 16 Sep 2021 09:28:19 -0700 Subject: [PATCH 040/554] drm/i915: Take pinning into account in __i915_gem_object_is_lmem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't blow up on a GEM_WARN_ON in __i915_gem_object_is_lmem if the object is pinned (not evictable). Signed-off-by: Matthew Brost Cc: Thomas Hellström Reviewed-by: Thomas Hellström Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-6-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c index 034226c5d4d0..d659239fcbcc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c @@ -56,8 +56,8 @@ bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj) * @obj: The object to check. * * This function is intended to be called from within the fence signaling - * path where the fence keeps the object from being migrated. For example - * during gpu reset or similar. + * path where the fence, or a pin, keeps the object from being migrated. For + * example during gpu reset or similar. * * Return: Whether the object is resident in lmem. */ @@ -66,7 +66,8 @@ bool __i915_gem_object_is_lmem(struct drm_i915_gem_object *obj) struct intel_memory_region *mr = READ_ONCE(obj->mm.region); #ifdef CONFIG_LOCKDEP - GEM_WARN_ON(dma_resv_test_signaled(obj->base.resv, true)); + GEM_WARN_ON(dma_resv_test_signaled(obj->base.resv, true) && + !i915_gem_object_evictable(obj)); #endif return mr && (mr->type == INTEL_MEMORY_LOCAL || mr->type == INTEL_MEMORY_STOLEN_LOCAL); From ff04f8beade56fead722d3f0ebcf63d4ab38e34d Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 17 Sep 2021 09:12:02 -0700 Subject: [PATCH 041/554] drm/i915/xehp: Check new fuse bits for SFC availability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xe_HP adds some new bits to the FUSE1 register to let us know whether a given SFC unit is present. We should take this into account while initializing SFC availability to our VCS and VECS engines. While we're at it, update the FUSE1 register definition to use REG_GENMASK / REG_FIELD_GET notation. Note that, the bspec confusingly names the fuse bits "disable" despite the register reflecting the *enable* status of the SFC units. The original architecture documents which the bspec is based on do properly name this field "SFC_ENABLE." Bspec: 52543 Cc: José Roberto de Souza Signed-off-by: Matt Roper Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210917161203.812251-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 25 ++++++++++++++++++----- drivers/gpu/drm/i915/gt/intel_gt_types.h | 3 +++ drivers/gpu/drm/i915/gt/intel_sseu.c | 5 ++--- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 332efea696a5..06dfe7f38953 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -398,7 +398,8 @@ static void __setup_engine_capabilities(struct intel_engine_cs *engine) engine->uabi_capabilities |= I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC; } else if (engine->class == VIDEO_ENHANCEMENT_CLASS) { - if (GRAPHICS_VER(i915) >= 9) + if (GRAPHICS_VER(i915) >= 9 && + engine->gt->info.sfc_mask & BIT(engine->instance)) engine->uabi_capabilities |= I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC; } @@ -474,18 +475,25 @@ void intel_engines_free(struct intel_gt *gt) } static -bool gen11_vdbox_has_sfc(struct drm_i915_private *i915, +bool gen11_vdbox_has_sfc(struct intel_gt *gt, unsigned int physical_vdbox, unsigned int logical_vdbox, u16 vdbox_mask) { + struct drm_i915_private *i915 = gt->i915; + /* * In Gen11, only even numbered logical VDBOXes are hooked * up to an SFC (Scaler & Format Converter) unit. * In Gen12, Even numbered physical instance always are connected * to an SFC. Odd numbered physical instances have SFC only if * previous even instance is fused off. + * + * Starting with Xe_HP, there's also a dedicated SFC_ENABLE field + * in the fuse register that tells us whether a specific SFC is present. */ - if (GRAPHICS_VER(i915) == 12) + if ((gt->info.sfc_mask & BIT(physical_vdbox / 2)) == 0) + return false; + else if (GRAPHICS_VER(i915) == 12) return (physical_vdbox % 2 == 0) || !(BIT(physical_vdbox - 1) & vdbox_mask); else if (GRAPHICS_VER(i915) == 11) @@ -512,7 +520,7 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) struct intel_uncore *uncore = gt->uncore; unsigned int logical_vdbox = 0; unsigned int i; - u32 media_fuse; + u32 media_fuse, fuse1; u16 vdbox_mask; u16 vebox_mask; @@ -534,6 +542,13 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) vebox_mask = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >> GEN11_GT_VEBOX_DISABLE_SHIFT; + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + fuse1 = intel_uncore_read(uncore, HSW_PAVP_FUSE1); + gt->info.sfc_mask = REG_FIELD_GET(XEHP_SFC_ENABLE_MASK, fuse1); + } else { + gt->info.sfc_mask = ~0; + } + for (i = 0; i < I915_MAX_VCS; i++) { if (!HAS_ENGINE(gt, _VCS(i))) { vdbox_mask &= ~BIT(i); @@ -546,7 +561,7 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) continue; } - if (gen11_vdbox_has_sfc(i915, i, logical_vdbox, vdbox_mask)) + if (gen11_vdbox_has_sfc(gt, i, logical_vdbox, vdbox_mask)) gt->info.vdbox_sfc_access |= BIT(i); logical_vdbox++; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index ce127cae9e49..9f711ee0d42c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -186,6 +186,9 @@ struct intel_gt { u8 num_engines; + /* General presence of SFC units */ + u8 sfc_mask; + /* Media engine access to SFC per instance */ u8 vdbox_sfc_access; diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index b0e09b58005e..bdf09051b8a0 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -514,10 +514,9 @@ static void hsw_sseu_info_init(struct intel_gt *gt) } fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1); - switch ((fuse1 & HSW_F1_EU_DIS_MASK) >> HSW_F1_EU_DIS_SHIFT) { + switch (REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)) { default: - MISSING_CASE((fuse1 & HSW_F1_EU_DIS_MASK) >> - HSW_F1_EU_DIS_SHIFT); + MISSING_CASE(REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)); fallthrough; case HSW_F1_EU_DIS_10EUS: sseu->eu_per_subslice = 10; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 76b437d5a37e..64d795461fc5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3108,8 +3108,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) /* Fuse readout registers for GT */ #define HSW_PAVP_FUSE1 _MMIO(0x911C) -#define HSW_F1_EU_DIS_SHIFT 16 -#define HSW_F1_EU_DIS_MASK (0x3 << HSW_F1_EU_DIS_SHIFT) +#define XEHP_SFC_ENABLE_MASK REG_GENMASK(27, 24) +#define HSW_F1_EU_DIS_MASK REG_GENMASK(17, 16) #define HSW_F1_EU_DIS_10EUS 0 #define HSW_F1_EU_DIS_8EUS 1 #define HSW_F1_EU_DIS_6EUS 2 From 45f63790e456455be6a69630042611083effe09b Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 17 Sep 2021 09:12:03 -0700 Subject: [PATCH 042/554] drm/i915: Check SFC fusing before recording/dumping SFC_DONE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Xe_HP and beyond the SFC unit may be fused off, even if the corresponding media engines are present. Check the SFC-specific fusing before trying to dump the SFC_DONE instances. Cc: José Roberto de Souza Signed-off-by: Matt Roper Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210917161203.812251-3-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/i915_gpu_error.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index b9f66dbd46bb..2a2d7643b551 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -753,7 +753,8 @@ static void err_print_gt(struct drm_i915_error_state_buf *m, * only exists if the corresponding VCS engine is * present. */ - if (!HAS_ENGINE(gt->_gt, _VCS(i * 2))) + if ((gt->_gt->info.sfc_mask & BIT(i)) == 0 || + !HAS_ENGINE(gt->_gt, _VCS(i * 2))) continue; err_printf(m, " SFC_DONE[%d]: 0x%08x\n", i, @@ -1632,7 +1633,8 @@ static void gt_record_regs(struct intel_gt_coredump *gt) * only exists if the corresponding VCS engine is * present. */ - if (!HAS_ENGINE(gt->_gt, _VCS(i * 2))) + if ((gt->_gt->info.sfc_mask & BIT(i)) == 0 || + !HAS_ENGINE(gt->_gt, _VCS(i * 2))) continue; gt->sfc_done[i] = From 1ab2b4cd128382ff64aaab55d6204362296139bc Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:25 -0700 Subject: [PATCH 043/554] drm/i915/uncore: Convert gen6/gen7 read operations to fwtable On gen6-gen8 (except vlv/chv) we don't use a forcewake lookup table; we simply check whether the register offset is < 0x40000, and return FORCEWAKE_RENDER if it is. To prepare for upcoming refactoring, let's define a single-entry forcewake table from [0x0, 0x3ffff] and switch these platforms over to use the fwtable reader functions. v2: - Drop __gen6_reg_read_fw_domains which is no longer used. (Tvrtko) Cc: Tvrtko Ursulin Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f9767054dbdf..8c09af1e9f7a 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -853,16 +853,6 @@ void assert_forcewakes_active(struct intel_uncore *uncore, /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000) -#define __gen6_reg_read_fw_domains(uncore, offset) \ -({ \ - enum forcewake_domains __fwd; \ - if (NEEDS_FORCE_WAKE(offset)) \ - __fwd = FORCEWAKE_RENDER; \ - else \ - __fwd = 0; \ - __fwd; \ -}) - static int fw_range_cmp(u32 offset, const struct intel_forcewake_range *entry) { if (offset < entry->start) @@ -1064,6 +1054,10 @@ gen6_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) __fwd; \ }) +static const struct intel_forcewake_range __gen6_fw_ranges[] = { + GEN_FW_RANGE(0x0, 0x3ffff, FORCEWAKE_RENDER), +}; + /* *Must* be sorted by offset ranges! See intel_fw_table_check(). */ static const struct intel_forcewake_range __chv_fw_ranges[] = { GEN_FW_RANGE(0x2000, 0x3fff, FORCEWAKE_RENDER), @@ -1623,7 +1617,6 @@ __gen_read(func, 64) __gen_reg_read_funcs(gen11_fwtable); __gen_reg_read_funcs(fwtable); -__gen_reg_read_funcs(gen6); #undef __gen_reg_read_funcs #undef GEN6_READ_FOOTER @@ -2111,15 +2104,17 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) == 8) { + ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen8); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen6); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_VALLEYVIEW(i915)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __vlv_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen6); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_GRAPHICS_VER(i915, 6, 7)) { + ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen6); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen6); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } uncore->pmic_bus_access_nb.notifier_call = i915_pmic_bus_access_notifier; From 6cdbb1018238a363b9b842dc2a5733c9109319c6 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:26 -0700 Subject: [PATCH 044/554] drm/i915/uncore: Associate shadow table with uncore Store a reference to a platform's shadow table inside the uncore, the same as we do with the forcewake table. This will allow us to use a single set of functions that operate on the shadow table reference rather than generating lots of nearly-identical functions via macros that differ only in terms of the table that they reference. Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-3-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 40 +++++++++++++++++++---------- drivers/gpu/drm/i915/intel_uncore.h | 7 +++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 8c09af1e9f7a..a733bf6f6519 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1026,17 +1026,16 @@ static int mmio_range_cmp(u32 key, const struct i915_range *range) return 0; } -#define __is_X_shadowed(x) \ -static bool is_##x##_shadowed(u32 offset) \ -{ \ - const struct i915_range *regs = x##_shadowed_regs; \ - return BSEARCH(offset, regs, ARRAY_SIZE(x##_shadowed_regs), \ - mmio_range_cmp); \ -} +static bool is_shadowed(struct intel_uncore *uncore, u32 offset) +{ + if (drm_WARN_ON(&uncore->i915->drm, !uncore->shadowed_reg_table)) + return false; -__is_X_shadowed(gen8) -__is_X_shadowed(gen11) -__is_X_shadowed(gen12) + return BSEARCH(offset, + uncore->shadowed_reg_table, + uncore->shadowed_reg_table_entries, + mmio_range_cmp); +} static enum forcewake_domains gen6_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) @@ -1047,7 +1046,7 @@ gen6_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) #define __gen8_reg_write_fw_domains(uncore, offset) \ ({ \ enum forcewake_domains __fwd; \ - if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(offset)) \ + if (NEEDS_FORCE_WAKE(offset) && !is_shadowed(uncore, offset)) \ __fwd = FORCEWAKE_RENDER; \ else \ __fwd = 0; \ @@ -1081,7 +1080,7 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = { #define __fwtable_reg_write_fw_domains(uncore, offset) \ ({ \ enum forcewake_domains __fwd = 0; \ - if (NEEDS_FORCE_WAKE((offset)) && !is_gen8_shadowed(offset)) \ + if (NEEDS_FORCE_WAKE((offset)) && !is_shadowed(uncore, offset)) \ __fwd = find_fw_domain(uncore, offset); \ __fwd; \ }) @@ -1090,7 +1089,7 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = { ({ \ enum forcewake_domains __fwd = 0; \ const u32 __offset = (offset); \ - if (!is_gen11_shadowed(__offset)) \ + if (!is_shadowed(uncore, __offset)) \ __fwd = find_fw_domain(uncore, __offset); \ __fwd; \ }) @@ -1099,7 +1098,7 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = { ({ \ enum forcewake_domains __fwd = 0; \ const u32 __offset = (offset); \ - if (!is_gen12_shadowed(__offset)) \ + if (!is_shadowed(uncore, __offset)) \ __fwd = find_fw_domain(uncore, __offset); \ __fwd; \ }) @@ -1969,6 +1968,12 @@ out: (uncore)->fw_domains_table_entries = ARRAY_SIZE((d)); \ } +#define ASSIGN_SHADOW_TABLE(uncore, d) \ +{ \ + (uncore)->shadowed_reg_table = d; \ + (uncore)->shadowed_reg_table_entries = ARRAY_SIZE((d)); \ +} + static int i915_pmic_bus_access_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -2081,30 +2086,37 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __dg2_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __xehp_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER(i915) >= 12) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen12_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER(i915) == 11) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen11_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen11_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen11_fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (IS_GRAPHICS_VER(i915, 9, 10)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen9_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_CHERRYVIEW(i915)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __chv_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) == 8) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen8); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_VALLEYVIEW(i915)) { diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 531665b08039..2f31c50eeae2 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -142,6 +142,13 @@ struct intel_uncore { const struct intel_forcewake_range *fw_domains_table; unsigned int fw_domains_table_entries; + /* + * Shadowed registers are special cases where we can safely write + * to the register *without* grabbing forcewake. + */ + const struct i915_range *shadowed_reg_table; + unsigned int shadowed_reg_table_entries; + struct notifier_block pmic_bus_access_nb; struct intel_uncore_funcs funcs; From 09b2a597de37032c7571d1b066b5d336df8c14eb Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:27 -0700 Subject: [PATCH 045/554] drm/i915/uncore: Replace gen8 write functions with general fwtable Now that we have both a standard forcewake table (albeit a single-entry table) and the shadow table stored in the uncore, we can drop the gen8-specific write handlers in favor of the general fwtable version. Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-4-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index a733bf6f6519..f3c77f617458 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1043,16 +1043,6 @@ gen6_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) return FORCEWAKE_RENDER; } -#define __gen8_reg_write_fw_domains(uncore, offset) \ -({ \ - enum forcewake_domains __fwd; \ - if (NEEDS_FORCE_WAKE(offset) && !is_shadowed(uncore, offset)) \ - __fwd = FORCEWAKE_RENDER; \ - else \ - __fwd = 0; \ - __fwd; \ -}) - static const struct intel_forcewake_range __gen6_fw_ranges[] = { GEN_FW_RANGE(0x0, 0x3ffff, FORCEWAKE_RENDER), }; @@ -1707,7 +1697,6 @@ __gen_write(func, 32) __gen_reg_write_funcs(gen12_fwtable); __gen_reg_write_funcs(gen11_fwtable); __gen_reg_write_funcs(fwtable); -__gen_reg_write_funcs(gen8); #undef __gen_reg_write_funcs #undef GEN6_WRITE_FOOTER @@ -2117,7 +2106,7 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) } else if (GRAPHICS_VER(i915) == 8) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); - ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen8); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_VALLEYVIEW(i915)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __vlv_fw_ranges); From aef02736a8516a578098a9f066c67e891a075cb4 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:28 -0700 Subject: [PATCH 046/554] drm/i915/uncore: Drop gen11/gen12 mmio write handlers Now that the reference to the shadow table is stored within the uncore, we don't need to generate separate fwtable, gen11_fwtable, and gen12_fwtable variants of the register write functions; a single 'fwtable' implementation will work for all of those platforms now. While consolidating the functions, gen11/gen12 pick up a NEEDS_FORCE_WAKE() check that they didn't have before, allowing them to bypass a lot of forcewake/shadow checking for non-GT registers (e.g., display). However since these later platforms also introduce media engines at higher MMIO offsets, the definition of NEEDS_FORCE_WAKE() is extended to also consider register offsets above GEN11_BSD_RING_BASE. v2: - Restore NEEDS_FORCE_WAKE(), but extend it for compatibility with the gen11+ platforms by also passing offsets above GEN11_BSD_RING_BASE. (Chris, Tvrtko) Cc: Tvrtko Ursulin Cc: Chris Wilson Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-5-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 60 ++++++++++------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f3c77f617458..00da0b718293 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -851,7 +851,10 @@ void assert_forcewakes_active(struct intel_uncore *uncore, } /* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000) +#define NEEDS_FORCE_WAKE(reg) ({ \ + u32 __reg = (reg); \ + __reg < 0x40000 || __reg >= GEN11_BSD_RING_BASE; \ +}) static int fw_range_cmp(u32 offset, const struct intel_forcewake_range *entry) { @@ -1068,27 +1071,10 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = { }; #define __fwtable_reg_write_fw_domains(uncore, offset) \ -({ \ - enum forcewake_domains __fwd = 0; \ - if (NEEDS_FORCE_WAKE((offset)) && !is_shadowed(uncore, offset)) \ - __fwd = find_fw_domain(uncore, offset); \ - __fwd; \ -}) - -#define __gen11_fwtable_reg_write_fw_domains(uncore, offset) \ ({ \ enum forcewake_domains __fwd = 0; \ const u32 __offset = (offset); \ - if (!is_shadowed(uncore, __offset)) \ - __fwd = find_fw_domain(uncore, __offset); \ - __fwd; \ -}) - -#define __gen12_fwtable_reg_write_fw_domains(uncore, offset) \ -({ \ - enum forcewake_domains __fwd = 0; \ - const u32 __offset = (offset); \ - if (!is_shadowed(uncore, __offset)) \ + if (NEEDS_FORCE_WAKE((__offset)) && !is_shadowed(uncore, __offset)) \ __fwd = find_fw_domain(uncore, __offset); \ __fwd; \ }) @@ -1672,33 +1658,29 @@ __gen6_write(8) __gen6_write(16) __gen6_write(32) -#define __gen_write(func, x) \ +#define __gen_fwtable_write(x) \ static void \ -func##_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \ +fwtable_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \ enum forcewake_domains fw_engine; \ GEN6_WRITE_HEADER; \ - fw_engine = __##func##_reg_write_fw_domains(uncore, offset); \ + fw_engine = __fwtable_reg_write_fw_domains(uncore, offset); \ if (fw_engine) \ __force_wake_auto(uncore, fw_engine); \ __raw_uncore_write##x(uncore, reg, val); \ GEN6_WRITE_FOOTER; \ } -#define __gen_reg_write_funcs(func) \ -static enum forcewake_domains \ -func##_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) { \ - return __##func##_reg_write_fw_domains(uncore, i915_mmio_reg_offset(reg)); \ -} \ -\ -__gen_write(func, 8) \ -__gen_write(func, 16) \ -__gen_write(func, 32) +static enum forcewake_domains +fwtable_reg_write_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) +{ + return __fwtable_reg_write_fw_domains(uncore, i915_mmio_reg_offset(reg)); +} -__gen_reg_write_funcs(gen12_fwtable); -__gen_reg_write_funcs(gen11_fwtable); -__gen_reg_write_funcs(fwtable); +__gen_fwtable_write(8) +__gen_fwtable_write(16) +__gen_fwtable_write(32) -#undef __gen_reg_write_funcs +#undef __gen_fwtable_write #undef GEN6_WRITE_FOOTER #undef GEN6_WRITE_HEADER @@ -2076,22 +2058,22 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __dg2_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); - ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __xehp_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); - ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER(i915) >= 12) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen12_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); - ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen12_fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (GRAPHICS_VER(i915) == 11) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen11_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen11_shadowed_regs); - ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen11_fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); } else if (IS_GRAPHICS_VER(i915, 9, 10)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen9_fw_ranges); From e5b32ae34b02c74d3327789281b88c1e59fdca30 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:29 -0700 Subject: [PATCH 047/554] drm/i915/uncore: Drop gen11 mmio read handlers Consolidate down to just a single 'fwtable' implementation. For reads we don't need to worry about shadow tables. While consolidating the functions, gen11/gen12 pick up a NEEDS_FORCE_WAKE() check that they didn't have before, allowing them to bypass a lot of forcewake/shadow checking for non-GT registers (e.g., display). v2: - Restore NEEDS_FORCE_WAKE() check. (Chris, Tvrtko) Cc: Chris Wilson Cc: Tvrtko Ursulin Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-6-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 40 ++++++++++++----------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 00da0b718293..2547a9e02efc 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -935,9 +935,6 @@ static const struct intel_forcewake_range __vlv_fw_ranges[] = { __fwd; \ }) -#define __gen11_fwtable_reg_read_fw_domains(uncore, offset) \ - find_fw_domain(uncore, offset) - /* *Must* be sorted by offset! See intel_shadow_table_check(). */ static const struct i915_range gen8_shadowed_regs[] = { { .start = 0x2030, .end = 0x2030 }, @@ -1567,33 +1564,30 @@ static inline void __force_wake_auto(struct intel_uncore *uncore, ___force_wake_auto(uncore, fw_domains); } -#define __gen_read(func, x) \ +#define __gen_fwtable_read(x) \ static u##x \ -func##_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) { \ +fwtable_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) \ +{ \ enum forcewake_domains fw_engine; \ GEN6_READ_HEADER(x); \ - fw_engine = __##func##_reg_read_fw_domains(uncore, offset); \ + fw_engine = __fwtable_reg_read_fw_domains(uncore, offset); \ if (fw_engine) \ __force_wake_auto(uncore, fw_engine); \ val = __raw_uncore_read##x(uncore, reg); \ GEN6_READ_FOOTER; \ } -#define __gen_reg_read_funcs(func) \ -static enum forcewake_domains \ -func##_reg_read_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) { \ - return __##func##_reg_read_fw_domains(uncore, i915_mmio_reg_offset(reg)); \ -} \ -\ -__gen_read(func, 8) \ -__gen_read(func, 16) \ -__gen_read(func, 32) \ -__gen_read(func, 64) +static enum forcewake_domains +fwtable_reg_read_fw_domains(struct intel_uncore *uncore, i915_reg_t reg) { + return __fwtable_reg_read_fw_domains(uncore, i915_mmio_reg_offset(reg)); +} -__gen_reg_read_funcs(gen11_fwtable); -__gen_reg_read_funcs(fwtable); +__gen_fwtable_read(8) +__gen_fwtable_read(16) +__gen_fwtable_read(32) +__gen_fwtable_read(64) -#undef __gen_reg_read_funcs +#undef __gen_fwtable_read #undef GEN6_READ_FOOTER #undef GEN6_READ_HEADER @@ -2059,22 +2053,22 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) ASSIGN_FW_DOMAINS_TABLE(uncore, __dg2_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __xehp_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) >= 12) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen12_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) == 11) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen11_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen11_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, gen11_fwtable); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_GRAPHICS_VER(i915, 9, 10)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen9_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); From c74e66d47e883d7fa345a74154d355a297b1abbd Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 10 Sep 2021 13:10:30 -0700 Subject: [PATCH 048/554] drm/i915/dg2: Add DG2-specific shadow register table We thought the DG2 table of shadowed registers would be the same as the gen12/xehp table, but it turns out that there are a few minor differences that require us to define a new DG2-specific table: * One register is removed (0xC4D4) * One register is added (0xC4E0) Signed-off-by: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210910201030.3436066-7-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 41 ++++++++++++++++++- drivers/gpu/drm/i915/selftests/intel_uncore.c | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 2547a9e02efc..c8e7c71f0896 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1016,6 +1016,45 @@ static const struct i915_range gen12_shadowed_regs[] = { { .start = 0x1F8510, .end = 0x1F8550 }, }; +static const struct i915_range dg2_shadowed_regs[] = { + { .start = 0x2030, .end = 0x2030 }, + { .start = 0x2510, .end = 0x2550 }, + { .start = 0xA008, .end = 0xA00C }, + { .start = 0xA188, .end = 0xA188 }, + { .start = 0xA278, .end = 0xA278 }, + { .start = 0xA540, .end = 0xA56C }, + { .start = 0xC4C8, .end = 0xC4C8 }, + { .start = 0xC4E0, .end = 0xC4E0 }, + { .start = 0xC600, .end = 0xC600 }, + { .start = 0xC658, .end = 0xC658 }, + { .start = 0x22030, .end = 0x22030 }, + { .start = 0x22510, .end = 0x22550 }, + { .start = 0x1C0030, .end = 0x1C0030 }, + { .start = 0x1C0510, .end = 0x1C0550 }, + { .start = 0x1C4030, .end = 0x1C4030 }, + { .start = 0x1C4510, .end = 0x1C4550 }, + { .start = 0x1C8030, .end = 0x1C8030 }, + { .start = 0x1C8510, .end = 0x1C8550 }, + { .start = 0x1D0030, .end = 0x1D0030 }, + { .start = 0x1D0510, .end = 0x1D0550 }, + { .start = 0x1D4030, .end = 0x1D4030 }, + { .start = 0x1D4510, .end = 0x1D4550 }, + { .start = 0x1D8030, .end = 0x1D8030 }, + { .start = 0x1D8510, .end = 0x1D8550 }, + { .start = 0x1E0030, .end = 0x1E0030 }, + { .start = 0x1E0510, .end = 0x1E0550 }, + { .start = 0x1E4030, .end = 0x1E4030 }, + { .start = 0x1E4510, .end = 0x1E4550 }, + { .start = 0x1E8030, .end = 0x1E8030 }, + { .start = 0x1E8510, .end = 0x1E8550 }, + { .start = 0x1F0030, .end = 0x1F0030 }, + { .start = 0x1F0510, .end = 0x1F0550 }, + { .start = 0x1F4030, .end = 0x1F4030 }, + { .start = 0x1F4510, .end = 0x1F4550 }, + { .start = 0x1F8030, .end = 0x1F8030 }, + { .start = 0x1F8510, .end = 0x1F8550 }, +}; + static int mmio_range_cmp(u32 key, const struct i915_range *range) { if (key < range->start) @@ -2051,7 +2090,7 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __dg2_fw_ranges); - ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); + ASSIGN_SHADOW_TABLE(uncore, dg2_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 22ef2c87df1a..bc8128170a99 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -68,6 +68,7 @@ static int intel_shadow_table_check(void) { gen8_shadowed_regs, ARRAY_SIZE(gen8_shadowed_regs) }, { gen11_shadowed_regs, ARRAY_SIZE(gen11_shadowed_regs) }, { gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) }, + { dg2_shadowed_regs, ARRAY_SIZE(dg2_shadowed_regs) }, }; const struct i915_range *range; unsigned int i, j; From 68c03c0e985edaf8f5ed44d56c931f9290d9311a Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 15 Sep 2021 12:41:53 +0100 Subject: [PATCH 049/554] drm/i915/debugfs: Do not report currently active engine when describing objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not very useful to have code which tries to report a rapidly transient state which will not report anything majority of the time, especially since it is currently only used from /i915_gem_framebuffers. Signed-off-by: Tvrtko Ursulin Acked-by: Christian König Cc: Daniel Vetter Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210915114153.951670-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.h | 17 ----------------- drivers/gpu/drm/i915/i915_debugfs.c | 5 ----- 2 files changed, 22 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 48112b9d76df..3043fcbd31bd 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -503,23 +503,6 @@ i915_gem_object_finish_access(struct drm_i915_gem_object *obj) i915_gem_object_unpin_pages(obj); } -static inline struct intel_engine_cs * -i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj) -{ - struct intel_engine_cs *engine = NULL; - struct dma_fence *fence; - - rcu_read_lock(); - fence = dma_resv_get_excl_unlocked(obj->base.resv); - rcu_read_unlock(); - - if (fence && dma_fence_is_i915(fence) && !dma_fence_is_signaled(fence)) - engine = to_request(fence)->engine; - dma_fence_put(fence); - - return engine; -} - void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj, unsigned int cache_level); void i915_gem_object_flush_if_display(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9f2cfcf7aa6a..fdbd46ff59e0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -140,7 +140,6 @@ void i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - struct intel_engine_cs *engine; struct i915_vma *vma; int pin_count = 0; @@ -230,10 +229,6 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_printf(m, " (stolen: %08llx)", obj->stolen->start); if (i915_gem_object_is_framebuffer(obj)) seq_printf(m, " (fb)"); - - engine = i915_gem_object_last_write_engine(obj); - if (engine) - seq_printf(m, " (%s)", engine->name); } static int i915_gem_object_info(struct seq_file *m, void *data) From e6e0edfdbbab30fcfe5e40c051190f556a527925 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Tue, 7 Sep 2021 17:06:58 +0530 Subject: [PATCH 050/554] drm/i915/display: Add HDR mode helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper function with returns if HDR mode in on Signed-off-by: Tejas Upadhyay Link: https://patchwork.freedesktop.org/patch/msgid/20210907113658.1351456-1-tejaskumarx.surendrakumar.upadhyay@intel.com [vsyrjala: fix up alignment to match codingstyle] Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/display/intel_display.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f6c0c595f631..21ca15f69d2c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -183,6 +183,12 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv) dev_priv->czclk_freq); } +static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) +{ + return (crtc_state->active_planes & + ~(icl_hdr_plane_mask() | BIT(PLANE_CURSOR))) == 0; +} + /* WA Display #0827: Gen9:all */ static void skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) @@ -5258,9 +5264,7 @@ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state) val |= PIPEMISC_YUV420_ENABLE | PIPEMISC_YUV420_MODE_FULL_BLEND; - if (DISPLAY_VER(dev_priv) >= 11 && - (crtc_state->active_planes & ~(icl_hdr_plane_mask() | - BIT(PLANE_CURSOR))) == 0) + if (DISPLAY_VER(dev_priv) >= 11 && is_hdr_mode(crtc_state)) val |= PIPEMISC_HDR_MODE_PRECISION; if (DISPLAY_VER(dev_priv) >= 12) From 5a623ff81d6f85015b8000e910dd8ee27edee819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 May 2021 15:57:38 +0300 Subject: [PATCH 051/554] drm/i915: s/crtc_state/new_crtc_state/ etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_plane_atomic_calc_changes() deals with both the old and new crtc/plane states. Make the variable names reflect that more clearly. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210514125751.17075-2-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 38 ++++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 21ca15f69d2c..23b1e0ccc72d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6362,27 +6362,27 @@ static bool needs_scaling(const struct intel_plane_state *state) } int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *crtc_state, + struct intel_crtc_state *new_crtc_state, const struct intel_plane_state *old_plane_state, - struct intel_plane_state *plane_state) + struct intel_plane_state *new_plane_state) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - bool mode_changed = intel_crtc_needs_modeset(crtc_state); + bool mode_changed = intel_crtc_needs_modeset(new_crtc_state); bool was_crtc_enabled = old_crtc_state->hw.active; - bool is_crtc_enabled = crtc_state->hw.active; + bool is_crtc_enabled = new_crtc_state->hw.active; bool turn_off, turn_on, visible, was_visible; int ret; if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_CURSOR) { - ret = skl_update_scaler_plane(crtc_state, plane_state); + ret = skl_update_scaler_plane(new_crtc_state, new_plane_state); if (ret) return ret; } was_visible = old_plane_state->uapi.visible; - visible = plane_state->uapi.visible; + visible = new_plane_state->uapi.visible; if (!was_crtc_enabled && drm_WARN_ON(&dev_priv->drm, was_visible)) was_visible = false; @@ -6398,7 +6398,7 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat * only combine the results from all planes in the current place? */ if (!is_crtc_enabled) { - intel_plane_set_invisible(crtc_state, plane_state); + intel_plane_set_invisible(new_crtc_state, new_plane_state); visible = false; } @@ -6417,28 +6417,28 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat if (turn_on) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) - crtc_state->update_wm_pre = true; + new_crtc_state->update_wm_pre = true; /* must disable cxsr around plane enable/disable */ if (plane->id != PLANE_CURSOR) - crtc_state->disable_cxsr = true; + new_crtc_state->disable_cxsr = true; } else if (turn_off) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) - crtc_state->update_wm_post = true; + new_crtc_state->update_wm_post = true; /* must disable cxsr around plane enable/disable */ if (plane->id != PLANE_CURSOR) - crtc_state->disable_cxsr = true; - } else if (intel_wm_need_update(old_plane_state, plane_state)) { + new_crtc_state->disable_cxsr = true; + } else if (intel_wm_need_update(old_plane_state, new_plane_state)) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) { /* FIXME bollocks */ - crtc_state->update_wm_pre = true; - crtc_state->update_wm_post = true; + new_crtc_state->update_wm_pre = true; + new_crtc_state->update_wm_post = true; } } if (visible || was_visible) - crtc_state->fb_bits |= plane->frontbuffer_bit; + new_crtc_state->fb_bits |= plane->frontbuffer_bit; /* * ILK/SNB DVSACNTR/Sprite Enable @@ -6477,8 +6477,8 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat (IS_IRONLAKE(dev_priv) || IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) && (turn_on || (!needs_scaling(old_plane_state) && - needs_scaling(plane_state)))) - crtc_state->disable_lp_wm = true; + needs_scaling(new_plane_state)))) + new_crtc_state->disable_lp_wm = true; return 0; } From 8f27dbf0987ad5941f969456fa6f65850866ba2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 May 2021 15:57:40 +0300 Subject: [PATCH 052/554] drm/i915: Use u8 consistently for active_planes bitmask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be consistent in that active_planes bitmask fits in a u8. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210514125751.17075-4-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cfc41f8fa74a..9452f5af070d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1708,7 +1708,7 @@ static int vlv_compute_fifo(struct intel_crtc_state *crtc_state) const struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2]; struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state; - unsigned int active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); + u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); int num_active_planes = hweight8(active_planes); const int fifo_size = 511; int fifo_extra, fifo_left = fifo_size; @@ -1900,8 +1900,8 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state, struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal; const struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state; - int num_active_planes = hweight8(crtc_state->active_planes & - ~BIT(PLANE_CURSOR)); + u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); + int num_active_planes = hweight8(active_planes); bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi); const struct intel_plane_state *old_plane_state; const struct intel_plane_state *new_plane_state; From 0cf771b5d02244d2b2515cb17d967e19bf33e83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 May 2021 15:57:39 +0300 Subject: [PATCH 053/554] drm/i915: Fix g4x cxsr enable condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The intention was to check whether the primary plane is enabled without any sprites planes being enabled. Instead we ended up checking whether just any one of the planes is enabled. g4x isn't vlv/chv and cxsr only works with the primary plane. Fix the check to examine the bitmask of active planes rather than the number of bits set in said bitmask. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210514125751.17075-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9452f5af070d..456bc6e16fc9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1376,8 +1376,7 @@ static int g4x_compute_pipe_wm(struct intel_atomic_state *state, struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal; - int num_active_planes = hweight8(crtc_state->active_planes & - ~BIT(PLANE_CURSOR)); + u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); const struct g4x_pipe_wm *raw; const struct intel_plane_state *old_plane_state; const struct intel_plane_state *new_plane_state; @@ -1417,7 +1416,7 @@ static int g4x_compute_pipe_wm(struct intel_atomic_state *state, wm_state->sr.cursor = raw->plane[PLANE_CURSOR]; wm_state->sr.fbc = raw->fbc; - wm_state->cxsr = num_active_planes == BIT(PLANE_PRIMARY); + wm_state->cxsr = active_planes == BIT(PLANE_PRIMARY); level = G4X_WM_LEVEL_HPLL; if (!g4x_raw_crtc_wm_is_valid(crtc_state, level)) From 52913626cf9abc7d0117fdeac6d3013b230d1d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 May 2021 15:57:41 +0300 Subject: [PATCH 054/554] drm/i915: Apply WaUse32BppForSRWM to elk as well as ctg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The w/a database lists this for both ctg and elk. So let's apply it to elk as well. And add the w/a name. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210514125751.17075-5-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 456bc6e16fc9..74fd6aa7afc7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1152,17 +1152,13 @@ static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state, cpp = plane_state->hw.fb->format->cpp[0]; /* - * Not 100% sure which way ELK should go here as the - * spec only says CL/CTG should assume 32bpp and BW - * doesn't need to. But as these things followed the - * mobile vs. desktop lines on gen3 as well, let's - * assume ELK doesn't need this. + * WaUse32BppForSRWM:ctg,elk * - * The spec also fails to list such a restriction for - * the HPLL watermark, which seems a little strange. + * The spec fails to list this restriction for the + * HPLL watermark, which seems a little strange. * Let's use 32bpp for the HPLL watermark as well. */ - if (IS_GM45(dev_priv) && plane->id == PLANE_PRIMARY && + if (plane->id == PLANE_PRIMARY && level != G4X_WM_LEVEL_NORMAL) cpp = max(cpp, 4u); From aad24cc4bd563200e9536b044bdde1550b00103b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Sep 2021 21:27:10 +0300 Subject: [PATCH 055/554] drm/i915: Use tile block based dimensions for CCS origin x, y check The tile size for all surface types is 4 kbyte (or 2 kbyte on old platforms), with the exception of the TGL/ADL CCS surface where the tile size is 64 bytes. To be able to remap CCS FBs the CCS surface tile needs to be defined as 4 kbyte as well (the granularity of GTT pages in a remapped view). The only place using the dimension of the 64 byte CCS area is the initial check for the main vs. CCS plane origin coordinate match. To prepare for adding support for remapping CCS FBs let's call the 64 byte CCS area a 'tile block' and add a helper to retrieve the dimensions for it. No functional change. Cc: Juha-Pekka Heikkila Signed-off-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 30 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index e4b8602ec0cd..0cf568a9cb1c 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -143,14 +143,14 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) { - if (is_gen12_ccs_plane(fb, color_plane)) - return 1; - return intel_tile_size(to_i915(fb->dev)) / intel_tile_width_bytes(fb, color_plane); } -/* Return the tile dimensions in pixel units */ +/* + * Return the tile dimensions in pixel units, based on the (2 or 4 kbyte) GTT + * page tile size. + */ static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, unsigned int *tile_width, unsigned int *tile_height) @@ -162,6 +162,21 @@ static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, *tile_height = intel_tile_height(fb, color_plane); } +/* + * Return the tile dimensions in pixel units, based on the tile block size. + * The block covers the full GTT page sized tile on all tiled surfaces and + * it's a 64 byte portion of the tile on TGL+ CCS surfaces. + */ +static void intel_tile_block_dims(const struct drm_framebuffer *fb, int color_plane, + unsigned int *tile_width, + unsigned int *tile_height) +{ + intel_tile_dims(fb, color_plane, tile_width, tile_height); + + if (is_gen12_ccs_plane(fb, color_plane)) + *tile_height = 1; +} + unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane) { unsigned int tile_width, tile_height; @@ -567,7 +582,12 @@ static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane if (!is_ccs_plane(fb, ccs_plane) || is_gen12_ccs_cc_plane(fb, ccs_plane)) return 0; - intel_tile_dims(fb, ccs_plane, &tile_width, &tile_height); + /* + * While all the tile dimensions are based on a 2k or 4k GTT page size + * here the main and CCS coordinates must match only within a (64 byte + * on TGL+) block inside the tile. + */ + intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height); intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); tile_width *= hsub; From 9814948e3cfea1771b9f816fb75cae1db4526bd2 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Sep 2021 21:27:11 +0300 Subject: [PATCH 056/554] drm/i915/adlp: Require always a power-of-two sized CCS surface stride At the moment CCS FB strides must be power-of-two sized, but a follow-up change will add support remapping these FBs, allowing the FB passed in by userspace to have a non-POT sized stride. For these remapped FBs we can only remap the main surface, not the CCS surface. This means that userspace has to always generate the CCS surface aligning to the POT stride padded main surface (by setting up the CCS AUX pagetables accordingly). Adjust the CCS surface stride check to enforce this. No functional change. v2: - Fix the gen12_ccs_aux_stride() is not static sparse warning. Cc: Juha-Pekka Heikkila Signed-off-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 34 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 0cf568a9cb1c..a0db67e85c71 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -63,10 +63,36 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) return ccs_plane - fb->format->num_planes / 2; } -static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane) +static unsigned int gen12_aligned_scanout_stride(const struct intel_framebuffer *fb, + int color_plane) { - return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)], - 512) * 64; + struct drm_i915_private *i915 = to_i915(fb->base.dev); + unsigned int stride = fb->base.pitches[color_plane]; + + if (IS_ALDERLAKE_P(i915)) + return roundup_pow_of_two(max(stride, + 8u * intel_tile_width_bytes(&fb->base, color_plane))); + + return stride; +} + +static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_plane) +{ + struct drm_i915_private *i915 = to_i915(fb->base.dev); + int main_plane = skl_ccs_to_main_plane(&fb->base, ccs_plane); + unsigned int main_stride = fb->base.pitches[main_plane]; + unsigned int main_tile_width = intel_tile_width_bytes(&fb->base, main_plane); + + /* + * On ADL-P the AUX stride must align with a power-of-two aligned main + * surface stride. The stride of the allocated main surface object can + * be less than this POT stride, which is then autopadded to the POT + * size. + */ + if (IS_ALDERLAKE_P(i915)) + main_stride = gen12_aligned_scanout_stride(fb, main_plane); + + return DIV_ROUND_UP(main_stride, 4 * main_tile_width) * 64; } int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) @@ -1379,7 +1405,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, } if (is_gen12_ccs_plane(fb, i) && !is_gen12_ccs_cc_plane(fb, i)) { - int ccs_aux_stride = gen12_ccs_aux_stride(fb, i); + int ccs_aux_stride = gen12_ccs_aux_stride(intel_fb, i); if (fb->pitches[i] != ccs_aux_stride) { drm_dbg_kms(&dev_priv->drm, From 92dff6c79b16cad7f197fb5cd4756cf8db9ff777 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Sep 2021 21:27:12 +0300 Subject: [PATCH 057/554] drm/i915/adlp: Assert that VMAs in DPT start at 0 Atm the DPT object can accommodate only one VMA, so the VMA offset will be always 0. Add an assert for this. Cc: Juha-Pekka Heikkila Signed-off-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-4-imre.deak@intel.com --- drivers/gpu/drm/i915/display/skl_universal_plane.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 724e7b04f3b6..f50282b60de4 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -993,6 +993,11 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, u32 offset = plane_state->view.color_plane[color_plane].offset; if (intel_fb_uses_dpt(fb)) { + /* + * The DPT object contains only one vma, so the VMA's offset + * within the DPT is always 0. + */ + WARN_ON(plane_state->dpt_vma->node.start); WARN_ON(offset & 0x1fffff); return offset >> 9; } else { From 929dd111dcf8395e72635e0e7a4e502a6bb6b3d0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Sep 2021 21:27:13 +0300 Subject: [PATCH 058/554] drm/i915: Follow a new->old platform check order in intel_fb_stride_alignment Follow the usual new->old order in intel_fb_stride_alignment() platform check ladder. Cc: Juha-Pekka Heikkila Signed-off-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index a0db67e85c71..479c76c7958c 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1158,6 +1158,12 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) tile_width = intel_tile_width_bytes(fb, color_plane); if (is_ccs_modifier(fb->modifier)) { + /* + * On TGL the surface stride must be 4 tile aligned, mapped by + * one 64 byte cacheline on the CCS AUX surface. + */ + if (DISPLAY_VER(dev_priv) >= 12) + tile_width *= 4; /* * Display WA #0531: skl,bxt,kbl,glk * @@ -1167,14 +1173,8 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) * require the entire fb to accommodate that to avoid * potential runtime errors at plane configuration time. */ - if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) && - color_plane == 0 && fb->width > 3840) - tile_width *= 4; - /* - * The main surface pitch must be padded to a multiple of four - * tile widths. - */ - else if (DISPLAY_VER(dev_priv) >= 12) + else if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) && + color_plane == 0 && fb->width > 3840) tile_width *= 4; } return tile_width; From 54fc4f134e096bc508a095348cb4b4965aa1c07b Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 22 Sep 2021 17:30:29 -0700 Subject: [PATCH 059/554] drm/i915/uncore: fwtable read handlers are now used on all forcewake platforms With the recent refactor of the uncore mmio handling, all forcewake-based platforms (i.e., graphics version 6 and beyond) now use the 'fwtable' read handlers. Let's pull the assignment out of the per-platform if/else ladder to make this more obvious. Suggested-by: Tvrtko Ursulin Suggested-by: Lucas De Marchi Signed-off-by: Matt Roper Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210923003029.2194375-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index c8e7c71f0896..678a99de07fe 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -2088,49 +2088,42 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) return ret; forcewake_early_sanitize(uncore, 0); + ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __dg2_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, dg2_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __xehp_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) >= 12) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen12_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen12_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) == 11) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen11_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen11_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_GRAPHICS_VER(i915, 9, 10)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen9_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_CHERRYVIEW(i915)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __chv_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (GRAPHICS_VER(i915) == 8) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, gen8_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_VALLEYVIEW(i915)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __vlv_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen6); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } else if (IS_GRAPHICS_VER(i915, 6, 7)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __gen6_fw_ranges); ASSIGN_WRITE_MMIO_VFUNCS(uncore, gen6); - ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); } uncore->pmic_bus_access_nb.notifier_call = i915_pmic_bus_access_notifier; From 3d1adc3d64cfc544044feeca9c892599199f9616 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Sep 2021 21:27:14 +0300 Subject: [PATCH 060/554] drm/i915/adlp: Add support for remapping CCS FBs Add support for remapping CCS FBs on ADL-P to remove the restriction of the power-of-two sized stride and the 2MB surface offset alignment for these FBs. We can only remap the tiles on the main surface, not the tiles on the CCS surface, so userspace has to generate the CCS surface aligning to the POT size padded main surface stride (by programming the AUX pagetable accordingly). For the required AUX pagetable setup, this requires that either the main surface stride is 8 tiles or that the stride is 16 tiles aligned (= 64 kbytes, the area mapped by one AUX PTE). v2: - Init intel_remapped_info::plane_alignment only for remapped views and do this from intel_fb_view_init(). Cc: Juha-Pekka Heikkila Signed-off-by: Imre Deak Reviewed-by: Juha-Pekka Heikkila Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 5 +- .../drm/i915/display/intel_display_types.h | 2 - drivers/gpu/drm/i915/display/intel_fb.c | 93 +++++++++++-------- drivers/gpu/drm/i915/gt/intel_ggtt.c | 29 +++++- drivers/gpu/drm/i915/i915_vma_types.h | 7 +- 5 files changed, 89 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 23b1e0ccc72d..49d99915b440 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -899,8 +899,11 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info unsigned int size = 0; int i; - for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) + for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { + if (rem_info->plane_alignment) + size = ALIGN(size, rem_info->plane_alignment); size += rem_info->plane[i].dst_stride * rem_info->plane[i].height; + } return size; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e9e806d90eec..73930c24d7fb 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -103,8 +103,6 @@ struct intel_fb_view { * in the rotated and remapped GTT view all no-CCS formats (up to 2 * color planes) are supported. * - * TODO: add support for CCS formats in the remapped GTT view. - * * The view information shared by all FB color planes in the FB, * like dst x/y and src/dst width, is stored separately in * intel_plane_state. diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 479c76c7958c..fa1f375e696b 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -357,15 +357,29 @@ void intel_fb_plane_get_subsampling(int *hsub, int *vsub, static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h) { + struct drm_i915_private *i915 = to_i915(fb->base.dev); int main_plane = is_ccs_plane(&fb->base, color_plane) ? skl_ccs_to_main_plane(&fb->base, color_plane) : 0; + unsigned int main_width = fb->base.width; + unsigned int main_height = fb->base.height; int main_hsub, main_vsub; int hsub, vsub; + /* + * On ADL-P the CCS AUX surface layout always aligns with the + * power-of-two aligned main surface stride. The main surface + * stride in the allocated FB object may not be power-of-two + * sized, in which case it is auto-padded to the POT size. + */ + if (IS_ALDERLAKE_P(i915) && is_ccs_plane(&fb->base, color_plane)) + main_width = gen12_aligned_scanout_stride(fb, 0) / + fb->base.format->cpp[0]; + intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane); intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane); - *w = fb->base.width / main_hsub / hsub; - *h = fb->base.height / main_vsub / vsub; + + *w = main_width / main_hsub / hsub; + *h = main_height / main_vsub / vsub; } static u32 intel_adjust_tile_offset(int *x, int *y, @@ -547,17 +561,8 @@ static int intel_fb_offset_to_xy(int *x, int *y, unsigned int height; u32 alignment; - /* - * All DPT color planes must be 512*4k aligned (the amount mapped by a - * single DPT page). For ADL_P CCS FBs this only works by requiring - * the allocated offsets to be 2MB aligned. Once supoort to remap - * such FBs is added we can remove this requirement, as then all the - * planes can be remapped to an aligned offset. - */ - if (IS_ALDERLAKE_P(i915) && is_ccs_modifier(fb->modifier)) - alignment = 512 * 4096; - else if (DISPLAY_VER(i915) >= 12 && - is_semiplanar_uv_plane(fb, color_plane)) + if (DISPLAY_VER(i915) >= 12 && + is_semiplanar_uv_plane(fb, color_plane)) alignment = intel_tile_row_size(fb, color_plane); else if (fb->modifier != DRM_FORMAT_MOD_LINEAR) alignment = intel_tile_size(i915); @@ -688,8 +693,7 @@ bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) { struct drm_i915_private *i915 = to_i915(fb->base.dev); - return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR && - !is_ccs_modifier(fb->base.modifier); + return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR; } static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation) @@ -809,14 +813,16 @@ static unsigned int plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, unsigned int pitch_tiles) { - if (intel_fb_needs_pot_stride_remap(fb)) + if (intel_fb_needs_pot_stride_remap(fb)) { + unsigned int min_stride = is_ccs_plane(&fb->base, color_plane) ? 2 : 8; /* * ADL_P, the only platform needing a POT stride has a minimum - * of 8 stride tiles. + * of 8 main surface and 2 CCS AUX stride tiles. */ - return roundup_pow_of_two(max(pitch_tiles, 8u)); - else + return roundup_pow_of_two(max(pitch_tiles, min_stride)); + } else { return pitch_tiles; + } } static unsigned int @@ -852,7 +858,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p unsigned int tile_height = dims->tile_height; unsigned int tile_size = intel_tile_size(i915); struct drm_rect r; - u32 size; + u32 size = 0; assign_chk_ovf(i915, remap_info->offset, obj_offset); assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims)); @@ -877,7 +883,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p color_plane_info->stride = remap_info->dst_stride * tile_height; - size = remap_info->dst_stride * remap_info->width; + size += remap_info->dst_stride * remap_info->width; /* rotate the tile dimensions to match the GTT view */ swap(tile_width, tile_height); @@ -886,6 +892,14 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p check_array_bounds(i915, view->gtt.remapped.plane, color_plane); + if (view->gtt.remapped.plane_alignment) { + unsigned int aligned_offset = ALIGN(gtt_offset, + view->gtt.remapped.plane_alignment); + + size += aligned_offset - gtt_offset; + gtt_offset = aligned_offset; + } + assign_chk_ovf(i915, remap_info->dst_stride, plane_view_dst_stride_tiles(fb, color_plane, remap_info->width)); @@ -895,7 +909,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p color_plane_info->stride = remap_info->dst_stride * tile_width * fb->base.format->cpp[color_plane]; - size = remap_info->dst_stride * remap_info->height; + size += remap_info->dst_stride * remap_info->height; } /* @@ -942,10 +956,14 @@ calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane, return tiles; } -static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_type view_type) +static void intel_fb_view_init(struct drm_i915_private *i915, struct intel_fb_view *view, + enum i915_ggtt_view_type view_type) { memset(view, 0, sizeof(*view)); view->gtt.type = view_type; + + if (view_type == I915_GGTT_VIEW_REMAPPED && IS_ALDERLAKE_P(i915)) + view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE; } bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb) @@ -966,16 +984,16 @@ int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer * int i, num_planes = fb->base.format->num_planes; unsigned int tile_size = intel_tile_size(i915); - intel_fb_view_init(&fb->normal_view, I915_GGTT_VIEW_NORMAL); + intel_fb_view_init(i915, &fb->normal_view, I915_GGTT_VIEW_NORMAL); drm_WARN_ON(&i915->drm, intel_fb_supports_90_270_rotation(fb) && intel_fb_needs_pot_stride_remap(fb)); if (intel_fb_supports_90_270_rotation(fb)) - intel_fb_view_init(&fb->rotated_view, I915_GGTT_VIEW_ROTATED); + intel_fb_view_init(i915, &fb->rotated_view, I915_GGTT_VIEW_ROTATED); if (intel_fb_needs_pot_stride_remap(fb)) - intel_fb_view_init(&fb->remapped_view, I915_GGTT_VIEW_REMAPPED); + intel_fb_view_init(i915, &fb->remapped_view, I915_GGTT_VIEW_REMAPPED); for (i = 0; i < num_planes; i++) { struct fb_plane_view_dims view_dims; @@ -1053,7 +1071,7 @@ static void intel_plane_remap_gtt(struct intel_plane_state *plane_state) unsigned int src_w, src_h; u32 gtt_offset = 0; - intel_fb_view_init(&plane_state->view, + intel_fb_view_init(i915, &plane_state->view, drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED : I915_GGTT_VIEW_REMAPPED); @@ -1158,11 +1176,19 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) tile_width = intel_tile_width_bytes(fb, color_plane); if (is_ccs_modifier(fb->modifier)) { + /* + * On ADL-P the stride must be either 8 tiles or a stride + * that is aligned to 16 tiles, required by the 16 tiles = + * 64 kbyte CCS AUX PTE granularity, allowing CCS FBs to be + * remapped. + */ + if (IS_ALDERLAKE_P(dev_priv)) + tile_width *= fb->pitches[0] <= tile_width * 8 ? 8 : 16; /* * On TGL the surface stride must be 4 tile aligned, mapped by * one 64 byte cacheline on the CCS AUX surface. */ - if (DISPLAY_VER(dev_priv) >= 12) + else if (DISPLAY_VER(dev_priv) >= 12) tile_width *= 4; /* * Display WA #0531: skl,bxt,kbl,glk @@ -1416,17 +1442,6 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, } } - /* TODO: Add POT stride remapping support for CCS formats as well. */ - if (IS_ALDERLAKE_P(dev_priv) && - mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR && - !intel_fb_needs_pot_stride_remap(intel_fb) && - !is_power_of_2(mode_cmd->pitches[i])) { - drm_dbg_kms(&dev_priv->drm, - "plane %d pitch (%d) must be power of two for tiled buffers\n", - i, mode_cmd->pitches[i]); - goto err; - } - fb->obj[i] = &obj->base; } diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index de3ac58fceec..cbd0e1010a46 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -1373,13 +1373,28 @@ err_st_alloc: } static struct scatterlist * -remap_pages(struct drm_i915_gem_object *obj, unsigned int offset, +remap_pages(struct drm_i915_gem_object *obj, + unsigned int offset, unsigned int alignment_pad, unsigned int width, unsigned int height, unsigned int src_stride, unsigned int dst_stride, struct sg_table *st, struct scatterlist *sg) { unsigned int row; + if (alignment_pad) { + st->nents++; + + /* + * The DE ignores the PTEs for the padding tiles, the sg entry + * here is just a convenience to indicate how many padding PTEs + * to insert at this spot. + */ + sg_set_page(sg, NULL, alignment_pad * 4096, 0); + sg_dma_address(sg) = 0; + sg_dma_len(sg) = alignment_pad * 4096; + sg = sg_next(sg); + } + for (row = 0; row < height; row++) { unsigned int left = width * I915_GTT_PAGE_SIZE; @@ -1439,6 +1454,7 @@ intel_remap_pages(struct intel_remapped_info *rem_info, struct drm_i915_private *i915 = to_i915(obj->base.dev); struct sg_table *st; struct scatterlist *sg; + unsigned int gtt_offset = 0; int ret = -ENOMEM; int i; @@ -1455,10 +1471,19 @@ intel_remap_pages(struct intel_remapped_info *rem_info, sg = st->sgl; for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { - sg = remap_pages(obj, rem_info->plane[i].offset, + unsigned int alignment_pad = 0; + + if (rem_info->plane_alignment) + alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset; + + sg = remap_pages(obj, + rem_info->plane[i].offset, alignment_pad, rem_info->plane[i].width, rem_info->plane[i].height, rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, st, sg); + + gtt_offset += alignment_pad + + rem_info->plane[i].dst_stride * rem_info->plane[i].height; } i915_sg_trim(st); diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h index 995b502d7e5d..80e93bf00f2e 100644 --- a/drivers/gpu/drm/i915/i915_vma_types.h +++ b/drivers/gpu/drm/i915/i915_vma_types.h @@ -105,8 +105,9 @@ struct intel_remapped_plane_info { } __packed; struct intel_remapped_info { - struct intel_remapped_plane_info plane[2]; - u32 unused_mbz; + struct intel_remapped_plane_info plane[4]; + /* in gtt pages */ + u32 plane_alignment; } __packed; struct intel_rotation_info { @@ -129,7 +130,7 @@ static inline void assert_i915_gem_gtt_types(void) { BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 2 * sizeof(u32) + 8 * sizeof(u16)); BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int)); - BUILD_BUG_ON(sizeof(struct intel_remapped_info) != 3 * sizeof(u32) + 8 * sizeof(u16)); + BUILD_BUG_ON(sizeof(struct intel_remapped_info) != 5 * sizeof(u32) + 16 * sizeof(u16)); /* Check that rotation/remapped shares offsets for simplicity */ BUILD_BUG_ON(offsetof(struct intel_remapped_info, plane[0]) != From 017792a041183c4f5ec595f386e76a40ed728cfc Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Mon, 20 Sep 2021 16:05:00 +0900 Subject: [PATCH 061/554] drm/i915/guc, docs: Fix pdfdocs build error by removing nested grid Nested grids in grid-table cells are not specified as proper ReST constructs. Commit 572f2a5cd974 ("drm/i915/guc: Update firmware to v62.0.0") added a couple of kerneldoc tables of the form: +---+-------+------------------------------------------------------+ | 1 | 31:0 | +------------------------------------------------+ | +---+-------+ | | | |...| | | Embedded `HXG Message`_ | | +---+-------+ | | | | n | 31:0 | +------------------------------------------------+ | +---+-------+------------------------------------------------------+ For "make htmldocs", they happen to work as one might expect, but they are incompatible with "make latexdocs" and "make pdfdocs", and cause the generated gpu.tex file to become incomplete and unbuildable by xelatex. Restore the compatibility by removing those nested grids in the tables. Size comparison of generated gpu.tex: Sphinx 2.4.4 Sphinx 4.2.0 v5.14: 3238686 3841631 v5.15-rc1: 376270 432729 with this fix: 3377846 3998095 Fixes: 572f2a5cd974 ("drm/i915/guc: Update firmware to v62.0.0") Cc: John Harrison Cc: Michal Wajdeczko Cc: Matthew Brost Cc: Daniele Ceraolo Spurio Cc: Matt Roper Cc: Jonathan Corbet Signed-off-by: Akira Yokosawa Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/4a227569-074f-c501-58bb-d0d8f60a8ae9@gmail.com --- .../gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h | 10 +++++----- .../drm/i915/gt/uc/abi/guc_communication_mmio_abi.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h index 99e1fad5ca20..c9086a600bce 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h @@ -102,11 +102,11 @@ static_assert(sizeof(struct guc_ct_buffer_desc) == 64); * | +-------+--------------------------------------------------------------+ * | | 7:0 | NUM_DWORDS = length (in dwords) of the embedded HXG message | * +---+-------+--------------------------------------------------------------+ - * | 1 | 31:0 | +--------------------------------------------------------+ | - * +---+-------+ | | | - * |...| | | Embedded `HXG Message`_ | | - * +---+-------+ | | | - * | n | 31:0 | +--------------------------------------------------------+ | + * | 1 | 31:0 | | + * +---+-------+ | + * |...| | [Embedded `HXG Message`_] | + * +---+-------+ | + * | n | 31:0 | | * +---+-------+--------------------------------------------------------------+ */ diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h index bbf1ddb77434..9baa3cb07d13 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h @@ -38,11 +38,11 @@ * +---+-------+--------------------------------------------------------------+ * | | Bits | Description | * +===+=======+==============================================================+ - * | 0 | 31:0 | +--------------------------------------------------------+ | - * +---+-------+ | | | - * |...| | | Embedded `HXG Message`_ | | - * +---+-------+ | | | - * | n | 31:0 | +--------------------------------------------------------+ | + * | 0 | 31:0 | | + * +---+-------+ | + * |...| | [Embedded `HXG Message`_] | + * +---+-------+ | + * | n | 31:0 | | * +---+-------+--------------------------------------------------------------+ */ From 27493cb8747e8389a70a053445daf6a5c7888c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Sep 2021 14:52:40 -0700 Subject: [PATCH 062/554] drm/i915/display/dmc: Set DC_STATE_DEBUG_MASK_CORES after firmware load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Specification asks for DC_STATE_DEBUG_MASK_CORES to be set for all platforms that supports DMC, not only for geminilake and broxton. While at is also taking the oportunity to simply the code. BSpec: 7402 BSpec: 49436 Reviewed-by: Imre Deak Cc: Imre Deak Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210922215242.66683-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b0268552b286..2dc9d632969d 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -255,20 +255,10 @@ intel_get_stepping_info(struct drm_i915_private *i915, static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv) { - u32 val, mask; - - mask = DC_STATE_DEBUG_MASK_MEMORY_UP; - - if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - mask |= DC_STATE_DEBUG_MASK_CORES; - /* The below bit doesn't need to be cleared ever afterwards */ - val = intel_de_read(dev_priv, DC_STATE_DEBUG); - if ((val & mask) != mask) { - val |= mask; - intel_de_write(dev_priv, DC_STATE_DEBUG, val); - intel_de_posting_read(dev_priv, DC_STATE_DEBUG); - } + intel_de_rmw(dev_priv, DC_STATE_DEBUG, 0, + DC_STATE_DEBUG_MASK_CORES | DC_STATE_DEBUG_MASK_MEMORY_UP); + intel_de_posting_read(dev_priv, DC_STATE_DEBUG); } /** From 73262db68c27ed25452ffd3b57e051e1791de713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Sep 2021 14:52:41 -0700 Subject: [PATCH 063/554] drm/i915/display: Match PSR2 selective fetch sequences with specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were not completely following the selective fetch programming sequence, here some things we were doing wrong: - not programming plane selective fetch a PSR2_MAN_TRK_CTL registers when doing a modeset - programming PSR2_MAN_TRK_CTL out of vblank With this changes the last remainig underrun found in Alderlake-P is fixed. Bspec: 55229 Tested-by: Gwan-gyeong Mun Reviewed-by: Gwan-gyeong Mun Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210922215242.66683-2-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 4 ++- drivers/gpu/drm/i915/display/intel_display.c | 12 +++---- drivers/gpu/drm/i915/display/intel_psr.c | 33 ++++++++++++++----- drivers/gpu/drm/i915/display/intel_psr.h | 2 ++ .../drm/i915/display/skl_universal_plane.c | 4 +-- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index c7618fef0143..901ad3a4c8c3 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -536,8 +536,10 @@ static void i9xx_update_cursor(struct intel_plane *plane, if (DISPLAY_VER(dev_priv) >= 9) skl_write_cursor_wm(plane, crtc_state); - if (!intel_crtc_needs_modeset(crtc_state)) + if (plane_state) intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0); + else + intel_psr2_disable_plane_sel_fetch(plane, crtc_state); if (plane->cursor.base != base || plane->cursor.size != fbc_ctl || diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 49d99915b440..ac33bb935e9b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6819,11 +6819,9 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, } - if (!mode_changed) { - ret = intel_psr2_sel_fetch_update(state, crtc); - if (ret) - return ret; - } + ret = intel_psr2_sel_fetch_update(state, crtc); + if (ret) + return ret; return 0; } @@ -9716,10 +9714,10 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, if (new_crtc_state->update_pipe) intel_pipe_fastset(old_crtc_state, new_crtc_state); - - intel_psr2_program_trans_man_trk_ctl(new_crtc_state); } + intel_psr2_program_trans_man_trk_ctl(new_crtc_state); + if (dev_priv->display.atomic_update_watermarks) dev_priv->display.atomic_update_watermarks(state, crtc); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index c1894b056d6c..868e5205dd09 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -561,15 +561,16 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_PSR2_SU_SDP_SCANLINE; if (intel_dp->psr.psr2_sel_fetch_enabled) { + u32 tmp; + /* Wa_1408330847 */ if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, CHICKEN_PAR1_1, DIS_RAM_BYPASS_PSR2_MAN_TRACK, DIS_RAM_BYPASS_PSR2_MAN_TRACK); - intel_de_write(dev_priv, - PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), - PSR2_MAN_TRK_CTL_ENABLE); + tmp = intel_de_read(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder)); + drm_WARN_ON(&dev_priv->drm, !(tmp & PSR2_MAN_TRK_CTL_ENABLE)); } else if (HAS_PSR2_SEL_FETCH(dev_priv)) { intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0); @@ -1450,6 +1451,18 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); } +void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, @@ -1464,11 +1477,11 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, if (!crtc_state->enable_psr2_sel_fetch) return; - val = plane_state ? plane_state->ctl : 0; - val &= plane->id == PLANE_CURSOR ? val : PLANE_SEL_FETCH_CTL_ENABLE; - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), val); - if (!val || plane->id == PLANE_CURSOR) + if (plane->id == PLANE_CURSOR) { + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), + plane_state->ctl); return; + } clip = &plane_state->psr2_sel_fetch_area; @@ -1487,14 +1500,16 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, val = (drm_rect_height(clip) - 1) << 16; val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1; intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val); + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), + PLANE_SEL_FETCH_CTL_ENABLE); } void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - if (!HAS_PSR2_SEL_FETCH(dev_priv) || - !crtc_state->enable_psr2_sel_fetch) + if (!crtc_state->enable_psr2_sel_fetch) return; intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 641521b101c8..e502964697c6 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -51,6 +51,8 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, int color_plane); +void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state); void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index f50282b60de4..91f1be7174e5 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -656,6 +656,7 @@ skl_disable_plane(struct intel_plane *plane, skl_write_plane_wm(plane, crtc_state); + intel_psr2_disable_plane_sel_fetch(plane, crtc_state); intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); @@ -1101,8 +1102,7 @@ skl_program_plane(struct intel_plane *plane, (plane_state->view.color_plane[1].y << 16) | plane_state->view.color_plane[1].x); - if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) - intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); + intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); /* * Enable the scaler before the plane so that we don't From 9ce5884e5139037445d0efcf37aeba21008011ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 22 Sep 2021 14:52:42 -0700 Subject: [PATCH 064/554] drm/i915/display: Only keep PSR enabled if there is active planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PSR always had a requirement to only be enabled if there is active planes but not following that never caused any issues. But that changes in Alderlake-P, leaving PSR enabled without active planes causes transcoder/port underruns. Similar behavior was fixed during the pipe disable sequence by commit 84030adb9e27 ("drm/i915/display: Disable audio, DRRS and PSR before planes"). intel_dp_compute_psr_vsc_sdp() had to move from intel_psr_enable_locked() to intel_psr_compute_config() because we need to be able to disable/enable PSR from atomic states without connector and encoder state. Reviewed-by: Gwan-gyeong Mun Cc: Ville Syrjälä Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210922215242.66683-3-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 - drivers/gpu/drm/i915/display/intel_display.c | 14 +- .../drm/i915/display/intel_display_types.h | 3 +- drivers/gpu/drm/i915/display/intel_dp.c | 6 +- drivers/gpu/drm/i915/display/intel_dp.h | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 140 ++++++++++-------- drivers/gpu/drm/i915/display/intel_psr.h | 11 +- 7 files changed, 98 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index bba0ab99836b..a4667741d354 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3034,7 +3034,6 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, intel_dp_stop_link_train(intel_dp, crtc_state); intel_edp_backlight_on(crtc_state, conn_state); - intel_psr_enable(intel_dp, crtc_state, conn_state); if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); @@ -3255,7 +3254,6 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state, intel_ddi_set_dp_msa(crtc_state, conn_state); - intel_psr_update(intel_dp, crtc_state, conn_state); intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); intel_drrs_update(intel_dp, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ac33bb935e9b..f27c294beb92 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8098,10 +8098,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (bp_gamma) PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma); - PIPE_CONF_CHECK_BOOL(has_psr); - PIPE_CONF_CHECK_BOOL(has_psr2); - PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch); - PIPE_CONF_CHECK_I(dc3co_exitline); + if (current_config->active_planes) { + PIPE_CONF_CHECK_BOOL(has_psr); + PIPE_CONF_CHECK_BOOL(has_psr2); + PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch); + PIPE_CONF_CHECK_I(dc3co_exitline); + } } PIPE_CONF_CHECK_BOOL(double_wide); @@ -8158,7 +8160,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(min_voltage_level); } - if (fastset && (current_config->has_psr || pipe_config->has_psr)) + if (current_config->has_psr || pipe_config->has_psr) PIPE_CONF_CHECK_X_WITH_MASK(infoframes.enable, ~intel_hdmi_infoframe_enable(DP_SDP_VSC)); else @@ -10212,6 +10214,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_encoders_update_prepare(state); intel_dbuf_pre_plane_update(state); + intel_psr_pre_plane_update(state); for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->uapi.async_flip) @@ -10275,6 +10278,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } intel_dbuf_post_plane_update(state); + intel_psr_post_plane_update(state); for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { intel_post_plane_update(state, crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 73930c24d7fb..9413ebae15f5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1054,12 +1054,14 @@ struct intel_crtc_state { struct intel_link_m_n dp_m2_n2; bool has_drrs; + /* PSR is supported but might not be enabled due the lack of enabled planes */ bool has_psr; bool has_psr2; bool enable_psr2_sel_fetch; bool req_psr2_sdp_prior_scanline; u32 dc3co_exitline; u16 su_y_granularity; + struct drm_dp_vsc_sdp psr_vsc; /* * Frequence the dpll for the port should run at. Differs from the @@ -1523,7 +1525,6 @@ struct intel_psr { u32 dc3co_exitline; u32 dc3co_exit_delay; struct delayed_work dc3co_work; - struct drm_dp_vsc_sdp vsc; }; struct intel_dp { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7559911c140a..378008873e03 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, { vsc->sdp_type = DP_SDP_VSC; - if (intel_dp->psr.psr2_enabled) { + if (crtc_state->has_psr2) { if (intel_dp->psr.colorimetry_support && intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { /* [PSR2, +Colorimetry] */ @@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, g4x_dp_set_clock(encoder, pipe_config); intel_vrr_compute_config(pipe_config, conn_state); - intel_psr_compute_config(intel_dp, pipe_config); + intel_psr_compute_config(intel_dp, pipe_config, conn_state); intel_drrs_compute_config(intel_dp, pipe_config, output_bpp, constant_n); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); @@ -2888,7 +2888,7 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder, void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, - struct drm_dp_vsc_sdp *vsc) + const struct drm_dp_vsc_sdp *vsc) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 94b568704b22..3343c2591680 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, struct drm_dp_vsc_sdp *vsc); void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, - struct drm_dp_vsc_sdp *vsc); + const struct drm_dp_vsc_sdp *vsc); void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 868e5205dd09..19a96d3c4acf 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -950,7 +950,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, } void intel_psr_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) + struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const struct drm_display_mode *adjusted_mode = @@ -1002,7 +1003,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, crtc_state->has_psr = true; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); + crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); + intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, + &crtc_state->psr_vsc); } void intel_psr_get_config(struct intel_encoder *encoder, @@ -1182,8 +1186,7 @@ static bool psr_interrupt_error_check(struct intel_dp *intel_dp) } static void intel_psr_enable_locked(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) + const struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -1210,9 +1213,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", intel_dp->psr.psr2_enabled ? "2" : "1"); - intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, - &intel_dp->psr.vsc); - intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc); + intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); intel_psr_enable_source(intel_dp); @@ -1222,33 +1223,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, intel_psr_activate(intel_dp); } -/** - * intel_psr_enable - Enable PSR - * @intel_dp: Intel DP - * @crtc_state: new CRTC state - * @conn_state: new CONNECTOR state - * - * This function can only be called after the pipe is fully trained and enabled. - */ -void intel_psr_enable(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - - if (!CAN_PSR(intel_dp)) - return; - - if (!crtc_state->has_psr) - return; - - drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp); - - mutex_lock(&intel_dp->psr.lock); - intel_psr_enable_locked(intel_dp, crtc_state, conn_state); - mutex_unlock(&intel_dp->psr.lock); -} - static void intel_psr_exit(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -1734,48 +1708,92 @@ skip_sel_fetch_set_loop: return 0; } -/** - * intel_psr_update - Update PSR state - * @intel_dp: Intel DP - * @crtc_state: new CRTC state - * @conn_state: new CONNECTOR state - * - * This functions will update PSR states, disabling, enabling or switching PSR - * version when executing fastsets. For full modeset, intel_psr_disable() and - * intel_psr_enable() should be called instead. - */ -void intel_psr_update(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) +static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state, + const struct intel_crtc_state *crtc_state) { - struct intel_psr *psr = &intel_dp->psr; - bool enable, psr2_enable; + struct intel_encoder *encoder; - if (!CAN_PSR(intel_dp)) + for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_psr *psr = &intel_dp->psr; + bool needs_to_disable = false; + + mutex_lock(&psr->lock); + + /* + * Reasons to disable: + * - PSR disabled in new state + * - All planes will go inactive + * - Changing between PSR versions + */ + needs_to_disable |= !crtc_state->has_psr; + needs_to_disable |= !crtc_state->active_planes; + needs_to_disable |= crtc_state->has_psr2 != psr->psr2_enabled; + + if (psr->enabled && needs_to_disable) + intel_psr_disable_locked(intel_dp); + + mutex_unlock(&psr->lock); + } +} + +void intel_psr_pre_plane_update(const struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + int i; + + if (!HAS_PSR(dev_priv)) return; - mutex_lock(&intel_dp->psr.lock); + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) + _intel_psr_pre_plane_update(state, crtc_state); +} - enable = crtc_state->has_psr; - psr2_enable = crtc_state->has_psr2; +static void _intel_psr_post_plane_update(const struct intel_atomic_state *state, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_encoder *encoder; + + if (!crtc_state->has_psr) + return; + + for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_psr *psr = &intel_dp->psr; + + mutex_lock(&psr->lock); + + drm_WARN_ON(&dev_priv->drm, psr->enabled && !crtc_state->active_planes); + + /* Only enable if there is active planes */ + if (!psr->enabled && crtc_state->active_planes) + intel_psr_enable_locked(intel_dp, crtc_state); - if (enable == psr->enabled && psr2_enable == psr->psr2_enabled && - crtc_state->enable_psr2_sel_fetch == psr->psr2_sel_fetch_enabled) { /* Force a PSR exit when enabling CRC to avoid CRC timeouts */ if (crtc_state->crc_enabled && psr->enabled) psr_force_hw_tracking_exit(intel_dp); - goto unlock; + mutex_unlock(&psr->lock); } +} - if (psr->enabled) - intel_psr_disable_locked(intel_dp); +void intel_psr_post_plane_update(const struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + int i; - if (enable) - intel_psr_enable_locked(intel_dp, crtc_state, conn_state); + if (!HAS_PSR(dev_priv)) + return; -unlock: - mutex_unlock(&intel_dp->psr.lock); + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) + _intel_psr_post_plane_update(state, crtc_state); } /** diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index e502964697c6..facffbacd357 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -20,14 +20,10 @@ struct intel_plane; struct intel_encoder; void intel_psr_init_dpcd(struct intel_dp *intel_dp); -void intel_psr_enable(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state); +void intel_psr_pre_plane_update(const struct intel_atomic_state *state); +void intel_psr_post_plane_update(const struct intel_atomic_state *state); void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state); -void intel_psr_update(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state); int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value); void intel_psr_invalidate(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, @@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, enum fb_op_origin origin); void intel_psr_init(struct intel_dp *intel_dp); void intel_psr_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state); + struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state); void intel_psr_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config); void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); From ab98ebb9a99aa0a9970d973fb7511e33f774f797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 May 2021 15:57:42 +0300 Subject: [PATCH 065/554] drm/i915: Fix HPLL watermark readout for g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If HPLL watermarks are already enabled, let's not mark them as disabled by forgetting to bump 'level' before we call g4x_raw_plane_wm_set(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210514125751.17075-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 74fd6aa7afc7..97b68bbbc689 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6828,7 +6828,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) for_each_plane_id_on_crtc(crtc, plane_id) raw->plane[plane_id] = active->wm.plane[plane_id]; - if (++level > max_level) + level = G4X_WM_LEVEL_SR; + if (level > max_level) goto out; raw = &crtc_state->wm.g4x.raw[level]; @@ -6837,7 +6838,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) raw->plane[PLANE_SPRITE0] = 0; raw->fbc = active->sr.fbc; - if (++level > max_level) + level = G4X_WM_LEVEL_HPLL; + if (level > max_level) goto out; raw = &crtc_state->wm.g4x.raw[level]; @@ -6846,6 +6848,7 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) raw->plane[PLANE_SPRITE0] = 0; raw->fbc = active->hpll.fbc; + level++; out: for_each_plane_id_on_crtc(crtc, plane_id) g4x_raw_plane_wm_set(crtc_state, level, From 2dfa597d249cbe16962ac142c882b30f7ff385e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 10:38:05 +0200 Subject: [PATCH 066/554] drm/i915/gem: Fix a lockdep warning the __i915_gem_is_lmem() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somehow we managed to invert the test for i915_gem_object_evictable(), which causes a warning in DG1 BAT, igt@debugfs_test@read_all_entries. Fix the lock check to only warn if the object *is* indeed evictable and not protected from eviction by fences. Cc: Matthew Brost Fixes: 91160c839824 ("drm/i915: Take pinning into account in __i915_gem_object_is_lmem") Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922083807.888206-2-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c index d659239fcbcc..444f8268b9c5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c @@ -67,7 +67,7 @@ bool __i915_gem_object_is_lmem(struct drm_i915_gem_object *obj) #ifdef CONFIG_LOCKDEP GEM_WARN_ON(dma_resv_test_signaled(obj->base.resv, true) && - !i915_gem_object_evictable(obj)); + i915_gem_object_evictable(obj)); #endif return mr && (mr->type == INTEL_MEMORY_LOCAL || mr->type == INTEL_MEMORY_STOLEN_LOCAL); From 0d9388635a22331d39989b96d5830b486d9c8900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:19 +0200 Subject: [PATCH 067/554] drm/i915/ttm: Implement a function to copy the contents of two TTM-based objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When backing up or restoring contents of pinned objects at suspend / resume time we need to allocate a new object as the backup. Add a function to facilitate copies between the two. Some data needs to be copied before the migration context is ready for operation, so make sure we can disable accelerated copies. v2: - Fix a missing return value check (Matthew Auld) Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-2-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 69 +++++++++++++++++++++---- drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 4 ++ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 1e9fb126cb7b..ce2b7386e494 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -429,6 +429,7 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj, static int i915_ttm_accel_move(struct ttm_buffer_object *bo, bool clear, struct ttm_resource *dst_mem, + struct ttm_tt *dst_ttm, struct sg_table *dst_st) { struct drm_i915_private *i915 = container_of(bo->bdev, typeof(*i915), @@ -438,14 +439,14 @@ static int i915_ttm_accel_move(struct ttm_buffer_object *bo, struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); struct sg_table *src_st; struct i915_request *rq; - struct ttm_tt *ttm = bo->ttm; + struct ttm_tt *src_ttm = bo->ttm; enum i915_cache_level src_level, dst_level; int ret; if (!i915->gt.migrate.context) return -EINVAL; - dst_level = i915_ttm_cache_level(i915, dst_mem, ttm); + dst_level = i915_ttm_cache_level(i915, dst_mem, dst_ttm); if (clear) { if (bo->type == ttm_bo_type_kernel) return -EINVAL; @@ -462,10 +463,10 @@ static int i915_ttm_accel_move(struct ttm_buffer_object *bo, } intel_engine_pm_put(i915->gt.migrate.context->engine); } else { - src_st = src_man->use_tt ? i915_ttm_tt_get_st(ttm) : + src_st = src_man->use_tt ? i915_ttm_tt_get_st(src_ttm) : obj->ttm.cached_io_st; - src_level = i915_ttm_cache_level(i915, bo->resource, ttm); + src_level = i915_ttm_cache_level(i915, bo->resource, src_ttm); intel_engine_pm_get(i915->gt.migrate.context->engine); ret = intel_context_migrate_copy(i915->gt.migrate.context, NULL, src_st->sgl, src_level, @@ -485,11 +486,14 @@ static int i915_ttm_accel_move(struct ttm_buffer_object *bo, static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear, struct ttm_resource *dst_mem, - struct sg_table *dst_st) + struct ttm_tt *dst_ttm, + struct sg_table *dst_st, + bool allow_accel) { - int ret; + int ret = -EINVAL; - ret = i915_ttm_accel_move(bo, clear, dst_mem, dst_st); + if (allow_accel) + ret = i915_ttm_accel_move(bo, clear, dst_mem, dst_ttm, dst_st); if (ret) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); struct intel_memory_region *dst_reg, *src_reg; @@ -504,7 +508,7 @@ static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear, GEM_BUG_ON(!dst_reg || !src_reg); dst_iter = !cpu_maps_iomem(dst_mem) ? - ttm_kmap_iter_tt_init(&_dst_iter.tt, bo->ttm) : + ttm_kmap_iter_tt_init(&_dst_iter.tt, dst_ttm) : ttm_kmap_iter_iomap_init(&_dst_iter.io, &dst_reg->iomap, dst_st, dst_reg->region.start); @@ -559,7 +563,7 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, clear = !cpu_maps_iomem(bo->resource) && (!ttm || !ttm_tt_is_populated(ttm)); if (!(clear && ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC))) - __i915_ttm_move(bo, clear, dst_mem, dst_st); + __i915_ttm_move(bo, clear, dst_mem, bo->ttm, dst_st, true); ttm_bo_move_sync_cleanup(bo, dst_mem); i915_ttm_adjust_domains_after_move(obj); @@ -974,3 +978,50 @@ i915_gem_ttm_system_setup(struct drm_i915_private *i915, intel_memory_region_set_name(mr, "system-ttm"); return mr; } + +/** + * i915_gem_obj_copy_ttm - Copy the contents of one ttm-based gem object to + * another + * @dst: The destination object + * @src: The source object + * @allow_accel: Allow using the blitter. Otherwise TTM memcpy is used. + * @intr: Whether to perform waits interruptible: + * + * Note: The caller is responsible for assuring that the underlying + * TTM objects are populated if needed and locked. + * + * Return: Zero on success. Negative error code on error. If @intr == true, + * then it may return -ERESTARTSYS or -EINTR. + */ +int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, + struct drm_i915_gem_object *src, + bool allow_accel, bool intr) +{ + struct ttm_buffer_object *dst_bo = i915_gem_to_ttm(dst); + struct ttm_buffer_object *src_bo = i915_gem_to_ttm(src); + struct ttm_operation_ctx ctx = { + .interruptible = intr, + }; + struct sg_table *dst_st; + int ret; + + assert_object_held(dst); + assert_object_held(src); + + /* + * Sync for now. This will change with async moves. + */ + ret = ttm_bo_wait_ctx(dst_bo, &ctx); + if (!ret) + ret = ttm_bo_wait_ctx(src_bo, &ctx); + if (ret) + return ret; + + dst_st = gpu_binds_iomem(dst_bo->resource) ? + dst->ttm.cached_io_st : i915_ttm_tt_get_st(dst_bo->ttm); + + __i915_ttm_move(src_bo, false, dst_bo->resource, dst_bo->ttm, + dst_st, allow_accel); + + return 0; +} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h index 40927f67b6d9..34ac78d47b0d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h @@ -46,4 +46,8 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, resource_size_t size, resource_size_t page_size, unsigned int flags); + +int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, + struct drm_i915_gem_object *src, + bool allow_accel, bool intr); #endif From d80ee88e0769e2e05afeb5d04b4dc43fc107b0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:20 +0200 Subject: [PATCH 068/554] drm/i915/gem: Implement a function to process all gem objects of a region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An upcoming common pattern is to traverse the region object list and perform certain actions on all objects in a region. It's a little tricky to get the list locking right, in particular since a gem object may change region unless it's pinned or the object lock is held. Define a function that does this for us and that takes an argument that defines the action to be performed on each object. v3: - Improve structure documentation a bit (Matthew Auld) Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-3-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_region.c | 70 ++++++++++++++++++++++ drivers/gpu/drm/i915/gem/i915_gem_region.h | 37 ++++++++++++ 2 files changed, 107 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c index 1f557b2178ed..a016ccec36f3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c @@ -80,3 +80,73 @@ err_object_free: i915_gem_object_free(obj); return ERR_PTR(err); } + +/** + * i915_gem_process_region - Iterate over all objects of a region using ops + * to process and optionally skip objects + * @mr: The memory region + * @apply: ops and private data + * + * This function can be used to iterate over the regions object list, + * checking whether to skip objects, and, if not, lock the objects and + * process them using the supplied ops. Note that this function temporarily + * removes objects from the region list while iterating, so that if run + * concurrently with itself may not iterate over all objects. + * + * Return: 0 if successful, negative error code on failure. + */ +int i915_gem_process_region(struct intel_memory_region *mr, + struct i915_gem_apply_to_region *apply) +{ + const struct i915_gem_apply_to_region_ops *ops = apply->ops; + struct drm_i915_gem_object *obj; + struct list_head still_in_list; + int ret = 0; + + /* + * In the future, a non-NULL apply->ww could mean the caller is + * already in a locking transaction and provides its own context. + */ + GEM_WARN_ON(apply->ww); + + INIT_LIST_HEAD(&still_in_list); + mutex_lock(&mr->objects.lock); + for (;;) { + struct i915_gem_ww_ctx ww; + + obj = list_first_entry_or_null(&mr->objects.list, typeof(*obj), + mm.region_link); + if (!obj) + break; + + list_move_tail(&obj->mm.region_link, &still_in_list); + if (!kref_get_unless_zero(&obj->base.refcount)) + continue; + + /* + * Note: Someone else might be migrating the object at this + * point. The object's region is not stable until we lock + * the object. + */ + mutex_unlock(&mr->objects.lock); + apply->ww = &ww; + for_i915_gem_ww(&ww, ret, apply->interruptible) { + ret = i915_gem_object_lock(obj, apply->ww); + if (ret) + continue; + + if (obj->mm.region == mr) + ret = ops->process_obj(apply, obj); + /* Implicit object unlock */ + } + + i915_gem_object_put(obj); + mutex_lock(&mr->objects.lock); + if (ret) + break; + } + list_splice_tail(&still_in_list, &mr->objects.list); + mutex_unlock(&mr->objects.lock); + + return ret; +} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.h b/drivers/gpu/drm/i915/gem/i915_gem_region.h index 1008e580a89a..fcaa12d657d4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_region.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.h @@ -12,6 +12,41 @@ struct intel_memory_region; struct drm_i915_gem_object; struct sg_table; +struct i915_gem_apply_to_region; + +/** + * struct i915_gem_apply_to_region_ops - ops to use when iterating over all + * region objects. + */ +struct i915_gem_apply_to_region_ops { + /** + * process_obj - Process the current object + * @apply: Embed this for private data. + * @obj: The current object. + * + * Note that if this function is part of a ww transaction, and + * if returns -EDEADLK for one of the objects, it may be + * rerun for that same object in the same pass. + */ + int (*process_obj)(struct i915_gem_apply_to_region *apply, + struct drm_i915_gem_object *obj); +}; + +/** + * struct i915_gem_apply_to_region - Argument to the struct + * i915_gem_apply_to_region_ops functions. + * @ops: The ops for the operation. + * @ww: Locking context used for the transaction. + * @interruptible: Whether to perform object locking interruptible. + * + * This structure is intended to be embedded in a private struct if needed + */ +struct i915_gem_apply_to_region { + const struct i915_gem_apply_to_region_ops *ops; + struct i915_gem_ww_ctx *ww; + u32 interruptible:1; +}; + void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj, struct intel_memory_region *mem); void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj); @@ -22,4 +57,6 @@ i915_gem_object_create_region(struct intel_memory_region *mem, resource_size_t page_size, unsigned int flags); +int i915_gem_process_region(struct intel_memory_region *mr, + struct i915_gem_apply_to_region *apply); #endif From 81387fc4f6e080806da7a481eca0052fc76cfbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:21 +0200 Subject: [PATCH 069/554] drm/i915/gt: Increase suspend timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With GuC submission on DG1, the execution of the requests times out for the gem_exec_suspend igt test case after executing around 800-900 of 1000 submitted requests. Given the time we allow elsewhere for fences to signal (in the order of seconds), increase the timeout before we mark the gt wedged and proceed. Signed-off-by: Thomas Hellström Acked-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-4-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index dea8e2479897..f84f2bfe2de0 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -19,6 +19,8 @@ #include "intel_rps.h" #include "intel_wakeref.h" +#define I915_GT_SUSPEND_IDLE_TIMEOUT (HZ / 2) + static void user_forcewake(struct intel_gt *gt, bool suspend) { int count = atomic_read(>->user_wakeref); @@ -279,7 +281,7 @@ static void wait_for_suspend(struct intel_gt *gt) if (!intel_gt_pm_is_awake(gt)) return; - if (intel_gt_wait_for_idle(gt, I915_GEM_IDLE_TIMEOUT) == -ETIME) { + if (intel_gt_wait_for_idle(gt, I915_GT_SUSPEND_IDLE_TIMEOUT) == -ETIME) { /* * Forcibly cancel outstanding work and leave * the gpu quiet. From c56ce9565374e565a4d9eb79aff60a7c19fd4b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:22 +0200 Subject: [PATCH 070/554] drm/i915 Implement LMEM backup and restore for suspend / resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just evict unpinned objects to system. For pinned LMEM objects, make a backup system object and blit the contents to that. Backup is performed in three steps, 1: Opportunistically evict evictable objects using the gpu blitter. 2: After gt idle, evict evictable objects using the gpu blitter. This will be modified in an upcoming patch to backup pinned objects that are not used by the blitter itself. 3: Backup remaining pinned objects using memcpy. Also move uC suspend to after 2) to make sure we have a functional GuC during 2) if using GuC submission. v2: - Major refactor to make sure gem_exec_suspend@hang-SX subtests work, and suspend / resume works with a slightly modified GuC submission enabling patch series. v3: - Fix a potential use-after-free (Matthew Auld) - Use i915_gem_object_create_shmem() instead of i915_gem_object_create_region (Matthew Auld) - Minor simplifications (Matthew Auld) - Fix up kerneldoc for i195_ttm_restore_region(). - Final lmem_suspend() call moved to i915_gem_backup_suspend from i915_gem_suspend_late, since the latter gets called at driver unload and we don't unnecessarily want to run it at that time. v4: - Interface change of ttm- & lmem suspend / resume functions to use flags rather than bools. (Matthew Auld) - Completely drop the i915_gem_backup_suspend change (Matthew Auld) Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-5-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/Makefile | 1 + .../gpu/drm/i915/gem/i915_gem_object_types.h | 1 + drivers/gpu/drm/i915/gem/i915_gem_pm.c | 87 ++++++++ drivers/gpu/drm/i915/gem/i915_gem_pm.h | 1 + drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 30 ++- drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 10 + drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c | 202 ++++++++++++++++++ drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.h | 26 +++ drivers/gpu/drm/i915/gt/intel_gt_pm.c | 4 +- drivers/gpu/drm/i915/i915_drv.c | 4 +- 10 files changed, 353 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0823ea80fdc6..3b9a60adfe57 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -154,6 +154,7 @@ gem-y += \ gem/i915_gem_throttle.o \ gem/i915_gem_tiling.o \ gem/i915_gem_ttm.o \ + gem/i915_gem_ttm_pm.o \ gem/i915_gem_userptr.o \ gem/i915_gem_wait.o \ gem/i915_gemfs.o diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 2471f36aaff3..734cc8e16481 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -534,6 +534,7 @@ struct drm_i915_gem_object { struct { struct sg_table *cached_io_st; struct i915_gem_object_page_iter get_io_page; + struct drm_i915_gem_object *backup; bool created:1; } ttm; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 8b9d7d14c4bd..12b37b4c1192 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -5,6 +5,7 @@ */ #include "gem/i915_gem_pm.h" +#include "gem/i915_gem_ttm_pm.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" #include "gt/intel_gt_requests.h" @@ -39,6 +40,84 @@ void i915_gem_suspend(struct drm_i915_private *i915) i915_gem_drain_freed_objects(i915); } +static int lmem_restore(struct drm_i915_private *i915, u32 flags) +{ + struct intel_memory_region *mr; + int ret = 0, id; + + for_each_memory_region(mr, i915, id) { + if (mr->type == INTEL_MEMORY_LOCAL) { + ret = i915_ttm_restore_region(mr, flags); + if (ret) + break; + } + } + + return ret; +} + +static int lmem_suspend(struct drm_i915_private *i915, u32 flags) +{ + struct intel_memory_region *mr; + int ret = 0, id; + + for_each_memory_region(mr, i915, id) { + if (mr->type == INTEL_MEMORY_LOCAL) { + ret = i915_ttm_backup_region(mr, flags); + if (ret) + break; + } + } + + return ret; +} + +static void lmem_recover(struct drm_i915_private *i915) +{ + struct intel_memory_region *mr; + int id; + + for_each_memory_region(mr, i915, id) + if (mr->type == INTEL_MEMORY_LOCAL) + i915_ttm_recover_region(mr); +} + +int i915_gem_backup_suspend(struct drm_i915_private *i915) +{ + int ret; + + /* Opportunistically try to evict unpinned objects */ + ret = lmem_suspend(i915, I915_TTM_BACKUP_ALLOW_GPU); + if (ret) + goto out_recover; + + i915_gem_suspend(i915); + + /* + * More objects may have become unpinned as requests were + * retired. Now try to evict again. The gt may be wedged here + * in which case we automatically fall back to memcpy. + */ + ret = lmem_suspend(i915, I915_TTM_BACKUP_ALLOW_GPU); + if (ret) + goto out_recover; + + /* + * Remaining objects are backed up using memcpy once we've stopped + * using the migrate context. + */ + ret = lmem_suspend(i915, I915_TTM_BACKUP_PINNED); + if (ret) + goto out_recover; + + return 0; + +out_recover: + lmem_recover(i915); + + return ret; +} + void i915_gem_suspend_late(struct drm_i915_private *i915) { struct drm_i915_gem_object *obj; @@ -128,12 +207,20 @@ int i915_gem_freeze_late(struct drm_i915_private *i915) void i915_gem_resume(struct drm_i915_private *i915) { + int ret; + GEM_TRACE("%s\n", dev_name(i915->drm.dev)); + ret = lmem_restore(i915, 0); + GEM_WARN_ON(ret); + /* * As we didn't flush the kernel context before suspend, we cannot * guarantee that the context image is complete. So let's just reset * it and start again. */ intel_gt_resume(&i915->gt); + + ret = lmem_restore(i915, I915_TTM_BACKUP_ALLOW_GPU); + GEM_WARN_ON(ret); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.h b/drivers/gpu/drm/i915/gem/i915_gem_pm.h index c9a66630e92e..bedf1e95941a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.h @@ -18,6 +18,7 @@ void i915_gem_idle_work_handler(struct work_struct *work); void i915_gem_suspend(struct drm_i915_private *i915); void i915_gem_suspend_late(struct drm_i915_private *i915); +int i915_gem_backup_suspend(struct drm_i915_private *i915); int i915_gem_freeze(struct drm_i915_private *i915); int i915_gem_freeze_late(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index ce2b7386e494..bbaaee5668e4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -10,18 +10,16 @@ #include "intel_memory_region.h" #include "intel_region_ttm.h" +#include "gem/i915_gem_mman.h" #include "gem/i915_gem_object.h" #include "gem/i915_gem_region.h" #include "gem/i915_gem_ttm.h" -#include "gem/i915_gem_mman.h" +#include "gem/i915_gem_ttm_pm.h" + -#include "gt/intel_migrate.h" #include "gt/intel_engine_pm.h" - -#define I915_PL_LMEM0 TTM_PL_PRIV -#define I915_PL_SYSTEM TTM_PL_SYSTEM -#define I915_PL_STOLEN TTM_PL_VRAM -#define I915_PL_GGTT TTM_PL_TT +#include "gt/intel_gt.h" +#include "gt/intel_migrate.h" #define I915_TTM_PRIO_PURGE 0 #define I915_TTM_PRIO_NO_PAGES 1 @@ -64,6 +62,20 @@ static struct ttm_placement i915_sys_placement = { .busy_placement = &sys_placement_flags, }; +/** + * i915_ttm_sys_placement - Return the struct ttm_placement to be + * used for an object in system memory. + * + * Rather than making the struct extern, use this + * function. + * + * Return: A pointer to a static variable for sys placement. + */ +struct ttm_placement *i915_ttm_sys_placement(void) +{ + return &i915_sys_placement; +} + static int i915_ttm_err_to_gem(int err) { /* Fastpath */ @@ -443,7 +455,7 @@ static int i915_ttm_accel_move(struct ttm_buffer_object *bo, enum i915_cache_level src_level, dst_level; int ret; - if (!i915->gt.migrate.context) + if (!i915->gt.migrate.context || intel_gt_is_wedged(&i915->gt)) return -EINVAL; dst_level = i915_ttm_cache_level(i915, dst_mem, dst_ttm); @@ -887,6 +899,8 @@ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); + i915_ttm_backup_free(obj); + /* This releases all gem object bindings to the backend. */ __i915_gem_free_object(obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h index 34ac78d47b0d..0b7291dd897c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h @@ -50,4 +50,14 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, struct drm_i915_gem_object *src, bool allow_accel, bool intr); + +/* Internal I915 TTM declarations and definitions below. */ + +#define I915_PL_LMEM0 TTM_PL_PRIV +#define I915_PL_SYSTEM TTM_PL_SYSTEM +#define I915_PL_STOLEN TTM_PL_VRAM +#define I915_PL_GGTT TTM_PL_TT + +struct ttm_placement *i915_ttm_sys_placement(void); + #endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c new file mode 100644 index 000000000000..cb1c46724f70 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include +#include + +#include "i915_drv.h" +#include "intel_memory_region.h" +#include "intel_region_ttm.h" + +#include "gem/i915_gem_region.h" +#include "gem/i915_gem_ttm.h" +#include "gem/i915_gem_ttm_pm.h" + +/** + * i915_ttm_backup_free - Free any backup attached to this object + * @obj: The object whose backup is to be freed. + */ +void i915_ttm_backup_free(struct drm_i915_gem_object *obj) +{ + if (obj->ttm.backup) { + i915_gem_object_put(obj->ttm.backup); + obj->ttm.backup = NULL; + } +} + +/** + * struct i915_gem_ttm_pm_apply - Apply-to-region subclass for restore + * @base: The i915_gem_apply_to_region we derive from. + * @allow_gpu: Whether using the gpu blitter is allowed. + * @backup_pinned: On backup, backup also pinned objects. + */ +struct i915_gem_ttm_pm_apply { + struct i915_gem_apply_to_region base; + bool allow_gpu : 1; + bool backup_pinned : 1; +}; + +static int i915_ttm_backup(struct i915_gem_apply_to_region *apply, + struct drm_i915_gem_object *obj) +{ + struct i915_gem_ttm_pm_apply *pm_apply = + container_of(apply, typeof(*pm_apply), base); + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); + struct ttm_buffer_object *backup_bo; + struct drm_i915_private *i915 = + container_of(bo->bdev, typeof(*i915), bdev); + struct drm_i915_gem_object *backup; + struct ttm_operation_ctx ctx = {}; + int err = 0; + + if (bo->resource->mem_type == I915_PL_SYSTEM || obj->ttm.backup) + return 0; + + if (pm_apply->allow_gpu && i915_gem_object_evictable(obj)) + return ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx); + + if (!pm_apply->backup_pinned) + return 0; + + backup = i915_gem_object_create_shmem(i915, obj->base.size); + if (IS_ERR(backup)) + return PTR_ERR(backup); + + err = i915_gem_object_lock(backup, apply->ww); + if (err) + goto out_no_lock; + + backup_bo = i915_gem_to_ttm(backup); + err = ttm_tt_populate(backup_bo->bdev, backup_bo->ttm, &ctx); + if (err) + goto out_no_populate; + + err = i915_gem_obj_copy_ttm(backup, obj, pm_apply->allow_gpu, false); + GEM_WARN_ON(err); + + obj->ttm.backup = backup; + return 0; + +out_no_populate: + i915_gem_ww_unlock_single(backup); +out_no_lock: + i915_gem_object_put(backup); + + return err; +} + +static int i915_ttm_recover(struct i915_gem_apply_to_region *apply, + struct drm_i915_gem_object *obj) +{ + i915_ttm_backup_free(obj); + return 0; +} + +/** + * i915_ttm_recover_region - Free the backup of all objects of a region + * @mr: The memory region + * + * Checks all objects of a region if there is backup attached and if so + * frees that backup. Typically this is called to recover after a partially + * performed backup. + */ +void i915_ttm_recover_region(struct intel_memory_region *mr) +{ + static const struct i915_gem_apply_to_region_ops recover_ops = { + .process_obj = i915_ttm_recover, + }; + struct i915_gem_apply_to_region apply = {.ops = &recover_ops}; + int ret; + + ret = i915_gem_process_region(mr, &apply); + GEM_WARN_ON(ret); +} + +/** + * i915_ttm_backup_region - Back up all objects of a region to smem. + * @mr: The memory region + * @allow_gpu: Whether to allow the gpu blitter for this backup. + * @backup_pinned: Backup also pinned objects. + * + * Loops over all objects of a region and either evicts them if they are + * evictable or backs them up using a backup object if they are pinned. + * + * Return: Zero on success. Negative error code on error. + */ +int i915_ttm_backup_region(struct intel_memory_region *mr, u32 flags) +{ + static const struct i915_gem_apply_to_region_ops backup_ops = { + .process_obj = i915_ttm_backup, + }; + struct i915_gem_ttm_pm_apply pm_apply = { + .base = {.ops = &backup_ops}, + .allow_gpu = flags & I915_TTM_BACKUP_ALLOW_GPU, + .backup_pinned = flags & I915_TTM_BACKUP_PINNED, + }; + + return i915_gem_process_region(mr, &pm_apply.base); +} + +static int i915_ttm_restore(struct i915_gem_apply_to_region *apply, + struct drm_i915_gem_object *obj) +{ + struct i915_gem_ttm_pm_apply *pm_apply = + container_of(apply, typeof(*pm_apply), base); + struct drm_i915_gem_object *backup = obj->ttm.backup; + struct ttm_buffer_object *backup_bo = i915_gem_to_ttm(backup); + struct ttm_operation_ctx ctx = {}; + int err; + + if (!backup) + return 0; + + if (!pm_apply->allow_gpu && (obj->flags & I915_BO_ALLOC_USER)) + return 0; + + err = i915_gem_object_lock(backup, apply->ww); + if (err) + return err; + + /* Content may have been swapped. */ + err = ttm_tt_populate(backup_bo->bdev, backup_bo->ttm, &ctx); + if (!err) { + err = i915_gem_obj_copy_ttm(obj, backup, pm_apply->allow_gpu, + false); + GEM_WARN_ON(err); + + obj->ttm.backup = NULL; + err = 0; + } + + i915_gem_ww_unlock_single(backup); + + if (!err) + i915_gem_object_put(backup); + + return err; +} + +/** + * i915_ttm_restore_region - Restore backed-up objects of a region from smem. + * @mr: The memory region + * @allow_gpu: Whether to allow the gpu blitter to recover. + * + * Loops over all objects of a region and if they are backed-up, restores + * them from smem. + * + * Return: Zero on success. Negative error code on error. + */ +int i915_ttm_restore_region(struct intel_memory_region *mr, u32 flags) +{ + static const struct i915_gem_apply_to_region_ops restore_ops = { + .process_obj = i915_ttm_restore, + }; + struct i915_gem_ttm_pm_apply pm_apply = { + .base = {.ops = &restore_ops}, + .allow_gpu = flags & I915_TTM_BACKUP_ALLOW_GPU, + }; + + return i915_gem_process_region(mr, &pm_apply.base); +} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.h new file mode 100644 index 000000000000..25ed67a31571 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef _I915_GEM_TTM_PM_H_ +#define _I915_GEM_TTM_PM_H_ + +#include + +struct intel_memory_region; +struct drm_i915_gem_object; + +#define I915_TTM_BACKUP_ALLOW_GPU BIT(0) +#define I915_TTM_BACKUP_PINNED BIT(1) + +int i915_ttm_backup_region(struct intel_memory_region *mr, u32 flags); + +void i915_ttm_recover_region(struct intel_memory_region *mr); + +int i915_ttm_restore_region(struct intel_memory_region *mr, u32 flags); + +/* Internal I915 TTM functions below. */ +void i915_ttm_backup_free(struct drm_i915_gem_object *obj); + +#endif diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index f84f2bfe2de0..e9da36530b45 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -297,8 +297,6 @@ void intel_gt_suspend_prepare(struct intel_gt *gt) { user_forcewake(gt, true); wait_for_suspend(gt); - - intel_uc_suspend(>->uc); } static suspend_state_t pm_suspend_target(void) @@ -322,6 +320,8 @@ void intel_gt_suspend_late(struct intel_gt *gt) GEM_BUG_ON(gt->awake); + intel_uc_suspend(>->uc); + /* * On disabling the device, we want to turn off HW access to memory * that we no longer own. diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3cf61bead2f6..ed7b421cad44 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1094,9 +1094,7 @@ static int i915_drm_prepare(struct drm_device *dev) * split out that work and pull it forward so that after point, * the GPU is not woken again. */ - i915_gem_suspend(i915); - - return 0; + return i915_gem_backup_suspend(i915); } static int i915_drm_suspend(struct drm_device *dev) From 3e42cc61275f95fd7f022b6380b95428efe134d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:23 +0200 Subject: [PATCH 071/554] drm/i915/gt: Register the migrate contexts with their engines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pinned contexts, like the migrate contexts need reset after resume since their context image may have been lost. Also the GuC needs to register pinned contexts. Add a list to struct intel_engine_cs where we add all pinned contexts on creation, and traverse that list at resume time to reset the pinned contexts. This fixes the kms_pipe_crc_basic@suspend-read-crc-pipe-a selftest for now, but proper LMEM backup / restore is needed for full suspend functionality. However, note that even with full LMEM backup / restore it may be desirable to keep the reset since backing up the migrate context images must happen using memcpy() after the migrate context has become inactive, and for performance- and other reasons we want to avoid memcpy() from LMEM. Also traverse the list at guc_init_lrc_mapping() calling guc_kernel_context_pin() for the pinned contexts, like is already done for the kernel context. v2: - Don't reset the contexts on each __engine_unpark() but rather at resume time (Chris Wilson). v3: - Reset contexts in the engine sanitize callback. (Chris Wilson) Cc: Tvrtko Ursulin Cc: Matthew Auld Cc: Maarten Lankhorst Cc: Brost Matthew Cc: Chris Wilson Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-6-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_context_types.h | 8 +++++++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 4 ++++ drivers/gpu/drm/i915/gt/intel_engine_pm.c | 23 +++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_engine_pm.h | 2 ++ drivers/gpu/drm/i915/gt/intel_engine_types.h | 7 ++++++ .../drm/i915/gt/intel_execlists_submission.c | 2 ++ .../gpu/drm/i915/gt/intel_ring_submission.c | 3 +++ drivers/gpu/drm/i915/gt/mock_engine.c | 2 ++ .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 12 +++++++--- 9 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 930569a1a01f..12252c411159 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -153,6 +153,14 @@ struct intel_context { /** sseu: Control eu/slice partitioning */ struct intel_sseu sseu; + /** + * pinned_contexts_link: List link for the engine's pinned contexts. + * This is only used if this is a perma-pinned kernel context and + * the list is assumed to only be manipulated during driver load + * or unload time so no mutex protection currently. + */ + struct list_head pinned_contexts_link; + u8 wa_bb_page; /* if set, page num reserved for context workarounds */ struct { diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 06dfe7f38953..2ae57e4656a3 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -320,6 +320,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id) BUILD_BUG_ON(BITS_PER_TYPE(engine->mask) < I915_NUM_ENGINES); + INIT_LIST_HEAD(&engine->pinned_contexts_list); engine->id = id; engine->legacy_idx = INVALID_ENGINE; engine->mask = BIT(id); @@ -890,6 +891,8 @@ intel_engine_create_pinned_context(struct intel_engine_cs *engine, return ERR_PTR(err); } + list_add_tail(&ce->pinned_contexts_link, &engine->pinned_contexts_list); + /* * Give our perma-pinned kernel timelines a separate lockdep class, * so that we can use them from within the normal user timelines @@ -912,6 +915,7 @@ void intel_engine_destroy_pinned_context(struct intel_context *ce) list_del(&ce->timeline->engine_link); mutex_unlock(&hwsp->vm->mutex); + list_del(&ce->pinned_contexts_link); intel_context_unpin(ce); intel_context_put(ce); } diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index 1f07ac4e0672..dacd62773735 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -298,6 +298,29 @@ void intel_engine_init__pm(struct intel_engine_cs *engine) intel_engine_init_heartbeat(engine); } +/** + * intel_engine_reset_pinned_contexts - Reset the pinned contexts of + * an engine. + * @engine: The engine whose pinned contexts we want to reset. + * + * Typically the pinned context LMEM images lose or get their content + * corrupted on suspend. This function resets their images. + */ +void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine) +{ + struct intel_context *ce; + + list_for_each_entry(ce, &engine->pinned_contexts_list, + pinned_contexts_link) { + /* kernel context gets reset at __engine_unpark() */ + if (ce == engine->kernel_context) + continue; + + dbg_poison_ce(ce); + ce->ops->reset(ce); + } +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_engine_pm.c" #endif diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h index 70ea46d6cfb0..8520c595f5e1 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h @@ -69,4 +69,6 @@ intel_engine_create_kernel_request(struct intel_engine_cs *engine) void intel_engine_init__pm(struct intel_engine_cs *engine); +void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine); + #endif /* INTEL_ENGINE_PM_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index bfbfe53c23dd..5ae1207c363b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -307,6 +307,13 @@ struct intel_engine_cs { struct intel_context *kernel_context; /* pinned */ + /** + * pinned_contexts_list: List of pinned contexts. This list is only + * assumed to be manipulated during driver load- or unload time and + * does therefore not have any additional protection. + */ + struct list_head pinned_contexts_list; + intel_engine_mask_t saturated; /* submitting semaphores too late? */ struct { diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 87c595e4efe2..7147fe80919e 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -2787,6 +2787,8 @@ static void execlists_sanitize(struct intel_engine_cs *engine) /* And scrub the dirty cachelines for the HWSP */ clflush_cache_range(engine->status_page.addr, PAGE_SIZE); + + intel_engine_reset_pinned_contexts(engine); } static void enable_error_interrupt(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index 3c65efcb7bed..593524195707 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -17,6 +17,7 @@ #include "intel_ring.h" #include "shmem_utils.h" #include "intel_engine_heartbeat.h" +#include "intel_engine_pm.h" /* Rough estimate of the typical request size, performing a flush, * set-context and then emitting the batch. @@ -292,6 +293,8 @@ static void xcs_sanitize(struct intel_engine_cs *engine) /* And scrub the dirty cachelines for the HWSP */ clflush_cache_range(engine->status_page.addr, PAGE_SIZE); + + intel_engine_reset_pinned_contexts(engine); } static void reset_prepare(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c index 2c1af030310c..8b89215afe46 100644 --- a/drivers/gpu/drm/i915/gt/mock_engine.c +++ b/drivers/gpu/drm/i915/gt/mock_engine.c @@ -376,6 +376,8 @@ int mock_engine_init(struct intel_engine_cs *engine) { struct intel_context *ce; + INIT_LIST_HEAD(&engine->pinned_contexts_list); + engine->sched_engine = i915_sched_engine_create(ENGINE_MOCK); if (!engine->sched_engine) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index c7a41802b448..ba0de35f6323 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2477,6 +2477,8 @@ static void guc_sanitize(struct intel_engine_cs *engine) /* And scrub the dirty cachelines for the HWSP */ clflush_cache_range(engine->status_page.addr, PAGE_SIZE); + + intel_engine_reset_pinned_contexts(engine); } static void setup_hwsp(struct intel_engine_cs *engine) @@ -2552,9 +2554,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc) * and even it did this code would be run again. */ - for_each_engine(engine, gt, id) - if (engine->kernel_context) - guc_kernel_context_pin(guc, engine->kernel_context); + for_each_engine(engine, gt, id) { + struct intel_context *ce; + + list_for_each_entry(ce, &engine->pinned_contexts_list, + pinned_contexts_link) + guc_kernel_context_pin(guc, ce); + } } static void guc_release(struct intel_engine_cs *engine) From 0d8ee5ba8db46c1c833f212a85f8f6d79286722a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:24 +0200 Subject: [PATCH 072/554] drm/i915: Don't back up pinned LMEM context images and rings during suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pinned context images are now reset during resume. Don't back them up, and assuming that rings can be assumed empty at suspend, don't back them up either. Introduce a new object flag, I915_BO_ALLOC_PM_VOLATILE meaning that an object is allowed to lose its content on suspend. v3: - Slight documentation clarification (Matthew Auld) Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-7-thomas.hellstrom@linux.intel.com --- .../gpu/drm/i915/gem/i915_gem_object_types.h | 17 ++++++++++------- drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c | 3 +++ drivers/gpu/drm/i915/gt/intel_lrc.c | 3 ++- drivers/gpu/drm/i915/gt/intel_ring.c | 3 ++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 734cc8e16481..118691ce81d7 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -288,16 +288,19 @@ struct drm_i915_gem_object { I915_SELFTEST_DECLARE(struct list_head st_link); unsigned long flags; -#define I915_BO_ALLOC_CONTIGUOUS BIT(0) -#define I915_BO_ALLOC_VOLATILE BIT(1) -#define I915_BO_ALLOC_CPU_CLEAR BIT(2) -#define I915_BO_ALLOC_USER BIT(3) +#define I915_BO_ALLOC_CONTIGUOUS BIT(0) +#define I915_BO_ALLOC_VOLATILE BIT(1) +#define I915_BO_ALLOC_CPU_CLEAR BIT(2) +#define I915_BO_ALLOC_USER BIT(3) +/* Object is allowed to lose its contents on suspend / resume, even if pinned */ +#define I915_BO_ALLOC_PM_VOLATILE BIT(4) #define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \ I915_BO_ALLOC_VOLATILE | \ I915_BO_ALLOC_CPU_CLEAR | \ - I915_BO_ALLOC_USER) -#define I915_BO_READONLY BIT(4) -#define I915_TILING_QUIRK_BIT 5 /* unknown swizzling; do not release! */ + I915_BO_ALLOC_USER | \ + I915_BO_ALLOC_PM_VOLATILE) +#define I915_BO_READONLY BIT(5) +#define I915_TILING_QUIRK_BIT 6 /* unknown swizzling; do not release! */ /** * @mem_flags - Mutable placement-related flags diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c index cb1c46724f70..03a00d193f40 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c @@ -60,6 +60,9 @@ static int i915_ttm_backup(struct i915_gem_apply_to_region *apply, if (!pm_apply->backup_pinned) return 0; + if (obj->flags & I915_BO_ALLOC_PM_VOLATILE) + return 0; + backup = i915_gem_object_create_shmem(i915, obj->base.size); if (IS_ERR(backup)) return PTR_ERR(backup); diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 6ba8daea2f56..3ef9eaf8c50e 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -942,7 +942,8 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) context_size += PAGE_SIZE; } - obj = i915_gem_object_create_lmem(engine->i915, context_size, 0); + obj = i915_gem_object_create_lmem(engine->i915, context_size, + I915_BO_ALLOC_PM_VOLATILE); if (IS_ERR(obj)) obj = i915_gem_object_create_shmem(engine->i915, context_size); if (IS_ERR(obj)) diff --git a/drivers/gpu/drm/i915/gt/intel_ring.c b/drivers/gpu/drm/i915/gt/intel_ring.c index 7c4d5158e03b..2fdd52b62092 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring.c +++ b/drivers/gpu/drm/i915/gt/intel_ring.c @@ -112,7 +112,8 @@ static struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size) struct drm_i915_gem_object *obj; struct i915_vma *vma; - obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_VOLATILE); + obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_VOLATILE | + I915_BO_ALLOC_PM_VOLATILE); if (IS_ERR(obj) && i915_ggtt_has_aperture(ggtt)) obj = i915_gem_object_create_stolen(i915, size); if (IS_ERR(obj)) From a259cc14eca8af7955f340c387ab843f2f7389f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 22 Sep 2021 08:25:25 +0200 Subject: [PATCH 073/554] drm/i915: Reduce the number of objects subject to memcpy recover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We really only need memcpy restore for objects that affect the operability of the migrate context. That is, primarily the page-table objects of the migrate VM. Add an object flag, I915_BO_ALLOC_PM_EARLY for objects that need early restores using memcpy and a way to assign LMEM page-table object flags to be used by the vms. Restore objects without this flag with the gpu blitter and only objects carrying the flag using TTM memcpy. Initially mark the migrate, gt, gtt and vgpu vms to use this flag, and defer for a later audit which vms actually need it. Most importantly, user- allocated vms with pinned page-table objects can be restored using the blitter. Performance-wise memcpy restore is probably as fast as gpu restore if not faster, but using gpu restore will help tackling future restrictions in mappable LMEM size. v4: - Don't mark the aliasing ppgtt page table flags for early resume, but rather the ggtt page table flags as intended. (Matthew Auld) - The check for user buffer objects during early resume is pointless, since they are never marked I915_BO_ALLOC_PM_EARLY. (Matthew Auld) v5: - Mark GuC LMEM objects with I915_BO_ALLOC_PM_EARLY to have them restored before we fire up the migrate context. Cc: Matthew Brost Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-8-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 9 ++++++--- drivers/gpu/drm/i915/gem/i915_gem_pm.c | 6 +++++- drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c | 5 +++-- drivers/gpu/drm/i915/gem/selftests/huge_pages.c | 2 +- drivers/gpu/drm/i915/gt/gen6_ppgtt.c | 2 +- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 5 +++-- drivers/gpu/drm/i915/gt/gen8_ppgtt.h | 4 +++- drivers/gpu/drm/i915/gt/intel_ggtt.c | 3 ++- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- drivers/gpu/drm/i915/gt/intel_gtt.c | 3 ++- drivers/gpu/drm/i915/gt/intel_gtt.h | 9 +++++++-- drivers/gpu/drm/i915/gt/intel_migrate.c | 2 +- drivers/gpu/drm/i915/gt/intel_ppgtt.c | 13 ++++++++----- drivers/gpu/drm/i915/gt/selftest_hangcheck.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc.c | 3 ++- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 7 +++++-- drivers/gpu/drm/i915/gvt/scheduler.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 4 ++-- 19 files changed, 56 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index c2ab0e22db0a..8208fd5b72c3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -1287,7 +1287,7 @@ i915_gem_create_context(struct drm_i915_private *i915, } else if (HAS_FULL_PPGTT(i915)) { struct i915_ppgtt *ppgtt; - ppgtt = i915_ppgtt_create(&i915->gt); + ppgtt = i915_ppgtt_create(&i915->gt, 0); if (IS_ERR(ppgtt)) { drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); @@ -1465,7 +1465,7 @@ int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data, if (args->flags) return -EINVAL; - ppgtt = i915_ppgtt_create(&i915->gt); + ppgtt = i915_ppgtt_create(&i915->gt, 0); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 118691ce81d7..fa2ba9e2a4d0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -294,13 +294,16 @@ struct drm_i915_gem_object { #define I915_BO_ALLOC_USER BIT(3) /* Object is allowed to lose its contents on suspend / resume, even if pinned */ #define I915_BO_ALLOC_PM_VOLATILE BIT(4) +/* Object needs to be restored early using memcpy during resume */ +#define I915_BO_ALLOC_PM_EARLY BIT(5) #define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \ I915_BO_ALLOC_VOLATILE | \ I915_BO_ALLOC_CPU_CLEAR | \ I915_BO_ALLOC_USER | \ - I915_BO_ALLOC_PM_VOLATILE) -#define I915_BO_READONLY BIT(5) -#define I915_TILING_QUIRK_BIT 6 /* unknown swizzling; do not release! */ + I915_BO_ALLOC_PM_VOLATILE | \ + I915_BO_ALLOC_PM_EARLY) +#define I915_BO_READONLY BIT(6) +#define I915_TILING_QUIRK_BIT 7 /* unknown swizzling; do not release! */ /** * @mem_flags - Mutable placement-related flags diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 12b37b4c1192..726b40e1fbb0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -97,8 +97,12 @@ int i915_gem_backup_suspend(struct drm_i915_private *i915) * More objects may have become unpinned as requests were * retired. Now try to evict again. The gt may be wedged here * in which case we automatically fall back to memcpy. + * We allow also backing up pinned objects that have not been + * marked for early recover, and that may contain, for example, + * page-tables for the migrate context. */ - ret = lmem_suspend(i915, I915_TTM_BACKUP_ALLOW_GPU); + ret = lmem_suspend(i915, I915_TTM_BACKUP_ALLOW_GPU | + I915_TTM_BACKUP_PINNED); if (ret) goto out_recover; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c index 03a00d193f40..3b6d14b5c604 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c @@ -57,7 +57,8 @@ static int i915_ttm_backup(struct i915_gem_apply_to_region *apply, if (pm_apply->allow_gpu && i915_gem_object_evictable(obj)) return ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx); - if (!pm_apply->backup_pinned) + if (!pm_apply->backup_pinned || + (pm_apply->allow_gpu && (obj->flags & I915_BO_ALLOC_PM_EARLY))) return 0; if (obj->flags & I915_BO_ALLOC_PM_VOLATILE) @@ -155,7 +156,7 @@ static int i915_ttm_restore(struct i915_gem_apply_to_region *apply, if (!backup) return 0; - if (!pm_apply->allow_gpu && (obj->flags & I915_BO_ALLOC_USER)) + if (!pm_apply->allow_gpu && !(obj->flags & I915_BO_ALLOC_PM_EARLY)) return 0; err = i915_gem_object_lock(backup, apply->ww); diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 0827634c842c..77d84a9e8789 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -1645,7 +1645,7 @@ int i915_gem_huge_page_mock_selftests(void) mkwrite_device_info(dev_priv)->ppgtt_type = INTEL_PPGTT_FULL; mkwrite_device_info(dev_priv)->ppgtt_size = 48; - ppgtt = i915_ppgtt_create(&dev_priv->gt); + ppgtt = i915_ppgtt_create(&dev_priv->gt, 0); if (IS_ERR(ppgtt)) { err = PTR_ERR(ppgtt); goto out_unlock; diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c index 1aee5e6b1b23..890191f286e3 100644 --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c @@ -429,7 +429,7 @@ struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt) mutex_init(&ppgtt->flush); mutex_init(&ppgtt->pin_mutex); - ppgtt_init(&ppgtt->base, gt); + ppgtt_init(&ppgtt->base, gt, 0); ppgtt->base.vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen6_pte_t)); ppgtt->base.vm.top = 1; diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 6a5af995f5b1..037a9a6e4889 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -753,7 +753,8 @@ err_pd: * space. * */ -struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt) +struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, + unsigned long lmem_pt_obj_flags) { struct i915_ppgtt *ppgtt; int err; @@ -762,7 +763,7 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt) if (!ppgtt) return ERR_PTR(-ENOMEM); - ppgtt_init(ppgtt, gt); + ppgtt_init(ppgtt, gt, lmem_pt_obj_flags); ppgtt->vm.top = i915_vm_is_4lvl(&ppgtt->vm) ? 3 : 2; ppgtt->vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen8_pte_t)); diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.h b/drivers/gpu/drm/i915/gt/gen8_ppgtt.h index b9028c2ad3c7..f541d19264b4 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.h +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.h @@ -12,7 +12,9 @@ struct i915_address_space; struct intel_gt; enum i915_cache_level; -struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt); +struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, + unsigned long lmem_pt_obj_flags); + u64 gen8_ggtt_pte_encode(dma_addr_t addr, enum i915_cache_level level, u32 flags); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 8d71f67926f1..06576fc1310e 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -644,7 +644,7 @@ static int init_aliasing_ppgtt(struct i915_ggtt *ggtt) struct i915_ppgtt *ppgtt; int err; - ppgtt = i915_ppgtt_create(ggtt->vm.gt); + ppgtt = i915_ppgtt_create(ggtt->vm.gt, 0); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); @@ -909,6 +909,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) size = gen8_get_total_gtt_size(snb_gmch_ctl); ggtt->vm.alloc_pt_dma = alloc_pt_dma; + ggtt->vm.lmem_pt_obj_flags = I915_BO_ALLOC_PM_EARLY; ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; ggtt->vm.cleanup = gen6_gmch_remove; diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 5753c5943ed9..4037c3778225 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -481,7 +481,7 @@ static void intel_gt_fini_scratch(struct intel_gt *gt) static struct i915_address_space *kernel_vm(struct intel_gt *gt) { if (INTEL_PPGTT(gt->i915) > INTEL_PPGTT_ALIASING) - return &i915_ppgtt_create(gt)->vm; + return &i915_ppgtt_create(gt, I915_BO_ALLOC_PM_EARLY)->vm; else return i915_vm_get(>->ggtt->vm); } diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index a0c2b952aa57..67d14afa6623 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -28,7 +28,8 @@ struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz) * used the passed in size for the page size, which should ensure it * also has the same alignment. */ - obj = __i915_gem_object_create_lmem_with_ps(vm->i915, sz, sz, 0); + obj = __i915_gem_object_create_lmem_with_ps(vm->i915, sz, sz, + vm->lmem_pt_obj_flags); /* * Ensure all paging structures for this vm share the same dma-resv * object underneath, with the idea that one object_lock() will lock diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index 5b539bd7645d..bc6750263359 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -260,6 +260,9 @@ struct i915_address_space { u8 pd_shift; u8 scratch_order; + /* Flags used when creating page-table objects for this vm */ + unsigned long lmem_pt_obj_flags; + struct drm_i915_gem_object * (*alloc_pt_dma)(struct i915_address_space *vm, int sz); @@ -519,7 +522,8 @@ i915_page_dir_dma_addr(const struct i915_ppgtt *ppgtt, const unsigned int n) return __px_dma(pt ? px_base(pt) : ppgtt->vm.scratch[ppgtt->vm.top]); } -void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt); +void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt, + unsigned long lmem_pt_obj_flags); int i915_ggtt_probe_hw(struct drm_i915_private *i915); int i915_ggtt_init_hw(struct drm_i915_private *i915); @@ -537,7 +541,8 @@ static inline bool i915_ggtt_has_aperture(const struct i915_ggtt *ggtt) int i915_ppgtt_init_hw(struct intel_gt *gt); -struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt); +struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt, + unsigned long lmem_pt_obj_flags); void i915_ggtt_suspend(struct i915_ggtt *gtt); void i915_ggtt_resume(struct i915_ggtt *ggtt); diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c b/drivers/gpu/drm/i915/gt/intel_migrate.c index 1dac21aa7e5c..afb1cce9a352 100644 --- a/drivers/gpu/drm/i915/gt/intel_migrate.c +++ b/drivers/gpu/drm/i915/gt/intel_migrate.c @@ -78,7 +78,7 @@ static struct i915_address_space *migrate_vm(struct intel_gt *gt) * TODO: Add support for huge LMEM PTEs */ - vm = i915_ppgtt_create(gt); + vm = i915_ppgtt_create(gt, I915_BO_ALLOC_PM_EARLY); if (IS_ERR(vm)) return ERR_CAST(vm); diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c b/drivers/gpu/drm/i915/gt/intel_ppgtt.c index 886060f7e6fc..4396bfd630d8 100644 --- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c @@ -155,19 +155,20 @@ int i915_ppgtt_init_hw(struct intel_gt *gt) } static struct i915_ppgtt * -__ppgtt_create(struct intel_gt *gt) +__ppgtt_create(struct intel_gt *gt, unsigned long lmem_pt_obj_flags) { if (GRAPHICS_VER(gt->i915) < 8) return gen6_ppgtt_create(gt); else - return gen8_ppgtt_create(gt); + return gen8_ppgtt_create(gt, lmem_pt_obj_flags); } -struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt) +struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt, + unsigned long lmem_pt_obj_flags) { struct i915_ppgtt *ppgtt; - ppgtt = __ppgtt_create(gt); + ppgtt = __ppgtt_create(gt, lmem_pt_obj_flags); if (IS_ERR(ppgtt)) return ppgtt; @@ -298,7 +299,8 @@ int ppgtt_set_pages(struct i915_vma *vma) return 0; } -void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt) +void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt, + unsigned long lmem_pt_obj_flags) { struct drm_i915_private *i915 = gt->i915; @@ -306,6 +308,7 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt) ppgtt->vm.i915 = i915; ppgtt->vm.dma = i915->drm.dev; ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size); + ppgtt->vm.lmem_pt_obj_flags = lmem_pt_obj_flags; dma_resv_init(&ppgtt->vm._resv); i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT); diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c index 7e6fdabac599..7e2d99dd012d 100644 --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c @@ -1596,7 +1596,7 @@ static int igt_reset_evict_ppgtt(void *arg) if (INTEL_PPGTT(gt->i915) < INTEL_PPGTT_FULL) return 0; - ppgtt = i915_ppgtt_create(gt); + ppgtt = i915_ppgtt_create(gt, 0); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 8ffb689066f6..8f8182bf7c11 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -651,7 +651,8 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) if (HAS_LMEM(gt->i915)) obj = i915_gem_object_create_lmem(gt->i915, size, I915_BO_ALLOC_CPU_CLEAR | - I915_BO_ALLOC_CONTIGUOUS); + I915_BO_ALLOC_CONTIGUOUS | + I915_BO_ALLOC_PM_EARLY); else obj = i915_gem_object_create_shmem(gt->i915, size); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index a685d563df72..3aa87be4f2e4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -372,10 +372,13 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) uc_fw->private_data_size = css->private_data_size; - if (HAS_LMEM(i915)) + if (HAS_LMEM(i915)) { obj = i915_gem_object_create_lmem_from_data(i915, fw->data, fw->size); - else + if (!IS_ERR(obj)) + obj->flags |= I915_BO_ALLOC_PM_EARLY; + } else { obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); + } if (IS_ERR(obj)) { err = PTR_ERR(obj); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index b56a8e37a3cd..0d18e13e3468 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -1386,7 +1386,7 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu) enum intel_engine_id i; int ret; - ppgtt = i915_ppgtt_create(&i915->gt); + ppgtt = i915_ppgtt_create(&i915->gt, I915_BO_ALLOC_PM_EARLY); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 2d60a5a5b065..46f4236039a9 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -155,7 +155,7 @@ static int igt_ppgtt_alloc(void *arg) if (!HAS_PPGTT(dev_priv)) return 0; - ppgtt = i915_ppgtt_create(&dev_priv->gt); + ppgtt = i915_ppgtt_create(&dev_priv->gt, 0); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); @@ -1053,7 +1053,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv, if (IS_ERR(file)) return PTR_ERR(file); - ppgtt = i915_ppgtt_create(&dev_priv->gt); + ppgtt = i915_ppgtt_create(&dev_priv->gt, 0); if (IS_ERR(ppgtt)) { err = PTR_ERR(ppgtt); goto out_free; From be988eaee1cb208c4445db46bc3ceaf75f586f0b Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 21 Sep 2021 14:42:02 +0100 Subject: [PATCH 074/554] drm/i915/request: fix early tracepoints Currently we blow up in trace_dma_fence_init, when calling into get_driver_name or get_timeline_name, since both the engine and context might be NULL(or contain some garbage address) in the case of newly allocated slab objects via the request ctor. Note that we also use SLAB_TYPESAFE_BY_RCU here, which allows requests to be immediately freed, but delay freeing the underlying page by an RCU grace period. With this scheme requests can be re-allocated, at the same time as they are also being read by some lockless RCU lookup mechanism. In the ctor case, which is only called for new slab objects(i.e allocate new page and call the ctor for each object) it's safe to reset the context/engine prior to calling into dma_fence_init, since we can be certain that no one is doing an RCU lookup which might depend on peeking at the engine/context, like in active_engine(), since the object can't yet be externally visible. In the recycled case(which might also be externally visible) the request refcount always transitions from 0->1 after we set the context/engine etc, which should ensure it's valid to dereference the engine for example, when doing an RCU list-walk, so long as we can also increment the refcount first. If the refcount is already zero, then the request is considered complete/released. If it's non-zero, then the request might be in the process of being re-allocated, or potentially still in flight, however after successfully incrementing the refcount, it's possible to carefully inspect the request state, to determine if the request is still what we were looking for. Note that all externally visible requests returned to the cache must have zero refcount. One possible fix then is to move dma_fence_init out from the request ctor. Originally this was how it was done, but it was moved in: commit 855e39e65cfc33a73724f1cc644ffc5754864a20 Author: Chris Wilson Date: Mon Feb 3 09:41:48 2020 +0000 drm/i915: Initialise basic fence before acquiring seqno where it looks like intel_timeline_get_seqno() relied on some of the rq->fence state, but that is no longer the case since: commit 12ca695d2c1ed26b2dcbb528b42813bd0f216cfc Author: Maarten Lankhorst Date: Tue Mar 23 16:49:50 2021 +0100 drm/i915: Do not share hwsp across contexts any more, v8. intel_timeline_get_seqno() could also be cleaned up slightly by dropping the request argument. Moving dma_fence_init back out of the ctor, should ensure we have enough of the request initialised in case of trace_dma_fence_init. Functionally this should be the same, and is effectively what we were already open coding before, except now we also assign the fence->lock and fence->ops, but since these are invariant for recycled requests(which might be externally visible), and will therefore already hold the same value, it shouldn't matter. An alternative fix, since we don't yet have a fully initialised request when in the ctor, is just setting the context/engine as NULL, but this does require adding some extra handling in get_driver_name etc. v2(Daniel): - Try to make the commit message less confusing Fixes: 855e39e65cfc ("drm/i915: Initialise basic fence before acquiring seqno") Signed-off-by: Matthew Auld Cc: Michael Mason Cc: Daniel Vetter Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210921134202.3803151-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/i915_request.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index ce446716d092..79da5eca60af 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -829,8 +829,6 @@ static void __i915_request_ctor(void *arg) i915_sw_fence_init(&rq->submit, submit_notify); i915_sw_fence_init(&rq->semaphore, semaphore_notify); - dma_fence_init(&rq->fence, &i915_fence_ops, &rq->lock, 0, 0); - rq->capture_list = NULL; init_llist_head(&rq->execute_cb); @@ -905,17 +903,12 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp) rq->ring = ce->ring; rq->execution_mask = ce->engine->mask; - kref_init(&rq->fence.refcount); - rq->fence.flags = 0; - rq->fence.error = 0; - INIT_LIST_HEAD(&rq->fence.cb_list); - ret = intel_timeline_get_seqno(tl, rq, &seqno); if (ret) goto err_free; - rq->fence.context = tl->fence_context; - rq->fence.seqno = seqno; + dma_fence_init(&rq->fence, &i915_fence_ops, &rq->lock, + tl->fence_context, seqno); RCU_INIT_POINTER(rq->timeline, tl); rq->hwsp_seqno = tl->hwsp_seqno; From 6341eb6f39bb76018676dc85e01596bf32a592f6 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 21 Sep 2021 15:21:16 +0100 Subject: [PATCH 075/554] drm/i915/selftests: exercise shmem_writeback with THP In commit: commit 1e6decf30af5c5c75445ed6ad4e65a26de578a03 Author: Hugh Dickins Date: Thu Sep 2 14:54:43 2021 -0700 shmem: shmem_writepage() split unlikely i915 THP it looks THP + shmem_writeback was an unexpected combination, and ends up hitting some BUG_ON, but it also looks like that is now fixed. While the IGTs did eventually hit this(although not during pre-merge it seems), it's likely worthwhile adding some explicit coverage for this scenario in the shrink_thp selftest. References: https://gitlab.freedesktop.org/drm/intel/-/issues/4166 Signed-off-by: Matthew Auld Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20210921142116.3807946-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/selftests/huge_pages.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 77d84a9e8789..41d0680f3bd7 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -1589,7 +1589,8 @@ static int igt_shrink_thp(void *arg) i915_gem_shrink(NULL, i915, -1UL, NULL, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | - I915_SHRINK_ACTIVE); + I915_SHRINK_ACTIVE | + I915_SHRINK_WRITEBACK); if (should_swap == i915_gem_object_has_pages(obj)) { pr_err("unexpected pages mismatch, should_swap=%s\n", yesno(should_swap)); From bdc1a2d2a32cea5748f2b31bcf7eb865dd8a9fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Sep 2021 07:21:51 +0300 Subject: [PATCH 076/554] drm/i915/fbc: Rework cfb stride/size calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code to calculate the cfb stride/size is a bit of mess. The cfb size is getting calculated based purely on the plane stride and plane height. That doesn't account for extra alignment we want for the cfb stride. The gen9 override stride OTOH is just calculated based on the plane width, and it does try to make things more aligned but any extra alignment added there is not considered in the cfb size calculations. So not at all convinced this is working as intended. Additionally the compression limit handling is split between the cfb allocation code and g4x_dpfc_ctl_limit() (for the 16bpp case), which is just confusing. Let's streamline the whole thing: - Start with the plane stride, convert that into cfb stride (cfb is always 4 bytes per pixel). All the calculations will assume 1:1 compression limit since that will give us the max values, and we don't yet know how much stolen memory we will be able to allocate - Align the cfb stride to 512 bytes on modern platforms. This guarantees the 4 line segment will be 512 byte aligned regardles of the final compression limit we choose later. The 512 byte alignment for the segment is required by at least some of the platforms, and just doing it always seems like the easiest option - Figure out if we need to use the override stride or not. For X-tiled it's never needed since the plane stride is already 512 byte aligned, for Y-tiled it will be needed if the plane stride is not a multiple of 512 bytes, and for linear it's apparently always needed because the hardware miscalculates the cfb stride as PLANE_STRIDE*512 instead of the PLANE_STRIDE*64 that it use with linear. - The cfb size will be calculated based on the aligned cfb stride to guarantee we actually reserved enough stolen memory and the FBC hw won't end up scribbling over whatever else is allocated in stolen - The compression limit handling we just do fully in the cfb allocation code to make things less confusing v2: Write the min cfb segment stride calculation in a more explicit way to make it clear what is going on v3: Remeber to update fbc->limit when changing to 16bpp Reviewed-by: Uma Shankar #v2 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210923042151.19052-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 180 +++++++++++++++-------- drivers/gpu/drm/i915/i915_drv.h | 4 +- 2 files changed, 123 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index b1c1a23c36be..e3934424040b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -62,19 +62,76 @@ static void intel_fbc_get_plane_source_size(const struct intel_fbc_state_cache * *height = cache->plane.src_h; } -static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv, - const struct intel_fbc_state_cache *cache) +/* plane stride in pixels */ +static unsigned int intel_fbc_plane_stride(const struct intel_plane_state *plane_state) { - int lines; + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int stride; + + stride = plane_state->view.color_plane[0].stride; + if (!drm_rotation_90_or_270(plane_state->hw.rotation)) + stride /= fb->format->cpp[0]; + + return stride; +} + +/* plane stride based cfb stride in bytes, assuming 1:1 compression limit */ +static unsigned int _intel_fbc_cfb_stride(const struct intel_fbc_state_cache *cache) +{ + unsigned int cpp = 4; /* FBC always 4 bytes per pixel */ + + return cache->fb.stride * cpp; +} + +/* minimum acceptable cfb stride in bytes, assuming 1:1 compression limit */ +static unsigned int skl_fbc_min_cfb_stride(const struct intel_fbc_state_cache *cache) +{ + unsigned int limit = 4; /* 1:4 compression limit is the worst case */ + unsigned int cpp = 4; /* FBC always 4 bytes per pixel */ + unsigned int height = 4; /* FBC segment is 4 lines */ + unsigned int stride; + + /* minimum segment stride we can use */ + stride = cache->plane.src_w * cpp * height / limit; + + /* + * At least some of the platforms require each 4 line segment to + * be 512 byte aligned. Just do it always for simplicity. + */ + stride = ALIGN(stride, 512); + + /* convert back to single line equivalent with 1:1 compression limit */ + return stride * limit / height; +} + +/* properly aligned cfb stride in bytes, assuming 1:1 compression limit */ +static unsigned int intel_fbc_cfb_stride(struct drm_i915_private *i915, + const struct intel_fbc_state_cache *cache) +{ + unsigned int stride = _intel_fbc_cfb_stride(cache); + + /* + * At least some of the platforms require each 4 line segment to + * be 512 byte aligned. Aligning each line to 512 bytes guarantees + * that regardless of the compression limit we choose later. + */ + if (DISPLAY_VER(i915) == 9) + return max(ALIGN(stride, 512), skl_fbc_min_cfb_stride(cache)); + else + return stride; +} + +static unsigned int intel_fbc_cfb_size(struct drm_i915_private *dev_priv, + const struct intel_fbc_state_cache *cache) +{ + int lines = cache->plane.src_h; - intel_fbc_get_plane_source_size(cache, NULL, &lines); if (DISPLAY_VER(dev_priv) == 7) lines = min(lines, 2048); else if (DISPLAY_VER(dev_priv) >= 8) lines = min(lines, 2560); - /* Hardware needs the full buffer stride, not just the active area. */ - return lines * cache->fb.stride; + return lines * intel_fbc_cfb_stride(dev_priv, cache); } static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv) @@ -150,15 +207,9 @@ static bool i8xx_fbc_is_active(struct drm_i915_private *dev_priv) static u32 g4x_dpfc_ctl_limit(struct drm_i915_private *i915) { - const struct intel_fbc_reg_params *params = &i915->fbc.params; - int limit = i915->fbc.limit; - - if (params->fb.format->cpp[0] == 2) - limit <<= 1; - - switch (limit) { + switch (i915->fbc.limit) { default: - MISSING_CASE(limit); + MISSING_CASE(i915->fbc.limit); fallthrough; case 1: return DPFC_CTL_LIMIT_1X; @@ -301,7 +352,8 @@ static bool ilk_fbc_is_active(struct drm_i915_private *dev_priv) static void gen7_fbc_activate(struct drm_i915_private *dev_priv) { - struct intel_fbc_reg_params *params = &dev_priv->fbc.params; + struct intel_fbc *fbc = &dev_priv->fbc; + const struct intel_fbc_reg_params *params = &fbc->params; u32 dpfc_ctl; /* Display WA #0529: skl, kbl, bxt. */ @@ -310,7 +362,7 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) if (params->override_cfb_stride) val |= CHICKEN_FBC_STRIDE_OVERRIDE | - CHICKEN_FBC_STRIDE(params->override_cfb_stride); + CHICKEN_FBC_STRIDE(params->override_cfb_stride / fbc->limit); intel_de_rmw(dev_priv, CHICKEN_MISC_4, CHICKEN_FBC_STRIDE_OVERRIDE | @@ -443,7 +495,12 @@ static u64 intel_fbc_stolen_end(struct drm_i915_private *dev_priv) return min(end, intel_fbc_cfb_base_max(dev_priv)); } -static int intel_fbc_max_limit(struct drm_i915_private *dev_priv, int fb_cpp) +static int intel_fbc_min_limit(int fb_cpp) +{ + return fb_cpp == 2 ? 2 : 1; +} + +static int intel_fbc_max_limit(struct drm_i915_private *dev_priv) { /* * FIXME: FBC1 can have arbitrary cfb stride, @@ -457,16 +514,17 @@ static int intel_fbc_max_limit(struct drm_i915_private *dev_priv, int fb_cpp) return 1; /* FBC2 can only do 1:1, 1:2, 1:4 */ - return fb_cpp == 2 ? 2 : 4; + return 4; } static int find_compression_limit(struct drm_i915_private *dev_priv, - unsigned int size, - unsigned int fb_cpp) + unsigned int size, int min_limit) { struct intel_fbc *fbc = &dev_priv->fbc; u64 end = intel_fbc_stolen_end(dev_priv); - int ret, limit = 1; + int ret, limit = min_limit; + + size /= limit; /* Try to over-allocate to reduce reallocations and fragmentation. */ ret = i915_gem_stolen_insert_node_in_range(dev_priv, &fbc->compressed_fb, @@ -474,7 +532,7 @@ static int find_compression_limit(struct drm_i915_private *dev_priv, if (ret == 0) return limit; - for (; limit <= intel_fbc_max_limit(dev_priv, fb_cpp); limit <<= 1) { + for (; limit <= intel_fbc_max_limit(dev_priv); limit <<= 1) { ret = i915_gem_stolen_insert_node_in_range(dev_priv, &fbc->compressed_fb, size >>= 1, 4096, 0, end); if (ret == 0) @@ -485,7 +543,7 @@ static int find_compression_limit(struct drm_i915_private *dev_priv, } static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, - unsigned int size, unsigned int fb_cpp) + unsigned int size, int min_limit) { struct intel_fbc *fbc = &dev_priv->fbc; int ret; @@ -502,13 +560,12 @@ static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, goto err; } - ret = find_compression_limit(dev_priv, size, fb_cpp); + ret = find_compression_limit(dev_priv, size, min_limit); if (!ret) goto err_llb; - else if (ret > 1) { + else if (ret > min_limit) drm_info_once(&dev_priv->drm, "Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n"); - } fbc->limit = ret; @@ -719,11 +776,7 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, cache->fb.format = fb->format; cache->fb.modifier = fb->modifier; - - /* FIXME is this correct? */ - cache->fb.stride = plane_state->view.color_plane[0].stride; - if (drm_rotation_90_or_270(plane_state->hw.rotation)) - cache->fb.stride *= fb->format->cpp[0]; + cache->fb.stride = intel_fbc_plane_stride(plane_state); /* FBC1 compression interval: arbitrary choice of 1 second */ cache->interval = drm_mode_vrefresh(&crtc_state->hw.adjusted_mode); @@ -746,27 +799,29 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; - return intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache) > + return intel_fbc_cfb_size(dev_priv, &fbc->state_cache) > fbc->compressed_fb.size * fbc->limit; } -static u16 intel_fbc_override_cfb_stride(struct drm_i915_private *dev_priv) +static u16 intel_fbc_override_cfb_stride(struct drm_i915_private *dev_priv, + const struct intel_fbc_state_cache *cache) { - struct intel_fbc *fbc = &dev_priv->fbc; - struct intel_fbc_state_cache *cache = &fbc->state_cache; + unsigned int stride = _intel_fbc_cfb_stride(cache); + unsigned int stride_aligned = intel_fbc_cfb_stride(dev_priv, cache); - if ((DISPLAY_VER(dev_priv) == 9) && - cache->fb.modifier != I915_FORMAT_MOD_X_TILED) - return DIV_ROUND_UP(cache->plane.src_w, 32 * fbc->limit) * 8; - else - return 0; -} + /* + * Override stride in 64 byte units per 4 line segment. + * + * Gen9 hw miscalculates cfb stride for linear as + * PLANE_STRIDE*512 instead of PLANE_STRIDE*64, so + * we always need to use the override there. + */ + if (stride != stride_aligned || + (DISPLAY_VER(dev_priv) == 9 && + cache->fb.modifier == DRM_FORMAT_MOD_LINEAR)) + return stride_aligned * 4 / 64; -static bool intel_fbc_override_cfb_stride_changed(struct drm_i915_private *dev_priv) -{ - struct intel_fbc *fbc = &dev_priv->fbc; - - return fbc->params.override_cfb_stride != intel_fbc_override_cfb_stride(dev_priv); + return 0; } static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv) @@ -861,7 +916,8 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) return false; } - if (!stride_is_valid(dev_priv, cache->fb.modifier, cache->fb.stride)) { + if (!stride_is_valid(dev_priv, cache->fb.modifier, + cache->fb.stride * cache->fb.format->cpp[0])) { fbc->no_fbc_reason = "framebuffer stride not supported"; return false; } @@ -949,9 +1005,9 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, params->fb.modifier = cache->fb.modifier; params->fb.stride = cache->fb.stride; - params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); - - params->override_cfb_stride = cache->override_cfb_stride; + params->cfb_stride = intel_fbc_cfb_stride(dev_priv, cache); + params->cfb_size = intel_fbc_cfb_size(dev_priv, cache); + params->override_cfb_stride = intel_fbc_override_cfb_stride(dev_priv, cache); params->plane_visible = cache->plane.visible; } @@ -982,10 +1038,13 @@ static bool intel_fbc_can_flip_nuke(const struct intel_crtc_state *crtc_state) if (params->fb.stride != cache->fb.stride) return false; - if (params->cfb_size != intel_fbc_calculate_cfb_size(dev_priv, cache)) + if (params->cfb_stride != intel_fbc_cfb_stride(dev_priv, cache)) return false; - if (params->override_cfb_stride != cache->override_cfb_stride) + if (params->cfb_size != intel_fbc_cfb_size(dev_priv, cache)) + return false; + + if (params->override_cfb_stride != intel_fbc_override_cfb_stride(dev_priv, cache)) return false; return true; @@ -1250,16 +1309,22 @@ static void intel_fbc_enable(struct intel_atomic_state *state, intel_atomic_get_new_plane_state(state, plane); struct intel_fbc *fbc = &dev_priv->fbc; struct intel_fbc_state_cache *cache = &fbc->state_cache; + int min_limit; if (!plane->has_fbc || !plane_state) return; + min_limit = intel_fbc_min_limit(plane_state->hw.fb ? + plane_state->hw.fb->format->cpp[0] : 0); + mutex_lock(&fbc->lock); if (fbc->crtc) { - if (fbc->crtc != crtc || - (!intel_fbc_cfb_size_changed(dev_priv) && - !intel_fbc_override_cfb_stride_changed(dev_priv))) + if (fbc->crtc != crtc) + goto out; + + if (fbc->limit >= min_limit && + !intel_fbc_cfb_size_changed(dev_priv)) goto out; __intel_fbc_disable(dev_priv); @@ -1274,15 +1339,12 @@ static void intel_fbc_enable(struct intel_atomic_state *state, goto out; if (intel_fbc_alloc_cfb(dev_priv, - intel_fbc_calculate_cfb_size(dev_priv, cache), - plane_state->hw.fb->format->cpp[0])) { + intel_fbc_cfb_size(dev_priv, cache), min_limit)) { cache->plane.visible = false; fbc->no_fbc_reason = "not enough stolen memory"; goto out; } - cache->override_cfb_stride = intel_fbc_override_cfb_stride(dev_priv); - drm_dbg_kms(&dev_priv->drm, "Enabling FBC on pipe %c\n", pipe_name(crtc->pipe)); fbc->no_fbc_reason = "FBC enabled but not active yet\n"; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b9fd54f24f95..004c12a22295 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -453,7 +453,6 @@ struct intel_fbc { } fb; unsigned int fence_y_offset; - u16 override_cfb_stride; u16 interval; s8 fence_id; bool psr2_active; @@ -478,7 +477,8 @@ struct intel_fbc { u64 modifier; } fb; - int cfb_size; + unsigned int cfb_stride; + unsigned int cfb_size; unsigned int fence_y_offset; u16 override_cfb_stride; u16 interval; From 2f051f6774bb8c6807b2287e6ca482089bd92364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Sep 2021 18:25:15 +0300 Subject: [PATCH 077/554] drm/i915/fbc: Align FBC segments to 512B on glk+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the same 512 byte FBC segment alignment to glk+ as we use on skl+. The only real difference is that we now have a dedicated register for the FBC override stride. Not 100% sure which platforms really need the 512B alignment, but it's easiest to just do it on everything. Also the hardware no longer seems to misclaculate the CFB stride for linear, so we can omit the use of the override stride for linear unless the stride is misaligned. Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210921152517.803-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 14 +++++++++++--- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index e3934424040b..eeb97305e767 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -115,7 +115,7 @@ static unsigned int intel_fbc_cfb_stride(struct drm_i915_private *i915, * be 512 byte aligned. Aligning each line to 512 bytes guarantees * that regardless of the compression limit we choose later. */ - if (DISPLAY_VER(i915) == 9) + if (DISPLAY_VER(i915) >= 9) return max(ALIGN(stride, 512), skl_fbc_min_cfb_stride(cache)); else return stride; @@ -356,10 +356,18 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) const struct intel_fbc_reg_params *params = &fbc->params; u32 dpfc_ctl; - /* Display WA #0529: skl, kbl, bxt. */ - if (DISPLAY_VER(dev_priv) == 9) { + if (DISPLAY_VER(dev_priv) >= 10) { u32 val = 0; + if (params->override_cfb_stride) + val |= FBC_STRIDE_OVERRIDE | + FBC_STRIDE(params->override_cfb_stride / fbc->limit); + + intel_de_write(dev_priv, GLK_FBC_STRIDE, val); + } else if (DISPLAY_VER(dev_priv) == 9) { + u32 val = 0; + + /* Display WA #0529: skl, kbl, bxt. */ if (params->override_cfb_stride) val |= CHICKEN_FBC_STRIDE_OVERRIDE | CHICKEN_FBC_STRIDE(params->override_cfb_stride / fbc->limit); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 61d29068925c..24017d38c6f6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3360,6 +3360,10 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ILK_DPFC_DISABLE_DUMMY0 (1 << 8) #define ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL (1 << 14) #define ILK_DPFC_NUKE_ON_ANY_MODIFICATION (1 << 23) +#define GLK_FBC_STRIDE _MMIO(0x43228) +#define FBC_STRIDE_OVERRIDE REG_BIT(15) +#define FBC_STRIDE_MASK REG_GENMASK(14, 0) +#define FBC_STRIDE(x) REG_FIELD_PREP(FBC_STRIDE_MASK, (x)) #define ILK_FBC_RT_BASE _MMIO(0x2128) #define ILK_FBC_RT_VALID (1 << 0) #define SNB_FBC_FRONT_BUFFER (1 << 1) From 5f524aea39d9e2a74c063f340a77516e454badce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Sep 2021 21:12:45 +0300 Subject: [PATCH 078/554] drm/i915/fbc: Implement Wa_16011863758 for icl+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's some kind of weird corner cases in FBC which requires FBC segments to be separated by at least one extra cacheline. Make sure that is present. v2: Respin to fit in with skl_fbc_min_cfb_stride() v3: Make it build Reviewed-by: Juha-Pekka Heikkila #v1 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210921181245.15091-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index eeb97305e767..37ebed8d228d 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -84,7 +84,8 @@ static unsigned int _intel_fbc_cfb_stride(const struct intel_fbc_state_cache *ca } /* minimum acceptable cfb stride in bytes, assuming 1:1 compression limit */ -static unsigned int skl_fbc_min_cfb_stride(const struct intel_fbc_state_cache *cache) +static unsigned int skl_fbc_min_cfb_stride(struct drm_i915_private *i915, + const struct intel_fbc_state_cache *cache) { unsigned int limit = 4; /* 1:4 compression limit is the worst case */ unsigned int cpp = 4; /* FBC always 4 bytes per pixel */ @@ -94,6 +95,13 @@ static unsigned int skl_fbc_min_cfb_stride(const struct intel_fbc_state_cache *c /* minimum segment stride we can use */ stride = cache->plane.src_w * cpp * height / limit; + /* + * Wa_16011863758: icl+ + * Avoid some hardware segment address miscalculation. + */ + if (DISPLAY_VER(i915) >= 11) + stride += 64; + /* * At least some of the platforms require each 4 line segment to * be 512 byte aligned. Just do it always for simplicity. @@ -116,7 +124,7 @@ static unsigned int intel_fbc_cfb_stride(struct drm_i915_private *i915, * that regardless of the compression limit we choose later. */ if (DISPLAY_VER(i915) >= 9) - return max(ALIGN(stride, 512), skl_fbc_min_cfb_stride(cache)); + return max(ALIGN(stride, 512), skl_fbc_min_cfb_stride(i915, cache)); else return stride; } From 09bbdd8730dce85db1d945961dbf0ea4066eb6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Sep 2021 18:25:17 +0300 Subject: [PATCH 079/554] drm/i915/fbc: Allow higher compression limits on FBC1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On FBC1 we can specify an arbitrary cfb stride. The hw will simply throw away any compressed line that would exceed the specified limit and keep using the uncompressed data instead. Thus we can allow arbitrary compression limits. The one thing we have to keep in mind though is that the cfb stride is specified in units of 32B (gen2) or 64B (gen3+). Fortunately X-tile is already 128B (gen2) or 512B (gen3+) wide so as long as we limit outselves to the same 4x compression limit that FBC2 has we are guaranteed to have a sufficiently aligned cfb stride. Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210921152517.803-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 37ebed8d228d..46f62fdf9eee 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -164,15 +164,13 @@ static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv) static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) { - struct intel_fbc_reg_params *params = &dev_priv->fbc.params; + struct intel_fbc *fbc = &dev_priv->fbc; + const struct intel_fbc_reg_params *params = &fbc->params; int cfb_pitch; int i; u32 fbc_ctl; - /* Note: fbc.limit == 1 for i8xx */ - cfb_pitch = params->cfb_size / FBC_LL_SIZE; - if (params->fb.stride < cfb_pitch) - cfb_pitch = params->fb.stride; + cfb_pitch = params->cfb_stride / fbc->limit; /* FBC_CTL wants 32B or 64B units */ if (DISPLAY_VER(dev_priv) == 2) @@ -518,18 +516,14 @@ static int intel_fbc_min_limit(int fb_cpp) static int intel_fbc_max_limit(struct drm_i915_private *dev_priv) { - /* - * FIXME: FBC1 can have arbitrary cfb stride, - * so we could support different compression ratios. - */ - if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) - return 1; - /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(dev_priv)) return 1; - /* FBC2 can only do 1:1, 1:2, 1:4 */ + /* + * FBC2 can only do 1:1, 1:2, 1:4, we limit + * FBC1 to the same out of convenience. + */ return 4; } From a837a0686308d95ad9c48d32b4dfe86a17dc98c2 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Tue, 14 Sep 2021 14:34:12 +0530 Subject: [PATCH 080/554] drm/i915: Remove warning from the rps worker In commit 4e5c8a99e1cb ("drm/i915: Drop i915_request.lock requirement for intel_rps_boost()"), we decoupled the rps worker from the pm so that we could avoid the synchronization penalty which makes the assertion liable to run too early. Which makes warning invalid hence removed. Fixes: 4e5c8a99e1cb ("drm/i915: Drop i915_request.lock requirement for intel_rps_boost()") Reviewed-by: Chris Wilson Signed-off-by: Tejas Upadhyay Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210914090412.1393498-1-tejaskumarx.surendrakumar.upadhyay@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index e1a198bbd135..172de6c9f949 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -882,8 +882,6 @@ void intel_rps_park(struct intel_rps *rps) if (!intel_rps_is_enabled(rps)) return; - GEM_BUG_ON(atomic_read(&rps->num_waiters)); - if (!intel_rps_clear_active(rps)) return; From 74af1e2c16749514fc8db4fc97e59ce897b73fc9 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 24 Sep 2021 18:38:25 +0200 Subject: [PATCH 081/554] drm/i915: Flush buffer pools on driver remove We currently do an explicit flush of the buffer pools within the call path of drm_driver.release(); this removes all buffers, regardless of their age, freeing the buffers' associated resources (objects, address space areas). However there is other code that runs within the drm_driver.release() call chain that expects objects and their associated address space areas have already been flushed. Since buffer pools auto-flush old buffers once per second in a worker thread, there's a small window where if we remove the driver while there are still objects in buffers with an age of less than one second, the assumptions of the other release code may be violated. By moving the flush to driver remove (which executes earlier via the pci_driver.remove() flow) we're ensuring that all buffers are flushed and their associated objects freed before some other code in pci_driver.remove() flushes those objects so they are released before _any_ code in drm_driver.release() that check completness of those flushes executes. v2: Reword commit description as suggested by Matt. Signed-off-by: Janusz Krzysztofik Cc: Chris Wilson Cc: Matt Roper Signed-off-by: Matt Roper Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210924163825.634606-1-janusz.krzysztofik@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 2 ++ drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 4037c3778225..5b3acf2b064e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -741,6 +741,8 @@ void intel_gt_driver_remove(struct intel_gt *gt) intel_uc_driver_remove(>->uc); intel_engines_release(gt); + + intel_gt_flush_buffer_pool(gt); } void intel_gt_driver_unregister(struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c index aa0a59c5b614..acc49c56a9f3 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c @@ -245,8 +245,6 @@ void intel_gt_fini_buffer_pool(struct intel_gt *gt) struct intel_gt_buffer_pool *pool = >->buffer_pool; int n; - intel_gt_flush_buffer_pool(gt); - for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) GEM_BUG_ON(!list_empty(&pool->cache_list[n])); } From c6b40ee330fe09b332715bb7ec1467e4fcbe2e65 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Mon, 6 Sep 2021 12:12:59 +0800 Subject: [PATCH 082/554] drm/i915/audio: Use BIOS provided value for RKL HDA link Commit 989634fb49ad ("drm/i915/audio: set HDA link parameters in driver") makes HDMI audio on Lenovo P350 disappear. So in addition to TGL, extend the logic to RKL to use BIOS provided value to fix the regression. Fixes: 989634fb49ad ("drm/i915/audio: set HDA link parameters in driver") Reviewed-by: Kai Vehmanen Signed-off-by: Kai-Heng Feng Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210906041300.508458-1-kai.heng.feng@canonical.com --- drivers/gpu/drm/i915/display/intel_audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 532237588511..4e0f96bf6158 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -1308,8 +1308,9 @@ static void i915_audio_component_init(struct drm_i915_private *dev_priv) else aud_freq = aud_freq_init; - /* use BIOS provided value for TGL unless it is a known bad value */ - if (IS_TIGERLAKE(dev_priv) && aud_freq_init != AUD_FREQ_TGL_BROKEN) + /* use BIOS provided value for TGL and RKL unless it is a known bad value */ + if ((IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) && + aud_freq_init != AUD_FREQ_TGL_BROKEN) aud_freq = aud_freq_init; drm_dbg_kms(&dev_priv->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n", From d576b31bdece7b5034047cbe21170e948198d32f Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Fri, 24 Sep 2021 15:46:46 +0100 Subject: [PATCH 083/554] drm/i915: remember to call i915_sw_fence_fini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seems to fix some object-debug splat which appeared while debugging something unrelated. v2: s/guc_blocked/guc_state.blocked/ Signed-off-by: Matthew Auld Cc: Ville Syrjälä Cc: Matthew Brost Tested-by: Ville Syrjälä Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20210924144646.4096402-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index ff637147b1a9..e9a0cad5c34d 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -419,6 +419,7 @@ void intel_context_fini(struct intel_context *ce) mutex_destroy(&ce->pin_mutex); i915_active_fini(&ce->active); + i915_sw_fence_fini(&ce->guc_state.blocked); } void i915_context_module_exit(void) From 2a764b7c708a796e6b45c39f12b962371278ca05 Mon Sep 17 00:00:00 2001 From: Vandita Kulkarni Date: Wed, 15 Sep 2021 11:13:38 +0530 Subject: [PATCH 084/554] drm/i915/display: Fix the dsc check while selecting min_cdclk The right parameter that selects second dsc engine is dsc_split. Hence use dsc_split instead of slice_count while selecting the cdclk in order to accommodate 1ppc limitaion of vdsc. Fixes: fe01883fdcef ("drm/i915: Get proper min cdclk if vDSC enabled") Suggested-by: Jani Nikula Signed-off-by: Vandita Kulkarni Reviewed-by: Jani Nikula Signed-off-by: Uma Shankar Link: https://patchwork.freedesktop.org/patch/msgid/20210915054338.29869-1-vandita.kulkarni@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 9aec17b33819..3a1cdb3937aa 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2140,13 +2140,11 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk); /* - * VDSC engine can process only 1 pixel per Cd clock. - * In case VDSC is used and max slice count == 1, - * max supported pixel clock should be 100% of CD clock. - * Then do min_cdclk and pixel clock comparison to get cdclk. + * When we decide to use only one VDSC engine, since + * each VDSC operates with 1 ppc throughput, pixel clock + * cannot be higher than the VDSC clock (cdclk) */ - if (crtc_state->dsc.compression_enable && - crtc_state->dsc.slice_count == 1) + if (crtc_state->dsc.compression_enable && !crtc_state->dsc.dsc_split) min_cdclk = max(min_cdclk, (int)crtc_state->pixel_rate); /* From 5716c8c6f4b6a985acaf83a19d89131c113f7aeb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:45 +0300 Subject: [PATCH 085/554] drm/i915/uncore: split the fw get function into separate vfunc constify it while here. drop the put function since it was never overloaded and always has done the same thing, no point in indirecting it for show. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/41c3e1896162fc08e22e40b00642791365a8c00e.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 70 ++++++++++++++++------------- drivers/gpu/drm/i915/intel_uncore.h | 7 +-- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 6b38bc2811c1..2dac69d92c1b 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -36,6 +36,12 @@ #define __raw_posting_read(...) ((void)__raw_uncore_read32(__VA_ARGS__)) +static void +fw_domains_get(struct intel_uncore *uncore, enum forcewake_domains fw_domains) +{ + uncore->fw_get_funcs->force_wake_get(uncore, fw_domains); +} + void intel_uncore_mmio_debug_init_early(struct intel_uncore_mmio_debug *mmio_debug) { @@ -248,7 +254,7 @@ fw_domain_put(const struct intel_uncore_forcewake_domain *d) } static void -fw_domains_get(struct intel_uncore *uncore, enum forcewake_domains fw_domains) +fw_domains_get_normal(struct intel_uncore *uncore, enum forcewake_domains fw_domains) { struct intel_uncore_forcewake_domain *d; unsigned int tmp; @@ -396,7 +402,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer) GEM_BUG_ON(!domain->wake_count); if (--domain->wake_count == 0) - uncore->funcs.force_wake_put(uncore, domain->mask); + fw_domains_put(uncore, domain->mask); spin_unlock_irqrestore(&uncore->lock, irqflags); @@ -454,7 +460,7 @@ intel_uncore_forcewake_reset(struct intel_uncore *uncore) fw = uncore->fw_domains_active; if (fw) - uncore->funcs.force_wake_put(uncore, fw); + fw_domains_put(uncore, fw); fw_domains_reset(uncore, uncore->fw_domains); assert_forcewakes_inactive(uncore); @@ -562,7 +568,7 @@ static void forcewake_early_sanitize(struct intel_uncore *uncore, intel_uncore_forcewake_reset(uncore); if (restore_forcewake) { spin_lock_irq(&uncore->lock); - uncore->funcs.force_wake_get(uncore, restore_forcewake); + fw_domains_get(uncore, restore_forcewake); if (intel_uncore_has_fifo(uncore)) uncore->fifo_count = fifo_free_entries(uncore); @@ -623,7 +629,7 @@ static void __intel_uncore_forcewake_get(struct intel_uncore *uncore, } if (fw_domains) - uncore->funcs.force_wake_get(uncore, fw_domains); + fw_domains_get(uncore, fw_domains); } /** @@ -644,7 +650,7 @@ void intel_uncore_forcewake_get(struct intel_uncore *uncore, { unsigned long irqflags; - if (!uncore->funcs.force_wake_get) + if (!uncore->fw_get_funcs) return; assert_rpm_wakelock_held(uncore->rpm); @@ -711,7 +717,7 @@ void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore, { lockdep_assert_held(&uncore->lock); - if (!uncore->funcs.force_wake_get) + if (!uncore->fw_get_funcs) return; __intel_uncore_forcewake_get(uncore, fw_domains); @@ -733,7 +739,7 @@ static void __intel_uncore_forcewake_put(struct intel_uncore *uncore, continue; } - uncore->funcs.force_wake_put(uncore, domain->mask); + fw_domains_put(uncore, domain->mask); } } @@ -750,7 +756,7 @@ void intel_uncore_forcewake_put(struct intel_uncore *uncore, { unsigned long irqflags; - if (!uncore->funcs.force_wake_put) + if (!uncore->fw_get_funcs) return; spin_lock_irqsave(&uncore->lock, irqflags); @@ -769,7 +775,7 @@ void intel_uncore_forcewake_flush(struct intel_uncore *uncore, struct intel_uncore_forcewake_domain *domain; unsigned int tmp; - if (!uncore->funcs.force_wake_put) + if (!uncore->fw_get_funcs) return; fw_domains &= uncore->fw_domains; @@ -793,7 +799,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore, { lockdep_assert_held(&uncore->lock); - if (!uncore->funcs.force_wake_put) + if (!uncore->fw_get_funcs) return; __intel_uncore_forcewake_put(uncore, fw_domains); @@ -801,7 +807,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore, void assert_forcewakes_inactive(struct intel_uncore *uncore) { - if (!uncore->funcs.force_wake_get) + if (!uncore->fw_get_funcs) return; drm_WARN(&uncore->i915->drm, uncore->fw_domains_active, @@ -818,7 +824,7 @@ void assert_forcewakes_active(struct intel_uncore *uncore, if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)) return; - if (!uncore->funcs.force_wake_get) + if (!uncore->fw_get_funcs) return; spin_lock_irq(&uncore->lock); @@ -1605,7 +1611,7 @@ static noinline void ___force_wake_auto(struct intel_uncore *uncore, for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) fw_domain_arm_timer(domain); - uncore->funcs.force_wake_get(uncore, fw_domains); + fw_domains_get(uncore, fw_domains); } static inline void __force_wake_auto(struct intel_uncore *uncore, @@ -1866,6 +1872,18 @@ static void intel_uncore_fw_domains_fini(struct intel_uncore *uncore) fw_domain_fini(uncore, d->id); } +static const struct intel_uncore_fw_get uncore_get_fallback = { + .force_wake_get = fw_domains_get_with_fallback +}; + +static const struct intel_uncore_fw_get uncore_get_normal = { + .force_wake_get = fw_domains_get_normal, +}; + +static const struct intel_uncore_fw_get uncore_get_thread_status = { + .force_wake_get = fw_domains_get_with_thread_status +}; + static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) { struct drm_i915_private *i915 = uncore->i915; @@ -1881,8 +1899,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) intel_engine_mask_t emask = INTEL_INFO(i915)->platform_engine_mask; int i; - uncore->funcs.force_wake_get = fw_domains_get_with_fallback; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_fallback; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_RENDER_GEN9, FORCEWAKE_ACK_RENDER_GEN9); @@ -1907,8 +1924,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i)); } } else if (IS_GRAPHICS_VER(i915, 9, 10)) { - uncore->funcs.force_wake_get = fw_domains_get_with_fallback; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_fallback; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_RENDER_GEN9, FORCEWAKE_ACK_RENDER_GEN9); @@ -1918,16 +1934,13 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA, FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9); } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { - uncore->funcs.force_wake_get = fw_domains_get; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_normal; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_VLV, FORCEWAKE_ACK_VLV); fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA, FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV); } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { - uncore->funcs.force_wake_get = - fw_domains_get_with_thread_status; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_thread_status; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_MT, FORCEWAKE_ACK_HSW); } else if (IS_IVYBRIDGE(i915)) { @@ -1942,9 +1955,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) * (correctly) interpreted by the test below as MT * forcewake being disabled. */ - uncore->funcs.force_wake_get = - fw_domains_get_with_thread_status; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_thread_status; /* We need to init first for ECOBUS access and then * determine later if we want to reinit, in case of MT access is @@ -1975,9 +1986,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) FORCEWAKE, FORCEWAKE_ACK); } } else if (GRAPHICS_VER(i915) == 6) { - uncore->funcs.force_wake_get = - fw_domains_get_with_thread_status; - uncore->funcs.force_wake_put = fw_domains_put; + uncore->fw_get_funcs = &uncore_get_thread_status; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE, FORCEWAKE_ACK); } @@ -2186,8 +2195,7 @@ int intel_uncore_init_mmio(struct intel_uncore *uncore) } /* make sure fw funcs are set if and only if we have fw*/ - GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.force_wake_get); - GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.force_wake_put); + GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->fw_get_funcs); GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.read_fw_domains); GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.write_fw_domains); diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 3c0b0a8b5250..1a7448f5f16f 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -84,12 +84,12 @@ enum forcewake_domains { FORCEWAKE_ALL = BIT(FW_DOMAIN_ID_COUNT) - 1, }; -struct intel_uncore_funcs { +struct intel_uncore_fw_get { void (*force_wake_get)(struct intel_uncore *uncore, enum forcewake_domains domains); - void (*force_wake_put)(struct intel_uncore *uncore, - enum forcewake_domains domains); +}; +struct intel_uncore_funcs { enum forcewake_domains (*read_fw_domains)(struct intel_uncore *uncore, i915_reg_t r); enum forcewake_domains (*write_fw_domains)(struct intel_uncore *uncore, @@ -137,6 +137,7 @@ struct intel_uncore { unsigned int fw_domains_table_entries; struct notifier_block pmic_bus_access_nb; + const struct intel_uncore_fw_get *fw_get_funcs; struct intel_uncore_funcs funcs; unsigned int fifo_count; From 758b2fc26640c3641fb145cf61bc79a255dae5ea Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:46 +0300 Subject: [PATCH 086/554] drm/i915/pm: drop get_fifo_size vfunc. The i845_update_wm code was always calling the i845 variant, and the i9xx_update_wm had only a choice between i830 and i9xx paths, hardly worth the vfunc overhead. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/07523b1e46cd10adb2991ed4d2619b542a48c1ce.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_pm.c | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 004c12a22295..92850f591c82 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -330,8 +330,6 @@ struct drm_i915_display_funcs { const struct intel_cdclk_config *cdclk_config, enum pipe pipe); int (*bw_calc_min_cdclk)(struct intel_atomic_state *state); - int (*get_fifo_size)(struct drm_i915_private *dev_priv, - enum i9xx_plane_id i9xx_plane); int (*compute_pipe_wm)(struct intel_atomic_state *state, struct intel_crtc *crtc); int (*compute_intermediate_wm)(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 97b68bbbc689..0e0309733c79 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2342,7 +2342,10 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) else wm_info = &i830_a_wm_info; - fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_A); + if (DISPLAY_VER(dev_priv) == 2) + fifo_size = i830_get_fifo_size(dev_priv, PLANE_A); + else + fifo_size = i9xx_get_fifo_size(dev_priv, PLANE_A); crtc = intel_get_crtc_for_plane(dev_priv, PLANE_A); if (intel_crtc_active(crtc)) { const struct drm_display_mode *pipe_mode = @@ -2369,7 +2372,10 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) if (DISPLAY_VER(dev_priv) == 2) wm_info = &i830_bc_wm_info; - fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B); + if (DISPLAY_VER(dev_priv) == 2) + fifo_size = i830_get_fifo_size(dev_priv, PLANE_B); + else + fifo_size = i9xx_get_fifo_size(dev_priv, PLANE_B); crtc = intel_get_crtc_for_plane(dev_priv, PLANE_B); if (intel_crtc_active(crtc)) { const struct drm_display_mode *pipe_mode = @@ -2485,7 +2491,7 @@ static void i845_update_wm(struct intel_crtc *unused_crtc) pipe_mode = &crtc->config->hw.pipe_mode; planea_wm = intel_calculate_wm(pipe_mode->crtc_clock, &i845_wm_info, - dev_priv->display.get_fifo_size(dev_priv, PLANE_A), + i845_get_fifo_size(dev_priv, PLANE_A), 4, pessimal_latency_ns); fwater_lo = intel_uncore_read(&dev_priv->uncore, FW_BLC) & ~0xfff; fwater_lo |= (3<<8) | planea_wm; @@ -8052,15 +8058,11 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->display.update_wm = i965_update_wm; } else if (DISPLAY_VER(dev_priv) == 3) { dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i9xx_get_fifo_size; } else if (DISPLAY_VER(dev_priv) == 2) { - if (INTEL_NUM_PIPES(dev_priv) == 1) { + if (INTEL_NUM_PIPES(dev_priv) == 1) dev_priv->display.update_wm = i845_update_wm; - dev_priv->display.get_fifo_size = i845_get_fifo_size; - } else { + else dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i830_get_fifo_size; - } } else { drm_err(&dev_priv->drm, "unexpected fall-through in %s\n", __func__); From ef9c66a0aea5c2f42a7cee721e61949c745c927b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:47 +0300 Subject: [PATCH 087/554] drm/i915: make update_wm take a dev_priv. The crtc was never being used here. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/70438bface47fa683cda8a9e95d0556fca448172.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 10 +++++----- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 20 +++++++------------- drivers/gpu/drm/i915/intel_pm.h | 2 +- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f27c294beb92..566a7d2feb1a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2383,7 +2383,7 @@ static void intel_post_plane_update(struct intel_atomic_state *state, intel_frontbuffer_flip(dev_priv, new_crtc_state->fb_bits); if (new_crtc_state->update_wm_post && new_crtc_state->hw.active) - intel_update_watermarks(crtc); + intel_update_watermarks(dev_priv); if (hsw_post_update_enable_ips(old_crtc_state, new_crtc_state)) hsw_enable_ips(new_crtc_state); @@ -2540,7 +2540,7 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, if (dev_priv->display.initial_watermarks) dev_priv->display.initial_watermarks(state, crtc); else if (new_crtc_state->update_wm_pre) - intel_update_watermarks(crtc); + intel_update_watermarks(dev_priv); } /* @@ -3587,7 +3587,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, if (dev_priv->display.initial_watermarks) dev_priv->display.initial_watermarks(state, crtc); else - intel_update_watermarks(crtc); + intel_update_watermarks(dev_priv); intel_enable_transcoder(new_crtc_state); intel_crtc_vblank_on(new_crtc_state); @@ -3654,7 +3654,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); if (!dev_priv->display.initial_watermarks) - intel_update_watermarks(crtc); + intel_update_watermarks(dev_priv); /* clock the pipe down to 640x480@60 to potentially save power */ if (IS_I830(dev_priv)) @@ -3730,7 +3730,7 @@ static void intel_crtc_disable_noatomic(struct intel_crtc *crtc, encoder->base.crtc = NULL; intel_fbc_disable(crtc); - intel_update_watermarks(crtc); + intel_update_watermarks(dev_priv); intel_disable_shared_dpll(crtc_state); intel_display_power_put_all_in_set(dev_priv, &crtc->enabled_power_domains); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 92850f591c82..97bfeadaab94 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -341,7 +341,7 @@ struct drm_i915_display_funcs { void (*optimize_watermarks)(struct intel_atomic_state *state, struct intel_crtc *crtc); int (*compute_global_watermarks)(struct intel_atomic_state *state); - void (*update_wm)(struct intel_crtc *crtc); + void (*update_wm)(struct drm_i915_private *dev_priv); int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); u8 (*calc_voltage_level)(int cdclk); /* Returns the active state of the crtc, and if the crtc is active, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0e0309733c79..226f456cde3a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -881,9 +881,8 @@ static struct intel_crtc *single_enabled_crtc(struct drm_i915_private *dev_priv) return enabled; } -static void pnv_update_wm(struct intel_crtc *unused_crtc) +static void pnv_update_wm(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev); struct intel_crtc *crtc; const struct cxsr_latency *latency; u32 reg; @@ -2248,9 +2247,8 @@ static void vlv_optimize_watermarks(struct intel_atomic_state *state, mutex_unlock(&dev_priv->wm.wm_mutex); } -static void i965_update_wm(struct intel_crtc *unused_crtc) +static void i965_update_wm(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev); struct intel_crtc *crtc; int srwm = 1; int cursor_sr = 16; @@ -2324,9 +2322,8 @@ static void i965_update_wm(struct intel_crtc *unused_crtc) #undef FW_WM -static void i9xx_update_wm(struct intel_crtc *unused_crtc) +static void i9xx_update_wm(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev); const struct intel_watermark_params *wm_info; u32 fwater_lo; u32 fwater_hi; @@ -2476,9 +2473,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) intel_set_memory_cxsr(dev_priv, true); } -static void i845_update_wm(struct intel_crtc *unused_crtc) +static void i845_update_wm(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev); struct intel_crtc *crtc; const struct drm_display_mode *pipe_mode; u32 fwater_lo; @@ -7136,7 +7132,7 @@ void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv) /** * intel_update_watermarks - update FIFO watermark values based on current modes - * @crtc: the #intel_crtc on which to compute the WM + * @dev_priv: i915 device * * Calculate watermark values for the various WM regs based on current mode * and plane configuration. @@ -7167,12 +7163,10 @@ void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv) * We don't use the sprite, so we can ignore that. And on Crestline we have * to set the non-SR watermarks to 8. */ -void intel_update_watermarks(struct intel_crtc *crtc) +void intel_update_watermarks(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - if (dev_priv->display.update_wm) - dev_priv->display.update_wm(crtc); + dev_priv->display.update_wm(dev_priv); } void intel_enable_ipc(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index 941b3ae555c8..99bce0b4f5fb 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -29,7 +29,7 @@ struct skl_wm_level; void intel_init_clock_gating(struct drm_i915_private *dev_priv); void intel_suspend_hw(struct drm_i915_private *dev_priv); int ilk_wm_max_level(const struct drm_i915_private *dev_priv); -void intel_update_watermarks(struct intel_crtc *crtc); +void intel_update_watermarks(struct drm_i915_private *dev_priv); void intel_init_pm(struct drm_i915_private *dev_priv); void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv); void intel_pm_setup(struct drm_i915_private *dev_priv); From 02a1a6351e439638cb04852eb57c129b60ce36b5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:48 +0300 Subject: [PATCH 088/554] drm/i915/wm: provide wrappers around watermark vfuncs calls (v3) This moves one wrapper from the pm->display side, and creates wrappers for all the others, this should simplify things later. One thing to note is that the code checks the existence of some of these ptrs, so the wrappers are a bit complicated by that. Suggested by Jani. v2: fixup warnings in wrong place error. v3 by Jani: fix intel_compute_global_watermarks() return value check Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/ee2760c45896568c9dd9114a575509619bd44ef2.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 185 ++++++++++++------- drivers/gpu/drm/i915/intel_pm.c | 39 ---- drivers/gpu/drm/i915/intel_pm.h | 1 - 3 files changed, 123 insertions(+), 102 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 566a7d2feb1a..9af433a7cbf1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -126,6 +126,101 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +/** + * intel_update_watermarks - update FIFO watermark values based on current modes + * @dev_priv: i915 device + * + * Calculate watermark values for the various WM regs based on current mode + * and plane configuration. + * + * There are several cases to deal with here: + * - normal (i.e. non-self-refresh) + * - self-refresh (SR) mode + * - lines are large relative to FIFO size (buffer can hold up to 2) + * - lines are small relative to FIFO size (buffer can hold more than 2 + * lines), so need to account for TLB latency + * + * The normal calculation is: + * watermark = dotclock * bytes per pixel * latency + * where latency is platform & configuration dependent (we assume pessimal + * values here). + * + * The SR calculation is: + * watermark = (trunc(latency/line time)+1) * surface width * + * bytes per pixel + * where + * line time = htotal / dotclock + * surface width = hdisplay for normal plane and 64 for cursor + * and latency is assumed to be high, as above. + * + * The final value programmed to the register should always be rounded up, + * and include an extra 2 entries to account for clock crossings. + * + * We don't use the sprite, so we can ignore that. And on Crestline we have + * to set the non-SR watermarks to 8. + */ +static void intel_update_watermarks(struct drm_i915_private *dev_priv) +{ + if (dev_priv->display.update_wm) + dev_priv->display.update_wm(dev_priv); +} + +static int intel_compute_pipe_wm(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (dev_priv->display.compute_pipe_wm) + return dev_priv->display.compute_pipe_wm(state, crtc); + return 0; +} + +static int intel_compute_intermediate_wm(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (!dev_priv->display.compute_intermediate_wm) + return 0; + if (drm_WARN_ON(&dev_priv->drm, + !dev_priv->display.compute_pipe_wm)) + return 0; + return dev_priv->display.compute_intermediate_wm(state, crtc); +} + +static bool intel_initial_watermarks(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (dev_priv->display.initial_watermarks) { + dev_priv->display.initial_watermarks(state, crtc); + return true; + } + return false; +} + +static void intel_atomic_update_watermarks(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (dev_priv->display.atomic_update_watermarks) + dev_priv->display.atomic_update_watermarks(state, crtc); +} + +static void intel_optimize_watermarks(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (dev_priv->display.optimize_watermarks) + dev_priv->display.optimize_watermarks(state, crtc); +} + +static int intel_compute_global_watermarks(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + if (dev_priv->display.compute_global_watermarks) + return dev_priv->display.compute_global_watermarks(state); + return 0; +} + /* returns HPLL frequency in kHz */ int vlv_get_hpll_vco(struct drm_i915_private *dev_priv) { @@ -2537,10 +2632,9 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, * we'll continue to update watermarks the old way, if flags tell * us to. */ - if (dev_priv->display.initial_watermarks) - dev_priv->display.initial_watermarks(state, crtc); - else if (new_crtc_state->update_wm_pre) - intel_update_watermarks(dev_priv); + if (!intel_initial_watermarks(state, crtc)) + if (new_crtc_state->update_wm_pre) + intel_update_watermarks(dev_priv); } /* @@ -2912,8 +3006,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); - if (dev_priv->display.initial_watermarks) - dev_priv->display.initial_watermarks(state, crtc); + intel_initial_watermarks(state, crtc); intel_enable_transcoder(new_crtc_state); if (new_crtc_state->has_pch_encoder) @@ -3123,8 +3216,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) >= 11) icl_set_pipe_chicken(new_crtc_state); - if (dev_priv->display.initial_watermarks) - dev_priv->display.initial_watermarks(state, crtc); + intel_initial_watermarks(state, crtc); if (DISPLAY_VER(dev_priv) >= 11) { const struct intel_dbuf_state *dbuf_state = @@ -3541,7 +3633,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); - dev_priv->display.initial_watermarks(state, crtc); + intel_initial_watermarks(state, crtc); intel_enable_transcoder(new_crtc_state); intel_crtc_vblank_on(new_crtc_state); @@ -3584,9 +3676,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); - if (dev_priv->display.initial_watermarks) - dev_priv->display.initial_watermarks(state, crtc); - else + if (!intel_initial_watermarks(state, crtc)) intel_update_watermarks(dev_priv); intel_enable_transcoder(new_crtc_state); @@ -6765,32 +6855,23 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, return ret; } - if (dev_priv->display.compute_pipe_wm) { - ret = dev_priv->display.compute_pipe_wm(state, crtc); - if (ret) { - drm_dbg_kms(&dev_priv->drm, - "Target pipe watermarks are invalid\n"); - return ret; - } - + ret = intel_compute_pipe_wm(state, crtc); + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "Target pipe watermarks are invalid\n"); + return ret; } - if (dev_priv->display.compute_intermediate_wm) { - if (drm_WARN_ON(&dev_priv->drm, - !dev_priv->display.compute_pipe_wm)) - return 0; - - /* - * Calculate 'intermediate' watermarks that satisfy both the - * old state and the new state. We can program these - * immediately. - */ - ret = dev_priv->display.compute_intermediate_wm(state, crtc); - if (ret) { - drm_dbg_kms(&dev_priv->drm, - "No valid intermediate pipe watermarks are possible\n"); - return ret; - } + /* + * Calculate 'intermediate' watermarks that satisfy both the + * old state and the new state. We can program these + * immediately. + */ + ret = intel_compute_intermediate_wm(state, crtc); + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "No valid intermediate pipe watermarks are possible\n"); + return ret; } if (DISPLAY_VER(dev_priv) >= 9) { @@ -8883,23 +8964,6 @@ static int intel_modeset_checks(struct intel_atomic_state *state) return 0; } -/* - * Handle calculation of various watermark data at the end of the atomic check - * phase. The code here should be run after the per-crtc and per-plane 'check' - * handlers to ensure that all derived state has been updated. - */ -static int calc_watermark_data(struct intel_atomic_state *state) -{ - struct drm_device *dev = state->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - - /* Is there platform-specific watermark information to calculate? */ - if (dev_priv->display.compute_global_watermarks) - return dev_priv->display.compute_global_watermarks(state); - - return 0; -} - static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_state, struct intel_crtc_state *new_crtc_state) { @@ -9546,7 +9610,7 @@ static int intel_atomic_check(struct drm_device *dev, goto fail; intel_fbc_choose_crtc(dev_priv, state); - ret = calc_watermark_data(state); + ret = intel_compute_global_watermarks(state); if (ret) goto fail; @@ -9720,8 +9784,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, intel_psr2_program_trans_man_trk_ctl(new_crtc_state); - if (dev_priv->display.atomic_update_watermarks) - dev_priv->display.atomic_update_watermarks(state, crtc); + intel_atomic_update_watermarks(state, crtc); } static void commit_pipe_post_planes(struct intel_atomic_state *state, @@ -9848,9 +9911,8 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state, /* FIXME unify this for all platforms */ if (!new_crtc_state->hw.active && - !HAS_GMCH(dev_priv) && - dev_priv->display.initial_watermarks) - dev_priv->display.initial_watermarks(state, crtc); + !HAS_GMCH(dev_priv)) + intel_initial_watermarks(state, crtc); } static void intel_commit_modeset_disables(struct intel_atomic_state *state) @@ -10273,8 +10335,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) if (DISPLAY_VER(dev_priv) == 2 && planes_enabling(old_crtc_state, new_crtc_state)) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true); - if (dev_priv->display.optimize_watermarks) - dev_priv->display.optimize_watermarks(state, crtc); + intel_optimize_watermarks(state, crtc); } intel_dbuf_post_plane_update(state); @@ -11376,7 +11437,7 @@ retry: /* Write calculated watermark values back */ for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) { crtc_state->wm.need_postvbl_update = true; - dev_priv->display.optimize_watermarks(intel_state, crtc); + intel_optimize_watermarks(intel_state, crtc); to_intel_crtc_state(crtc->base.state)->wm = crtc_state->wm; } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 226f456cde3a..11c9df62391d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7130,45 +7130,6 @@ void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv) !(intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) & DISP_FBC_WM_DIS); } -/** - * intel_update_watermarks - update FIFO watermark values based on current modes - * @dev_priv: i915 device - * - * Calculate watermark values for the various WM regs based on current mode - * and plane configuration. - * - * There are several cases to deal with here: - * - normal (i.e. non-self-refresh) - * - self-refresh (SR) mode - * - lines are large relative to FIFO size (buffer can hold up to 2) - * - lines are small relative to FIFO size (buffer can hold more than 2 - * lines), so need to account for TLB latency - * - * The normal calculation is: - * watermark = dotclock * bytes per pixel * latency - * where latency is platform & configuration dependent (we assume pessimal - * values here). - * - * The SR calculation is: - * watermark = (trunc(latency/line time)+1) * surface width * - * bytes per pixel - * where - * line time = htotal / dotclock - * surface width = hdisplay for normal plane and 64 for cursor - * and latency is assumed to be high, as above. - * - * The final value programmed to the register should always be rounded up, - * and include an extra 2 entries to account for clock crossings. - * - * We don't use the sprite, so we can ignore that. And on Crestline we have - * to set the non-SR watermarks to 8. - */ -void intel_update_watermarks(struct drm_i915_private *dev_priv) -{ - if (dev_priv->display.update_wm) - dev_priv->display.update_wm(dev_priv); -} - void intel_enable_ipc(struct drm_i915_private *dev_priv) { u32 val; diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index 99bce0b4f5fb..990cdcaf85ce 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -29,7 +29,6 @@ struct skl_wm_level; void intel_init_clock_gating(struct drm_i915_private *dev_priv); void intel_suspend_hw(struct drm_i915_private *dev_priv); int ilk_wm_max_level(const struct drm_i915_private *dev_priv); -void intel_update_watermarks(struct drm_i915_private *dev_priv); void intel_init_pm(struct drm_i915_private *dev_priv); void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv); void intel_pm_setup(struct drm_i915_private *dev_priv); From 44892ffafa5abfb90598ebad18656f9db61592bf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:49 +0300 Subject: [PATCH 089/554] drm/i915: add wrappers around cdclk vtable funcs. This adds wrappers around all the vtable callers so they are in one place. Suggested by Jani. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/c3dd7aaad039e76acde9dda7211468907aa657c0.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 47 +++++++++++++++---- drivers/gpu/drm/i915/display/intel_cdclk.h | 4 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- .../drm/i915/display/intel_display_power.c | 2 +- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 3a1cdb3937aa..ff01fe9be35c 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -59,6 +59,37 @@ * dividers can be programmed correctly. */ +void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, + struct intel_cdclk_config *cdclk_config) +{ + dev_priv->display.get_cdclk(dev_priv, cdclk_config); +} + +int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + return dev_priv->display.bw_calc_min_cdclk(state); +} + +static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv, + const struct intel_cdclk_config *cdclk_config, + enum pipe pipe) +{ + dev_priv->display.set_cdclk(dev_priv, cdclk_config, pipe); +} + +static int intel_cdclk_modeset_calc_cdclk(struct drm_i915_private *dev_priv, + struct intel_cdclk_state *cdclk_config) +{ + return dev_priv->display.modeset_calc_cdclk(cdclk_config); +} + +static u8 intel_cdclk_calc_voltage_level(struct drm_i915_private *dev_priv, + int cdclk) +{ + return dev_priv->display.calc_voltage_level(cdclk); +} + static void fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { @@ -1466,7 +1497,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, * at least what the CDCLK frequency requires. */ cdclk_config->voltage_level = - dev_priv->display.calc_voltage_level(cdclk_config->cdclk); + intel_cdclk_calc_voltage_level(dev_priv, cdclk_config->cdclk); } static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) @@ -1777,7 +1808,7 @@ static void bxt_cdclk_init_hw(struct drm_i915_private *dev_priv) cdclk_config.cdclk = bxt_calc_cdclk(dev_priv, 0); cdclk_config.vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk_config.cdclk); cdclk_config.voltage_level = - dev_priv->display.calc_voltage_level(cdclk_config.cdclk); + intel_cdclk_calc_voltage_level(dev_priv, cdclk_config.cdclk); bxt_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); } @@ -1789,7 +1820,7 @@ static void bxt_cdclk_uninit_hw(struct drm_i915_private *dev_priv) cdclk_config.cdclk = cdclk_config.bypass; cdclk_config.vco = 0; cdclk_config.voltage_level = - dev_priv->display.calc_voltage_level(cdclk_config.cdclk); + intel_cdclk_calc_voltage_level(dev_priv, cdclk_config.cdclk); bxt_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); } @@ -1956,7 +1987,7 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, &dev_priv->gmbus_mutex); } - dev_priv->display.set_cdclk(dev_priv, cdclk_config, pipe); + intel_cdclk_set_cdclk(dev_priv, cdclk_config, pipe); for_each_intel_dp(&dev_priv->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -2422,7 +2453,7 @@ static int bxt_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) cdclk_state->logical.cdclk = cdclk; cdclk_state->logical.voltage_level = max_t(int, min_voltage_level, - dev_priv->display.calc_voltage_level(cdclk)); + intel_cdclk_calc_voltage_level(dev_priv, cdclk)); if (!cdclk_state->active_pipes) { cdclk = bxt_calc_cdclk(dev_priv, cdclk_state->force_min_cdclk); @@ -2431,7 +2462,7 @@ static int bxt_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) cdclk_state->actual.vco = vco; cdclk_state->actual.cdclk = cdclk; cdclk_state->actual.voltage_level = - dev_priv->display.calc_voltage_level(cdclk); + intel_cdclk_calc_voltage_level(dev_priv, cdclk); } else { cdclk_state->actual = cdclk_state->logical; } @@ -2523,7 +2554,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) new_cdclk_state->active_pipes = intel_calc_active_pipes(state, old_cdclk_state->active_pipes); - ret = dev_priv->display.modeset_calc_cdclk(new_cdclk_state); + ret = intel_cdclk_modeset_calc_cdclk(dev_priv, new_cdclk_state); if (ret) return ret; @@ -2703,7 +2734,7 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv) */ void intel_update_cdclk(struct drm_i915_private *dev_priv) { - dev_priv->display.get_cdclk(dev_priv, &dev_priv->cdclk.hw); + intel_cdclk_get_cdclk(dev_priv, &dev_priv->cdclk.hw); /* * 9:0 CMBUS [sic] CDCLK frequency (cdfreq): diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h index b34eb00fb327..309b3f394e24 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.h +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h @@ -68,7 +68,9 @@ void intel_set_cdclk_post_plane_update(struct intel_atomic_state *state); void intel_dump_cdclk_config(const struct intel_cdclk_config *cdclk_config, const char *context); int intel_modeset_calc_cdclk(struct intel_atomic_state *state); - +void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, + struct intel_cdclk_config *cdclk_config); +int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state); struct intel_cdclk_state * intel_atomic_get_cdclk_state(struct intel_atomic_state *state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9af433a7cbf1..5cb6ccdf744a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9159,7 +9159,7 @@ static int intel_atomic_check_cdclk(struct intel_atomic_state *state, old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk) *need_cdclk_calc = true; - ret = dev_priv->display.bw_calc_min_cdclk(state); + ret = intel_cdclk_bw_calc_min_cdclk(state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index cce1a926fcc1..a274e2b33e91 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1195,7 +1195,7 @@ static void gen9_disable_dc_states(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - dev_priv->display.get_cdclk(dev_priv, &cdclk_config); + intel_cdclk_get_cdclk(dev_priv, &cdclk_config); /* Can't read out voltage_level so can't use intel_cdclk_changed() */ drm_WARN_ON(&dev_priv->drm, intel_cdclk_needs_modeset(&dev_priv->cdclk.hw, From 4360a2b54fd7e6c7ff66869b2fbb55cac7a9c325 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:50 +0300 Subject: [PATCH 090/554] drm/i915/display: add intel_fdi_link_train wrapper. This wraps the fdi link training vfunc to make it clearer. Suggested by Jani. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1bb978bcb6f16fbdaf08f2800a179b774525b59e.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_fdi.c | 8 ++++++++ drivers/gpu/drm/i915/display/intel_fdi.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5cb6ccdf744a..d7319d5fb4d4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2165,7 +2165,7 @@ static void ilk_pch_enable(const struct intel_atomic_state *state, assert_pch_transcoder_disabled(dev_priv, pipe); /* For PCH output, training FDI link */ - dev_priv->display.fdi_link_train(crtc, crtc_state); + intel_fdi_link_train(crtc, crtc_state); /* We need to program the right clock selection before writing the pixel * mutliplier into the DPLL. */ diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 96ff12ad0873..d20669e53663 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -10,6 +10,14 @@ #include "intel_fdi.h" #include "intel_sideband.h" +void intel_fdi_link_train(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + dev_priv->display.fdi_link_train(crtc, crtc_state); +} + /* units of 100MHz */ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index 60acf2133145..61cb216a09f5 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -26,4 +26,6 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, void intel_fdi_pll_freq_update(struct drm_i915_private *i915); void lpt_fdi_program_mphy(struct drm_i915_private *i915); +void intel_fdi_link_train(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state); #endif From 46d8e4a1da52460912392f51fcda2326be7217a2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:51 +0300 Subject: [PATCH 091/554] drm/i915: split clock gating init from display vtable This function is only used inside intel_pm.c Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/95d626a7329ab5779804762894e304e12c6dbe1f.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 9 ++++++- drivers/gpu/drm/i915/intel_pm.c | 48 ++++++++++++++++----------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 97bfeadaab94..bbb28b854f46 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -323,6 +323,11 @@ struct intel_crtc; struct intel_limit; struct dpll; +/* functions used internal in intel_pm.c */ +struct drm_i915_clock_gating_funcs { + void (*init_clock_gating)(struct drm_i915_private *dev_priv); +}; + struct drm_i915_display_funcs { void (*get_cdclk)(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config); @@ -365,7 +370,6 @@ struct drm_i915_display_funcs { const struct drm_connector_state *old_conn_state); void (*fdi_link_train)(struct intel_crtc *crtc, const struct intel_crtc_state *crtc_state); - void (*init_clock_gating)(struct drm_i915_private *dev_priv); void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); /* clock updates for mode set */ /* cursor updates */ @@ -954,6 +958,9 @@ struct drm_i915_private { /* unbound hipri wq for page flips/plane updates */ struct workqueue_struct *flip_wq; + /* pm private clock gating functions */ + struct drm_i915_clock_gating_funcs clock_gating_funcs; + /* Display functions */ struct drm_i915_display_funcs display; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 11c9df62391d..34d6faee8969 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7869,7 +7869,7 @@ static void i830_init_clock_gating(struct drm_i915_private *dev_priv) void intel_init_clock_gating(struct drm_i915_private *dev_priv) { - dev_priv->display.init_clock_gating(dev_priv); + dev_priv->clock_gating_funcs.init_clock_gating(dev_priv); } void intel_suspend_hw(struct drm_i915_private *dev_priv) @@ -7896,52 +7896,52 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv) void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) { if (IS_ALDERLAKE_P(dev_priv)) - dev_priv->display.init_clock_gating = adlp_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = adlp_init_clock_gating; else if (IS_DG1(dev_priv)) - dev_priv->display.init_clock_gating = dg1_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = dg1_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 12) - dev_priv->display.init_clock_gating = gen12lp_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = gen12lp_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 11) - dev_priv->display.init_clock_gating = icl_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = icl_init_clock_gating; else if (IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) - dev_priv->display.init_clock_gating = cfl_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = cfl_init_clock_gating; else if (IS_SKYLAKE(dev_priv)) - dev_priv->display.init_clock_gating = skl_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = skl_init_clock_gating; else if (IS_KABYLAKE(dev_priv)) - dev_priv->display.init_clock_gating = kbl_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = kbl_init_clock_gating; else if (IS_BROXTON(dev_priv)) - dev_priv->display.init_clock_gating = bxt_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = bxt_init_clock_gating; else if (IS_GEMINILAKE(dev_priv)) - dev_priv->display.init_clock_gating = glk_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = glk_init_clock_gating; else if (IS_BROADWELL(dev_priv)) - dev_priv->display.init_clock_gating = bdw_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = bdw_init_clock_gating; else if (IS_CHERRYVIEW(dev_priv)) - dev_priv->display.init_clock_gating = chv_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = chv_init_clock_gating; else if (IS_HASWELL(dev_priv)) - dev_priv->display.init_clock_gating = hsw_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = hsw_init_clock_gating; else if (IS_IVYBRIDGE(dev_priv)) - dev_priv->display.init_clock_gating = ivb_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = ivb_init_clock_gating; else if (IS_VALLEYVIEW(dev_priv)) - dev_priv->display.init_clock_gating = vlv_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = vlv_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 6) - dev_priv->display.init_clock_gating = gen6_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = gen6_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 5) - dev_priv->display.init_clock_gating = ilk_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = ilk_init_clock_gating; else if (IS_G4X(dev_priv)) - dev_priv->display.init_clock_gating = g4x_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = g4x_init_clock_gating; else if (IS_I965GM(dev_priv)) - dev_priv->display.init_clock_gating = i965gm_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = i965gm_init_clock_gating; else if (IS_I965G(dev_priv)) - dev_priv->display.init_clock_gating = i965g_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = i965g_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 3) - dev_priv->display.init_clock_gating = gen3_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = gen3_init_clock_gating; else if (IS_I85X(dev_priv) || IS_I865G(dev_priv)) - dev_priv->display.init_clock_gating = i85x_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = i85x_init_clock_gating; else if (GRAPHICS_VER(dev_priv) == 2) - dev_priv->display.init_clock_gating = i830_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = i830_init_clock_gating; else { MISSING_CASE(INTEL_DEVID(dev_priv)); - dev_priv->display.init_clock_gating = nop_init_clock_gating; + dev_priv->clock_gating_funcs.init_clock_gating = nop_init_clock_gating; } } From 27057882f62efdf110ed08282982b2d4a23382a9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:52 +0300 Subject: [PATCH 092/554] drm/i915: split watermark vfuncs from display vtable. These are the watermark api between display and pm. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/7130356324ef3de59b4e913f025d7dce822157ee.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 34 ++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 24 ++++++++---- drivers/gpu/drm/i915/intel_pm.c | 40 ++++++++++---------- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d7319d5fb4d4..6475435b8316 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -161,16 +161,16 @@ static void intel_modeset_setup_hw_state(struct drm_device *dev, */ static void intel_update_watermarks(struct drm_i915_private *dev_priv) { - if (dev_priv->display.update_wm) - dev_priv->display.update_wm(dev_priv); + if (dev_priv->wm_disp.update_wm) + dev_priv->wm_disp.update_wm(dev_priv); } static int intel_compute_pipe_wm(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->display.compute_pipe_wm) - return dev_priv->display.compute_pipe_wm(state, crtc); + if (dev_priv->wm_disp.compute_pipe_wm) + return dev_priv->wm_disp.compute_pipe_wm(state, crtc); return 0; } @@ -178,20 +178,20 @@ static int intel_compute_intermediate_wm(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (!dev_priv->display.compute_intermediate_wm) + if (!dev_priv->wm_disp.compute_intermediate_wm) return 0; if (drm_WARN_ON(&dev_priv->drm, - !dev_priv->display.compute_pipe_wm)) + !dev_priv->wm_disp.compute_pipe_wm)) return 0; - return dev_priv->display.compute_intermediate_wm(state, crtc); + return dev_priv->wm_disp.compute_intermediate_wm(state, crtc); } static bool intel_initial_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->display.initial_watermarks) { - dev_priv->display.initial_watermarks(state, crtc); + if (dev_priv->wm_disp.initial_watermarks) { + dev_priv->wm_disp.initial_watermarks(state, crtc); return true; } return false; @@ -201,23 +201,23 @@ static void intel_atomic_update_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->display.atomic_update_watermarks) - dev_priv->display.atomic_update_watermarks(state, crtc); + if (dev_priv->wm_disp.atomic_update_watermarks) + dev_priv->wm_disp.atomic_update_watermarks(state, crtc); } static void intel_optimize_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->display.optimize_watermarks) - dev_priv->display.optimize_watermarks(state, crtc); + if (dev_priv->wm_disp.optimize_watermarks) + dev_priv->wm_disp.optimize_watermarks(state, crtc); } static int intel_compute_global_watermarks(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->display.compute_global_watermarks) - return dev_priv->display.compute_global_watermarks(state); + if (dev_priv->wm_disp.compute_global_watermarks) + return dev_priv->wm_disp.compute_global_watermarks(state); return 0; } @@ -3743,7 +3743,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) != 2) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - if (!dev_priv->display.initial_watermarks) + if (!dev_priv->wm_disp.initial_watermarks) intel_update_watermarks(dev_priv); /* clock the pipe down to 640x480@60 to potentially save power */ @@ -11404,7 +11404,7 @@ static void sanitize_watermarks(struct drm_i915_private *dev_priv) int i; /* Only supported on platforms that use atomic watermark design */ - if (!dev_priv->display.optimize_watermarks) + if (!dev_priv->wm_disp.optimize_watermarks) return; state = drm_atomic_state_alloc(&dev_priv->drm); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bbb28b854f46..d1a0e110ac4f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -328,13 +328,10 @@ struct drm_i915_clock_gating_funcs { void (*init_clock_gating)(struct drm_i915_private *dev_priv); }; -struct drm_i915_display_funcs { - void (*get_cdclk)(struct drm_i915_private *dev_priv, - struct intel_cdclk_config *cdclk_config); - void (*set_cdclk)(struct drm_i915_private *dev_priv, - const struct intel_cdclk_config *cdclk_config, - enum pipe pipe); - int (*bw_calc_min_cdclk)(struct intel_atomic_state *state); +/* functions used for watermark calcs for display. */ +struct drm_i915_wm_disp_funcs { + /* update_wm is for legacy wm management */ + void (*update_wm)(struct drm_i915_private *dev_priv); int (*compute_pipe_wm)(struct intel_atomic_state *state, struct intel_crtc *crtc); int (*compute_intermediate_wm)(struct intel_atomic_state *state, @@ -346,7 +343,15 @@ struct drm_i915_display_funcs { void (*optimize_watermarks)(struct intel_atomic_state *state, struct intel_crtc *crtc); int (*compute_global_watermarks)(struct intel_atomic_state *state); - void (*update_wm)(struct drm_i915_private *dev_priv); +}; + +struct drm_i915_display_funcs { + void (*get_cdclk)(struct drm_i915_private *dev_priv, + struct intel_cdclk_config *cdclk_config); + void (*set_cdclk)(struct drm_i915_private *dev_priv, + const struct intel_cdclk_config *cdclk_config, + enum pipe pipe); + int (*bw_calc_min_cdclk)(struct intel_atomic_state *state); int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); u8 (*calc_voltage_level)(int cdclk); /* Returns the active state of the crtc, and if the crtc is active, @@ -961,6 +966,9 @@ struct drm_i915_private { /* pm private clock gating functions */ struct drm_i915_clock_gating_funcs clock_gating_funcs; + /* pm display functions */ + struct drm_i915_wm_disp_funcs wm_disp; + /* Display functions */ struct drm_i915_display_funcs display; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 34d6faee8969..b37888781ec9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7960,7 +7960,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv) /* For FIFO watermark updates */ if (DISPLAY_VER(dev_priv) >= 9) { skl_setup_wm_latency(dev_priv); - dev_priv->display.compute_global_watermarks = skl_compute_wm; + dev_priv->wm_disp.compute_global_watermarks = skl_compute_wm; } else if (HAS_PCH_SPLIT(dev_priv)) { ilk_setup_wm_latency(dev_priv); @@ -7968,12 +7968,12 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || (DISPLAY_VER(dev_priv) != 5 && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { - dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; - dev_priv->display.compute_intermediate_wm = + dev_priv->wm_disp.compute_pipe_wm = ilk_compute_pipe_wm; + dev_priv->wm_disp.compute_intermediate_wm = ilk_compute_intermediate_wm; - dev_priv->display.initial_watermarks = + dev_priv->wm_disp.initial_watermarks = ilk_initial_watermarks; - dev_priv->display.optimize_watermarks = + dev_priv->wm_disp.optimize_watermarks = ilk_optimize_watermarks; } else { drm_dbg_kms(&dev_priv->drm, @@ -7982,17 +7982,17 @@ void intel_init_pm(struct drm_i915_private *dev_priv) } } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { vlv_setup_wm_latency(dev_priv); - dev_priv->display.compute_pipe_wm = vlv_compute_pipe_wm; - dev_priv->display.compute_intermediate_wm = vlv_compute_intermediate_wm; - dev_priv->display.initial_watermarks = vlv_initial_watermarks; - dev_priv->display.optimize_watermarks = vlv_optimize_watermarks; - dev_priv->display.atomic_update_watermarks = vlv_atomic_update_fifo; + dev_priv->wm_disp.compute_pipe_wm = vlv_compute_pipe_wm; + dev_priv->wm_disp.compute_intermediate_wm = vlv_compute_intermediate_wm; + dev_priv->wm_disp.initial_watermarks = vlv_initial_watermarks; + dev_priv->wm_disp.optimize_watermarks = vlv_optimize_watermarks; + dev_priv->wm_disp.atomic_update_watermarks = vlv_atomic_update_fifo; } else if (IS_G4X(dev_priv)) { g4x_setup_wm_latency(dev_priv); - dev_priv->display.compute_pipe_wm = g4x_compute_pipe_wm; - dev_priv->display.compute_intermediate_wm = g4x_compute_intermediate_wm; - dev_priv->display.initial_watermarks = g4x_initial_watermarks; - dev_priv->display.optimize_watermarks = g4x_optimize_watermarks; + dev_priv->wm_disp.compute_pipe_wm = g4x_compute_pipe_wm; + dev_priv->wm_disp.compute_intermediate_wm = g4x_compute_intermediate_wm; + dev_priv->wm_disp.initial_watermarks = g4x_initial_watermarks; + dev_priv->wm_disp.optimize_watermarks = g4x_optimize_watermarks; } else if (IS_PINEVIEW(dev_priv)) { if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv), dev_priv->is_ddr3, @@ -8006,18 +8006,18 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->fsb_freq, dev_priv->mem_freq); /* Disable CxSR and never update its watermark again */ intel_set_memory_cxsr(dev_priv, false); - dev_priv->display.update_wm = NULL; + dev_priv->wm_disp.update_wm = NULL; } else - dev_priv->display.update_wm = pnv_update_wm; + dev_priv->wm_disp.update_wm = pnv_update_wm; } else if (DISPLAY_VER(dev_priv) == 4) { - dev_priv->display.update_wm = i965_update_wm; + dev_priv->wm_disp.update_wm = i965_update_wm; } else if (DISPLAY_VER(dev_priv) == 3) { - dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->wm_disp.update_wm = i9xx_update_wm; } else if (DISPLAY_VER(dev_priv) == 2) { if (INTEL_NUM_PIPES(dev_priv) == 1) - dev_priv->display.update_wm = i845_update_wm; + dev_priv->wm_disp.update_wm = i845_update_wm; else - dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->wm_disp.update_wm = i9xx_update_wm; } else { drm_err(&dev_priv->drm, "unexpected fall-through in %s\n", __func__); From 082800ab52d64cdb754c5d89361e737cdc44ffba Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:53 +0300 Subject: [PATCH 093/554] drm/i915: split color functions from display vtable These are only used internally in the color module Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/084a31362f1621d2f556069bb2bc47d362a63823.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 64 +++++++++++----------- drivers/gpu/drm/i915/i915_drv.h | 39 +++++++------ 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index afcb4bf3826c..ed79075158dd 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1137,14 +1137,14 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->display.load_luts(crtc_state); + dev_priv->color_funcs.load_luts(crtc_state); } void intel_color_commit(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->display.color_commit(crtc_state); + dev_priv->color_funcs.color_commit(crtc_state); } static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -1200,15 +1200,15 @@ int intel_color_check(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - return dev_priv->display.color_check(crtc_state); + return dev_priv->color_funcs.color_check(crtc_state); } void intel_color_get_config(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - if (dev_priv->display.read_luts) - dev_priv->display.read_luts(crtc_state); + if (dev_priv->color_funcs.read_luts) + dev_priv->color_funcs.read_luts(crtc_state); } static bool need_plane_update(struct intel_plane *plane, @@ -2101,51 +2101,51 @@ void intel_color_init(struct intel_crtc *crtc) if (HAS_GMCH(dev_priv)) { if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.color_check = chv_color_check; - dev_priv->display.color_commit = i9xx_color_commit; - dev_priv->display.load_luts = chv_load_luts; - dev_priv->display.read_luts = chv_read_luts; + dev_priv->color_funcs.color_check = chv_color_check; + dev_priv->color_funcs.color_commit = i9xx_color_commit; + dev_priv->color_funcs.load_luts = chv_load_luts; + dev_priv->color_funcs.read_luts = chv_read_luts; } else if (DISPLAY_VER(dev_priv) >= 4) { - dev_priv->display.color_check = i9xx_color_check; - dev_priv->display.color_commit = i9xx_color_commit; - dev_priv->display.load_luts = i965_load_luts; - dev_priv->display.read_luts = i965_read_luts; + dev_priv->color_funcs.color_check = i9xx_color_check; + dev_priv->color_funcs.color_commit = i9xx_color_commit; + dev_priv->color_funcs.load_luts = i965_load_luts; + dev_priv->color_funcs.read_luts = i965_read_luts; } else { - dev_priv->display.color_check = i9xx_color_check; - dev_priv->display.color_commit = i9xx_color_commit; - dev_priv->display.load_luts = i9xx_load_luts; - dev_priv->display.read_luts = i9xx_read_luts; + dev_priv->color_funcs.color_check = i9xx_color_check; + dev_priv->color_funcs.color_commit = i9xx_color_commit; + dev_priv->color_funcs.load_luts = i9xx_load_luts; + dev_priv->color_funcs.read_luts = i9xx_read_luts; } } else { if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->display.color_check = icl_color_check; + dev_priv->color_funcs.color_check = icl_color_check; else if (DISPLAY_VER(dev_priv) >= 10) - dev_priv->display.color_check = glk_color_check; + dev_priv->color_funcs.color_check = glk_color_check; else if (DISPLAY_VER(dev_priv) >= 7) - dev_priv->display.color_check = ivb_color_check; + dev_priv->color_funcs.color_check = ivb_color_check; else - dev_priv->display.color_check = ilk_color_check; + dev_priv->color_funcs.color_check = ilk_color_check; if (DISPLAY_VER(dev_priv) >= 9) - dev_priv->display.color_commit = skl_color_commit; + dev_priv->color_funcs.color_commit = skl_color_commit; else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) - dev_priv->display.color_commit = hsw_color_commit; + dev_priv->color_funcs.color_commit = hsw_color_commit; else - dev_priv->display.color_commit = ilk_color_commit; + dev_priv->color_funcs.color_commit = ilk_color_commit; if (DISPLAY_VER(dev_priv) >= 11) { - dev_priv->display.load_luts = icl_load_luts; - dev_priv->display.read_luts = icl_read_luts; + dev_priv->color_funcs.load_luts = icl_load_luts; + dev_priv->color_funcs.read_luts = icl_read_luts; } else if (DISPLAY_VER(dev_priv) == 10) { - dev_priv->display.load_luts = glk_load_luts; - dev_priv->display.read_luts = glk_read_luts; + dev_priv->color_funcs.load_luts = glk_load_luts; + dev_priv->color_funcs.read_luts = glk_read_luts; } else if (DISPLAY_VER(dev_priv) >= 8) { - dev_priv->display.load_luts = bdw_load_luts; + dev_priv->color_funcs.load_luts = bdw_load_luts; } else if (DISPLAY_VER(dev_priv) >= 7) { - dev_priv->display.load_luts = ivb_load_luts; + dev_priv->color_funcs.load_luts = ivb_load_luts; } else { - dev_priv->display.load_luts = ilk_load_luts; - dev_priv->display.read_luts = ilk_read_luts; + dev_priv->color_funcs.load_luts = ilk_load_luts; + dev_priv->color_funcs.read_luts = ilk_read_luts; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d1a0e110ac4f..65f5b2128708 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -345,6 +345,25 @@ struct drm_i915_wm_disp_funcs { int (*compute_global_watermarks)(struct intel_atomic_state *state); }; +struct intel_color_funcs { + int (*color_check)(struct intel_crtc_state *crtc_state); + /* + * Program double buffered color management registers during + * vblank evasion. The registers should then latch during the + * next vblank start, alongside any other double buffered registers + * involved with the same commit. + */ + void (*color_commit)(const struct intel_crtc_state *crtc_state); + /* + * Load LUTs (and other single buffered color management + * registers). Will (hopefully) be called during the vblank + * following the latching of any double buffered registers + * involved with the same commit. + */ + void (*load_luts)(const struct intel_crtc_state *crtc_state); + void (*read_luts)(struct intel_crtc_state *crtc_state); +}; + struct drm_i915_display_funcs { void (*get_cdclk)(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config); @@ -381,23 +400,6 @@ struct drm_i915_display_funcs { /* render clock increase/decrease */ /* display clock increase/decrease */ /* pll clock increase/decrease */ - - int (*color_check)(struct intel_crtc_state *crtc_state); - /* - * Program double buffered color management registers during - * vblank evasion. The registers should then latch during the - * next vblank start, alongside any other double buffered registers - * involved with the same commit. - */ - void (*color_commit)(const struct intel_crtc_state *crtc_state); - /* - * Load LUTs (and other single buffered color management - * registers). Will (hopefully) be called during the vblank - * following the latching of any double buffered registers - * involved with the same commit. - */ - void (*load_luts)(const struct intel_crtc_state *crtc_state); - void (*read_luts)(struct intel_crtc_state *crtc_state); }; @@ -972,6 +974,9 @@ struct drm_i915_private { /* Display functions */ struct drm_i915_display_funcs display; + /* Display internal color functions */ + struct intel_color_funcs color_funcs; + /* PCH chipset type */ enum intel_pch pch_type; unsigned short pch_id; From 7b75709ac8b566a386b1aa5642287ce6d4a78bd9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:54 +0300 Subject: [PATCH 094/554] drm/i915: split audio functions from display vtable These are only used internally in the audio code Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/d12257cc7685a9b52618f7da444ba1fc8848b4db.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 24 +++++++++++----------- drivers/gpu/drm/i915/i915_drv.h | 19 +++++++++++------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 4e0f96bf6158..bf96d1529775 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -848,8 +848,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; - if (dev_priv->display.audio_codec_enable) - dev_priv->display.audio_codec_enable(encoder, + if (dev_priv->audio_funcs.audio_codec_enable) + dev_priv->audio_funcs.audio_codec_enable(encoder, crtc_state, conn_state); @@ -893,8 +893,8 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, enum port port = encoder->port; enum pipe pipe = crtc->pipe; - if (dev_priv->display.audio_codec_disable) - dev_priv->display.audio_codec_disable(encoder, + if (dev_priv->audio_funcs.audio_codec_disable) + dev_priv->audio_funcs.audio_codec_disable(encoder, old_crtc_state, old_conn_state); @@ -922,17 +922,17 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, void intel_init_audio_hooks(struct drm_i915_private *dev_priv) { if (IS_G4X(dev_priv)) { - dev_priv->display.audio_codec_enable = g4x_audio_codec_enable; - dev_priv->display.audio_codec_disable = g4x_audio_codec_disable; + dev_priv->audio_funcs.audio_codec_enable = g4x_audio_codec_enable; + dev_priv->audio_funcs.audio_codec_disable = g4x_audio_codec_disable; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; - dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; + dev_priv->audio_funcs.audio_codec_enable = ilk_audio_codec_enable; + dev_priv->audio_funcs.audio_codec_disable = ilk_audio_codec_disable; } else if (IS_HASWELL(dev_priv) || DISPLAY_VER(dev_priv) >= 8) { - dev_priv->display.audio_codec_enable = hsw_audio_codec_enable; - dev_priv->display.audio_codec_disable = hsw_audio_codec_disable; + dev_priv->audio_funcs.audio_codec_enable = hsw_audio_codec_enable; + dev_priv->audio_funcs.audio_codec_disable = hsw_audio_codec_disable; } else if (HAS_PCH_SPLIT(dev_priv)) { - dev_priv->display.audio_codec_enable = ilk_audio_codec_enable; - dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; + dev_priv->audio_funcs.audio_codec_enable = ilk_audio_codec_enable; + dev_priv->audio_funcs.audio_codec_disable = ilk_audio_codec_disable; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 65f5b2128708..8f81c2bd2899 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -364,6 +364,15 @@ struct intel_color_funcs { void (*read_luts)(struct intel_crtc_state *crtc_state); }; +struct intel_audio_funcs { + void (*audio_codec_enable)(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); + void (*audio_codec_disable)(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state); +}; + struct drm_i915_display_funcs { void (*get_cdclk)(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config); @@ -386,12 +395,7 @@ struct drm_i915_display_funcs { struct intel_crtc *crtc); void (*commit_modeset_enables)(struct intel_atomic_state *state); void (*commit_modeset_disables)(struct intel_atomic_state *state); - void (*audio_codec_enable)(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state); - void (*audio_codec_disable)(struct intel_encoder *encoder, - const struct intel_crtc_state *old_crtc_state, - const struct drm_connector_state *old_conn_state); + void (*fdi_link_train)(struct intel_crtc *crtc, const struct intel_crtc_state *crtc_state); void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); @@ -977,6 +981,9 @@ struct drm_i915_private { /* Display internal color functions */ struct intel_color_funcs color_funcs; + /* Display internal audio functions */ + struct intel_audio_funcs audio_funcs; + /* PCH chipset type */ enum intel_pch pch_type; unsigned short pch_id; From 89ac34c14d7e48bf8066e35a9b4886208c06c4d8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:55 +0300 Subject: [PATCH 095/554] drm/i915: split cdclk functions from display vtable. This moves all the cdclk related functions into their own vtable. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/591b7b6a79c4ab644a161ae00b7d630b3ef16434.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 142 ++++++++++----------- drivers/gpu/drm/i915/i915_drv.h | 8 +- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index ff01fe9be35c..cf0a865df596 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -62,32 +62,32 @@ void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - dev_priv->display.get_cdclk(dev_priv, cdclk_config); + dev_priv->cdclk_funcs.get_cdclk(dev_priv, cdclk_config); } int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - return dev_priv->display.bw_calc_min_cdclk(state); + return dev_priv->cdclk_funcs.bw_calc_min_cdclk(state); } static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { - dev_priv->display.set_cdclk(dev_priv, cdclk_config, pipe); + dev_priv->cdclk_funcs.set_cdclk(dev_priv, cdclk_config, pipe); } static int intel_cdclk_modeset_calc_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_state *cdclk_config) { - return dev_priv->display.modeset_calc_cdclk(cdclk_config); + return dev_priv->cdclk_funcs.modeset_calc_cdclk(cdclk_config); } static u8 intel_cdclk_calc_voltage_level(struct drm_i915_private *dev_priv, int cdclk) { - return dev_priv->display.calc_voltage_level(cdclk); + return dev_priv->cdclk_funcs.calc_voltage_level(cdclk); } static void fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv, @@ -1963,7 +1963,7 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, if (!intel_cdclk_changed(&dev_priv->cdclk.hw, cdclk_config)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, !dev_priv->display.set_cdclk)) + if (drm_WARN_ON_ONCE(&dev_priv->drm, !dev_priv->cdclk_funcs.set_cdclk)) return; intel_dump_cdclk_config(cdclk_config, "Changing CDCLK to"); @@ -2891,119 +2891,119 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) { if (IS_DG2(dev_priv)) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; dev_priv->cdclk.table = dg2_cdclk_table; } else if (IS_ALDERLAKE_P(dev_priv)) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; /* Wa_22011320316:adl-p[a0] */ if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) dev_priv->cdclk.table = adlp_a_step_cdclk_table; else dev_priv->cdclk.table = adlp_cdclk_table; } else if (IS_ROCKETLAKE(dev_priv)) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; dev_priv->cdclk.table = rkl_cdclk_table; } else if (DISPLAY_VER(dev_priv) >= 12) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; dev_priv->cdclk.table = icl_cdclk_table; } else if (IS_JSL_EHL(dev_priv)) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = ehl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = ehl_calc_voltage_level; dev_priv->cdclk.table = icl_cdclk_table; } else if (DISPLAY_VER(dev_priv) >= 11) { - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = icl_calc_voltage_level; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = icl_calc_voltage_level; dev_priv->cdclk.table = icl_cdclk_table; } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.set_cdclk = bxt_set_cdclk; - dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->display.calc_voltage_level = bxt_calc_voltage_level; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->cdclk_funcs.calc_voltage_level = bxt_calc_voltage_level; if (IS_GEMINILAKE(dev_priv)) dev_priv->cdclk.table = glk_cdclk_table; else dev_priv->cdclk.table = bxt_cdclk_table; } else if (DISPLAY_VER(dev_priv) == 9) { - dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->display.set_cdclk = skl_set_cdclk; - dev_priv->display.modeset_calc_cdclk = skl_modeset_calc_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.set_cdclk = skl_set_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = skl_modeset_calc_cdclk; } else if (IS_BROADWELL(dev_priv)) { - dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->display.set_cdclk = bdw_set_cdclk; - dev_priv->display.modeset_calc_cdclk = bdw_modeset_calc_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.set_cdclk = bdw_set_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = bdw_modeset_calc_cdclk; } else if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->display.set_cdclk = chv_set_cdclk; - dev_priv->display.modeset_calc_cdclk = vlv_modeset_calc_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.set_cdclk = chv_set_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = vlv_modeset_calc_cdclk; } else if (IS_VALLEYVIEW(dev_priv)) { - dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->display.set_cdclk = vlv_set_cdclk; - dev_priv->display.modeset_calc_cdclk = vlv_modeset_calc_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.set_cdclk = vlv_set_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = vlv_modeset_calc_cdclk; } else { - dev_priv->display.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->display.modeset_calc_cdclk = fixed_modeset_calc_cdclk; + dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; + dev_priv->cdclk_funcs.modeset_calc_cdclk = fixed_modeset_calc_cdclk; } if (DISPLAY_VER(dev_priv) >= 10 || IS_BROXTON(dev_priv)) - dev_priv->display.get_cdclk = bxt_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = bxt_get_cdclk; else if (DISPLAY_VER(dev_priv) == 9) - dev_priv->display.get_cdclk = skl_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = skl_get_cdclk; else if (IS_BROADWELL(dev_priv)) - dev_priv->display.get_cdclk = bdw_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = bdw_get_cdclk; else if (IS_HASWELL(dev_priv)) - dev_priv->display.get_cdclk = hsw_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = hsw_get_cdclk; else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - dev_priv->display.get_cdclk = vlv_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = vlv_get_cdclk; else if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) - dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; else if (IS_IRONLAKE(dev_priv)) - dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_450mhz_get_cdclk; else if (IS_GM45(dev_priv)) - dev_priv->display.get_cdclk = gm45_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = gm45_get_cdclk; else if (IS_G45(dev_priv)) - dev_priv->display.get_cdclk = g33_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = g33_get_cdclk; else if (IS_I965GM(dev_priv)) - dev_priv->display.get_cdclk = i965gm_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = i965gm_get_cdclk; else if (IS_I965G(dev_priv)) - dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; else if (IS_PINEVIEW(dev_priv)) - dev_priv->display.get_cdclk = pnv_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = pnv_get_cdclk; else if (IS_G33(dev_priv)) - dev_priv->display.get_cdclk = g33_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = g33_get_cdclk; else if (IS_I945GM(dev_priv)) - dev_priv->display.get_cdclk = i945gm_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = i945gm_get_cdclk; else if (IS_I945G(dev_priv)) - dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; else if (IS_I915GM(dev_priv)) - dev_priv->display.get_cdclk = i915gm_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = i915gm_get_cdclk; else if (IS_I915G(dev_priv)) - dev_priv->display.get_cdclk = fixed_333mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_333mhz_get_cdclk; else if (IS_I865G(dev_priv)) - dev_priv->display.get_cdclk = fixed_266mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_266mhz_get_cdclk; else if (IS_I85X(dev_priv)) - dev_priv->display.get_cdclk = i85x_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = i85x_get_cdclk; else if (IS_I845G(dev_priv)) - dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_200mhz_get_cdclk; else if (IS_I830(dev_priv)) - dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_133mhz_get_cdclk; - if (drm_WARN(&dev_priv->drm, !dev_priv->display.get_cdclk, + if (drm_WARN(&dev_priv->drm, !dev_priv->cdclk_funcs.get_cdclk, "Unknown platform. Assuming 133 MHz CDCLK\n")) - dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk; + dev_priv->cdclk_funcs.get_cdclk = fixed_133mhz_get_cdclk; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8f81c2bd2899..6da19391ea0d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -373,7 +373,7 @@ struct intel_audio_funcs { const struct drm_connector_state *old_conn_state); }; -struct drm_i915_display_funcs { +struct intel_cdclk_funcs { void (*get_cdclk)(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config); void (*set_cdclk)(struct drm_i915_private *dev_priv, @@ -382,6 +382,9 @@ struct drm_i915_display_funcs { int (*bw_calc_min_cdclk)(struct intel_atomic_state *state); int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); u8 (*calc_voltage_level)(int cdclk); +}; + +struct drm_i915_display_funcs { /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, @@ -984,6 +987,9 @@ struct drm_i915_private { /* Display internal audio functions */ struct intel_audio_funcs audio_funcs; + /* Display CDCLK functions */ + struct intel_cdclk_funcs cdclk_funcs; + /* PCH chipset type */ enum intel_pch pch_type; unsigned short pch_id; From de1677c5e32ace87ca69861dc32115e824af3278 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:56 +0300 Subject: [PATCH 096/554] drm/i915: split irq hotplug function from display vtable This provide a service from irq to display, so make it separate Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/05f533064709764dff8bcfef6a58f9a8482dc5bb.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hotplug.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 9 ++++++++- drivers/gpu/drm/i915/i915_irq.c | 14 +++++++------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 47c85ac97c87..05f76aba4f8a 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -215,8 +215,8 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) static void intel_hpd_irq_setup(struct drm_i915_private *i915) { - if (i915->display_irqs_enabled && i915->display.hpd_irq_setup) - i915->display.hpd_irq_setup(i915); + if (i915->display_irqs_enabled && i915->hotplug_funcs.hpd_irq_setup) + i915->hotplug_funcs.hpd_irq_setup(i915); } static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6da19391ea0d..58db1e2789e2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -384,6 +384,10 @@ struct intel_cdclk_funcs { u8 (*calc_voltage_level)(int cdclk); }; +struct intel_hotplug_funcs { + void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); +}; + struct drm_i915_display_funcs { /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ @@ -401,7 +405,7 @@ struct drm_i915_display_funcs { void (*fdi_link_train)(struct intel_crtc *crtc, const struct intel_crtc_state *crtc_state); - void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); + /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -978,6 +982,9 @@ struct drm_i915_private { /* pm display functions */ struct drm_i915_wm_disp_funcs wm_disp; + /* irq display functions */ + struct intel_hotplug_funcs hotplug_funcs; + /* Display functions */ struct drm_i915_display_funcs display; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0a1681384c84..c35065f8f429 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4395,20 +4395,20 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (HAS_GMCH(dev_priv)) { if (I915_HAS_HOTPLUG(dev_priv)) - dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = i915_hpd_irq_setup; } else { if (HAS_PCH_DG1(dev_priv)) - dev_priv->display.hpd_irq_setup = dg1_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = dg1_hpd_irq_setup; else if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = gen11_hpd_irq_setup; else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = bxt_hpd_irq_setup; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - dev_priv->display.hpd_irq_setup = icp_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = icp_hpd_irq_setup; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = spt_hpd_irq_setup; else - dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; + dev_priv->hotplug_funcs.hpd_irq_setup = ilk_hpd_irq_setup; } } From 5c8c179bcaf6dbbc3381ae8afbb6dc5978d4f234 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:57 +0300 Subject: [PATCH 097/554] drm/i915: split fdi link training from display vtable. It may make sense to merge this with display again later, however the fdi use of the vtable is limited to only a few generations. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/7af7359b6cec33bd2d32152893d9a1e8f8cf7f21.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_fdi.c | 8 ++++---- drivers/gpu/drm/i915/i915_drv.h | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index d20669e53663..f828bebe8962 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -15,7 +15,7 @@ void intel_fdi_link_train(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - dev_priv->display.fdi_link_train(crtc, crtc_state); + dev_priv->fdi_funcs.fdi_link_train(crtc, crtc_state); } /* units of 100MHz */ @@ -1017,11 +1017,11 @@ void intel_fdi_init_hook(struct drm_i915_private *dev_priv) { if (IS_IRONLAKE(dev_priv)) { - dev_priv->display.fdi_link_train = ilk_fdi_link_train; + dev_priv->fdi_funcs.fdi_link_train = ilk_fdi_link_train; } else if (IS_SANDYBRIDGE(dev_priv)) { - dev_priv->display.fdi_link_train = gen6_fdi_link_train; + dev_priv->fdi_funcs.fdi_link_train = gen6_fdi_link_train; } else if (IS_IVYBRIDGE(dev_priv)) { /* FIXME: detect B0+ stepping and use auto training */ - dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; + dev_priv->fdi_funcs.fdi_link_train = ivb_manual_fdi_link_train; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 58db1e2789e2..c51142ffef54 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -388,6 +388,11 @@ struct intel_hotplug_funcs { void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); }; +struct intel_fdi_funcs { + void (*fdi_link_train)(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state); +}; + struct drm_i915_display_funcs { /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ @@ -403,9 +408,6 @@ struct drm_i915_display_funcs { void (*commit_modeset_enables)(struct intel_atomic_state *state); void (*commit_modeset_disables)(struct intel_atomic_state *state); - void (*fdi_link_train)(struct intel_crtc *crtc, - const struct intel_crtc_state *crtc_state); - /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -985,6 +987,9 @@ struct drm_i915_private { /* irq display functions */ struct intel_hotplug_funcs hotplug_funcs; + /* fdi display functions */ + struct intel_fdi_funcs fdi_funcs; + /* Display functions */ struct drm_i915_display_funcs display; From 903f3806f3e83b6590a7ed6846fb206ec505457f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:58 +0300 Subject: [PATCH 098/554] drm/i915: split the dpll clock compute out from display vtable. this single function might be possible to merge later, but for now it's simple to just split it out. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/ba570aa10b694b2e8640e0c58430fd0053c306b7.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 6 +++--- drivers/gpu/drm/i915/display/intel_dpll.c | 16 ++++++++-------- drivers/gpu/drm/i915/i915_drv.h | 8 +++++++- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 6475435b8316..146281bfec59 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6833,10 +6833,10 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, crtc_state->update_wm_post = true; if (mode_changed && crtc_state->hw.enable && - dev_priv->display.crtc_compute_clock && + dev_priv->dpll_funcs.crtc_compute_clock && !crtc_state->bigjoiner_slave && !drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) { - ret = dev_priv->display.crtc_compute_clock(crtc_state); + ret = dev_priv->dpll_funcs.crtc_compute_clock(crtc_state); if (ret) return ret; } @@ -8863,7 +8863,7 @@ static void intel_modeset_clear_plls(struct intel_atomic_state *state) struct intel_crtc *crtc; int i; - if (!dev_priv->display.crtc_compute_clock) + if (!dev_priv->dpll_funcs.crtc_compute_clock) return; for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 487d8721ecf8..7811f19acb6a 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1369,21 +1369,21 @@ void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) { if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv)) - dev_priv->display.crtc_compute_clock = hsw_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = hsw_crtc_compute_clock; else if (HAS_PCH_SPLIT(dev_priv)) - dev_priv->display.crtc_compute_clock = ilk_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = ilk_crtc_compute_clock; else if (IS_CHERRYVIEW(dev_priv)) - dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = chv_crtc_compute_clock; else if (IS_VALLEYVIEW(dev_priv)) - dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = vlv_crtc_compute_clock; else if (IS_G4X(dev_priv)) - dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = g4x_crtc_compute_clock; else if (IS_PINEVIEW(dev_priv)) - dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = pnv_crtc_compute_clock; else if (DISPLAY_VER(dev_priv) != 2) - dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = i9xx_crtc_compute_clock; else - dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock; + dev_priv->dpll_funcs.crtc_compute_clock = i8xx_crtc_compute_clock; } static bool i9xx_has_pps(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c51142ffef54..ed2d8b61fe4d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -393,6 +393,10 @@ struct intel_fdi_funcs { const struct intel_crtc_state *crtc_state); }; +struct intel_dpll_funcs { + int (*crtc_compute_clock)(struct intel_crtc_state *crtc_state); +}; + struct drm_i915_display_funcs { /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ @@ -400,7 +404,6 @@ struct drm_i915_display_funcs { struct intel_crtc_state *); void (*get_initial_plane_config)(struct intel_crtc *, struct intel_initial_plane_config *); - int (*crtc_compute_clock)(struct intel_crtc_state *crtc_state); void (*crtc_enable)(struct intel_atomic_state *state, struct intel_crtc *crtc); void (*crtc_disable)(struct intel_atomic_state *state, @@ -990,6 +993,9 @@ struct drm_i915_private { /* fdi display functions */ struct intel_fdi_funcs fdi_funcs; + /* display pll funcs */ + struct intel_dpll_funcs dpll_funcs; + /* Display functions */ struct drm_i915_display_funcs display; From 1c55b1e063d0ecd466a6163c37af528bd0ab3f2b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:57:59 +0300 Subject: [PATCH 099/554] drm/i915: constify fdi link training vtable Put the vtable into ro memory. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/ec4687956f9b98024fea55b2f0ed1e192e244ff1.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_fdi.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index f828bebe8962..af01d1fa761e 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -15,7 +15,7 @@ void intel_fdi_link_train(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - dev_priv->fdi_funcs.fdi_link_train(crtc, crtc_state); + dev_priv->fdi_funcs->fdi_link_train(crtc, crtc_state); } /* units of 100MHz */ @@ -1013,15 +1013,27 @@ void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv) intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY); } +static const struct intel_fdi_funcs ilk_funcs = { + .fdi_link_train = ilk_fdi_link_train, +}; + +static const struct intel_fdi_funcs gen6_funcs = { + .fdi_link_train = gen6_fdi_link_train, +}; + +static const struct intel_fdi_funcs ivb_funcs = { + .fdi_link_train = ivb_manual_fdi_link_train, +}; + void intel_fdi_init_hook(struct drm_i915_private *dev_priv) { if (IS_IRONLAKE(dev_priv)) { - dev_priv->fdi_funcs.fdi_link_train = ilk_fdi_link_train; + dev_priv->fdi_funcs = &ilk_funcs; } else if (IS_SANDYBRIDGE(dev_priv)) { - dev_priv->fdi_funcs.fdi_link_train = gen6_fdi_link_train; + dev_priv->fdi_funcs = &gen6_funcs; } else if (IS_IVYBRIDGE(dev_priv)) { /* FIXME: detect B0+ stepping and use auto training */ - dev_priv->fdi_funcs.fdi_link_train = ivb_manual_fdi_link_train; + dev_priv->fdi_funcs = &ivb_funcs; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ed2d8b61fe4d..e01fe2199e23 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -991,7 +991,7 @@ struct drm_i915_private { struct intel_hotplug_funcs hotplug_funcs; /* fdi display functions */ - struct intel_fdi_funcs fdi_funcs; + const struct intel_fdi_funcs *fdi_funcs; /* display pll funcs */ struct intel_dpll_funcs dpll_funcs; From cd030c7c11a4afbcc99da4af535d4336e5540767 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:00 +0300 Subject: [PATCH 100/554] drm/i915: constify hotplug function vtable. Use a macro to avoid mistakes, this type of macro is only used in a couple of places. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/af229c1e8ec894f177b344ab77b90e32c33428de.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hotplug.c | 4 +-- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 28 +++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 05f76aba4f8a..3c1cec953b42 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -215,8 +215,8 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) static void intel_hpd_irq_setup(struct drm_i915_private *i915) { - if (i915->display_irqs_enabled && i915->hotplug_funcs.hpd_irq_setup) - i915->hotplug_funcs.hpd_irq_setup(i915); + if (i915->display_irqs_enabled && i915->hotplug_funcs->hpd_irq_setup) + i915->hotplug_funcs->hpd_irq_setup(i915); } static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e01fe2199e23..6dcd5153d756 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -988,7 +988,7 @@ struct drm_i915_private { struct drm_i915_wm_disp_funcs wm_disp; /* irq display functions */ - struct intel_hotplug_funcs hotplug_funcs; + const struct intel_hotplug_funcs *hotplug_funcs; /* fdi display functions */ const struct intel_fdi_funcs *fdi_funcs; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c35065f8f429..77680bca46ee 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4345,6 +4345,20 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) return ret; } +#define HPD_FUNCS(platform) \ +static const struct intel_hotplug_funcs platform##_hpd_funcs = { \ + .hpd_irq_setup = platform##_hpd_irq_setup, \ +} + +HPD_FUNCS(i915); +HPD_FUNCS(dg1); +HPD_FUNCS(gen11); +HPD_FUNCS(bxt); +HPD_FUNCS(icp); +HPD_FUNCS(spt); +HPD_FUNCS(ilk); +#undef HPD_FUNCS + /** * intel_irq_init - initializes irq support * @dev_priv: i915 device instance @@ -4395,20 +4409,20 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (HAS_GMCH(dev_priv)) { if (I915_HAS_HOTPLUG(dev_priv)) - dev_priv->hotplug_funcs.hpd_irq_setup = i915_hpd_irq_setup; + dev_priv->hotplug_funcs = &i915_hpd_funcs; } else { if (HAS_PCH_DG1(dev_priv)) - dev_priv->hotplug_funcs.hpd_irq_setup = dg1_hpd_irq_setup; + dev_priv->hotplug_funcs = &dg1_hpd_funcs; else if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->hotplug_funcs.hpd_irq_setup = gen11_hpd_irq_setup; + dev_priv->hotplug_funcs = &gen11_hpd_funcs; else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - dev_priv->hotplug_funcs.hpd_irq_setup = bxt_hpd_irq_setup; + dev_priv->hotplug_funcs = &bxt_hpd_funcs; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - dev_priv->hotplug_funcs.hpd_irq_setup = icp_hpd_irq_setup; + dev_priv->hotplug_funcs = &icp_hpd_funcs; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) - dev_priv->hotplug_funcs.hpd_irq_setup = spt_hpd_irq_setup; + dev_priv->hotplug_funcs = &spt_hpd_funcs; else - dev_priv->hotplug_funcs.hpd_irq_setup = ilk_hpd_irq_setup; + dev_priv->hotplug_funcs = &ilk_hpd_funcs; } } From c6d27046552e830e64cefb2539dec789186833ec Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:01 +0300 Subject: [PATCH 101/554] drm/i915: constify color function vtable. This clarifies quite well what functions get used on what platforms instead of having to decipher the old tree. v2: fixed IVB mistake (Jani) Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/49e46e61206d4fdcf08fb5dc1978da3fce702134.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 138 ++++++++++++++------- drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 93 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index ed79075158dd..f5923f1c38bd 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1137,14 +1137,14 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->color_funcs.load_luts(crtc_state); + dev_priv->color_funcs->load_luts(crtc_state); } void intel_color_commit(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->color_funcs.color_commit(crtc_state); + dev_priv->color_funcs->color_commit(crtc_state); } static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -1200,15 +1200,15 @@ int intel_color_check(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - return dev_priv->color_funcs.color_check(crtc_state); + return dev_priv->color_funcs->color_check(crtc_state); } void intel_color_get_config(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - if (dev_priv->color_funcs.read_luts) - dev_priv->color_funcs.read_luts(crtc_state); + if (dev_priv->color_funcs->read_luts) + dev_priv->color_funcs->read_luts(crtc_state); } static bool need_plane_update(struct intel_plane *plane, @@ -2092,6 +2092,76 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state) } } +static const struct intel_color_funcs chv_color_funcs = { + .color_check = chv_color_check, + .color_commit = i9xx_color_commit, + .load_luts = chv_load_luts, + .read_luts = chv_read_luts, +}; + +static const struct intel_color_funcs i965_color_funcs = { + .color_check = i9xx_color_check, + .color_commit = i9xx_color_commit, + .load_luts = i965_load_luts, + .read_luts = i965_read_luts, +}; + +static const struct intel_color_funcs i9xx_color_funcs = { + .color_check = i9xx_color_check, + .color_commit = i9xx_color_commit, + .load_luts = i9xx_load_luts, + .read_luts = i9xx_read_luts, +}; + +static const struct intel_color_funcs icl_color_funcs = { + .color_check = icl_color_check, + .color_commit = skl_color_commit, + .load_luts = icl_load_luts, + .read_luts = icl_read_luts, +}; + +static const struct intel_color_funcs glk_color_funcs = { + .color_check = glk_color_check, + .color_commit = skl_color_commit, + .load_luts = glk_load_luts, + .read_luts = glk_read_luts, +}; + +static const struct intel_color_funcs skl_color_funcs = { + .color_check = ivb_color_check, + .color_commit = skl_color_commit, + .load_luts = bdw_load_luts, + .read_luts = NULL, +}; + +static const struct intel_color_funcs bdw_color_funcs = { + .color_check = ivb_color_check, + .color_commit = hsw_color_commit, + .load_luts = bdw_load_luts, + .read_luts = NULL, +}; + +static const struct intel_color_funcs hsw_color_funcs = { + .color_check = ivb_color_check, + .color_commit = hsw_color_commit, + .load_luts = ivb_load_luts, + .read_luts = NULL, +}; + +static const struct intel_color_funcs ivb_color_funcs = { + .color_check = ivb_color_check, + .color_commit = ilk_color_commit, + .load_luts = ivb_load_luts, + .read_luts = NULL, +}; + +static const struct intel_color_funcs ilk_color_funcs = { + .color_check = ilk_color_check, + .color_commit = ilk_color_commit, + .load_luts = ilk_load_luts, + .read_luts = ilk_read_luts, +}; + void intel_color_init(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -2101,52 +2171,28 @@ void intel_color_init(struct intel_crtc *crtc) if (HAS_GMCH(dev_priv)) { if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->color_funcs.color_check = chv_color_check; - dev_priv->color_funcs.color_commit = i9xx_color_commit; - dev_priv->color_funcs.load_luts = chv_load_luts; - dev_priv->color_funcs.read_luts = chv_read_luts; + dev_priv->color_funcs = &chv_color_funcs; } else if (DISPLAY_VER(dev_priv) >= 4) { - dev_priv->color_funcs.color_check = i9xx_color_check; - dev_priv->color_funcs.color_commit = i9xx_color_commit; - dev_priv->color_funcs.load_luts = i965_load_luts; - dev_priv->color_funcs.read_luts = i965_read_luts; + dev_priv->color_funcs = &i965_color_funcs; } else { - dev_priv->color_funcs.color_check = i9xx_color_check; - dev_priv->color_funcs.color_commit = i9xx_color_commit; - dev_priv->color_funcs.load_luts = i9xx_load_luts; - dev_priv->color_funcs.read_luts = i9xx_read_luts; + dev_priv->color_funcs = &i9xx_color_funcs; } } else { if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->color_funcs.color_check = icl_color_check; - else if (DISPLAY_VER(dev_priv) >= 10) - dev_priv->color_funcs.color_check = glk_color_check; - else if (DISPLAY_VER(dev_priv) >= 7) - dev_priv->color_funcs.color_check = ivb_color_check; - else - dev_priv->color_funcs.color_check = ilk_color_check; - - if (DISPLAY_VER(dev_priv) >= 9) - dev_priv->color_funcs.color_commit = skl_color_commit; - else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) - dev_priv->color_funcs.color_commit = hsw_color_commit; - else - dev_priv->color_funcs.color_commit = ilk_color_commit; - - if (DISPLAY_VER(dev_priv) >= 11) { - dev_priv->color_funcs.load_luts = icl_load_luts; - dev_priv->color_funcs.read_luts = icl_read_luts; - } else if (DISPLAY_VER(dev_priv) == 10) { - dev_priv->color_funcs.load_luts = glk_load_luts; - dev_priv->color_funcs.read_luts = glk_read_luts; - } else if (DISPLAY_VER(dev_priv) >= 8) { - dev_priv->color_funcs.load_luts = bdw_load_luts; - } else if (DISPLAY_VER(dev_priv) >= 7) { - dev_priv->color_funcs.load_luts = ivb_load_luts; - } else { - dev_priv->color_funcs.load_luts = ilk_load_luts; - dev_priv->color_funcs.read_luts = ilk_read_luts; - } + dev_priv->color_funcs = &icl_color_funcs; + else if (DISPLAY_VER(dev_priv) == 10) + dev_priv->color_funcs = &glk_color_funcs; + else if (DISPLAY_VER(dev_priv) == 9) + dev_priv->color_funcs = &skl_color_funcs; + else if (DISPLAY_VER(dev_priv) == 8) + dev_priv->color_funcs = &bdw_color_funcs; + else if (DISPLAY_VER(dev_priv) == 7) { + if (IS_HASWELL(dev_priv)) + dev_priv->color_funcs = &hsw_color_funcs; + else + dev_priv->color_funcs = &ivb_color_funcs; + } else + dev_priv->color_funcs = &ilk_color_funcs; } drm_crtc_enable_color_mgmt(&crtc->base, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6dcd5153d756..996855d498ec 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1000,7 +1000,7 @@ struct drm_i915_private { struct drm_i915_display_funcs display; /* Display internal color functions */ - struct intel_color_funcs color_funcs; + const struct intel_color_funcs *color_funcs; /* Display internal audio functions */ struct intel_audio_funcs audio_funcs; From 0a108bca94a8280ddfe2a87ad6b4173db6f0a454 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:02 +0300 Subject: [PATCH 102/554] drm/i915: constify the audio function vtable Move the functions into read-only tables. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/5a481307a5daab40a506c3b9a64b0b37e01a1a41.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 43 ++++++++++++++-------- drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index bf96d1529775..03e8c05a74f6 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -848,10 +848,10 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; - if (dev_priv->audio_funcs.audio_codec_enable) - dev_priv->audio_funcs.audio_codec_enable(encoder, - crtc_state, - conn_state); + if (dev_priv->audio_funcs) + dev_priv->audio_funcs->audio_codec_enable(encoder, + crtc_state, + conn_state); mutex_lock(&dev_priv->av_mutex); encoder->audio_connector = connector; @@ -893,10 +893,10 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, enum port port = encoder->port; enum pipe pipe = crtc->pipe; - if (dev_priv->audio_funcs.audio_codec_disable) - dev_priv->audio_funcs.audio_codec_disable(encoder, - old_crtc_state, - old_conn_state); + if (dev_priv->audio_funcs) + dev_priv->audio_funcs->audio_codec_disable(encoder, + old_crtc_state, + old_conn_state); mutex_lock(&dev_priv->av_mutex); encoder->audio_connector = NULL; @@ -915,6 +915,21 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, intel_lpe_audio_notify(dev_priv, pipe, port, NULL, 0, false); } +static const struct intel_audio_funcs g4x_audio_funcs = { + .audio_codec_enable = g4x_audio_codec_enable, + .audio_codec_disable = g4x_audio_codec_disable, +}; + +static const struct intel_audio_funcs ilk_audio_funcs = { + .audio_codec_enable = ilk_audio_codec_enable, + .audio_codec_disable = ilk_audio_codec_disable, +}; + +static const struct intel_audio_funcs hsw_audio_funcs = { + .audio_codec_enable = hsw_audio_codec_enable, + .audio_codec_disable = hsw_audio_codec_disable, +}; + /** * intel_init_audio_hooks - Set up chip specific audio hooks * @dev_priv: device private @@ -922,17 +937,13 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, void intel_init_audio_hooks(struct drm_i915_private *dev_priv) { if (IS_G4X(dev_priv)) { - dev_priv->audio_funcs.audio_codec_enable = g4x_audio_codec_enable; - dev_priv->audio_funcs.audio_codec_disable = g4x_audio_codec_disable; + dev_priv->audio_funcs = &g4x_audio_funcs; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - dev_priv->audio_funcs.audio_codec_enable = ilk_audio_codec_enable; - dev_priv->audio_funcs.audio_codec_disable = ilk_audio_codec_disable; + dev_priv->audio_funcs = &ilk_audio_funcs; } else if (IS_HASWELL(dev_priv) || DISPLAY_VER(dev_priv) >= 8) { - dev_priv->audio_funcs.audio_codec_enable = hsw_audio_codec_enable; - dev_priv->audio_funcs.audio_codec_disable = hsw_audio_codec_disable; + dev_priv->audio_funcs = &hsw_audio_funcs; } else if (HAS_PCH_SPLIT(dev_priv)) { - dev_priv->audio_funcs.audio_codec_enable = ilk_audio_codec_enable; - dev_priv->audio_funcs.audio_codec_disable = ilk_audio_codec_disable; + dev_priv->audio_funcs = &ilk_audio_funcs; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 996855d498ec..c3ec5271869e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1003,7 +1003,7 @@ struct drm_i915_private { const struct intel_color_funcs *color_funcs; /* Display internal audio functions */ - struct intel_audio_funcs audio_funcs; + const struct intel_audio_funcs *audio_funcs; /* Display CDCLK functions */ struct intel_cdclk_funcs cdclk_funcs; From a73477f8813cc9feedb7227cb9a382ef35212100 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:03 +0300 Subject: [PATCH 103/554] drm/i915: constify the dpll clock vtable Most the dpll vtable into read-only memory. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/0414a27317de3f335a8453a29486b746aa6862e7.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 6 +-- drivers/gpu/drm/i915/display/intel_dpll.c | 48 ++++++++++++++++---- drivers/gpu/drm/i915/i915_drv.h | 2 +- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 146281bfec59..9c72f1c5e96f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6833,10 +6833,10 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, crtc_state->update_wm_post = true; if (mode_changed && crtc_state->hw.enable && - dev_priv->dpll_funcs.crtc_compute_clock && + dev_priv->dpll_funcs && !crtc_state->bigjoiner_slave && !drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll)) { - ret = dev_priv->dpll_funcs.crtc_compute_clock(crtc_state); + ret = dev_priv->dpll_funcs->crtc_compute_clock(crtc_state); if (ret) return ret; } @@ -8863,7 +8863,7 @@ static void intel_modeset_clear_plls(struct intel_atomic_state *state) struct intel_crtc *crtc; int i; - if (!dev_priv->dpll_funcs.crtc_compute_clock) + if (!dev_priv->dpll_funcs) return; for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 7811f19acb6a..784e3ee658b5 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1365,25 +1365,57 @@ static int i8xx_crtc_compute_clock(struct intel_crtc_state *crtc_state) return 0; } +static const struct intel_dpll_funcs hsw_dpll_funcs = { + .crtc_compute_clock = hsw_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs ilk_dpll_funcs = { + .crtc_compute_clock = ilk_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs chv_dpll_funcs = { + .crtc_compute_clock = chv_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs vlv_dpll_funcs = { + .crtc_compute_clock = vlv_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs g4x_dpll_funcs = { + .crtc_compute_clock = g4x_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs pnv_dpll_funcs = { + .crtc_compute_clock = pnv_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs i9xx_dpll_funcs = { + .crtc_compute_clock = i9xx_crtc_compute_clock, +}; + +static const struct intel_dpll_funcs i8xx_dpll_funcs = { + .crtc_compute_clock = i8xx_crtc_compute_clock, +}; + void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) { if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = hsw_crtc_compute_clock; + dev_priv->dpll_funcs = &hsw_dpll_funcs; else if (HAS_PCH_SPLIT(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = ilk_crtc_compute_clock; + dev_priv->dpll_funcs = &ilk_dpll_funcs; else if (IS_CHERRYVIEW(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = chv_crtc_compute_clock; + dev_priv->dpll_funcs = &chv_dpll_funcs; else if (IS_VALLEYVIEW(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = vlv_crtc_compute_clock; + dev_priv->dpll_funcs = &vlv_dpll_funcs; else if (IS_G4X(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = g4x_crtc_compute_clock; + dev_priv->dpll_funcs = &g4x_dpll_funcs; else if (IS_PINEVIEW(dev_priv)) - dev_priv->dpll_funcs.crtc_compute_clock = pnv_crtc_compute_clock; + dev_priv->dpll_funcs = &pnv_dpll_funcs; else if (DISPLAY_VER(dev_priv) != 2) - dev_priv->dpll_funcs.crtc_compute_clock = i9xx_crtc_compute_clock; + dev_priv->dpll_funcs = &i9xx_dpll_funcs; else - dev_priv->dpll_funcs.crtc_compute_clock = i8xx_crtc_compute_clock; + dev_priv->dpll_funcs = &i8xx_dpll_funcs; } static bool i9xx_has_pps(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c3ec5271869e..cb72e2fe5417 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -994,7 +994,7 @@ struct drm_i915_private { const struct intel_fdi_funcs *fdi_funcs; /* display pll funcs */ - struct intel_dpll_funcs dpll_funcs; + const struct intel_dpll_funcs *dpll_funcs; /* Display functions */ struct drm_i915_display_funcs display; From 6b4cd9cba6208bd879e05ad7171f95bf9389bc98 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:04 +0300 Subject: [PATCH 104/554] drm/i915: constify the cdclk vtable This is a bit of a twisty one since each platform is slightly different, so might take some more review care. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/75e0139b28cca9ceff77de72c3ef737c101255ba.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 300 ++++++++++++++------- drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 206 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index cf0a865df596..ecb28e8f1eb6 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -62,32 +62,32 @@ void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - dev_priv->cdclk_funcs.get_cdclk(dev_priv, cdclk_config); + dev_priv->cdclk_funcs->get_cdclk(dev_priv, cdclk_config); } int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - return dev_priv->cdclk_funcs.bw_calc_min_cdclk(state); + return dev_priv->cdclk_funcs->bw_calc_min_cdclk(state); } static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { - dev_priv->cdclk_funcs.set_cdclk(dev_priv, cdclk_config, pipe); + dev_priv->cdclk_funcs->set_cdclk(dev_priv, cdclk_config, pipe); } static int intel_cdclk_modeset_calc_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_state *cdclk_config) { - return dev_priv->cdclk_funcs.modeset_calc_cdclk(cdclk_config); + return dev_priv->cdclk_funcs->modeset_calc_cdclk(cdclk_config); } static u8 intel_cdclk_calc_voltage_level(struct drm_i915_private *dev_priv, int cdclk) { - return dev_priv->cdclk_funcs.calc_voltage_level(cdclk); + return dev_priv->cdclk_funcs->calc_voltage_level(cdclk); } static void fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv, @@ -1963,7 +1963,7 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, if (!intel_cdclk_changed(&dev_priv->cdclk.hw, cdclk_config)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, !dev_priv->cdclk_funcs.set_cdclk)) + if (drm_WARN_ON_ONCE(&dev_priv->drm, !dev_priv->cdclk_funcs->set_cdclk)) return; intel_dump_cdclk_config(cdclk_config, "Changing CDCLK to"); @@ -2884,6 +2884,157 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) return freq; } +static struct intel_cdclk_funcs tgl_cdclk_funcs = { + .get_cdclk = bxt_get_cdclk, + .set_cdclk = bxt_set_cdclk, + .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, + .modeset_calc_cdclk = bxt_modeset_calc_cdclk, + .calc_voltage_level = tgl_calc_voltage_level, +}; + +static struct intel_cdclk_funcs ehl_cdclk_funcs = { + .get_cdclk = bxt_get_cdclk, + .set_cdclk = bxt_set_cdclk, + .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, + .modeset_calc_cdclk = bxt_modeset_calc_cdclk, + .calc_voltage_level = ehl_calc_voltage_level, +}; + +static struct intel_cdclk_funcs icl_cdclk_funcs = { + .get_cdclk = bxt_get_cdclk, + .set_cdclk = bxt_set_cdclk, + .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, + .modeset_calc_cdclk = bxt_modeset_calc_cdclk, + .calc_voltage_level = icl_calc_voltage_level, +}; + +static struct intel_cdclk_funcs bxt_cdclk_funcs = { + .get_cdclk = bxt_get_cdclk, + .set_cdclk = bxt_set_cdclk, + .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, + .modeset_calc_cdclk = bxt_modeset_calc_cdclk, + .calc_voltage_level = bxt_calc_voltage_level, +}; + +static struct intel_cdclk_funcs skl_cdclk_funcs = { + .get_cdclk = skl_get_cdclk, + .set_cdclk = skl_set_cdclk, + .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, + .modeset_calc_cdclk = skl_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs bdw_cdclk_funcs = { + .get_cdclk = bdw_get_cdclk, + .set_cdclk = bdw_set_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = bdw_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs chv_cdclk_funcs = { + .get_cdclk = vlv_get_cdclk, + .set_cdclk = chv_set_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = vlv_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs vlv_cdclk_funcs = { + .get_cdclk = vlv_get_cdclk, + .set_cdclk = vlv_set_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = vlv_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs hsw_cdclk_funcs = { + .get_cdclk = hsw_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +/* SNB, IVB, 965G, 945G */ +static struct intel_cdclk_funcs fixed_400mhz_cdclk_funcs = { + .get_cdclk = fixed_400mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs ilk_cdclk_funcs = { + .get_cdclk = fixed_450mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs gm45_cdclk_funcs = { + .get_cdclk = gm45_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +/* G45 uses G33 */ + +static struct intel_cdclk_funcs i965gm_cdclk_funcs = { + .get_cdclk = i965gm_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +/* i965G uses fixed 400 */ + +static struct intel_cdclk_funcs pnv_cdclk_funcs = { + .get_cdclk = pnv_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs g33_cdclk_funcs = { + .get_cdclk = g33_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i945gm_cdclk_funcs = { + .get_cdclk = i945gm_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +/* i945G uses fixed 400 */ + +static struct intel_cdclk_funcs i915gm_cdclk_funcs = { + .get_cdclk = i915gm_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i915g_cdclk_funcs = { + .get_cdclk = fixed_333mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i865g_cdclk_funcs = { + .get_cdclk = fixed_266mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i85x_cdclk_funcs = { + .get_cdclk = i85x_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i845g_cdclk_funcs = { + .get_cdclk = fixed_200mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + +static struct intel_cdclk_funcs i830_cdclk_funcs = { + .get_cdclk = fixed_133mhz_get_cdclk, + .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, + .modeset_calc_cdclk = fixed_modeset_calc_cdclk, +}; + /** * intel_init_cdclk_hooks - Initialize CDCLK related modesetting hooks * @dev_priv: i915 device @@ -2891,119 +3042,78 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) { if (IS_DG2(dev_priv)) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs = &tgl_cdclk_funcs; dev_priv->cdclk.table = dg2_cdclk_table; } else if (IS_ALDERLAKE_P(dev_priv)) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs = &tgl_cdclk_funcs; /* Wa_22011320316:adl-p[a0] */ if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) dev_priv->cdclk.table = adlp_a_step_cdclk_table; else dev_priv->cdclk.table = adlp_cdclk_table; } else if (IS_ROCKETLAKE(dev_priv)) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs = &tgl_cdclk_funcs; dev_priv->cdclk.table = rkl_cdclk_table; } else if (DISPLAY_VER(dev_priv) >= 12) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = tgl_calc_voltage_level; + dev_priv->cdclk_funcs = &tgl_cdclk_funcs; dev_priv->cdclk.table = icl_cdclk_table; } else if (IS_JSL_EHL(dev_priv)) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = ehl_calc_voltage_level; + dev_priv->cdclk_funcs = &ehl_cdclk_funcs; dev_priv->cdclk.table = icl_cdclk_table; } else if (DISPLAY_VER(dev_priv) >= 11) { - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = icl_calc_voltage_level; + dev_priv->cdclk_funcs = &icl_cdclk_funcs; dev_priv->cdclk.table = icl_cdclk_table; } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.set_cdclk = bxt_set_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bxt_modeset_calc_cdclk; - dev_priv->cdclk_funcs.calc_voltage_level = bxt_calc_voltage_level; + dev_priv->cdclk_funcs = &bxt_cdclk_funcs; if (IS_GEMINILAKE(dev_priv)) dev_priv->cdclk.table = glk_cdclk_table; else dev_priv->cdclk.table = bxt_cdclk_table; } else if (DISPLAY_VER(dev_priv) == 9) { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.set_cdclk = skl_set_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = skl_modeset_calc_cdclk; + dev_priv->cdclk_funcs = &skl_cdclk_funcs; } else if (IS_BROADWELL(dev_priv)) { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.set_cdclk = bdw_set_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = bdw_modeset_calc_cdclk; + dev_priv->cdclk_funcs = &bdw_cdclk_funcs; + } else if (IS_HASWELL(dev_priv)) { + dev_priv->cdclk_funcs = &hsw_cdclk_funcs; } else if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.set_cdclk = chv_set_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = vlv_modeset_calc_cdclk; + dev_priv->cdclk_funcs = &chv_cdclk_funcs; } else if (IS_VALLEYVIEW(dev_priv)) { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.set_cdclk = vlv_set_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = vlv_modeset_calc_cdclk; - } else { - dev_priv->cdclk_funcs.bw_calc_min_cdclk = intel_bw_calc_min_cdclk; - dev_priv->cdclk_funcs.modeset_calc_cdclk = fixed_modeset_calc_cdclk; + dev_priv->cdclk_funcs = &vlv_cdclk_funcs; + } else if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) { + dev_priv->cdclk_funcs = &fixed_400mhz_cdclk_funcs; + } else if (IS_IRONLAKE(dev_priv)) { + dev_priv->cdclk_funcs = &ilk_cdclk_funcs; + } else if (IS_GM45(dev_priv)) { + dev_priv->cdclk_funcs = &gm45_cdclk_funcs; + } else if (IS_G45(dev_priv)) { + dev_priv->cdclk_funcs = &g33_cdclk_funcs; + } else if (IS_I965GM(dev_priv)) { + dev_priv->cdclk_funcs = &i965gm_cdclk_funcs; + } else if (IS_I965G(dev_priv)) { + dev_priv->cdclk_funcs = &fixed_400mhz_cdclk_funcs; + } else if (IS_PINEVIEW(dev_priv)) { + dev_priv->cdclk_funcs = &pnv_cdclk_funcs; + } else if (IS_G33(dev_priv)) { + dev_priv->cdclk_funcs = &g33_cdclk_funcs; + } else if (IS_I945GM(dev_priv)) { + dev_priv->cdclk_funcs = &i945gm_cdclk_funcs; + } else if (IS_I945G(dev_priv)) { + dev_priv->cdclk_funcs = &fixed_400mhz_cdclk_funcs; + } else if (IS_I915GM(dev_priv)) { + dev_priv->cdclk_funcs = &i915gm_cdclk_funcs; + } else if (IS_I915G(dev_priv)) { + dev_priv->cdclk_funcs = &i915g_cdclk_funcs; + } else if (IS_I865G(dev_priv)) { + dev_priv->cdclk_funcs = &i865g_cdclk_funcs; + } else if (IS_I85X(dev_priv)) { + dev_priv->cdclk_funcs = &i85x_cdclk_funcs; + } else if (IS_I845G(dev_priv)) { + dev_priv->cdclk_funcs = &i845g_cdclk_funcs; + } else if (IS_I830(dev_priv)) { + dev_priv->cdclk_funcs = &i830_cdclk_funcs; } - if (DISPLAY_VER(dev_priv) >= 10 || IS_BROXTON(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = bxt_get_cdclk; - else if (DISPLAY_VER(dev_priv) == 9) - dev_priv->cdclk_funcs.get_cdclk = skl_get_cdclk; - else if (IS_BROADWELL(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = bdw_get_cdclk; - else if (IS_HASWELL(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = hsw_get_cdclk; - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = vlv_get_cdclk; - else if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; - else if (IS_IRONLAKE(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_450mhz_get_cdclk; - else if (IS_GM45(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = gm45_get_cdclk; - else if (IS_G45(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = g33_get_cdclk; - else if (IS_I965GM(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = i965gm_get_cdclk; - else if (IS_I965G(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; - else if (IS_PINEVIEW(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = pnv_get_cdclk; - else if (IS_G33(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = g33_get_cdclk; - else if (IS_I945GM(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = i945gm_get_cdclk; - else if (IS_I945G(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_400mhz_get_cdclk; - else if (IS_I915GM(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = i915gm_get_cdclk; - else if (IS_I915G(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_333mhz_get_cdclk; - else if (IS_I865G(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_266mhz_get_cdclk; - else if (IS_I85X(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = i85x_get_cdclk; - else if (IS_I845G(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_200mhz_get_cdclk; - else if (IS_I830(dev_priv)) - dev_priv->cdclk_funcs.get_cdclk = fixed_133mhz_get_cdclk; - - if (drm_WARN(&dev_priv->drm, !dev_priv->cdclk_funcs.get_cdclk, - "Unknown platform. Assuming 133 MHz CDCLK\n")) - dev_priv->cdclk_funcs.get_cdclk = fixed_133mhz_get_cdclk; + if (drm_WARN(&dev_priv->drm, !dev_priv->cdclk_funcs, + "Unknown platform. Assuming i830\n")) + dev_priv->cdclk_funcs = &i830_cdclk_funcs; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cb72e2fe5417..67638b4327f9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1006,7 +1006,7 @@ struct drm_i915_private { const struct intel_audio_funcs *audio_funcs; /* Display CDCLK functions */ - struct intel_cdclk_funcs cdclk_funcs; + const struct intel_cdclk_funcs *cdclk_funcs; /* PCH chipset type */ enum intel_pch pch_type; From cbc7617af0c194c35eebd08ca03dc98e2e8cfcb5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:05 +0300 Subject: [PATCH 105/554] drm/i915: drop unused function ptr and comments. There was some excess comments and an unused vtbl ptr. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/573a9366d33e2b7bd7b8215af614f03f3e562926.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 67638b4327f9..9c768ec57ce4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -409,13 +409,6 @@ struct drm_i915_display_funcs { void (*crtc_disable)(struct intel_atomic_state *state, struct intel_crtc *crtc); void (*commit_modeset_enables)(struct intel_atomic_state *state); - void (*commit_modeset_disables)(struct intel_atomic_state *state); - - /* clock updates for mode set */ - /* cursor updates */ - /* render clock increase/decrease */ - /* display clock increase/decrease */ - /* pll clock increase/decrease */ }; From d28c2f5c2383bddc0a277a9a8455dd2920a9b9ab Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:06 +0300 Subject: [PATCH 106/554] drm/i915: constify display function vtable Make nice clear tables instead of having things in two places. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/d0f7e2c792dc40804555d26b6ede62f4bd2f23d6.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 81 ++++++++++++-------- drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9c72f1c5e96f..e7ac92994abf 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3797,7 +3797,7 @@ static void intel_crtc_disable_noatomic(struct intel_crtc *crtc, drm_WARN_ON(&dev_priv->drm, IS_ERR(temp_crtc_state) || ret); - dev_priv->display.crtc_disable(to_intel_atomic_state(state), crtc); + dev_priv->display->crtc_disable(to_intel_atomic_state(state), crtc); drm_atomic_state_put(state); @@ -6006,7 +6006,7 @@ static bool intel_crtc_get_pipe_config(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); - if (!i915->display.get_pipe_config(crtc, crtc_state)) + if (!i915->display->get_pipe_config(crtc, crtc_state)) return false; crtc_state->hw.active = true; @@ -9816,7 +9816,7 @@ static void intel_enable_crtc(struct intel_atomic_state *state, intel_crtc_update_active_timings(new_crtc_state); - dev_priv->display.crtc_enable(state, crtc); + dev_priv->display->crtc_enable(state, crtc); if (new_crtc_state->bigjoiner_slave) return; @@ -9904,7 +9904,7 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state, */ intel_crtc_disable_pipe_crc(crtc); - dev_priv->display.crtc_disable(state, crtc); + dev_priv->display->crtc_disable(state, crtc); crtc->active = false; intel_fbc_disable(crtc); intel_disable_shared_dpll(old_crtc_state); @@ -10284,7 +10284,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.commit_modeset_enables(state); + dev_priv->display->commit_modeset_enables(state); if (state->modeset) { intel_encoders_update_complete(state); @@ -11288,6 +11288,46 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .atomic_state_free = intel_atomic_state_free, }; +static const struct drm_i915_display_funcs skl_display_funcs = { + .get_pipe_config = hsw_get_pipe_config, + .crtc_enable = hsw_crtc_enable, + .crtc_disable = hsw_crtc_disable, + .commit_modeset_enables = skl_commit_modeset_enables, + .get_initial_plane_config = skl_get_initial_plane_config, +}; + +static const struct drm_i915_display_funcs ddi_display_funcs = { + .get_pipe_config = hsw_get_pipe_config, + .crtc_enable = hsw_crtc_enable, + .crtc_disable = hsw_crtc_disable, + .commit_modeset_enables = intel_commit_modeset_enables, + .get_initial_plane_config = i9xx_get_initial_plane_config, +}; + +static const struct drm_i915_display_funcs pch_split_display_funcs = { + .get_pipe_config = ilk_get_pipe_config, + .crtc_enable = ilk_crtc_enable, + .crtc_disable = ilk_crtc_disable, + .commit_modeset_enables = intel_commit_modeset_enables, + .get_initial_plane_config = i9xx_get_initial_plane_config, +}; + +static const struct drm_i915_display_funcs vlv_display_funcs = { + .get_pipe_config = i9xx_get_pipe_config, + .crtc_enable = valleyview_crtc_enable, + .crtc_disable = i9xx_crtc_disable, + .commit_modeset_enables = intel_commit_modeset_enables, + .get_initial_plane_config = i9xx_get_initial_plane_config, +}; + +static const struct drm_i915_display_funcs i9xx_display_funcs = { + .get_pipe_config = i9xx_get_pipe_config, + .crtc_enable = i9xx_crtc_enable, + .crtc_disable = i9xx_crtc_disable, + .commit_modeset_enables = intel_commit_modeset_enables, + .get_initial_plane_config = i9xx_get_initial_plane_config, +}; + /** * intel_init_display_hooks - initialize the display modesetting hooks * @dev_priv: device private @@ -11303,38 +11343,19 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) intel_dpll_init_clock_hook(dev_priv); if (DISPLAY_VER(dev_priv) >= 9) { - dev_priv->display.get_pipe_config = hsw_get_pipe_config; - dev_priv->display.crtc_enable = hsw_crtc_enable; - dev_priv->display.crtc_disable = hsw_crtc_disable; + dev_priv->display = &skl_display_funcs; } else if (HAS_DDI(dev_priv)) { - dev_priv->display.get_pipe_config = hsw_get_pipe_config; - dev_priv->display.crtc_enable = hsw_crtc_enable; - dev_priv->display.crtc_disable = hsw_crtc_disable; + dev_priv->display = &ddi_display_funcs; } else if (HAS_PCH_SPLIT(dev_priv)) { - dev_priv->display.get_pipe_config = ilk_get_pipe_config; - dev_priv->display.crtc_enable = ilk_crtc_enable; - dev_priv->display.crtc_disable = ilk_crtc_disable; + dev_priv->display = &pch_split_display_funcs; } else if (IS_CHERRYVIEW(dev_priv) || IS_VALLEYVIEW(dev_priv)) { - dev_priv->display.get_pipe_config = i9xx_get_pipe_config; - dev_priv->display.crtc_enable = valleyview_crtc_enable; - dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display = &vlv_display_funcs; } else { - dev_priv->display.get_pipe_config = i9xx_get_pipe_config; - dev_priv->display.crtc_enable = i9xx_crtc_enable; - dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display = &i9xx_display_funcs; } intel_fdi_init_hook(dev_priv); - - if (DISPLAY_VER(dev_priv) >= 9) { - dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables; - dev_priv->display.get_initial_plane_config = skl_get_initial_plane_config; - } else { - dev_priv->display.commit_modeset_enables = intel_commit_modeset_enables; - dev_priv->display.get_initial_plane_config = i9xx_get_initial_plane_config; - } - } void intel_modeset_init_hw(struct drm_i915_private *i915) @@ -11762,7 +11783,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) * can even allow for smooth boot transitions if the BIOS * fb is large enough for the active pipe configuration. */ - i915->display.get_initial_plane_config(crtc, &plane_config); + i915->display->get_initial_plane_config(crtc, &plane_config); /* * If the fb is shared between multiple heads, we'll diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9c768ec57ce4..dd0d996972f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -990,7 +990,7 @@ struct drm_i915_private { const struct intel_dpll_funcs *dpll_funcs; /* Display functions */ - struct drm_i915_display_funcs display; + const struct drm_i915_display_funcs *display; /* Display internal color functions */ const struct intel_color_funcs *color_funcs; From eba4b7960f22f57750711aded092afd2b95d3b33 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:07 +0300 Subject: [PATCH 107/554] drm/i915: constify clock gating init vtable. I used a macro to avoid making any really silly mistakes here. Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/7c97f7e5ab0eae3c4cd7ce8344254356c34f3ad6.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 78 +++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dd0d996972f5..4e28645c73c6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -975,7 +975,7 @@ struct drm_i915_private { struct workqueue_struct *flip_wq; /* pm private clock gating functions */ - struct drm_i915_clock_gating_funcs clock_gating_funcs; + const struct drm_i915_clock_gating_funcs *clock_gating_funcs; /* pm display functions */ struct drm_i915_wm_disp_funcs wm_disp; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b37888781ec9..08e0195edeb7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7869,7 +7869,7 @@ static void i830_init_clock_gating(struct drm_i915_private *dev_priv) void intel_init_clock_gating(struct drm_i915_private *dev_priv) { - dev_priv->clock_gating_funcs.init_clock_gating(dev_priv); + dev_priv->clock_gating_funcs->init_clock_gating(dev_priv); } void intel_suspend_hw(struct drm_i915_private *dev_priv) @@ -7884,6 +7884,36 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv) "No clock gating settings or workarounds applied.\n"); } +#define CG_FUNCS(platform) \ +static const struct drm_i915_clock_gating_funcs platform##_clock_gating_funcs = { \ + .init_clock_gating = platform##_init_clock_gating, \ +} + +CG_FUNCS(adlp); +CG_FUNCS(dg1); +CG_FUNCS(gen12lp); +CG_FUNCS(icl); +CG_FUNCS(cfl); +CG_FUNCS(skl); +CG_FUNCS(kbl); +CG_FUNCS(bxt); +CG_FUNCS(glk); +CG_FUNCS(bdw); +CG_FUNCS(chv); +CG_FUNCS(hsw); +CG_FUNCS(ivb); +CG_FUNCS(vlv); +CG_FUNCS(gen6); +CG_FUNCS(ilk); +CG_FUNCS(g4x); +CG_FUNCS(i965gm); +CG_FUNCS(i965g); +CG_FUNCS(gen3); +CG_FUNCS(i85x); +CG_FUNCS(i830); +CG_FUNCS(nop); +#undef CG_FUNCS + /** * intel_init_clock_gating_hooks - setup the clock gating hooks * @dev_priv: device private @@ -7896,52 +7926,52 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv) void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) { if (IS_ALDERLAKE_P(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = adlp_init_clock_gating; + dev_priv->clock_gating_funcs = &adlp_clock_gating_funcs; else if (IS_DG1(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = dg1_init_clock_gating; + dev_priv->clock_gating_funcs = &dg1_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 12) - dev_priv->clock_gating_funcs.init_clock_gating = gen12lp_init_clock_gating; + dev_priv->clock_gating_funcs = &gen12lp_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 11) - dev_priv->clock_gating_funcs.init_clock_gating = icl_init_clock_gating; + dev_priv->clock_gating_funcs = &icl_clock_gating_funcs; else if (IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = cfl_init_clock_gating; + dev_priv->clock_gating_funcs = &cfl_clock_gating_funcs; else if (IS_SKYLAKE(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = skl_init_clock_gating; + dev_priv->clock_gating_funcs = &skl_clock_gating_funcs; else if (IS_KABYLAKE(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = kbl_init_clock_gating; + dev_priv->clock_gating_funcs = &kbl_clock_gating_funcs; else if (IS_BROXTON(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = bxt_init_clock_gating; + dev_priv->clock_gating_funcs = &bxt_clock_gating_funcs; else if (IS_GEMINILAKE(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = glk_init_clock_gating; + dev_priv->clock_gating_funcs = &glk_clock_gating_funcs; else if (IS_BROADWELL(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = bdw_init_clock_gating; + dev_priv->clock_gating_funcs = &bdw_clock_gating_funcs; else if (IS_CHERRYVIEW(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = chv_init_clock_gating; + dev_priv->clock_gating_funcs = &chv_clock_gating_funcs; else if (IS_HASWELL(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = hsw_init_clock_gating; + dev_priv->clock_gating_funcs = &hsw_clock_gating_funcs; else if (IS_IVYBRIDGE(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = ivb_init_clock_gating; + dev_priv->clock_gating_funcs = &ivb_clock_gating_funcs; else if (IS_VALLEYVIEW(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = vlv_init_clock_gating; + dev_priv->clock_gating_funcs = &vlv_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 6) - dev_priv->clock_gating_funcs.init_clock_gating = gen6_init_clock_gating; + dev_priv->clock_gating_funcs = &gen6_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 5) - dev_priv->clock_gating_funcs.init_clock_gating = ilk_init_clock_gating; + dev_priv->clock_gating_funcs = &ilk_clock_gating_funcs; else if (IS_G4X(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = g4x_init_clock_gating; + dev_priv->clock_gating_funcs = &g4x_clock_gating_funcs; else if (IS_I965GM(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = i965gm_init_clock_gating; + dev_priv->clock_gating_funcs = &i965gm_clock_gating_funcs; else if (IS_I965G(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = i965g_init_clock_gating; + dev_priv->clock_gating_funcs = &i965g_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 3) - dev_priv->clock_gating_funcs.init_clock_gating = gen3_init_clock_gating; + dev_priv->clock_gating_funcs = &gen3_clock_gating_funcs; else if (IS_I85X(dev_priv) || IS_I865G(dev_priv)) - dev_priv->clock_gating_funcs.init_clock_gating = i85x_init_clock_gating; + dev_priv->clock_gating_funcs = &i85x_clock_gating_funcs; else if (GRAPHICS_VER(dev_priv) == 2) - dev_priv->clock_gating_funcs.init_clock_gating = i830_init_clock_gating; + dev_priv->clock_gating_funcs = &i830_clock_gating_funcs; else { MISSING_CASE(INTEL_DEVID(dev_priv)); - dev_priv->clock_gating_funcs.init_clock_gating = nop_init_clock_gating; + dev_priv->clock_gating_funcs = &nop_clock_gating_funcs; } } From dde98a573c0a00a1501f087f89ee61ce93d416df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 29 Sep 2021 01:58:08 +0300 Subject: [PATCH 108/554] drm/i915: constify display wm vtable Use a nop table for the cases where CxSR doesn't init properly. v2: use a nop table (Jani) Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/bb0658d14afd02cca692cd58223800f68f4ff4ce.1632869550.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 34 ++++----- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 80 ++++++++++++++------ 3 files changed, 75 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e7ac92994abf..9e407760e51f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -161,16 +161,16 @@ static void intel_modeset_setup_hw_state(struct drm_device *dev, */ static void intel_update_watermarks(struct drm_i915_private *dev_priv) { - if (dev_priv->wm_disp.update_wm) - dev_priv->wm_disp.update_wm(dev_priv); + if (dev_priv->wm_disp->update_wm) + dev_priv->wm_disp->update_wm(dev_priv); } static int intel_compute_pipe_wm(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->wm_disp.compute_pipe_wm) - return dev_priv->wm_disp.compute_pipe_wm(state, crtc); + if (dev_priv->wm_disp->compute_pipe_wm) + return dev_priv->wm_disp->compute_pipe_wm(state, crtc); return 0; } @@ -178,20 +178,20 @@ static int intel_compute_intermediate_wm(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (!dev_priv->wm_disp.compute_intermediate_wm) + if (!dev_priv->wm_disp->compute_intermediate_wm) return 0; if (drm_WARN_ON(&dev_priv->drm, - !dev_priv->wm_disp.compute_pipe_wm)) + !dev_priv->wm_disp->compute_pipe_wm)) return 0; - return dev_priv->wm_disp.compute_intermediate_wm(state, crtc); + return dev_priv->wm_disp->compute_intermediate_wm(state, crtc); } static bool intel_initial_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->wm_disp.initial_watermarks) { - dev_priv->wm_disp.initial_watermarks(state, crtc); + if (dev_priv->wm_disp->initial_watermarks) { + dev_priv->wm_disp->initial_watermarks(state, crtc); return true; } return false; @@ -201,23 +201,23 @@ static void intel_atomic_update_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->wm_disp.atomic_update_watermarks) - dev_priv->wm_disp.atomic_update_watermarks(state, crtc); + if (dev_priv->wm_disp->atomic_update_watermarks) + dev_priv->wm_disp->atomic_update_watermarks(state, crtc); } static void intel_optimize_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->wm_disp.optimize_watermarks) - dev_priv->wm_disp.optimize_watermarks(state, crtc); + if (dev_priv->wm_disp->optimize_watermarks) + dev_priv->wm_disp->optimize_watermarks(state, crtc); } static int intel_compute_global_watermarks(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - if (dev_priv->wm_disp.compute_global_watermarks) - return dev_priv->wm_disp.compute_global_watermarks(state); + if (dev_priv->wm_disp->compute_global_watermarks) + return dev_priv->wm_disp->compute_global_watermarks(state); return 0; } @@ -3743,7 +3743,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) != 2) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - if (!dev_priv->wm_disp.initial_watermarks) + if (!dev_priv->wm_disp->initial_watermarks) intel_update_watermarks(dev_priv); /* clock the pipe down to 640x480@60 to potentially save power */ @@ -11425,7 +11425,7 @@ static void sanitize_watermarks(struct drm_i915_private *dev_priv) int i; /* Only supported on platforms that use atomic watermark design */ - if (!dev_priv->wm_disp.optimize_watermarks) + if (!dev_priv->wm_disp->optimize_watermarks) return; state = drm_atomic_state_alloc(&dev_priv->drm); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4e28645c73c6..133dadecafdb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -978,7 +978,7 @@ struct drm_i915_private { const struct drm_i915_clock_gating_funcs *clock_gating_funcs; /* pm display functions */ - struct drm_i915_wm_disp_funcs wm_disp; + const struct drm_i915_wm_disp_funcs *wm_disp; /* irq display functions */ const struct intel_hotplug_funcs *hotplug_funcs; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 08e0195edeb7..ef5f73934dab 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7975,6 +7975,51 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) } } +static const struct drm_i915_wm_disp_funcs skl_wm_funcs = { + .compute_global_watermarks = skl_compute_wm, +}; + +static const struct drm_i915_wm_disp_funcs ilk_wm_funcs = { + .compute_pipe_wm = ilk_compute_pipe_wm, + .compute_intermediate_wm = ilk_compute_intermediate_wm, + .initial_watermarks = ilk_initial_watermarks, + .optimize_watermarks = ilk_optimize_watermarks, +}; + +static const struct drm_i915_wm_disp_funcs vlv_wm_funcs = { + .compute_pipe_wm = vlv_compute_pipe_wm, + .compute_intermediate_wm = vlv_compute_intermediate_wm, + .initial_watermarks = vlv_initial_watermarks, + .optimize_watermarks = vlv_optimize_watermarks, + .atomic_update_watermarks = vlv_atomic_update_fifo, +}; + +static const struct drm_i915_wm_disp_funcs g4x_wm_funcs = { + .compute_pipe_wm = g4x_compute_pipe_wm, + .compute_intermediate_wm = g4x_compute_intermediate_wm, + .initial_watermarks = g4x_initial_watermarks, + .optimize_watermarks = g4x_optimize_watermarks, +}; + +static const struct drm_i915_wm_disp_funcs pnv_wm_funcs = { + .update_wm = pnv_update_wm, +}; + +static const struct drm_i915_wm_disp_funcs i965_wm_funcs = { + .update_wm = i965_update_wm, +}; + +static const struct drm_i915_wm_disp_funcs i9xx_wm_funcs = { + .update_wm = i9xx_update_wm, +}; + +static const struct drm_i915_wm_disp_funcs i845_wm_funcs = { + .update_wm = i845_update_wm, +}; + +static const struct drm_i915_wm_disp_funcs nop_funcs = { +}; + /* Set up chip specific power management-related functions */ void intel_init_pm(struct drm_i915_private *dev_priv) { @@ -7990,7 +8035,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv) /* For FIFO watermark updates */ if (DISPLAY_VER(dev_priv) >= 9) { skl_setup_wm_latency(dev_priv); - dev_priv->wm_disp.compute_global_watermarks = skl_compute_wm; + dev_priv->wm_disp = &skl_wm_funcs; } else if (HAS_PCH_SPLIT(dev_priv)) { ilk_setup_wm_latency(dev_priv); @@ -7998,31 +8043,19 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || (DISPLAY_VER(dev_priv) != 5 && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { - dev_priv->wm_disp.compute_pipe_wm = ilk_compute_pipe_wm; - dev_priv->wm_disp.compute_intermediate_wm = - ilk_compute_intermediate_wm; - dev_priv->wm_disp.initial_watermarks = - ilk_initial_watermarks; - dev_priv->wm_disp.optimize_watermarks = - ilk_optimize_watermarks; + dev_priv->wm_disp = &ilk_wm_funcs; } else { drm_dbg_kms(&dev_priv->drm, "Failed to read display plane latency. " "Disable CxSR\n"); + dev_priv->wm_disp = &nop_funcs; } } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { vlv_setup_wm_latency(dev_priv); - dev_priv->wm_disp.compute_pipe_wm = vlv_compute_pipe_wm; - dev_priv->wm_disp.compute_intermediate_wm = vlv_compute_intermediate_wm; - dev_priv->wm_disp.initial_watermarks = vlv_initial_watermarks; - dev_priv->wm_disp.optimize_watermarks = vlv_optimize_watermarks; - dev_priv->wm_disp.atomic_update_watermarks = vlv_atomic_update_fifo; + dev_priv->wm_disp = &vlv_wm_funcs; } else if (IS_G4X(dev_priv)) { g4x_setup_wm_latency(dev_priv); - dev_priv->wm_disp.compute_pipe_wm = g4x_compute_pipe_wm; - dev_priv->wm_disp.compute_intermediate_wm = g4x_compute_intermediate_wm; - dev_priv->wm_disp.initial_watermarks = g4x_initial_watermarks; - dev_priv->wm_disp.optimize_watermarks = g4x_optimize_watermarks; + dev_priv->wm_disp = &g4x_wm_funcs; } else if (IS_PINEVIEW(dev_priv)) { if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv), dev_priv->is_ddr3, @@ -8036,21 +8069,22 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->fsb_freq, dev_priv->mem_freq); /* Disable CxSR and never update its watermark again */ intel_set_memory_cxsr(dev_priv, false); - dev_priv->wm_disp.update_wm = NULL; + dev_priv->wm_disp = &nop_funcs; } else - dev_priv->wm_disp.update_wm = pnv_update_wm; + dev_priv->wm_disp = &pnv_wm_funcs; } else if (DISPLAY_VER(dev_priv) == 4) { - dev_priv->wm_disp.update_wm = i965_update_wm; + dev_priv->wm_disp = &i965_wm_funcs; } else if (DISPLAY_VER(dev_priv) == 3) { - dev_priv->wm_disp.update_wm = i9xx_update_wm; + dev_priv->wm_disp = &i9xx_wm_funcs; } else if (DISPLAY_VER(dev_priv) == 2) { if (INTEL_NUM_PIPES(dev_priv) == 1) - dev_priv->wm_disp.update_wm = i845_update_wm; + dev_priv->wm_disp = &i845_wm_funcs; else - dev_priv->wm_disp.update_wm = i9xx_update_wm; + dev_priv->wm_disp = &i9xx_wm_funcs; } else { drm_err(&dev_priv->drm, "unexpected fall-through in %s\n", __func__); + dev_priv->wm_disp = &nop_funcs; } } From cd7f5ca33585918febe5e2f6dc090a21cfa775b0 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Sep 2021 16:20:23 -0700 Subject: [PATCH 109/554] drm/virtio: implement context init: add virtio_gpu_fence_event Similar to DRM_VMW_EVENT_FENCE_SIGNALED. Sends a pollable event to the DRM file descriptor when a fence on a specific ring is signaled. One difference is the event is not exposed via the UAPI -- this is because host responses are on a shared memory buffer of type BLOB_MEM_GUEST [this is the common way to receive responses with virtgpu]. As such, there is no context specific read(..) implementation either -- just a poll(..) implementation. Signed-off-by: Gurchetan Singh Acked-by: Nicholas Verne Link: http://patchwork.freedesktop.org/patch/msgid/20210921232024.817-12-gurchetansingh@chromium.org Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_drv.c | 43 +++++++++++++++++++++++++- drivers/gpu/drm/virtio/virtgpu_drv.h | 7 +++++ drivers/gpu/drm/virtio/virtgpu_fence.c | 10 ++++++ drivers/gpu/drm/virtio/virtgpu_ioctl.c | 34 ++++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 9d963f1fda8f..749db18dcfa2 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -155,6 +157,35 @@ static void virtio_gpu_config_changed(struct virtio_device *vdev) schedule_work(&vgdev->config_changed_work); } +static __poll_t virtio_gpu_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct drm_file *drm_file = filp->private_data; + struct virtio_gpu_fpriv *vfpriv = drm_file->driver_priv; + struct drm_device *dev = drm_file->minor->dev; + struct drm_pending_event *e = NULL; + __poll_t mask = 0; + + if (!vfpriv->ring_idx_mask) + return drm_poll(filp, wait); + + poll_wait(filp, &drm_file->event_wait, wait); + + if (!list_empty(&drm_file->event_list)) { + spin_lock_irq(&dev->event_lock); + e = list_first_entry(&drm_file->event_list, + struct drm_pending_event, link); + drm_file->event_space += e->event->length; + list_del(&e->link); + spin_unlock_irq(&dev->event_lock); + + kfree(e); + mask |= EPOLLIN | EPOLLRDNORM; + } + + return mask; +} + static struct virtio_device_id id_table[] = { { VIRTIO_ID_GPU, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -194,7 +225,17 @@ MODULE_AUTHOR("Dave Airlie "); MODULE_AUTHOR("Gerd Hoffmann "); MODULE_AUTHOR("Alon Levy"); -DEFINE_DRM_GEM_FOPS(virtio_gpu_driver_fops); +static const struct file_operations virtio_gpu_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .compat_ioctl = drm_compat_ioctl, + .poll = virtio_gpu_poll, + .read = drm_read, + .llseek = noop_llseek, + .mmap = drm_gem_mmap +}; static const struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index cb60d52c2bd1..e0265fe74aa5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -138,11 +138,18 @@ struct virtio_gpu_fence_driver { spinlock_t lock; }; +#define VIRTGPU_EVENT_FENCE_SIGNALED_INTERNAL 0x10000000 +struct virtio_gpu_fence_event { + struct drm_pending_event base; + struct drm_event event; +}; + struct virtio_gpu_fence { struct dma_fence f; uint32_t ring_idx; uint64_t fence_id; bool emit_fence_info; + struct virtio_gpu_fence_event *e; struct virtio_gpu_fence_driver *drv; struct list_head node; }; diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 98a00c1e654d..f28357dbde35 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -152,11 +152,21 @@ void virtio_gpu_fence_event_process(struct virtio_gpu_device *vgdev, continue; dma_fence_signal_locked(&curr->f); + if (curr->e) { + drm_send_event(vgdev->ddev, &curr->e->base); + curr->e = NULL; + } + list_del(&curr->node); dma_fence_put(&curr->f); } dma_fence_signal_locked(&signaled->f); + if (signaled->e) { + drm_send_event(vgdev->ddev, &signaled->e->base); + signaled->e = NULL; + } + list_del(&signaled->node); dma_fence_put(&signaled->f); break; diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index be7b22a03884..fdaa7f3d9eeb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -38,6 +38,36 @@ VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \ VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) +static int virtio_gpu_fence_event_create(struct drm_device *dev, + struct drm_file *file, + struct virtio_gpu_fence *fence, + uint32_t ring_idx) +{ + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct virtio_gpu_fence_event *e = NULL; + int ret; + + if (!(vfpriv->ring_idx_mask & (1 << ring_idx))) + return 0; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return -ENOMEM; + + e->event.type = VIRTGPU_EVENT_FENCE_SIGNALED_INTERNAL; + e->event.length = sizeof(e->event); + + ret = drm_event_reserve_init(dev, file, &e->base, &e->event); + if (ret) + goto free; + + fence->e = e; + return 0; +free: + kfree(e); + return ret; +} + /* Must be called with &virtio_gpu_fpriv.struct_mutex held. */ static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev, struct virtio_gpu_fpriv *vfpriv) @@ -195,6 +225,10 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, goto out_unresv; } + ret = virtio_gpu_fence_event_create(dev, file, out_fence, ring_idx); + if (ret) + goto out_unresv; + if (out_fence_fd >= 0) { sync_file = sync_file_create(&out_fence->f); if (!sync_file) { From 78aa20fa4381623cf59a85d053486f98784ca3a0 Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Tue, 21 Sep 2021 16:20:24 -0700 Subject: [PATCH 110/554] drm/virtio: implement context init: advertise feature to userspace This advertises the context init feature to userspace, along with a mask of supported capabilities. Signed-off-by: Gurchetan Singh Acked-by: Lingfeng Yang Link: http://patchwork.freedesktop.org/patch/msgid/20210921232024.817-13-gurchetansingh@chromium.org Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index fdaa7f3d9eeb..5618a1d5879c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -286,6 +286,12 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_CROSS_DEVICE: value = vgdev->has_resource_assign_uuid ? 1 : 0; break; + case VIRTGPU_PARAM_CONTEXT_INIT: + value = vgdev->has_context_init ? 1 : 0; + break; + case VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs: + value = vgdev->capset_id_mask; + break; default: return -EINVAL; } From 239f3c2ee18376587026efecaea5250fa5926d20 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 28 Jul 2021 14:41:31 +0200 Subject: [PATCH 111/554] drm/i915: Fix runtime pm handling in i915_gem_shrink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to call intel_runtime_pm_put on error, fix it! Signed-off-by: Maarten Lankhorst Fixes: cf41a8f1dc1e ("drm/i915: Finally remove obj->mm.lock.") Cc: Thomas Hellström Cc: Daniel Vetter Cc: # v5.13+ Reviewed-by: Thomas Hellström Reviewed-by: Niranjana Vishwanathapura Link: https://patchwork.freedesktop.org/patch/msgid/20210830121006.2978297-9-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index e382b7f2353b..5ab136ffdeb2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -118,7 +118,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww, intel_wakeref_t wakeref = 0; unsigned long count = 0; unsigned long scanned = 0; - int err; + int err = 0; /* CHV + VTD workaround use stop_machine(); need to trylock vm->mutex */ bool trylock_vm = !ww && intel_vm_no_concurrent_access_wa(i915); @@ -242,12 +242,15 @@ skip: list_splice_tail(&still_in_list, phase->list); spin_unlock_irqrestore(&i915->mm.obj_lock, flags); if (err) - return err; + break; } if (shrink & I915_SHRINK_BOUND) intel_runtime_pm_put(&i915->runtime_pm, wakeref); + if (err) + return err; + if (nr_scanned) *nr_scanned += scanned; return count; From f5d28856b89baab4232a9f841e565763fcebcdf9 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 27 Sep 2021 12:41:02 +0100 Subject: [PATCH 112/554] drm/ttm: stop calling tt_swapin in vm_access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit: commit 09ac4fcb3f255e9225967c75f5893325c116cdbe Author: Felix Kuehling Date: Thu Jul 13 17:01:16 2017 -0400 drm/ttm: Implement vm_operations_struct.access v2 we added the vm_access hook, where we also directly call tt_swapin for some reason. If something is swapped-out then the ttm_tt must also be unpopulated, and since access_kmap should also call tt_populate, if needed, then swapping-in will already be handled there. If anything, calling tt_swapin directly here would likely always fail since the tt->pages won't yet be populated, or worse since the tt->pages array is never actually cleared in unpopulate this might lead to a nasty uaf. Fixes: 09ac4fcb3f25 ("drm/ttm: Implement vm_operations_struct.access v2") Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Reviewed-by: Thomas Hellström Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210927114114.152310-1-matthew.auld@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index f56be5bc0861..5b9b7fd01a69 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -519,11 +519,6 @@ int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr, switch (bo->resource->mem_type) { case TTM_PL_SYSTEM: - if (unlikely(bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { - ret = ttm_tt_swapin(bo->ttm); - if (unlikely(ret != 0)) - return ret; - } fallthrough; case TTM_PL_TT: ret = ttm_bo_vm_access_kmap(bo, offset, buf, len, write); From 635138f72e80849db3cc39549a462bafbecc896a Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 27 Sep 2021 12:41:03 +0100 Subject: [PATCH 113/554] drm/ttm: stop setting page->index for the ttm_tt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit: commit 58aa6622d32af7d2c08d45085f44c54554a16ed7 Author: Thomas Hellstrom Date: Fri Jan 3 11:47:23 2014 +0100 drm/ttm: Correctly set page mapping and -index members we started setting the page->mapping and page->index to point to the virtual address space, if the pages were faulted with TTM. Apparently this was needed for core-mm to able to reverse lookup the virtual address given the struct page, and potentially unmap it from the page tables. However as pointed out by Thomas, since we are now using PFN_MAP, instead of say PFN_MIXED, this should no longer be the case. There was also apparently some usecase in vmwgfx which needed this for dirty tracking, but that also doesn't appear to be the case anymore, as pointed out by Thomas. We still need keep the page->mapping for now, since that is still needed for different reasons, but we try to address that in the next patch. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210927114114.152310-2-matthew.auld@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 2 -- drivers/gpu/drm/ttm/ttm_tt.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 5b9b7fd01a69..9a2119fe4bdd 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -346,8 +346,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, } else if (unlikely(!page)) { break; } - page->index = drm_vma_node_start(&bo->base.vma_node) + - page_offset; pfn = page_to_pfn(page); } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index dae52433beeb..1cc04c224988 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -367,10 +367,8 @@ static void ttm_tt_clear_mapping(struct ttm_tt *ttm) if (ttm->page_flags & TTM_PAGE_FLAG_SG) return; - for (i = 0; i < ttm->num_pages; ++i) { + for (i = 0; i < ttm->num_pages; ++i) (*page)->mapping = NULL; - (*page++)->index = 0; - } } void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) From 21856e1e342505d79803d7342da3a348981b431c Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 27 Sep 2021 12:41:04 +0100 Subject: [PATCH 114/554] drm/ttm: move ttm_tt_{add, clear}_mapping into amdgpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that setting page->index shouldn't be needed anymore, we are just left with setting page->mapping, and here it looks like amdgpu is the only user, where pointing the page->mapping at the dev_mapping is used to verify that the pages do indeed belong to the device, if userspace later tries to touch them. v2(Christian): - Drop the functions altogether and just inline modifying the page->mapping Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210927114114.152310-3-matthew.auld@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 15 ++++++++++++++- drivers/gpu/drm/ttm/ttm_tt.c | 25 ------------------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 1129e17e9f09..60b12bb55244 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1119,6 +1119,8 @@ static int amdgpu_ttm_tt_populate(struct ttm_device *bdev, { struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); struct amdgpu_ttm_tt *gtt = (void *)ttm; + pgoff_t i; + int ret; /* user pages are bound by amdgpu_ttm_tt_pin_userptr() */ if (gtt->userptr) { @@ -1131,7 +1133,14 @@ static int amdgpu_ttm_tt_populate(struct ttm_device *bdev, if (ttm->page_flags & TTM_PAGE_FLAG_SG) return 0; - return ttm_pool_alloc(&adev->mman.bdev.pool, ttm, ctx); + ret = ttm_pool_alloc(&adev->mman.bdev.pool, ttm, ctx); + if (ret) + return ret; + + for (i = 0; i < ttm->num_pages; ++i) + ttm->pages[i]->mapping = bdev->dev_mapping; + + return 0; } /* @@ -1145,6 +1154,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev, { struct amdgpu_ttm_tt *gtt = (void *)ttm; struct amdgpu_device *adev; + pgoff_t i; amdgpu_ttm_backend_unbind(bdev, ttm); @@ -1158,6 +1168,9 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev, if (ttm->page_flags & TTM_PAGE_FLAG_SG) return; + for (i = 0; i < ttm->num_pages; ++i) + ttm->pages[i]->mapping = NULL; + adev = amdgpu_ttm_adev(bdev); return ttm_pool_free(&adev->mman.bdev.pool, ttm); } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 1cc04c224988..980ecb079b2c 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -289,17 +289,6 @@ out_err: return ret; } -static void ttm_tt_add_mapping(struct ttm_device *bdev, struct ttm_tt *ttm) -{ - pgoff_t i; - - if (ttm->page_flags & TTM_PAGE_FLAG_SG) - return; - - for (i = 0; i < ttm->num_pages; ++i) - ttm->pages[i]->mapping = bdev->dev_mapping; -} - int ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) { @@ -336,7 +325,6 @@ int ttm_tt_populate(struct ttm_device *bdev, if (ret) goto error; - ttm_tt_add_mapping(bdev, ttm); ttm->page_flags |= TTM_PAGE_FLAG_PRIV_POPULATED; if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { ret = ttm_tt_swapin(ttm); @@ -359,24 +347,11 @@ error: } EXPORT_SYMBOL(ttm_tt_populate); -static void ttm_tt_clear_mapping(struct ttm_tt *ttm) -{ - pgoff_t i; - struct page **page = ttm->pages; - - if (ttm->page_flags & TTM_PAGE_FLAG_SG) - return; - - for (i = 0; i < ttm->num_pages; ++i) - (*page)->mapping = NULL; -} - void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) { if (!ttm_tt_is_populated(ttm)) return; - ttm_tt_clear_mapping(ttm); if (bdev->funcs->ttm_tt_unpopulate) bdev->funcs->ttm_tt_unpopulate(bdev, ttm); else From d0f5d790ae863079025398015eb59347b01db455 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 27 Sep 2021 12:41:05 +0100 Subject: [PATCH 115/554] drm/ttm: remove TTM_PAGE_FLAG_NO_RETRY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No longer used it seems. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210927114114.152310-4-matthew.auld@intel.com Signed-off-by: Christian König --- include/drm/ttm/ttm_tt.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 89b15d673b22..842ce756213c 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -41,7 +41,6 @@ struct ttm_operation_ctx; #define TTM_PAGE_FLAG_SWAPPED (1 << 4) #define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6) #define TTM_PAGE_FLAG_SG (1 << 8) -#define TTM_PAGE_FLAG_NO_RETRY (1 << 9) #define TTM_PAGE_FLAG_PRIV_POPULATED (1 << 31) From 43d46f0b78bba5dc5ffb6f1b9a1d4c8d0c5dd1fc Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 29 Sep 2021 14:26:27 +0100 Subject: [PATCH 116/554] drm/ttm: s/FLAG_SG/FLAG_EXTERNAL/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It covers more than just ttm_bo_type_sg usage, like with say dma-buf, since one other user is userptr in amdgpu, and in the future we might have some more. Hence EXTERNAL is likely a more suitable name. v2(Christian): - Rename these to TTM_TT_FLAGS_* - Fix up all the holes in the flag values Suggested-by: Christian König Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210929132629.353541-1-matthew.auld@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 +++++----- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 ++-- drivers/gpu/drm/radeon/radeon_ttm.c | 8 ++++---- drivers/gpu/drm/ttm/ttm_bo.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo_util.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo_vm.c | 2 +- drivers/gpu/drm/ttm/ttm_pool.c | 2 +- drivers/gpu/drm/ttm/ttm_tt.c | 24 ++++++++++++------------ include/drm/ttm/ttm_device.h | 2 +- include/drm/ttm/ttm_tt.h | 18 +++++++++--------- 11 files changed, 42 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 60b12bb55244..e8d70b6e6737 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -894,7 +894,7 @@ static int amdgpu_ttm_backend_bind(struct ttm_device *bdev, DRM_ERROR("failed to pin userptr\n"); return r; } - } else if (ttm->page_flags & TTM_PAGE_FLAG_SG) { + } else if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) { if (!ttm->sg) { struct dma_buf_attachment *attach; struct sg_table *sgt; @@ -1130,7 +1130,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_device *bdev, return 0; } - if (ttm->page_flags & TTM_PAGE_FLAG_SG) + if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) return 0; ret = ttm_pool_alloc(&adev->mman.bdev.pool, ttm, ctx); @@ -1165,7 +1165,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev, return; } - if (ttm->page_flags & TTM_PAGE_FLAG_SG) + if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) return; for (i = 0; i < ttm->num_pages; ++i) @@ -1198,8 +1198,8 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, return -ENOMEM; } - /* Set TTM_PAGE_FLAG_SG before populate but after create. */ - bo->ttm->page_flags |= TTM_PAGE_FLAG_SG; + /* Set TTM_TT_FLAG_EXTERNAL before populate but after create. */ + bo->ttm->page_flags |= TTM_TT_FLAG_EXTERNAL; gtt = (void *)bo->ttm; gtt->userptr = addr; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index f0a61a9474fc..8beef57ba52b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -182,7 +182,7 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, if (obj->flags & I915_BO_ALLOC_CPU_CLEAR && man->use_tt) - page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + page_flags |= TTM_TT_FLAG_ZERO_ALLOC; ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, i915_ttm_select_tt_caching(obj)); @@ -451,7 +451,7 @@ static int i915_ttm_accel_move(struct ttm_buffer_object *bo, if (bo->type == ttm_bo_type_kernel) return -EINVAL; - if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC)) + if (ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC)) return 0; intel_engine_pm_get(i915->gt.migrate.context->engine); @@ -525,7 +525,7 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, /* Populate ttm with pages if needed. Typically system memory. */ if (bo->ttm && (dst_man->use_tt || - (bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED))) { + (bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED))) { ret = ttm_tt_populate(bo->bdev, bo->ttm, ctx); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 33dca2565cca..b2c7e0802ac3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1249,7 +1249,7 @@ nouveau_ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; struct device *dev; - bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL); if (ttm_tt_is_populated(ttm)) return 0; @@ -1272,7 +1272,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_device *bdev, { struct nouveau_drm *drm; struct device *dev; - bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL); if (slave) return; diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 7793249bc549..11b21d605584 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -545,14 +545,14 @@ static int radeon_ttm_tt_populate(struct ttm_device *bdev, { struct radeon_device *rdev = radeon_get_rdev(bdev); struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm); - bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL); if (gtt && gtt->userptr) { ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) return -ENOMEM; - ttm->page_flags |= TTM_PAGE_FLAG_SG; + ttm->page_flags |= TTM_TT_FLAG_EXTERNAL; return 0; } @@ -569,13 +569,13 @@ static void radeon_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm { struct radeon_device *rdev = radeon_get_rdev(bdev); struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm); - bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL); radeon_ttm_tt_unbind(bdev, ttm); if (gtt && gtt->userptr) { kfree(ttm->sg); - ttm->page_flags &= ~TTM_PAGE_FLAG_SG; + ttm->page_flags &= ~TTM_TT_FLAG_EXTERNAL; return; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3b22c0013dbf..d62b2013c367 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1115,8 +1115,8 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, return -EBUSY; if (!bo->ttm || !ttm_tt_is_populated(bo->ttm) || - bo->ttm->page_flags & TTM_PAGE_FLAG_SG || - bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED || + bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL || + bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED || !ttm_bo_get_unless_zero(bo)) { if (locked) dma_resv_unlock(bo->base.resv); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 1c5ffe2935af..82af095f6b81 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -103,7 +103,7 @@ void ttm_move_memcpy(struct ttm_buffer_object *bo, /* Don't move nonexistent data. Clear destination instead. */ if (src_ops->maps_tt && (!ttm || !ttm_tt_is_populated(ttm))) { - if (ttm && !(ttm->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC)) + if (ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC)) return; for (i = 0; i < num_pages; ++i) { @@ -150,7 +150,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, struct ttm_kmap_iter *dst_iter, *src_iter; int ret = 0; - if (ttm && ((ttm->page_flags & TTM_PAGE_FLAG_SWAPPED) || + if (ttm && ((ttm->page_flags & TTM_TT_FLAG_SWAPPED) || dst_man->use_tt)) { ret = ttm_tt_populate(bdev, ttm, ctx); if (ret) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 9a2119fe4bdd..950f4f132802 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -162,7 +162,7 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, * Refuse to fault imported pages. This should be handled * (if at all) by redirecting mmap to the exporter. */ - if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) { + if (bo->ttm && (bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) { dma_resv_unlock(bo->base.resv); return VM_FAULT_SIGBUS; } diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index c961a788b519..1bba0a0ed3f9 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -371,7 +371,7 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, WARN_ON(!num_pages || ttm_tt_is_populated(tt)); WARN_ON(dma_addr && !pool->dev); - if (tt->page_flags & TTM_PAGE_FLAG_ZERO_ALLOC) + if (tt->page_flags & TTM_TT_FLAG_ZERO_ALLOC) gfp_flags |= __GFP_ZERO; if (ctx->gfp_retry_mayfail) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 980ecb079b2c..86f31fde6e35 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -68,12 +68,12 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) switch (bo->type) { case ttm_bo_type_device: if (zero_alloc) - page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + page_flags |= TTM_TT_FLAG_ZERO_ALLOC; break; case ttm_bo_type_kernel: break; case ttm_bo_type_sg: - page_flags |= TTM_PAGE_FLAG_SG; + page_flags |= TTM_TT_FLAG_EXTERNAL; break; default: pr_err("Illegal buffer object type\n"); @@ -156,7 +156,7 @@ EXPORT_SYMBOL(ttm_tt_init); void ttm_tt_fini(struct ttm_tt *ttm) { - WARN_ON(ttm->page_flags & TTM_PAGE_FLAG_PRIV_POPULATED); + WARN_ON(ttm->page_flags & TTM_TT_FLAG_PRIV_POPULATED); if (ttm->swap_storage) fput(ttm->swap_storage); @@ -178,7 +178,7 @@ int ttm_sg_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, ttm_tt_init_fields(ttm, bo, page_flags, caching); - if (page_flags & TTM_PAGE_FLAG_SG) + if (page_flags & TTM_TT_FLAG_EXTERNAL) ret = ttm_sg_tt_alloc_page_directory(ttm); else ret = ttm_dma_tt_alloc_page_directory(ttm); @@ -224,7 +224,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm) fput(swap_storage); ttm->swap_storage = NULL; - ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; + ttm->page_flags &= ~TTM_TT_FLAG_SWAPPED; return 0; @@ -279,7 +279,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm, ttm_tt_unpopulate(bdev, ttm); ttm->swap_storage = swap_storage; - ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; + ttm->page_flags |= TTM_TT_FLAG_SWAPPED; return ttm->num_pages; @@ -300,7 +300,7 @@ int ttm_tt_populate(struct ttm_device *bdev, if (ttm_tt_is_populated(ttm)) return 0; - if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) { atomic_long_add(ttm->num_pages, &ttm_pages_allocated); if (bdev->pool.use_dma32) atomic_long_add(ttm->num_pages, @@ -325,8 +325,8 @@ int ttm_tt_populate(struct ttm_device *bdev, if (ret) goto error; - ttm->page_flags |= TTM_PAGE_FLAG_PRIV_POPULATED; - if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { + ttm->page_flags |= TTM_TT_FLAG_PRIV_POPULATED; + if (unlikely(ttm->page_flags & TTM_TT_FLAG_SWAPPED)) { ret = ttm_tt_swapin(ttm); if (unlikely(ret != 0)) { ttm_tt_unpopulate(bdev, ttm); @@ -337,7 +337,7 @@ int ttm_tt_populate(struct ttm_device *bdev, return 0; error: - if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) { atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); if (bdev->pool.use_dma32) atomic_long_sub(ttm->num_pages, @@ -357,14 +357,14 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) else ttm_pool_free(&bdev->pool, ttm); - if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) { atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); if (bdev->pool.use_dma32) atomic_long_sub(ttm->num_pages, &ttm_dma32_pages_allocated); } - ttm->page_flags &= ~TTM_PAGE_FLAG_PRIV_POPULATED; + ttm->page_flags &= ~TTM_TT_FLAG_PRIV_POPULATED; } #ifdef CONFIG_DEBUG_FS diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h index cbe03d45e883..0a4ddec78d8f 100644 --- a/include/drm/ttm/ttm_device.h +++ b/include/drm/ttm/ttm_device.h @@ -65,7 +65,7 @@ struct ttm_device_funcs { * ttm_tt_create * * @bo: The buffer object to create the ttm for. - * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * @page_flags: Page flags as identified by TTM_TT_FLAG_XX flags. * * Create a struct ttm_tt to back data with system memory pages. * No pages are actually allocated. diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 842ce756213c..b023cd58ff38 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -38,17 +38,17 @@ struct ttm_resource; struct ttm_buffer_object; struct ttm_operation_ctx; -#define TTM_PAGE_FLAG_SWAPPED (1 << 4) -#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6) -#define TTM_PAGE_FLAG_SG (1 << 8) +#define TTM_TT_FLAG_SWAPPED (1 << 0) +#define TTM_TT_FLAG_ZERO_ALLOC (1 << 1) +#define TTM_TT_FLAG_EXTERNAL (1 << 2) -#define TTM_PAGE_FLAG_PRIV_POPULATED (1 << 31) +#define TTM_TT_FLAG_PRIV_POPULATED (1 << 31) /** * struct ttm_tt * * @pages: Array of pages backing the data. - * @page_flags: see TTM_PAGE_FLAG_* + * @page_flags: see TTM_TT_FLAG_* * @num_pages: Number of pages in the page array. * @sg: for SG objects via dma-buf * @dma_address: The DMA (bus) addresses of the pages @@ -84,7 +84,7 @@ struct ttm_kmap_iter_tt { static inline bool ttm_tt_is_populated(struct ttm_tt *tt) { - return tt->page_flags & TTM_PAGE_FLAG_PRIV_POPULATED; + return tt->page_flags & TTM_TT_FLAG_PRIV_POPULATED; } /** @@ -103,7 +103,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc); * * @ttm: The struct ttm_tt. * @bo: The buffer object we create the ttm for. - * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * @page_flags: Page flags as identified by TTM_TT_FLAG_XX flags. * @caching: the desired caching state of the pages * * Create a struct ttm_tt to back data with system memory pages. @@ -178,7 +178,7 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm); */ static inline void ttm_tt_mark_for_clear(struct ttm_tt *ttm) { - ttm->page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + ttm->page_flags |= TTM_TT_FLAG_ZERO_ALLOC; } void ttm_tt_mgr_init(unsigned long num_pages, unsigned long num_dma32_pages); @@ -194,7 +194,7 @@ struct ttm_kmap_iter *ttm_kmap_iter_tt_init(struct ttm_kmap_iter_tt *iter_tt, * * @bo: Buffer object we allocate the ttm for. * @bridge: The agp bridge this device is sitting on. - * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * @page_flags: Page flags as identified by TTM_TT_FLAG_XX flags. * * * Create a TTM backend that uses the indicated AGP bridge as an aperture From a5a3dd42fe1314a77972d8682156078de3d0410d Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 29 Sep 2021 14:26:28 +0100 Subject: [PATCH 117/554] drm/ttm: add some kernel-doc for TTM_TT_FLAG_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move it to inline kernel-doc, otherwise we can't add empty lines it seems. Also drop the kernel-doc for pages_list, which doesn't seem to exist. v2(Christian): - Add a note that FLAG_SWAPPED shouldn't need to be touched by drivers. - Mention what FLAG_POPULATED does. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210929132629.353541-2-matthew.auld@intel.com Signed-off-by: Christian König --- include/drm/ttm/ttm_tt.h | 60 +++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index b023cd58ff38..86d74069be3e 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -38,35 +38,57 @@ struct ttm_resource; struct ttm_buffer_object; struct ttm_operation_ctx; +/** + * struct ttm_tt - This is a structure holding the pages, caching- and aperture + * binding status for a buffer object that isn't backed by fixed (VRAM / AGP) + * memory. + */ +struct ttm_tt { + /** @pages: Array of pages backing the data. */ + struct page **pages; + /** + * @page_flags: The page flags. + * + * Supported values: + * + * TTM_TT_FLAG_SWAPPED: Set by TTM when the pages have been unpopulated + * and swapped out by TTM. Calling ttm_tt_populate() will then swap the + * pages back in, and unset the flag. Drivers should in general never + * need to touch this. + * + * TTM_TT_FLAG_ZERO_ALLOC: Set if the pages will be zeroed on + * allocation. + * + * TTM_TT_FLAG_EXTERNAL: Set if the underlying pages were allocated + * externally, like with dma-buf or userptr. This effectively disables + * TTM swapping out such pages. Also important is to prevent TTM from + * ever directly mapping these pages. + * + * Note that enum ttm_bo_type.ttm_bo_type_sg objects will always enable + * this flag. + * + * TTM_TT_FLAG_PRIV_POPULATED: TTM internal only. DO NOT USE. This is + * set by TTM after ttm_tt_populate() has successfully returned, and is + * then unset when TTM calls ttm_tt_unpopulate(). + */ #define TTM_TT_FLAG_SWAPPED (1 << 0) #define TTM_TT_FLAG_ZERO_ALLOC (1 << 1) #define TTM_TT_FLAG_EXTERNAL (1 << 2) #define TTM_TT_FLAG_PRIV_POPULATED (1 << 31) - -/** - * struct ttm_tt - * - * @pages: Array of pages backing the data. - * @page_flags: see TTM_TT_FLAG_* - * @num_pages: Number of pages in the page array. - * @sg: for SG objects via dma-buf - * @dma_address: The DMA (bus) addresses of the pages - * @swap_storage: Pointer to shmem struct file for swap storage. - * @pages_list: used by some page allocation backend - * @caching: The current caching state of the pages, see enum ttm_caching. - * - * This is a structure holding the pages, caching- and aperture binding - * status for a buffer object that isn't backed by fixed (VRAM / AGP) - * memory. - */ -struct ttm_tt { - struct page **pages; uint32_t page_flags; + /** @num_pages: Number of pages in the page array. */ uint32_t num_pages; + /** @sg: for SG objects via dma-buf. */ struct sg_table *sg; + /** @dma_address: The DMA (bus) addresses of the pages. */ dma_addr_t *dma_address; + /** @swap_storage: Pointer to shmem struct file for swap storage. */ struct file *swap_storage; + /** + * @caching: The current caching state of the pages, see enum + * ttm_caching. + */ enum ttm_caching caching; }; From 49e7f76fc514cecf2cad1303fa74d99be7e5d9a6 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 29 Sep 2021 14:26:29 +0100 Subject: [PATCH 118/554] drm/ttm: add TTM_TT_FLAG_EXTERNAL_MAPPABLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit: commit 667a50db0477d47fdff01c666f5ee1ce26b5264c Author: Thomas Hellstrom Date: Fri Jan 3 11:17:18 2014 +0100 drm/ttm: Refuse to fault (prime-) imported pages we introduced the restriction that imported pages should not be directly mappable through TTM(this also extends to userptr). In the next patch we want to introduce a shmem_tt backend, which should follow all the existing rules with TTM_PAGE_FLAG_EXTERNAL, since it will need to handle swapping itself, but with the above mapping restriction lifted. v2(Christian): - Don't OR together EXTERNAL and EXTERNAL_MAPPABLE in the definition of EXTERNAL_MAPPABLE, just leave it the caller to handle this correctly, otherwise we might encounter subtle issues. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210929132629.353541-3-matthew.auld@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 6 ++++-- drivers/gpu/drm/ttm/ttm_tt.c | 3 +++ include/drm/ttm/ttm_tt.h | 19 ++++++++++++++++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 950f4f132802..33680c94127c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -163,8 +163,10 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, * (if at all) by redirecting mmap to the exporter. */ if (bo->ttm && (bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) { - dma_resv_unlock(bo->base.resv); - return VM_FAULT_SIGBUS; + if (!(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL_MAPPABLE)) { + dma_resv_unlock(bo->base.resv); + return VM_FAULT_SIGBUS; + } } return 0; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 86f31fde6e35..7e83c00a3f48 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -84,6 +84,9 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) if (unlikely(bo->ttm == NULL)) return -ENOMEM; + WARN_ON(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL_MAPPABLE && + !(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL)); + return 0; } diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 86d74069be3e..f20832139815 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -67,13 +67,26 @@ struct ttm_tt { * Note that enum ttm_bo_type.ttm_bo_type_sg objects will always enable * this flag. * + * TTM_TT_FLAG_EXTERNAL_MAPPABLE: Same behaviour as + * TTM_TT_FLAG_EXTERNAL, but with the reduced restriction that it is + * still valid to use TTM to map the pages directly. This is useful when + * implementing a ttm_tt backend which still allocates driver owned + * pages underneath(say with shmem). + * + * Note that since this also implies TTM_TT_FLAG_EXTERNAL, the usage + * here should always be: + * + * page_flags = TTM_TT_FLAG_EXTERNAL | + * TTM_TT_FLAG_EXTERNAL_MAPPABLE; + * * TTM_TT_FLAG_PRIV_POPULATED: TTM internal only. DO NOT USE. This is * set by TTM after ttm_tt_populate() has successfully returned, and is * then unset when TTM calls ttm_tt_unpopulate(). */ -#define TTM_TT_FLAG_SWAPPED (1 << 0) -#define TTM_TT_FLAG_ZERO_ALLOC (1 << 1) -#define TTM_TT_FLAG_EXTERNAL (1 << 2) +#define TTM_TT_FLAG_SWAPPED (1 << 0) +#define TTM_TT_FLAG_ZERO_ALLOC (1 << 1) +#define TTM_TT_FLAG_EXTERNAL (1 << 2) +#define TTM_TT_FLAG_EXTERNAL_MAPPABLE (1 << 3) #define TTM_TT_FLAG_PRIV_POPULATED (1 << 31) uint32_t page_flags; From 11408ea52786c2ae802b4cae32597fffe440147e Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Wed, 29 Sep 2021 10:54:42 +0530 Subject: [PATCH 119/554] drm/i915/gen11: Disable cursor clock gating in HDR mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display underrun in HDR mode when cursor is enabled. RTL fix will be implemented CLKGATE_DIS_PSL_A bit 28-46520h. As per W/A 1604331009, Disable cursor clock gating in HDR mode. Bspec : 33451 Changes since V6: - Address checkpatch warnings - Bit ordering Changes since V5: - replace intel_de_read with intel_de_rmw - Jani Changes since V4: - Added WA needed check - Ville - Replace BIT with REG_BIT - Ville - Add WA enable/disable support back which was added in V1 - Ville Changes since V3: - Disable WA when not in HDR mode or cursor plane not active - Ville - Extract required args from crtc_state - Ville - Create HDR mode API using bdw_set_pipemisc ref - Ville - Tested with HDR video as well full setmode, WA applies and disables Changes since V2: - Made it general gen11 WA - Removed WA needed check - Added cursor plane active check - Once WA enable, software will not disable Changes since V1: - Modified way CLKGATE_DIS_PSL bit 28 was modified Reviewed-by: Ville Syrjälä Signed-off-by: Tejas Upadhyay Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20210929052442.2543054-1-tejaskumarx.surendrakumar.upadhyay@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 32 ++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 33 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9e407760e51f..5e4440ac44a8 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -309,6 +309,15 @@ icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, intel_de_read(dev_priv, CLKGATE_DIS_PSL(pipe)) & ~DPFR_GATING_DIS); } +/* Wa_1604331009:icl,jsl,ehl */ +static void +icl_wa_cursorclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, + bool enable) +{ + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), CURSOR_GATING_DIS, + enable ? CURSOR_GATING_DIS : 0); +} + static bool is_trans_port_sync_slave(const struct intel_crtc_state *crtc_state) { @@ -2451,6 +2460,19 @@ static bool needs_scalerclk_wa(const struct intel_crtc_state *crtc_state) return false; } +static bool needs_cursorclk_wa(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + + /* Wa_1604331009:icl,jsl,ehl */ + if (is_hdr_mode(crtc_state) && + crtc_state->active_planes & BIT(PLANE_CURSOR) && + DISPLAY_VER(dev_priv) == 11) + return true; + + return false; +} + static bool planes_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { @@ -2493,6 +2515,11 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (needs_scalerclk_wa(old_crtc_state) && !needs_scalerclk_wa(new_crtc_state)) icl_wa_scalerclkgating(dev_priv, pipe, false); + + if (needs_cursorclk_wa(old_crtc_state) && + !needs_cursorclk_wa(new_crtc_state)) + icl_wa_cursorclkgating(dev_priv, pipe, false); + } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -2589,6 +2616,11 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, needs_scalerclk_wa(new_crtc_state)) icl_wa_scalerclkgating(dev_priv, pipe, true); + /* Wa_1604331009:icl,jsl,ehl */ + if (!needs_cursorclk_wa(old_crtc_state) && + needs_cursorclk_wa(new_crtc_state)) + icl_wa_cursorclkgating(dev_priv, pipe, true); + /* * Vblank time updates from the shadow to live plane control register * are blocked if the memory self-refresh mode is active at that diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 24017d38c6f6..c78337ab4f7b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4239,6 +4239,7 @@ enum { #define DUPS1_GATING_DIS (1 << 15) #define DUPS2_GATING_DIS (1 << 19) #define DUPS3_GATING_DIS (1 << 23) +#define CURSOR_GATING_DIS REG_BIT(28) #define DPF_GATING_DIS (1 << 10) #define DPF_RAM_GATING_DIS (1 << 9) #define DPFR_GATING_DIS (1 << 8) From 7194dc998dfffca096c30b3cd39625158608992d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:27 +0300 Subject: [PATCH 120/554] drm/i915/tc: Fix TypeC port init/resume time sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm during driver loading and system resume TypeC ports are accessed before their HW/SW state is synced. Move the TypeC port sanitization to the encoder's sync_state hook to fix this. v2: Handle the encoder disabled case in gen11_dsi_sync_state() as well (Jose, Jani) Fixes: f9e76a6e68d3 ("drm/i915: Add an encoder hook to sanitize its state during init/resume") Cc: José Roberto de Souza Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 10 ++++++++-- drivers/gpu/drm/i915/display/intel_ddi.c | 8 +++++++- drivers/gpu/drm/i915/display/intel_display.c | 20 +++++--------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 060bc8fb0d30..bd210166b079 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1599,8 +1599,14 @@ static void gen11_dsi_sync_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); - enum pipe pipe = intel_crtc->pipe; + struct intel_crtc *intel_crtc; + enum pipe pipe; + + if (!crtc_state) + return; + + intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); + pipe = intel_crtc->pipe; /* wa verify 1409054076:icl,jsl,ehl */ if (DISPLAY_VER(dev_priv) == 11 && pipe == PIPE_B && diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index a4667741d354..04572ce6630f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3838,7 +3838,13 @@ void hsw_ddi_get_config(struct intel_encoder *encoder, static void intel_ddi_sync_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - if (intel_crtc_has_dp_encoder(crtc_state)) + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_phy_is_tc(i915, phy)) + intel_tc_port_sanitize(enc_to_dig_port(encoder)); + + if (crtc_state && intel_crtc_has_dp_encoder(crtc_state)) intel_dp_sync_state(encoder, crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5e4440ac44a8..1a2b2b3ce56e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12317,18 +12317,16 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) readout_plane_state(dev_priv); for_each_intel_encoder(dev, encoder) { + struct intel_crtc_state *crtc_state = NULL; + pipe = 0; if (encoder->get_hw_state(encoder, &pipe)) { - struct intel_crtc_state *crtc_state; - crtc = intel_get_crtc_for_pipe(dev_priv, pipe); crtc_state = to_intel_crtc_state(crtc->base.state); encoder->base.crtc = &crtc->base; intel_encoder_get_config(encoder, crtc_state); - if (encoder->sync_state) - encoder->sync_state(encoder, crtc_state); /* read out to slave crtc as well for bigjoiner */ if (crtc_state->bigjoiner) { @@ -12343,6 +12341,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) encoder->base.crtc = NULL; } + if (encoder->sync_state) + encoder->sync_state(encoder, crtc_state); + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", encoder->base.base.id, encoder->base.name, @@ -12625,17 +12626,6 @@ intel_modeset_setup_hw_state(struct drm_device *dev, intel_modeset_readout_hw_state(dev); /* HW state is read out, now we need to sanitize this mess. */ - - /* Sanitize the TypeC port mode upfront, encoders depend on this */ - for_each_intel_encoder(dev, encoder) { - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - - /* We need to sanitize only the MST primary port. */ - if (encoder->type != INTEL_OUTPUT_DP_MST && - intel_phy_is_tc(dev_priv, phy)) - intel_tc_port_sanitize(enc_to_dig_port(encoder)); - } - get_encoder_power_domains(dev_priv); if (HAS_PCH_IBX(dev_priv)) From 4f7dad584fdce914d698233179a1188481789884 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:02 +0300 Subject: [PATCH 121/554] drm/i915/adlp/tc: Fix PHY connected check for Thunderbolt mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ADL-P the PHY ready (aka status complete on other platforms) flag is always set, besides when a DP-alt, legacy sink is connected also when a TBT sink is connected or nothing is connected. So assume the PHY to be connected when both the TBT live status and PHY ready flags are set. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3ffece568ed9..7dc3696085c7 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -509,6 +509,10 @@ static bool icl_tc_phy_is_connected(struct intel_digital_port *dig_port) return dig_port->tc_mode == TC_PORT_TBT_ALT; } + /* On ADL-P the PHY complete flag is set in TBT mode as well. */ + if (IS_ALDERLAKE_P(i915) && dig_port->tc_mode == TC_PORT_TBT_ALT) + return true; + if (!tc_phy_is_owned(dig_port)) { drm_dbg_kms(&i915->drm, "Port %s: PHY not owned\n", dig_port->tc_port_name); From 62e1e308ffd7a867ef82375f3cff7f8789ce6721 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:03 +0300 Subject: [PATCH 122/554] drm/i915/tc: Remove waiting for PHY complete during releasing ownership MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Waiting for the PHY complete flag to clear when releasing the PHY ownership was add in commit ddec362724f9 ("drm/i915: Wait for TypeC PHY complete flag to clear in safe mode") This isn't required by the spec, the vague idea was to make the handshake with the firmware more robust, without actual evidence for when it would be needed. Checking this again, the flag doesn't clear on ICL until after the PHY's PLL is disabled and the flag is permanently set on ADL-P. To avoid the spurious timeout messages in dmesg, just remove this wait. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-4-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 7dc3696085c7..0d3555437b0b 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -339,11 +339,6 @@ static bool icl_tc_phy_take_ownership(struct intel_digital_port *dig_port, intel_uncore_write(uncore, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia), val); - if (!take && wait_for(!tc_phy_status_complete(dig_port), 10)) - drm_dbg_kms(&i915->drm, - "Port %s: PHY complete clear timed out\n", - dig_port->tc_port_name); - return true; } From 30e114ef4b1620bd6768952279b53ea24e232efb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:28 +0300 Subject: [PATCH 123/554] drm/i915/tc: Check for DP-alt, legacy sinks before taking PHY ownership MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ADL-P the PHY ready/complete flag is always set even in TBT-alt mode. To avoid taking the PHY ownership and the following spurious "PHY sudden disconnect" messages on this platform when connecting the PHY in TBT mode, check if there is any DP-alt or legacy sink connected before taking the ownership. v2: (Jose) - Fix debug message clarifying that a TBT sink can be connected. - Add comments describing the PHY complete HW flag semantic differences between adl-p and other platforms. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 0d3555437b0b..4e5ff823a3a3 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -270,6 +270,14 @@ static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) return icl_tc_port_live_status_mask(dig_port); } +/* + * Return the PHY status complete flag indicating that display can acquire the + * PHY ownership. The IOM firmware sets this flag when a DP-alt or legacy sink + * is connected and it's ready to switch the ownership to display. The flag + * will be left cleared when a TBT-alt sink is connected, where the PHY is + * owned by the TBT subsystem and so switching the ownership to display is not + * required. + */ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); @@ -288,6 +296,13 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) return val & DP_PHY_MODE_STATUS_COMPLETED(dig_port->tc_phy_fia_idx); } +/* + * Return the PHY status complete flag indicating that display can acquire the + * PHY ownership. The IOM firmware sets this flag when it's ready to switch + * the ownership to display, regardless of what sink is connected (TBT-alt, + * DP-alt, legacy or nothing). For TBT-alt sinks the PHY is owned by the TBT + * subsystem and so switching the ownership to display is not required. + */ static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); @@ -424,6 +439,7 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, int required_lanes) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + u32 live_status_mask; int max_lanes; if (!tc_phy_status_complete(dig_port)) { @@ -432,6 +448,13 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, goto out_set_tbt_alt_mode; } + live_status_mask = tc_port_live_status_mask(dig_port); + if (!(live_status_mask & (BIT(TC_PORT_DP_ALT) | BIT(TC_PORT_LEGACY)))) { + drm_dbg_kms(&i915->drm, "Port %s: PHY ownership not required (live status %02x)\n", + dig_port->tc_port_name, live_status_mask); + goto out_set_tbt_alt_mode; + } + if (!tc_phy_take_ownership(dig_port, true) && !drm_WARN_ON(&i915->drm, dig_port->tc_legacy_port)) goto out_set_tbt_alt_mode; From 11a8970865b49c2a1e714ea3ba910d05fdde6944 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:05 +0300 Subject: [PATCH 124/554] drm/i915/tc: Add/use helpers to retrieve TypeC port properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of directly accessing the TypeC port internal struct members, add/use helpers to retrieve the corresponding properties. No functional change. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 31 +++++++------------ drivers/gpu/drm/i915/display/intel_display.c | 6 +--- .../drm/i915/display/intel_display_power.c | 4 +-- drivers/gpu/drm/i915/display/intel_dp_aux.c | 6 +--- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 5 +-- drivers/gpu/drm/i915/display/intel_tc.c | 24 ++++++++++++++ drivers/gpu/drm/i915/display/intel_tc.h | 4 +++ 7 files changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 04572ce6630f..0fe77854b455 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -288,7 +288,7 @@ static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder, if (IS_ALDERLAKE_P(i915) && intel_phy_is_tc(i915, phy)) { intel_dp->DP |= ddi_buf_phy_link_rate(crtc_state->port_clock); - if (dig_port->tc_mode != TC_PORT_TBT_ALT) + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) intel_dp->DP |= DDI_BUF_CTL_TC_PHY_OWNERSHIP; } } @@ -885,8 +885,7 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder, dig_port = enc_to_dig_port(encoder); - if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode != TC_PORT_TBT_ALT) { + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) { drm_WARN_ON(&dev_priv->drm, dig_port->ddi_io_wakeref); dig_port->ddi_io_wakeref = intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); @@ -1180,7 +1179,7 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int n_entries, ln; u32 val; - if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT) + if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) return; ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); @@ -1317,7 +1316,7 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, u32 val, dpcnt_mask, dpcnt_val; int n_entries, ln; - if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT) + if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) return; ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); @@ -2084,7 +2083,7 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, u8 width; if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode == TC_PORT_TBT_ALT) + intel_tc_port_in_tbt_alt_mode(dig_port)) return; if (DISPLAY_VER(dev_priv) >= 12) { @@ -2109,7 +2108,7 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, switch (pin_assignment) { case 0x0: drm_WARN_ON(&dev_priv->drm, - dig_port->tc_mode != TC_PORT_LEGACY); + !intel_tc_port_in_legacy_mode(dig_port)); if (width == 1) { ln1 |= MG_DP_MODE_CFG_DP_X1_MODE; } else { @@ -2354,7 +2353,6 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); int level = intel_ddi_dp_level(intel_dp, crtc_state); @@ -2378,8 +2376,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_clock(encoder, crtc_state); /* 4. Enable IO power */ - if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode != TC_PORT_TBT_ALT) + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) dig_port->ddi_io_wakeref = intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); @@ -2468,7 +2465,6 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); int level = intel_ddi_dp_level(intel_dp, crtc_state); @@ -2505,8 +2501,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_clock(encoder, crtc_state); /* 5. If IO power is controlled through PWR_WELL_CTL, Enable IO Power */ - if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode != TC_PORT_TBT_ALT) { + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) { drm_WARN_ON(&dev_priv->drm, dig_port->ddi_io_wakeref); dig_port->ddi_io_wakeref = intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); @@ -2611,7 +2606,6 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; - enum phy phy = intel_port_to_phy(dev_priv, port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); int level = intel_ddi_dp_level(intel_dp, crtc_state); @@ -2630,8 +2624,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_clock(encoder, crtc_state); - if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode != TC_PORT_TBT_ALT) { + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) { drm_WARN_ON(&dev_priv->drm, dig_port->ddi_io_wakeref); dig_port->ddi_io_wakeref = intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); @@ -2801,7 +2794,6 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; bool is_mst = intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); if (!is_mst) intel_dp_set_infoframes(encoder, false, @@ -2844,8 +2836,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, intel_pps_vdd_on(intel_dp); intel_pps_off(intel_dp); - if (!intel_phy_is_tc(dev_priv, phy) || - dig_port->tc_mode != TC_PORT_TBT_ALT) + if (!intel_tc_port_in_tbt_alt_mode(dig_port)) intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain, fetch_and_zero(&dig_port->ddi_io_wakeref)); @@ -3320,7 +3311,7 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state, intel_ddi_main_link_aux_domain(dig_port)); } - if (is_tc_port && dig_port->tc_mode != TC_PORT_TBT_ALT) + if (is_tc_port && !intel_tc_port_in_tbt_alt_mode(dig_port)) /* * Program the lane count for static/dynamic connections on * Type-C ports. Skip this step for TBT. diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1a2b2b3ce56e..4ce80ca7751f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3494,11 +3494,7 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port) enum intel_display_power_domain intel_aux_power_domain(struct intel_digital_port *dig_port) { - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); - - if (intel_phy_is_tc(dev_priv, phy) && - dig_port->tc_mode == TC_PORT_TBT_ALT) { + if (intel_tc_port_in_tbt_alt_mode(dig_port)) { switch (dig_port->aux_ch) { case AUX_CH_C: return POWER_DOMAIN_AUX_C_TBT; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index a274e2b33e91..2410c1a617ea 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -560,7 +560,7 @@ static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv, if (drm_WARN_ON(&dev_priv->drm, !dig_port)) return; - if (DISPLAY_VER(dev_priv) == 11 && dig_port->tc_legacy_port) + if (DISPLAY_VER(dev_priv) == 11 && intel_tc_cold_requires_aux_pw(dig_port)) return; drm_WARN_ON(&dev_priv->drm, !intel_tc_port_ref_held(dig_port)); @@ -629,7 +629,7 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, * exit sequence. */ timeout_expected = is_tbt || intel_tc_cold_requires_aux_pw(dig_port); - if (DISPLAY_VER(dev_priv) == 11 && dig_port->tc_legacy_port) + if (DISPLAY_VER(dev_priv) == 11 && intel_tc_cold_requires_aux_pw(dig_port)) icl_tc_cold_exit(dev_priv); hsw_wait_for_power_well_enable(dev_priv, power_well, timeout_expected); diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index f483f479dd0b..5fbb767fcd63 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -150,9 +150,6 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp, u32 unused) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *i915 = - to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); u32 ret; /* @@ -170,8 +167,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp, DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); - if (intel_phy_is_tc(i915, phy) && - dig_port->tc_mode == TC_PORT_TBT_ALT) + if (intel_tc_port_in_tbt_alt_mode(dig_port)) ret |= DP_AUX_CH_CTL_TBT_IO; return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 055992d099c7..0a7e04db04be 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -26,6 +26,7 @@ #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" +#include "intel_tc.h" /** * DOC: Display PLLs @@ -3101,8 +3102,8 @@ static void icl_update_active_dpll(struct intel_atomic_state *state, enc_to_dig_port(encoder); if (primary_port && - (primary_port->tc_mode == TC_PORT_DP_ALT || - primary_port->tc_mode == TC_PORT_LEGACY)) + (intel_tc_port_in_dp_alt_mode(primary_port) || + intel_tc_port_in_legacy_mode(primary_port))) port_dpll_id = ICL_PORT_DPLL_MG_PHY; icl_set_active_port_dpll(crtc_state, port_dpll_id); diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 4e5ff823a3a3..f9242056693e 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -23,6 +23,30 @@ static const char *tc_port_mode_name(enum tc_port_mode mode) return names[mode]; } +static bool intel_tc_port_in_mode(struct intel_digital_port *dig_port, + enum tc_port_mode mode) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + return intel_phy_is_tc(i915, phy) && dig_port->tc_mode == mode; +} + +bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port) +{ + return intel_tc_port_in_mode(dig_port, TC_PORT_TBT_ALT); +} + +bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port) +{ + return intel_tc_port_in_mode(dig_port, TC_PORT_DP_ALT); +} + +bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port) +{ + return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY); +} + static enum intel_display_power_domain tc_cold_get_power_domain(struct intel_digital_port *dig_port) { diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 0c881f645e27..0fdcddb4fc87 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -12,6 +12,10 @@ struct intel_digital_port; struct intel_encoder; +bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port); +bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); +bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); + bool intel_tc_port_connected(struct intel_encoder *encoder); void intel_tc_port_disconnect_phy(struct intel_digital_port *dig_port); From 675d23c14821fbaef3df5cbad94b42ec2e3a858a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:06 +0300 Subject: [PATCH 125/554] drm/i915/tc: Don't keep legacy TypeC ports in connected state w/o a sink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A follow-up patch will disconnect/reconnect PHYs around AUX transfers and modeset enable/disables. To prepare for that and make things consistent for all TypeC modes stop connecting the PHY in legacy mode without a sink being connected. This was done before since in legacy mode the PHY is dedicated to display usage, so there was no point in disconnecting it. However after the follow-up changes the TC-cold blocking power domains will be held as long as the PHY is in the connected state, so we'll need to disconnect/re-connect the PHY in all TypeC modes to allow for power saving. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f9242056693e..6d0a1b376767 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -527,8 +527,6 @@ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) { switch (dig_port->tc_mode) { case TC_PORT_LEGACY: - /* Nothing to do, we never disconnect from legacy mode */ - break; case TC_PORT_DP_ALT: tc_phy_take_ownership(dig_port, false); dig_port->tc_mode = TC_PORT_TBT_ALT; @@ -596,9 +594,7 @@ intel_tc_port_get_target_mode(struct intel_digital_port *dig_port) if (live_status_mask) return fls(live_status_mask) - 1; - return tc_phy_status_complete(dig_port) && - dig_port->tc_legacy_port ? TC_PORT_LEGACY : - TC_PORT_TBT_ALT; + return TC_PORT_TBT_ALT; } static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port, @@ -659,14 +655,8 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) "Port %s: PHY disconnected with %d active link(s)\n", dig_port->tc_port_name, active_links); intel_tc_port_link_init_refcount(dig_port, active_links); - - goto out; } - if (dig_port->tc_legacy_port) - icl_tc_phy_connect(dig_port, 1); - -out: drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n", dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); From 64851a32c463e5412561de67764d6fdc074bd193 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:29 +0300 Subject: [PATCH 126/554] drm/i915/tc: Add a mode for the TypeC PHY's disconnected state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A follow-up change will start to disconnect/re-connect PHYs around AUX transfers and modeset enable/disables. To prepare for that add a new TypeC PHY disconnected mode, to help tracking the TC-cold blocking power domain status (no power domain in disconnected state, mode dependent power domain in connected state). v2: Move the !disconnected mode and phy-owned asserts in __intel_tc_port_lock() later in the patchset, when the asserts will hold. (Jose) Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 1 + drivers/gpu/drm/i915/display/intel_tc.c | 22 +++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index d425ee77aad7..87b96fed5e0b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -270,6 +270,7 @@ enum tc_port { }; enum tc_port_mode { + TC_PORT_DISCONNECTED, TC_PORT_TBT_ALT, TC_PORT_DP_ALT, TC_PORT_LEGACY, diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 6d0a1b376767..62a3070abf0a 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -12,13 +12,14 @@ static const char *tc_port_mode_name(enum tc_port_mode mode) { static const char * const names[] = { + [TC_PORT_DISCONNECTED] = "disconnected", [TC_PORT_TBT_ALT] = "tbt-alt", [TC_PORT_DP_ALT] = "dp-alt", [TC_PORT_LEGACY] = "legacy", }; if (WARN_ON(mode >= ARRAY_SIZE(names))) - mode = TC_PORT_TBT_ALT; + mode = TC_PORT_DISCONNECTED; return names[mode]; } @@ -529,10 +530,11 @@ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) case TC_PORT_LEGACY: case TC_PORT_DP_ALT: tc_phy_take_ownership(dig_port, false); - dig_port->tc_mode = TC_PORT_TBT_ALT; - break; + fallthrough; case TC_PORT_TBT_ALT: - /* Nothing to do, we stay in TBT-alt mode */ + dig_port->tc_mode = TC_PORT_DISCONNECTED; + fallthrough; + case TC_PORT_DISCONNECTED: break; default: MISSING_CASE(dig_port->tc_mode); @@ -637,31 +639,34 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_encoder *encoder = &dig_port->base; - intel_wakeref_t tc_cold_wref; int active_links = 0; mutex_lock(&dig_port->tc_lock); - tc_cold_wref = tc_cold_block(dig_port); - dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); if (dig_port->dp.is_mst) active_links = intel_dp_mst_encoder_active_links(dig_port); else if (encoder->base.crtc) active_links = to_intel_crtc(encoder->base.crtc)->active; + drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED); if (active_links) { + intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port); + + dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); + if (!icl_tc_phy_is_connected(dig_port)) drm_dbg_kms(&i915->drm, "Port %s: PHY disconnected with %d active link(s)\n", dig_port->tc_port_name, active_links); intel_tc_port_link_init_refcount(dig_port, active_links); + + tc_cold_unblock(dig_port, tc_cold_wref); } drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n", dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); - tc_cold_unblock(dig_port, tc_cold_wref); mutex_unlock(&dig_port->tc_lock); } @@ -832,6 +837,7 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) mutex_init(&dig_port->tc_lock); dig_port->tc_legacy_port = is_legacy; + dig_port->tc_mode = TC_PORT_DISCONNECTED; dig_port->tc_link_refcount = 0; tc_port_load_fia_params(i915, dig_port); } From d0bc677056bd9de6eb731dd8bff889a5fe36e381 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:30 +0300 Subject: [PATCH 127/554] drm/i915/tc: Refactor TC-cold block/unblock helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A follow-up change will select the TC-cold blocking power domain based on the TypeC mode, prepare for that here. Also bring intel_tc_cold_requires_aux_pw() earlier to its logical place for readability. No functional change. v2: Add code comment about IOM reg accesses in TCCOLD. (Jose) Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-4-imre.deak@intel.com --- .../drm/i915/display/intel_display_types.h | 2 + drivers/gpu/drm/i915/display/intel_tc.c | 68 ++++++++++++------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 9413ebae15f5..f41fdc376a51 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1662,8 +1662,10 @@ struct intel_digital_port { enum intel_display_power_domain ddi_io_power_domain; intel_wakeref_t ddi_io_wakeref; intel_wakeref_t aux_wakeref; + struct mutex tc_lock; /* protects the TypeC port mode */ intel_wakeref_t tc_lock_wakeref; + enum intel_display_power_domain tc_lock_power_domain; int tc_link_refcount; bool tc_legacy_port:1; char tc_port_name[8]; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 62a3070abf0a..69c917fce03e 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -48,8 +48,16 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port) return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY); } +bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + + return (DISPLAY_VER(i915) == 11 && dig_port->tc_legacy_port) || + IS_ALDERLAKE_P(i915); +} + static enum intel_display_power_domain -tc_cold_get_power_domain(struct intel_digital_port *dig_port) +tc_cold_get_power_domain(struct intel_digital_port *dig_port, enum tc_port_mode mode) { if (intel_tc_cold_requires_aux_pw(dig_port)) return intel_legacy_aux_to_power_domain(dig_port->aux_ch); @@ -58,23 +66,30 @@ tc_cold_get_power_domain(struct intel_digital_port *dig_port) } static intel_wakeref_t -tc_cold_block(struct intel_digital_port *dig_port) +tc_cold_block_in_mode(struct intel_digital_port *dig_port, enum tc_port_mode mode, + enum intel_display_power_domain *domain) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum intel_display_power_domain domain; if (DISPLAY_VER(i915) == 11 && !dig_port->tc_legacy_port) return 0; - domain = tc_cold_get_power_domain(dig_port); - return intel_display_power_get(i915, domain); + *domain = tc_cold_get_power_domain(dig_port, mode); + + return intel_display_power_get(i915, *domain); +} + +static intel_wakeref_t +tc_cold_block(struct intel_digital_port *dig_port, enum intel_display_power_domain *domain) +{ + return tc_cold_block_in_mode(dig_port, dig_port->tc_mode, domain); } static void -tc_cold_unblock(struct intel_digital_port *dig_port, intel_wakeref_t wakeref) +tc_cold_unblock(struct intel_digital_port *dig_port, enum intel_display_power_domain domain, + intel_wakeref_t wakeref) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum intel_display_power_domain domain; /* * wakeref == -1, means some error happened saving save_depot_stack but @@ -84,8 +99,7 @@ tc_cold_unblock(struct intel_digital_port *dig_port, intel_wakeref_t wakeref) if (wakeref == 0) return; - domain = tc_cold_get_power_domain(dig_port); - intel_display_power_put_async(i915, domain, wakeref); + intel_display_power_put(i915, domain, wakeref); } static void @@ -98,7 +112,8 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port) return; enabled = intel_display_power_is_enabled(i915, - tc_cold_get_power_domain(dig_port)); + tc_cold_get_power_domain(dig_port, + dig_port->tc_mode)); drm_WARN_ON(&i915->drm, !enabled); } @@ -269,6 +284,11 @@ static u32 adl_tc_port_live_status_mask(struct intel_digital_port *dig_port) struct intel_uncore *uncore = &i915->uncore; u32 val, mask = 0; + /* + * On ADL-P HW/FW will wake from TCCOLD to complete the read access of + * registers in IOM. Note that this doesn't apply to PHY and FIA + * registers. + */ val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port)); if (val & TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT) mask |= BIT(TC_PORT_DP_ALT); @@ -650,7 +670,8 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED); if (active_links) { - intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port); + enum intel_display_power_domain domain; + intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port, &domain); dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); @@ -660,7 +681,7 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) dig_port->tc_port_name, active_links); intel_tc_port_link_init_refcount(dig_port, active_links); - tc_cold_unblock(dig_port, tc_cold_wref); + tc_cold_unblock(dig_port, domain, tc_cold_wref); } drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n", @@ -689,15 +710,16 @@ bool intel_tc_port_connected(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_connected; + enum intel_display_power_domain domain; intel_wakeref_t tc_cold_wref; intel_tc_port_lock(dig_port); - tc_cold_wref = tc_cold_block(dig_port); + tc_cold_wref = tc_cold_block(dig_port, &domain); is_connected = tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode); - tc_cold_unblock(dig_port, tc_cold_wref); + tc_cold_unblock(dig_port, domain, tc_cold_wref); intel_tc_port_unlock(dig_port); return is_connected; @@ -714,15 +736,16 @@ static void __intel_tc_port_lock(struct intel_digital_port *dig_port, mutex_lock(&dig_port->tc_lock); if (!dig_port->tc_link_refcount) { + enum intel_display_power_domain domain; intel_wakeref_t tc_cold_wref; - tc_cold_wref = tc_cold_block(dig_port); + tc_cold_wref = tc_cold_block(dig_port, &domain); if (force_disconnect || intel_tc_port_needs_reset(dig_port)) intel_tc_port_reset_mode(dig_port, required_lanes, force_disconnect); - tc_cold_unblock(dig_port, tc_cold_wref); + tc_cold_unblock(dig_port, domain, tc_cold_wref); } drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); @@ -787,6 +810,7 @@ void intel_tc_port_put_link(struct intel_digital_port *dig_port) static bool tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig_port) { + enum intel_display_power_domain domain; intel_wakeref_t wakeref; u32 val; @@ -794,9 +818,9 @@ tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig return false; mutex_lock(&dig_port->tc_lock); - wakeref = tc_cold_block(dig_port); + wakeref = tc_cold_block(dig_port, &domain); val = intel_uncore_read(&i915->uncore, PORT_TX_DFLEXDPSP(FIA1)); - tc_cold_unblock(dig_port, wakeref); + tc_cold_unblock(dig_port, domain, wakeref); mutex_unlock(&dig_port->tc_lock); drm_WARN_ON(&i915->drm, val == 0xffffffff); @@ -841,11 +865,3 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) dig_port->tc_link_refcount = 0; tc_port_load_fia_params(i915, dig_port); } - -bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - - return (DISPLAY_VER(i915) == 11 && dig_port->tc_legacy_port) || - IS_ALDERLAKE_P(i915); -} From 8e8289a00e6360e0b340db05b7e16dfb5e7be067 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:31 +0300 Subject: [PATCH 128/554] drm/i915/tc: Avoid using legacy AUX PW in TBT mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the ADL-P TBT mode the spec doesn't require blocking TC-cold by using the legacy AUX power domain. To avoid the timeouts that this would cause during PHY disconnect/reconnect sequences (which will be more frequent after a follow-up change) use the TC_COLD_OFF power domain in TBT mode on all platforms. On TGL this power domain blocks TC-cold via a PUNIT command, while on other platforms the domain just takes a runtime PM reference. If the HPD live status indicates that the port mode needs to be reset - for instance after switching from TBT to a DP-alt sink - still take the AUX domain, since the IOM firmware handshake requires this. v2: Rebased on v2 of the previous patch. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 55 ++++++++++++++++--------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 69c917fce03e..2df4d0beb636 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -59,10 +59,10 @@ bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port) static enum intel_display_power_domain tc_cold_get_power_domain(struct intel_digital_port *dig_port, enum tc_port_mode mode) { - if (intel_tc_cold_requires_aux_pw(dig_port)) - return intel_legacy_aux_to_power_domain(dig_port->aux_ch); - else + if (mode == TC_PORT_TBT_ALT || !intel_tc_cold_requires_aux_pw(dig_port)) return POWER_DOMAIN_TC_COLD_OFF; + + return intel_legacy_aux_to_power_domain(dig_port->aux_ch); } static intel_wakeref_t @@ -645,6 +645,36 @@ static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port, tc_port_mode_name(dig_port->tc_mode)); } +static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port) +{ + return intel_tc_port_get_target_mode(dig_port) != dig_port->tc_mode; +} + +static void intel_tc_port_update_mode(struct intel_digital_port *dig_port, + int required_lanes, bool force_disconnect) +{ + enum intel_display_power_domain domain; + intel_wakeref_t wref; + bool needs_reset = force_disconnect; + + if (!needs_reset) { + /* Get power domain required to check the hotplug live status. */ + wref = tc_cold_block(dig_port, &domain); + needs_reset = intel_tc_port_needs_reset(dig_port); + tc_cold_unblock(dig_port, domain, wref); + } + + if (!needs_reset) + return; + + /* Get power domain required for resetting the mode. */ + wref = tc_cold_block_in_mode(dig_port, TC_PORT_DISCONNECTED, &domain); + + intel_tc_port_reset_mode(dig_port, required_lanes, force_disconnect); + + tc_cold_unblock(dig_port, domain, wref); +} + static void intel_tc_port_link_init_refcount(struct intel_digital_port *dig_port, int refcount) @@ -691,11 +721,6 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) mutex_unlock(&dig_port->tc_lock); } -static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port) -{ - return intel_tc_port_get_target_mode(dig_port) != dig_port->tc_mode; -} - /* * The type-C ports are different because even when they are connected, they may * not be available/usable by the graphics driver: see the comment on @@ -735,18 +760,10 @@ static void __intel_tc_port_lock(struct intel_digital_port *dig_port, mutex_lock(&dig_port->tc_lock); - if (!dig_port->tc_link_refcount) { - enum intel_display_power_domain domain; - intel_wakeref_t tc_cold_wref; - tc_cold_wref = tc_cold_block(dig_port, &domain); - - if (force_disconnect || intel_tc_port_needs_reset(dig_port)) - intel_tc_port_reset_mode(dig_port, required_lanes, - force_disconnect); - - tc_cold_unblock(dig_port, domain, tc_cold_wref); - } + if (!dig_port->tc_link_refcount) + intel_tc_port_update_mode(dig_port, required_lanes, + force_disconnect); drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); dig_port->tc_lock_wakeref = wakeref; From 38c393462d01d2746f9f91c1a6482fded2b1b8bb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:10 +0300 Subject: [PATCH 129/554] drm/i915/icl/tc: Remove the ICL special casing during TC-cold blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While a TypeC port mode is locked a DISPLAY_CORE power domain reference is held, which implies a runtime PM ref. By removing the ICL !legacy port special casing, a TC_COLD_OFF power domain reference will be taken for such ports, which also translates to a runtime PM ref on that platform. A follow-up change will stop holding the DISPLAY_CORE power domain while the port is locked. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-11-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 2df4d0beb636..9367770de5d7 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -71,9 +71,6 @@ tc_cold_block_in_mode(struct intel_digital_port *dig_port, enum tc_port_mode mod { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (DISPLAY_VER(i915) == 11 && !dig_port->tc_legacy_port) - return 0; - *domain = tc_cold_get_power_domain(dig_port, mode); return intel_display_power_get(i915, *domain); @@ -108,9 +105,6 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port) struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); bool enabled; - if (DISPLAY_VER(i915) == 11 && !dig_port->tc_legacy_port) - return; - enabled = intel_display_power_is_enabled(i915, tc_cold_get_power_domain(dig_port, dig_port->tc_mode)); From 3e0abc7661c82266d3a3f27fbbadcc74cc4997e1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:32 +0300 Subject: [PATCH 130/554] drm/i915/tc: Fix TypeC PHY connect/disconnect logic on ADL-P MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far TC-cold was blocked only for the duration of TypeC mode resets. The DP-alt and legacy modes require TC-cold to be blocked also whenever the port is in use (AUX transfers, enable modeset), and this was ensured by the held PHY ownership flag. On ADL-P this doesn't work, since the PHY ownership flag is in a register backed by the PW#2 power well. Whenever this power well is disabled the ownership flag is cleared by the HW under the driver. The only way to cleanly release and re-acquire the PHY ownership flag and also allow for power saving (by disabling the display power wells and reaching DC5/6 states) is to hold the TC-cold blocking power domains while the PHY is connected and disconnect/reconnect the PHY on-demand around AUX transfers and modeset enable/disables. Let's do that, disconnecting a PHY with a 1 sec delay after it becomes idle. For consistency do this on all platforms and TypeC modes. v2: Add tc_mode!=disconnected and phy_is_owned asserts to __intel_tc_port_lock(). Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 7 +- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_tc.c | 93 ++++++++++++------- drivers/gpu/drm/i915/display/intel_tc.h | 2 +- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 0fe77854b455..51d07e9af9f3 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4017,8 +4017,11 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->dev); struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder)); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); intel_dp_encoder_flush_work(encoder); + if (intel_phy_is_tc(i915, phy)) + intel_tc_port_flush_work(dig_port); intel_display_power_flush_work(i915); drm_encoder_cleanup(encoder); @@ -4443,7 +4446,7 @@ static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) if (!intel_phy_is_tc(i915, phy)) return; - intel_tc_port_disconnect_phy(dig_port); + intel_tc_port_flush_work(dig_port); } static void intel_ddi_encoder_shutdown(struct intel_encoder *encoder) @@ -4458,7 +4461,7 @@ static void intel_ddi_encoder_shutdown(struct intel_encoder *encoder) if (!intel_phy_is_tc(i915, phy)) return; - intel_tc_port_disconnect_phy(dig_port); + intel_tc_port_flush_work(dig_port); } #define port_tc_name(port) ((port) - PORT_TC1 + '1') diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f41fdc376a51..632391197937 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1666,6 +1666,7 @@ struct intel_digital_port { struct mutex tc_lock; /* protects the TypeC port mode */ intel_wakeref_t tc_lock_wakeref; enum intel_display_power_domain tc_lock_power_domain; + struct delayed_work tc_disconnect_phy_work; int tc_link_refcount; bool tc_legacy_port:1; char tc_port_name[8]; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 9367770de5d7..66cb321a4488 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -666,6 +666,13 @@ static void intel_tc_port_update_mode(struct intel_digital_port *dig_port, intel_tc_port_reset_mode(dig_port, required_lanes, force_disconnect); + /* Get power domain matching the new mode after reset. */ + tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain, + fetch_and_zero(&dig_port->tc_lock_wakeref)); + if (dig_port->tc_mode != TC_PORT_DISCONNECTED) + dig_port->tc_lock_wakeref = tc_cold_block(dig_port, + &dig_port->tc_lock_power_domain); + tc_cold_unblock(dig_port, domain, wref); } @@ -693,6 +700,7 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) active_links = to_intel_crtc(encoder->base.crtc)->active; drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED); + drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); if (active_links) { enum intel_display_power_domain domain; intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port, &domain); @@ -705,6 +713,9 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) dig_port->tc_port_name, active_links); intel_tc_port_link_init_refcount(dig_port, active_links); + dig_port->tc_lock_wakeref = tc_cold_block(dig_port, + &dig_port->tc_lock_power_domain); + tc_cold_unblock(dig_port, domain, tc_cold_wref); } @@ -745,56 +756,67 @@ bool intel_tc_port_connected(struct intel_encoder *encoder) } static void __intel_tc_port_lock(struct intel_digital_port *dig_port, - int required_lanes, bool force_disconnect) + int required_lanes) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - intel_wakeref_t wakeref; - - wakeref = intel_display_power_get(i915, POWER_DOMAIN_DISPLAY_CORE); mutex_lock(&dig_port->tc_lock); + cancel_delayed_work(&dig_port->tc_disconnect_phy_work); if (!dig_port->tc_link_refcount) intel_tc_port_update_mode(dig_port, required_lanes, - force_disconnect); + false); - drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); - dig_port->tc_lock_wakeref = wakeref; + drm_WARN_ON(&i915->drm, dig_port->tc_mode == TC_PORT_DISCONNECTED); + drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_TBT_ALT && + !tc_phy_is_owned(dig_port)); } void intel_tc_port_lock(struct intel_digital_port *dig_port) { - __intel_tc_port_lock(dig_port, 1, false); + __intel_tc_port_lock(dig_port, 1); +} + +/** + * intel_tc_port_disconnect_phy_work: disconnect TypeC PHY from display port + * @dig_port: digital port + * + * Disconnect the given digital port from its TypeC PHY (handing back the + * control of the PHY to the TypeC subsystem). This will happen in a delayed + * manner after each aux transactions and modeset disables. + */ +static void intel_tc_port_disconnect_phy_work(struct work_struct *work) +{ + struct intel_digital_port *dig_port = + container_of(work, struct intel_digital_port, tc_disconnect_phy_work.work); + + mutex_lock(&dig_port->tc_lock); + + if (!dig_port->tc_link_refcount) + intel_tc_port_update_mode(dig_port, 1, true); + + mutex_unlock(&dig_port->tc_lock); +} + +/** + * intel_tc_port_flush_work: flush the work disconnecting the PHY + * @dig_port: digital port + * + * Flush the delayed work disconnecting an idle PHY. + */ +void intel_tc_port_flush_work(struct intel_digital_port *dig_port) +{ + flush_delayed_work(&dig_port->tc_disconnect_phy_work); } void intel_tc_port_unlock(struct intel_digital_port *dig_port) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - intel_wakeref_t wakeref = fetch_and_zero(&dig_port->tc_lock_wakeref); + if (!dig_port->tc_link_refcount && dig_port->tc_mode != TC_PORT_DISCONNECTED) + queue_delayed_work(system_unbound_wq, &dig_port->tc_disconnect_phy_work, + msecs_to_jiffies(1000)); mutex_unlock(&dig_port->tc_lock); - - intel_display_power_put_async(i915, POWER_DOMAIN_DISPLAY_CORE, - wakeref); -} - -/** - * intel_tc_port_disconnect_phy: disconnect TypeC PHY from display port - * @dig_port: digital port - * - * Disconnect the given digital port from its TypeC PHY (handing back the - * control of the PHY to the TypeC subsystem). The only purpose of this - * function is to force the disconnect even with a TypeC display output still - * plugged to the TypeC connector, which is required by the TypeC firmwares - * during system suspend and shutdown. Otherwise - during the unplug event - * handling - the PHY ownership is released automatically by - * intel_tc_port_reset_mode(), when calling this function is not required. - */ -void intel_tc_port_disconnect_phy(struct intel_digital_port *dig_port) -{ - __intel_tc_port_lock(dig_port, 1, true); - intel_tc_port_unlock(dig_port); } bool intel_tc_port_ref_held(struct intel_digital_port *dig_port) @@ -806,16 +828,16 @@ bool intel_tc_port_ref_held(struct intel_digital_port *dig_port) void intel_tc_port_get_link(struct intel_digital_port *dig_port, int required_lanes) { - __intel_tc_port_lock(dig_port, required_lanes, false); + __intel_tc_port_lock(dig_port, required_lanes); dig_port->tc_link_refcount++; intel_tc_port_unlock(dig_port); } void intel_tc_port_put_link(struct intel_digital_port *dig_port) { - mutex_lock(&dig_port->tc_lock); - dig_port->tc_link_refcount--; - mutex_unlock(&dig_port->tc_lock); + intel_tc_port_lock(dig_port); + --dig_port->tc_link_refcount; + intel_tc_port_unlock(dig_port); } static bool @@ -871,6 +893,7 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) "%c/TC#%d", port_name(port), tc_port + 1); mutex_init(&dig_port->tc_lock); + INIT_DELAYED_WORK(&dig_port->tc_disconnect_phy_work, intel_tc_port_disconnect_phy_work); dig_port->tc_legacy_port = is_legacy; dig_port->tc_mode = TC_PORT_DISCONNECTED; dig_port->tc_link_refcount = 0; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 0fdcddb4fc87..6b47b29f551c 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -17,7 +17,6 @@ bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); -void intel_tc_port_disconnect_phy(struct intel_digital_port *dig_port); u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port); u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); @@ -28,6 +27,7 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, void intel_tc_port_sanitize(struct intel_digital_port *dig_port); void intel_tc_port_lock(struct intel_digital_port *dig_port); void intel_tc_port_unlock(struct intel_digital_port *dig_port); +void intel_tc_port_flush_work(struct intel_digital_port *dig_port); void intel_tc_port_get_link(struct intel_digital_port *dig_port, int required_lanes); void intel_tc_port_put_link(struct intel_digital_port *dig_port); From ff67c4c0dd67b6dbb78a0d045100dd2f9dee88b0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Sep 2021 03:23:12 +0300 Subject: [PATCH 131/554] drm/i915/tc: Drop extra TC cold blocking from intel_tc_port_connected() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the previous patch the driver holds a power domain blocking TC-cold whenever the port is locked, so we can remove the extra blocking around the lock/unlock sequence. Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210921002313.1132357-13-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 66cb321a4488..4a14db604cba 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -740,16 +740,12 @@ bool intel_tc_port_connected(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_connected; - enum intel_display_power_domain domain; - intel_wakeref_t tc_cold_wref; intel_tc_port_lock(dig_port); - tc_cold_wref = tc_cold_block(dig_port, &domain); is_connected = tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode); - tc_cold_unblock(dig_port, domain, tc_cold_wref); intel_tc_port_unlock(dig_port); return is_connected; From b58a88682093b3438dad66f2c3d3a4d0a20ee1e8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Sep 2021 16:28:33 +0300 Subject: [PATCH 132/554] drm/i915/tc: Fix system hang on ADL-P during TypeC PHY disconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PHY ownership release->AUX PW disable steps during a modeset disable->PHY disconnect sequence can hang the system if the PHY disconnect happens after disabling the PHY's PLL. The spec doesn't require a specific order for these two steps, so this issue is still being root caused by HW/FW teams. Until that is found, let's make sure the disconnect happens before the PLL is disabled, and do this on all platforms for consistency. v2: Add a TODO comment to remove the w/a once the issue is root caused/fixed. (Jose) Cc: José Roberto de Souza Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210929132833.2253961-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 4a14db604cba..40faa18947c9 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -834,6 +834,14 @@ void intel_tc_port_put_link(struct intel_digital_port *dig_port) intel_tc_port_lock(dig_port); --dig_port->tc_link_refcount; intel_tc_port_unlock(dig_port); + + /* + * Disconnecting the PHY after the PHY's PLL gets disabled may + * hang the system on ADL-P, so disconnect the PHY here synchronously. + * TODO: remove this once the root cause of the ordering requirement + * is found/fixed. + */ + intel_tc_port_flush_work(dig_port); } static bool From 082436068c19316d5153229fd1b48dceccd0efee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Sep 2021 23:01:04 +0300 Subject: [PATCH 133/554] drm/i915: Extract intel_panel_mode_valid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract intel_panel_mode_valid() from the eDP code to a generic helper. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210923200109.4459-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 8 +++----- drivers/gpu/drm/i915/display/intel_panel.c | 18 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_panel.h | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 378008873e03..2b8b495fc2a9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -845,11 +845,9 @@ intel_dp_mode_valid(struct drm_connector *connector, return MODE_H_ILLEGAL; if (intel_dp_is_edp(intel_dp) && fixed_mode) { - if (mode->hdisplay != fixed_mode->hdisplay) - return MODE_PANEL; - - if (mode->vdisplay != fixed_mode->vdisplay) - return MODE_PANEL; + status = intel_panel_mode_valid(intel_connector, mode); + if (status != MODE_OK) + return status; target_clock = fixed_mode->clock; } diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 4804b6b86798..8a364bb1ce41 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -482,6 +482,24 @@ intel_panel_detect(struct drm_connector *connector, bool force) return connector_status_connected; } +enum drm_mode_status +intel_panel_mode_valid(struct intel_connector *connector, + const struct drm_display_mode *mode) +{ + const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode; + + if (!fixed_mode) + return MODE_OK; + + if (mode->hdisplay != fixed_mode->hdisplay) + return MODE_PANEL; + + if (mode->vdisplay != fixed_mode->vdisplay) + return MODE_PANEL; + + return MODE_OK; +} + int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, struct drm_display_mode *downclock_mode) diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index f6af1a98290c..71bad6d546fa 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -26,6 +26,9 @@ intel_panel_detect(struct drm_connector *connector, bool force); bool intel_panel_use_ssc(struct drm_i915_private *i915); void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); +enum drm_mode_status +intel_panel_mode_valid(struct intel_connector *connector, + const struct drm_display_mode *mode); int intel_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); struct drm_display_mode * From 8a567b1102270bd1bbbd6686cfe859aa891648b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Sep 2021 23:01:05 +0300 Subject: [PATCH 134/554] drm/i915: Use intel_panel_mode_valid() for DSI/LVDS/(s)DVO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All fixed mode panels should behave the same way when it comes to mode filtering. Reuse the intel_panel_mode_valid() for all of them. This changes the behaviour to match what we do for eDP, ie. reject anything that doesn't exactly match the fixed mode dimensions. Users can still manually provide different sized modes which will be handled by the panel fitter just as before. The difference is that we can no longer report funny modes in the connector's mode list. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210923200109.4459-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dsi.c | 11 +++++++---- drivers/gpu/drm/i915/display/intel_dvo.c | 14 ++++++++------ drivers/gpu/drm/i915/display/intel_lvds.c | 10 ++++++---- drivers/gpu/drm/i915/display/intel_sdvo.c | 12 ++++-------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c index f453ceb8d149..6f1171112a3a 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.c +++ b/drivers/gpu/drm/i915/display/intel_dsi.c @@ -5,6 +5,7 @@ #include #include "intel_dsi.h" +#include "intel_panel.h" int intel_dsi_bitrate(const struct intel_dsi *intel_dsi) { @@ -67,10 +68,12 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, return MODE_NO_DBLESCAN; if (fixed_mode) { - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; + enum drm_mode_status status; + + status = intel_panel_mode_valid(intel_connector, mode); + if (status != MODE_OK) + return status; + if (fixed_mode->clock > max_dotclk) return MODE_CLOCK_HIGH; } diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 86c903e9df60..f8fdc0386fd4 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -223,9 +223,10 @@ static enum drm_mode_status intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_dvo *intel_dvo = intel_attached_dvo(to_intel_connector(connector)); + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector); const struct drm_display_mode *fixed_mode = - to_intel_connector(connector)->panel.fixed_mode; + intel_connector->panel.fixed_mode; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; int target_clock = mode->clock; @@ -235,10 +236,11 @@ intel_dvo_mode_valid(struct drm_connector *connector, /* XXX: Validate clock range */ if (fixed_mode) { - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; + enum drm_mode_status status; + + status = intel_panel_mode_valid(intel_connector, mode); + if (status != MODE_OK) + return status; target_clock = fixed_mode->clock; } diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index e9fb402708a7..37e81bc71f7c 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -389,13 +389,15 @@ intel_lvds_mode_valid(struct drm_connector *connector, struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; int max_pixclk = to_i915(connector->dev)->max_dotclk_freq; + enum drm_mode_status status; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; + + status = intel_panel_mode_valid(intel_connector, mode); + if (status != MODE_OK) + return status; + if (fixed_mode->clock > max_pixclk) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 6cb27599ea03..fe0ea1db4cf1 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1873,7 +1873,6 @@ intel_sdvo_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (clock > max_dotclk) return MODE_CLOCK_HIGH; @@ -1890,14 +1889,11 @@ intel_sdvo_mode_valid(struct drm_connector *connector, return MODE_CLOCK_HIGH; if (IS_LVDS(intel_sdvo_connector)) { - const struct drm_display_mode *fixed_mode = - intel_sdvo_connector->base.panel.fixed_mode; + enum drm_mode_status status; - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; + status = intel_panel_mode_valid(&intel_sdvo_connector->base, mode); + if (status != MODE_OK) + return status; } return MODE_OK; From 00fc3787d277299c39a7c35290e79375c6de9f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Sep 2021 23:01:06 +0300 Subject: [PATCH 135/554] drm/i915: Reject modes that don't match fixed_mode vrefresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using a fixed mode we won't change the refresh rate ever. So filter out all modes that don't match the fixed_mode's refresh rate. I'm going to declare the "rounded to nearest Hz refresh rates must match" approach good enough for now. Note that we could start supporting multiple refresh rates with panels that can do it, but that would mean replacing the single fixed mode concept with a list of fixed modes. Then we could look for the closest match to the user's requested refresh rate and use that. But all of that would be a fair bit of work so we'll leave it for later. References: https://gitlab.freedesktop.org/drm/intel/-/issues/2939 References: https://gitlab.freedesktop.org/drm/intel/-/issues/3969 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210923200109.4459-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_panel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 8a364bb1ce41..b2ad0f065218 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -497,6 +497,9 @@ intel_panel_mode_valid(struct intel_connector *connector, if (mode->vdisplay != fixed_mode->vdisplay) return MODE_PANEL; + if (drm_mode_vrefresh(mode) != drm_mode_vrefresh(fixed_mode)) + return MODE_PANEL; + return MODE_OK; } From cff4c2c645cbb3e95d7aec9afb1a803dd2668ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Sep 2021 21:52:07 +0300 Subject: [PATCH 136/554] drm/i915: Introduce intel_panel_compute_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's introduce a compute_config() helper for fixed mode panels. For now all it does is the fixed_mode->adjusted_mode copy. Note that with sDVO we have to ask the external encoder chip to spit out our actual display timings for us, so the fixed_mode to adjusted_mode copy done by intel_panel_compute_config() is redundant, but we still want to use it to do other checks for us later. We'll be fine so long as we only call it before intel_sdvo_get_preferred_input_mode() overwrites adjusted_mode with the timings from the encoder. v2: Use intel_panel_compute_config() with sDVO Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210927185207.13620-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/icl_dsi.c | 7 ++++--- drivers/gpu/drm/i915/display/intel_dp.c | 5 +++-- drivers/gpu/drm/i915/display/intel_dvo.c | 10 ++++++++-- drivers/gpu/drm/i915/display/intel_lvds.c | 5 +++-- drivers/gpu/drm/i915/display/intel_panel.c | 11 +++++++++-- drivers/gpu/drm/i915/display/intel_panel.h | 2 ++ drivers/gpu/drm/i915/display/intel_sdvo.c | 7 +++++++ drivers/gpu/drm/i915/display/vlv_dsi.c | 4 +++- 8 files changed, 39 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index bd210166b079..c196993f0d68 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1672,14 +1672,15 @@ static int gen11_dsi_compute_config(struct intel_encoder *encoder, struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, base); struct intel_connector *intel_connector = intel_dsi->attached_connector; - const struct drm_display_mode *fixed_mode = - intel_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; int ret; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - intel_panel_fixed_mode(fixed_mode, adjusted_mode); + + ret = intel_panel_compute_config(intel_connector, adjusted_mode); + if (ret) + return ret; ret = intel_panel_fitting(pipe_config, conn_state); if (ret) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2b8b495fc2a9..b5cd188ca520 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1757,8 +1757,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON; if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) { - intel_panel_fixed_mode(intel_connector->panel.fixed_mode, - adjusted_mode); + ret = intel_panel_compute_config(intel_connector, adjusted_mode); + if (ret) + return ret; ret = intel_panel_fitting(pipe_config, conn_state); if (ret) diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index f8fdc0386fd4..2eeb209afc64 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -256,6 +256,7 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state) { struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + struct intel_connector *connector = to_intel_connector(conn_state->connector); const struct drm_display_mode *fixed_mode = intel_dvo->attached_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -266,8 +267,13 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - if (fixed_mode) - intel_panel_fixed_mode(fixed_mode, adjusted_mode); + if (fixed_mode) { + int ret; + + ret = intel_panel_compute_config(connector, adjusted_mode); + if (ret) + return ret; + } if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 37e81bc71f7c..130e6ea61e11 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -444,8 +444,9 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - intel_panel_fixed_mode(intel_connector->panel.fixed_mode, - adjusted_mode); + ret = intel_panel_compute_config(intel_connector, adjusted_mode); + if (ret) + return ret; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index b2ad0f065218..77c1ca387de0 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -45,12 +45,19 @@ bool intel_panel_use_ssc(struct drm_i915_private *i915) && !(i915->quirks & QUIRK_LVDS_SSC_DISABLE); } -void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode, - struct drm_display_mode *adjusted_mode) +int intel_panel_compute_config(struct intel_connector *connector, + struct drm_display_mode *adjusted_mode) { + const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode; + + if (!fixed_mode) + return 0; + drm_mode_copy(adjusted_mode, fixed_mode); drm_mode_set_crtcinfo(adjusted_mode, 0); + + return 0; } static bool is_downclock_mode(const struct drm_display_mode *downclock_mode, diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index 71bad6d546fa..d50b3f7e9e58 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -31,6 +31,8 @@ intel_panel_mode_valid(struct intel_connector *connector, const struct drm_display_mode *mode); int intel_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); +int intel_panel_compute_config(struct intel_connector *connector, + struct drm_display_mode *adjusted_mode); struct drm_display_mode * intel_panel_edid_downclock_mode(struct intel_connector *connector, const struct drm_display_mode *fixed_mode); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index fe0ea1db4cf1..2dc6c3742ba2 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1335,6 +1335,13 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, adjusted_mode); pipe_config->sdvo_tv_clock = true; } else if (IS_LVDS(intel_sdvo_connector)) { + int ret; + + ret = intel_panel_compute_config(&intel_sdvo_connector->base, + adjusted_mode); + if (ret) + return ret; + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, intel_sdvo_connector->base.panel.fixed_mode)) return -EINVAL; diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index b0a2b6b96799..260e852245e9 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -279,7 +279,9 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder, pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; if (fixed_mode) { - intel_panel_fixed_mode(fixed_mode, adjusted_mode); + ret = intel_panel_compute_config(intel_connector, adjusted_mode); + if (ret) + return ret; ret = intel_panel_fitting(pipe_config, conn_state); if (ret) From f5b8c316092f2501ca32ac32f5c6303e2c58ef50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 29 Sep 2021 21:45:36 +0300 Subject: [PATCH 137/554] drm/i915: Reject user modes that don't match fixed mode's refresh rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using a panel with a fixed mode we don't change the refresh rate of the display. Reject any user requested mode which doesn't match that fixed refresh rate. Unfortunately when Xorg sees the scaling_mode property on the connecor it likes to automagically cook up modes whose refresh rate is a fair bit off from the fixed refresh rate we use. So we have to give it some extra latitude so that we don't start to reject all of it. v2: sDVO now uses intel_panel_compute_config() too v3: Add a debug message to inform the user what happened References: https://gitlab.freedesktop.org/drm/intel/-/issues/2939 References: https://gitlab.freedesktop.org/drm/intel/-/issues/3969 Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210929184536.8332-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_panel.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 77c1ca387de0..a0c8e43db5eb 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -53,6 +53,21 @@ int intel_panel_compute_config(struct intel_connector *connector, if (!fixed_mode) return 0; + /* + * We don't want to lie too much to the user about the refresh + * rate they're going to get. But we have to allow a bit of latitude + * for Xorg since it likes to automagically cook up modes with slightly + * off refresh rates. + */ + if (abs(drm_mode_vrefresh(adjusted_mode) - drm_mode_vrefresh(fixed_mode)) > 1) { + drm_dbg_kms(connector->base.dev, + "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n", + connector->base.base.id, connector->base.name, + drm_mode_vrefresh(adjusted_mode), drm_mode_vrefresh(fixed_mode)); + + return -EINVAL; + } + drm_mode_copy(adjusted_mode, fixed_mode); drm_mode_set_crtcinfo(adjusted_mode, 0); From 7eadfbfe0f3bf5aad18133b7d1856778e1896b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Sep 2021 23:01:09 +0300 Subject: [PATCH 138/554] drm/i915: Drop pointless fixed_mode checks from dsi code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't support dsi displays without a fixed mode, so drop all the pointless checks. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210923200109.4459-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dsi.c | 15 ++++----- drivers/gpu/drm/i915/display/vlv_dsi.c | 41 ++++++++++-------------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c index 6f1171112a3a..6b0301ba046e 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.c +++ b/drivers/gpu/drm/i915/display/intel_dsi.c @@ -61,22 +61,19 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, struct intel_connector *intel_connector = to_intel_connector(connector); const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + enum drm_mode_status status; drm_dbg_kms(&dev_priv->drm, "\n"); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (fixed_mode) { - enum drm_mode_status status; + status = intel_panel_mode_valid(intel_connector, mode); + if (status != MODE_OK) + return status; - status = intel_panel_mode_valid(intel_connector, mode); - if (status != MODE_OK) - return status; - - if (fixed_mode->clock > max_dotclk) - return MODE_CLOCK_HIGH; - } + if (fixed_mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; return intel_mode_valid_max_plane_size(dev_priv, mode, false); } diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 260e852245e9..081b772bfe10 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -271,22 +271,19 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, base); struct intel_connector *intel_connector = intel_dsi->attached_connector; - const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; int ret; drm_dbg_kms(&dev_priv->drm, "\n"); pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - if (fixed_mode) { - ret = intel_panel_compute_config(intel_connector, adjusted_mode); - if (ret) - return ret; + ret = intel_panel_compute_config(intel_connector, adjusted_mode); + if (ret) + return ret; - ret = intel_panel_fitting(pipe_config, conn_state); - if (ret) - return ret; - } + ret = intel_panel_fitting(pipe_config, conn_state); + if (ret) + return ret; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; @@ -1633,25 +1630,21 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = { static void vlv_dsi_add_properties(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u32 allowed_scalers; - if (connector->panel.fixed_mode) { - u32 allowed_scalers; + allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); + if (!HAS_GMCH(dev_priv)) + allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); - if (!HAS_GMCH(dev_priv)) - allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); + drm_connector_attach_scaling_mode_property(&connector->base, + allowed_scalers); - drm_connector_attach_scaling_mode_property(&connector->base, - allowed_scalers); + connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; - connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; - - drm_connector_set_panel_orientation_with_quirk( - &connector->base, - intel_dsi_get_panel_orientation(connector), - connector->panel.fixed_mode->hdisplay, - connector->panel.fixed_mode->vdisplay); - } + drm_connector_set_panel_orientation_with_quirk(&connector->base, + intel_dsi_get_panel_orientation(connector), + connector->panel.fixed_mode->hdisplay, + connector->panel.fixed_mode->vdisplay); } #define NS_KHZ_RATIO 1000000 From 1e39da5a200b7ffe2a157e95b33005cacc351cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 29 Sep 2021 19:24:04 +0300 Subject: [PATCH 139/554] drm/i915: Enable TPS3/4 on all platforms that support them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using HBR2/3 support as a proxy for TPS3/4 support. The two are no longer 1:1 in the hardware, arguably they never were due to HSW ULX which does support TPS3 while being limited to HBR1. In more recent times GLK gained support for TPS4 while being limited to HBR2. And on CNL+ some ports support HBR3 while others are limited to HBR2, but all ports support TPS4. v2: s/INTEL_GEN/DISPLAY_VER/ Reviewed-by: Manasi Navare Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210929162404.6717-1-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 12 +++----- drivers/gpu/drm/i915/display/intel_dp.h | 4 +-- .../drm/i915/display/intel_dp_link_training.c | 30 +++++++++---------- drivers/gpu/drm/i915/display/intel_psr.c | 2 +- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index b5cd188ca520..8f5a935b72b6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -927,18 +927,14 @@ intel_dp_mode_valid(struct drm_connector *connector, return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner); } -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp) +bool intel_dp_source_supports_tps3(struct drm_i915_private *i915) { - int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1]; - - return max_rate >= 540000; + return DISPLAY_VER(i915) >= 9 || IS_BROADWELL(i915) || IS_HASWELL(i915); } -bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp) +bool intel_dp_source_supports_tps4(struct drm_i915_private *i915) { - int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1]; - - return max_rate >= 810000; + return DISPLAY_VER(i915) >= 10; } static void snprintf_int_array(char *str, size_t len, diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 3343c2591680..ce229026dc91 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -73,8 +73,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, u8 *link_bw, u8 *rate_select); -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp); -bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp); +bool intel_dp_source_supports_tps3(struct drm_i915_private *i915); +bool intel_dp_source_supports_tps4(struct drm_i915_private *i915); bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 4f116cd32846..449499a5c4c1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -611,6 +611,7 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); bool source_tps3, sink_tps3, source_tps4, sink_tps4; /* UHBR+ use separate 128b/132b TPS2 */ @@ -618,41 +619,40 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp, return DP_TRAINING_PATTERN_2; /* - * Intel platforms that support HBR3 also support TPS4. It is mandatory - * for all downstream devices that support HBR3. There are no known eDP - * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1 - * specification. + * TPS4 support is mandatory for all downstream devices that + * support HBR3. There are no known eDP panels that support + * TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1 specification. * LTTPRs must support TPS4. */ - source_tps4 = intel_dp_source_supports_hbr3(intel_dp); + source_tps4 = intel_dp_source_supports_tps4(i915); sink_tps4 = dp_phy != DP_PHY_DPRX || drm_dp_tps4_supported(intel_dp->dpcd); if (source_tps4 && sink_tps4) { return DP_TRAINING_PATTERN_4; } else if (crtc_state->port_clock == 810000) { if (!source_tps4) - drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "8.1 Gbps link rate without source HBR3/TPS4 support\n"); + drm_dbg_kms(&i915->drm, + "8.1 Gbps link rate without source TPS4 support\n"); if (!sink_tps4) - drm_dbg_kms(&dp_to_i915(intel_dp)->drm, + drm_dbg_kms(&i915->drm, "8.1 Gbps link rate without sink TPS4 support\n"); } + /* - * Intel platforms that support HBR2 also support TPS3. TPS3 support is - * also mandatory for downstream devices that support HBR2. However, not - * all sinks follow the spec. + * TPS3 support is mandatory for downstream devices that + * support HBR2. However, not all sinks follow the spec. */ - source_tps3 = intel_dp_source_supports_hbr2(intel_dp); + source_tps3 = intel_dp_source_supports_tps3(i915); sink_tps3 = dp_phy != DP_PHY_DPRX || drm_dp_tps3_supported(intel_dp->dpcd); if (source_tps3 && sink_tps3) { return DP_TRAINING_PATTERN_3; } else if (crtc_state->port_clock >= 540000) { if (!source_tps3) - drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - ">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n"); + drm_dbg_kms(&i915->drm, + ">=5.4/6.48 Gbps link rate without source TPS3 support\n"); if (!sink_tps3) - drm_dbg_kms(&dp_to_i915(intel_dp)->drm, + drm_dbg_kms(&i915->drm, ">=5.4/6.48 Gbps link rate without sink TPS3 support\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 19a96d3c4acf..f489bf9ca096 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -426,7 +426,7 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) val |= EDP_PSR_TP2_TP3_TIME_2500us; check_tp3_sel: - if (intel_dp_source_supports_hbr2(intel_dp) && + if (intel_dp_source_supports_tps3(dev_priv) && drm_dp_tps3_supported(intel_dp->dpcd)) val |= EDP_PSR_TP1_TP3_SEL; else From 2709abc8d14a1e67d8ecc81abc33d7119fe3dabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 24 Sep 2021 17:13:30 +0300 Subject: [PATCH 140/554] drm/i915/fbc: Allow FBC with Yf tiling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FBC+Yf tiling seems to work just fine, and unlike with linear the hardware does appear to correctly calculate the CFB stride with using the override stride on both cfl and glk. So no need for any additional tweaks. Cc: Uma Shankar #v2 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210924141330.1515-1-ville.syrjala@linux.intel.com Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_fbc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 46f62fdf9eee..687431faf02f 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -746,6 +746,7 @@ static bool tiling_is_valid(struct drm_i915_private *dev_priv, switch (modifier) { case DRM_FORMAT_MOD_LINEAR: case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: return DISPLAY_VER(dev_priv) >= 9; case I915_FORMAT_MOD_X_TILED: return true; From a471a526bc38347ab9fa6b07f399e2172d88536e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:33 +0300 Subject: [PATCH 141/554] drm/i915: Pimp HSW+ transcoder state readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the HSW+ transcoder state readout to just read through all the possible transcoders for the pipe, and stuff the results in a bitmask. We can conveniently cross check the bitmask for invalid combinations of enabled transcoders, and later we can easily extend the bitmask readout to handle the bigjoiner case. One slight change in behaviour is that we no longer read out the AONOFF->force_pfit.pfit bit for all the enabled "panel transcoders". But having more than one enabled would anyway be illegal so no big loss. Also the AONOFF selection should only ever be used on HSW, which only has the EDP transcoder an no DSI transcoders. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-10-ville.syrjala@linux.intel.com Reviewed-by: Manasi Navare --- drivers/gpu/drm/i915/display/intel_display.c | 130 ++++++++++++++----- 1 file changed, 95 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4ce80ca7751f..d731c12da718 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5724,6 +5724,21 @@ out: return ret; } +static bool transcoder_ddi_func_is_enabled(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + enum intel_display_power_domain power_domain; + intel_wakeref_t wakeref; + u32 tmp = 0; + + power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder); + + with_intel_display_power_if_enabled(dev_priv, power_domain, wakeref) + tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder)); + + return tmp & TRANS_DDI_FUNC_ENABLE; +} + static u8 hsw_panel_transcoders(struct drm_i915_private *i915) { u8 panel_transcoder_mask = BIT(TRANSCODER_EDP); @@ -5734,55 +5749,39 @@ static u8 hsw_panel_transcoders(struct drm_i915_private *i915) return panel_transcoder_mask; } -static bool hsw_get_transcoder_state(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config, - struct intel_display_power_domain_set *power_domain_set) +static u8 hsw_enabled_transcoders(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); u8 panel_transcoder_mask = hsw_panel_transcoders(dev_priv); - unsigned long enabled_panel_transcoders = 0; - enum transcoder panel_transcoder; - u32 tmp; - - /* - * The pipe->transcoder mapping is fixed with the exception of the eDP - * and DSI transcoders handled below. - */ - pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; + enum transcoder cpu_transcoder; + u8 enabled_transcoders = 0; /* * XXX: Do intel_display_power_get_if_enabled before reading this (for * consistency and less surprising code; it's in always on power). */ - for_each_cpu_transcoder_masked(dev_priv, panel_transcoder, + for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, panel_transcoder_mask) { - bool force_thru = false; + enum intel_display_power_domain power_domain; + intel_wakeref_t wakeref; enum pipe trans_pipe; + u32 tmp = 0; + + power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder); + with_intel_display_power_if_enabled(dev_priv, power_domain, wakeref) + tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder)); - tmp = intel_de_read(dev_priv, - TRANS_DDI_FUNC_CTL(panel_transcoder)); if (!(tmp & TRANS_DDI_FUNC_ENABLE)) continue; - /* - * Log all enabled ones, only use the first one. - * - * FIXME: This won't work for two separate DSI displays. - */ - enabled_panel_transcoders |= BIT(panel_transcoder); - if (enabled_panel_transcoders != BIT(panel_transcoder)) - continue; - switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { default: drm_WARN(dev, 1, "unknown pipe linked to transcoder %s\n", - transcoder_name(panel_transcoder)); + transcoder_name(cpu_transcoder)); fallthrough; case TRANS_DDI_EDP_INPUT_A_ONOFF: - force_thru = true; - fallthrough; case TRANS_DDI_EDP_INPUT_A_ON: trans_pipe = PIPE_A; break; @@ -5797,22 +5796,83 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc, break; } - if (trans_pipe == crtc->pipe) { - pipe_config->cpu_transcoder = panel_transcoder; - pipe_config->pch_pfit.force_thru = force_thru; - } + if (trans_pipe == crtc->pipe) + enabled_transcoders |= BIT(cpu_transcoder); } + cpu_transcoder = (enum transcoder) crtc->pipe; + if (transcoder_ddi_func_is_enabled(dev_priv, cpu_transcoder)) + enabled_transcoders |= BIT(cpu_transcoder); + + return enabled_transcoders; +} + +static bool has_edp_transcoders(u8 enabled_transcoders) +{ + return enabled_transcoders & BIT(TRANSCODER_EDP); +} + +static bool has_dsi_transcoders(u8 enabled_transcoders) +{ + return enabled_transcoders & (BIT(TRANSCODER_DSI_0) | + BIT(TRANSCODER_DSI_1)); +} + +static bool has_pipe_transcoders(u8 enabled_transcoders) +{ + return enabled_transcoders & ~(BIT(TRANSCODER_EDP) | + BIT(TRANSCODER_DSI_0) | + BIT(TRANSCODER_DSI_1)); +} + +static void assert_enabled_transcoders(struct drm_i915_private *i915, + u8 enabled_transcoders) +{ + /* Only one type of transcoder please */ + drm_WARN_ON(&i915->drm, + has_edp_transcoders(enabled_transcoders) + + has_dsi_transcoders(enabled_transcoders) + + has_pipe_transcoders(enabled_transcoders) > 1); + + /* Only DSI transcoders can be ganged */ + drm_WARN_ON(&i915->drm, + !has_dsi_transcoders(enabled_transcoders) && + !is_power_of_2(enabled_transcoders)); +} + +static bool hsw_get_transcoder_state(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config, + struct intel_display_power_domain_set *power_domain_set) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + unsigned long enabled_transcoders; + u32 tmp; + + enabled_transcoders = hsw_enabled_transcoders(crtc); + if (!enabled_transcoders) + return false; + + assert_enabled_transcoders(dev_priv, enabled_transcoders); + /* - * Valid combos: none, eDP, DSI0, DSI1, DSI0+DSI1 + * With the exception of DSI we should only ever have + * a single enabled transcoder. With DSI let's just + * pick the first one. */ - drm_WARN_ON(dev, (enabled_panel_transcoders & BIT(TRANSCODER_EDP)) && - enabled_panel_transcoders != BIT(TRANSCODER_EDP)); + pipe_config->cpu_transcoder = ffs(enabled_transcoders) - 1; if (!intel_display_power_get_in_set_if_enabled(dev_priv, power_domain_set, POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder))) return false; + if (hsw_panel_transcoders(dev_priv) & BIT(pipe_config->cpu_transcoder)) { + tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder)); + + if ((tmp & TRANS_DDI_EDP_INPUT_MASK) == TRANS_DDI_EDP_INPUT_A_ONOFF) + pipe_config->pch_pfit.force_thru = true; + } + tmp = intel_de_read(dev_priv, PIPECONF(pipe_config->cpu_transcoder)); return tmp & PIPECONF_ENABLE; From ef46972ac8518caf8c8409b750f4728ba8b820ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Sep 2021 17:44:34 +0300 Subject: [PATCH 142/554] drm/i915: Configure TRANSCONF just the once with bigjoiner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's not configure the single transcoder's TRANSCONF multiple times with bigjoiner. No real harm I suppose but since we already have the bigjoiner if statement directly above might as well suck this in there and skip the redundant programming. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210913144440.23008-11-ville.syrjala@linux.intel.com Reviewed-by: Manasi Navare --- drivers/gpu/drm/i915/display/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d731c12da718..a4453dd1bb51 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3215,10 +3215,9 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, &new_crtc_state->fdi_m_n, NULL); hsw_set_frame_start_delay(new_crtc_state); - } - if (!transcoder_is_dsi(cpu_transcoder)) hsw_set_transconf(new_crtc_state); + } crtc->active = true; From f0b6b01b3efe74afd2de59c894105e13b121a01e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 29 Sep 2021 10:59:50 +0200 Subject: [PATCH 143/554] drm/i915: Add ww context to intel_dpt_pin, v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure i915_vma_pin_iomap and vma_unpin are done with dpt->obj lock held. I don't think there's much of a point in merging intel_dpt_pin() with intel_pin_fb_obj_dpt(), they touch different objects. Changes since v1: - Fix using the wrong pointer to retrieve error code (Julia) Signed-off-by: Maarten Lankhorst Reported-by: kernel test robot Reported-by: Julia Lawall Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20210929085950.3063191-1-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dpt.c | 42 +++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index de62bd77b15e..8f7b1f7534a4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -121,32 +121,42 @@ struct i915_vma *intel_dpt_pin(struct i915_address_space *vm) intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *iomem; + struct i915_gem_ww_ctx ww; + int err; wakeref = intel_runtime_pm_get(&i915->runtime_pm); atomic_inc(&i915->gpu_error.pending_fb_pin); - vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096, - HAS_LMEM(i915) ? 0 : PIN_MAPPABLE); - if (IS_ERR(vma)) - goto err; + for_i915_gem_ww(&ww, err, true) { + err = i915_gem_object_lock(dpt->obj, &ww); + if (err) + continue; - iomem = i915_vma_pin_iomap(vma); - i915_vma_unpin(vma); - if (IS_ERR(iomem)) { - vma = ERR_CAST(iomem); - goto err; + vma = i915_gem_object_ggtt_pin_ww(dpt->obj, &ww, NULL, 0, 4096, + HAS_LMEM(i915) ? 0 : PIN_MAPPABLE); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + continue; + } + + iomem = i915_vma_pin_iomap(vma); + i915_vma_unpin(vma); + + if (IS_ERR(iomem)) { + err = PTR_ERR(iomem); + continue; + } + + dpt->vma = vma; + dpt->iomem = iomem; + + i915_vma_get(vma); } - dpt->vma = vma; - dpt->iomem = iomem; - - i915_vma_get(vma); - -err: atomic_dec(&i915->gpu_error.pending_fb_pin); intel_runtime_pm_put(&i915->runtime_pm, wakeref); - return vma; + return err ? ERR_PTR(err) : vma; } void intel_dpt_unpin(struct i915_address_space *vm) From 59050d783848d9b62e9d8fb6ce0cd00771c2bf87 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 28 Sep 2021 20:13:33 +0200 Subject: [PATCH 144/554] drm/bridge: Add stubs for devm_drm_of_get_bridge when OF is disabled If CONFIG_OF is disabled, devm_drm_of_get_bridge won't be compiled in and drivers using that function will fail to build. Add an inline stub so that we can still build-test those cases. Reported-by: Randy Dunlap Signed-off-by: Maxime Ripard Acked-by: Randy Dunlap # build-tested Link: https://patchwork.freedesktop.org/patch/msgid/20210928181333.1176840-1-maxime@cerno.tech --- include/drm/drm_bridge.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index a445298e1c25..061d87313fac 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -919,9 +919,20 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, struct drm_panel *panel, u32 connector_type); -struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, struct device_node *node, - u32 port, u32 endpoint); struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge); #endif +#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL_BRIDGE) +struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, struct device_node *node, + u32 port, u32 endpoint); +#else +static inline struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, + struct device_node *node, + u32 port, + u32 endpoint) +{ + return ERR_PTR(-ENODEV); +} +#endif + #endif From c4f6120302f616a3fd3cd248a102f0ae2a9ba09c Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 25 Sep 2021 20:46:12 +0800 Subject: [PATCH 145/554] drm/i915: Use direction definition DMA_BIDIRECTIONAL instead of PCI_DMA_BIDIRECTIONAL Replace direction definition PCI_DMA_BIDIRECTIONAL with DMA_BIDIRECTIONAL, because it helps to enhance readability and avoid possible inconsistency. Signed-off-by: Cai Huoqing Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210925124613.144-1-caihuoqing@baidu.com --- drivers/gpu/drm/i915/gt/intel_region_lmem.c | 4 ++-- drivers/gpu/drm/i915/gvt/gtt.c | 17 ++++++++--------- drivers/gpu/drm/i915/gvt/kvmgt.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index a74b72f50cc9..afb35d2e5c73 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -32,7 +32,7 @@ static int init_fake_lmem_bar(struct intel_memory_region *mem) mem->remap_addr = dma_map_resource(i915->drm.dev, mem->region.start, mem->fake_mappable.size, - PCI_DMA_BIDIRECTIONAL, + DMA_BIDIRECTIONAL, DMA_ATTR_FORCE_CONTIGUOUS); if (dma_mapping_error(i915->drm.dev, mem->remap_addr)) { drm_mm_remove_node(&mem->fake_mappable); @@ -62,7 +62,7 @@ static void release_fake_lmem_bar(struct intel_memory_region *mem) dma_unmap_resource(mem->i915->drm.dev, mem->remap_addr, mem->fake_mappable.size, - PCI_DMA_BIDIRECTIONAL, + DMA_BIDIRECTIONAL, DMA_ATTR_FORCE_CONTIGUOUS); } diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index e5c2fdfc20e3..53d0cb327539 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -745,7 +745,7 @@ static void ppgtt_free_spt(struct intel_vgpu_ppgtt_spt *spt) trace_spt_free(spt->vgpu->id, spt, spt->guest_page.type); dma_unmap_page(kdev, spt->shadow_page.mfn << I915_GTT_PAGE_SHIFT, 4096, - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); radix_tree_delete(&spt->vgpu->gtt.spt_tree, spt->shadow_page.mfn); @@ -849,7 +849,7 @@ retry: */ spt->shadow_page.type = type; daddr = dma_map_page(kdev, spt->shadow_page.page, - 0, 4096, PCI_DMA_BIDIRECTIONAL); + 0, 4096, DMA_BIDIRECTIONAL); if (dma_mapping_error(kdev, daddr)) { gvt_vgpu_err("fail to map dma addr\n"); ret = -EINVAL; @@ -865,7 +865,7 @@ retry: return spt; err_unmap_dma: - dma_unmap_page(kdev, daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + dma_unmap_page(kdev, daddr, PAGE_SIZE, DMA_BIDIRECTIONAL); err_free_spt: free_spt(spt); return ERR_PTR(ret); @@ -2409,8 +2409,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, return -ENOMEM; } - daddr = dma_map_page(dev, virt_to_page(scratch_pt), 0, - 4096, PCI_DMA_BIDIRECTIONAL); + daddr = dma_map_page(dev, virt_to_page(scratch_pt), 0, 4096, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, daddr)) { gvt_vgpu_err("fail to dmamap scratch_pt\n"); __free_page(virt_to_page(scratch_pt)); @@ -2461,7 +2460,7 @@ static int release_scratch_page_tree(struct intel_vgpu *vgpu) if (vgpu->gtt.scratch_pt[i].page != NULL) { daddr = (dma_addr_t)(vgpu->gtt.scratch_pt[i].page_mfn << I915_GTT_PAGE_SHIFT); - dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL); + dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL); __free_page(vgpu->gtt.scratch_pt[i].page); vgpu->gtt.scratch_pt[i].page = NULL; vgpu->gtt.scratch_pt[i].page_mfn = 0; @@ -2741,7 +2740,7 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) } daddr = dma_map_page(dev, virt_to_page(page), 0, - 4096, PCI_DMA_BIDIRECTIONAL); + 4096, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, daddr)) { gvt_err("fail to dmamap scratch ggtt page\n"); __free_page(virt_to_page(page)); @@ -2755,7 +2754,7 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) ret = setup_spt_oos(gvt); if (ret) { gvt_err("fail to initialize SPT oos\n"); - dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL); + dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL); __free_page(gvt->gtt.scratch_page); return ret; } @@ -2779,7 +2778,7 @@ void intel_gvt_clean_gtt(struct intel_gvt *gvt) dma_addr_t daddr = (dma_addr_t)(gvt->gtt.scratch_mfn << I915_GTT_PAGE_SHIFT); - dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL); + dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL); __free_page(gvt->gtt.scratch_page); diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 7efa386449d1..20b82fb036f8 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -328,7 +328,7 @@ static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, return ret; /* Setup DMA mapping. */ - *dma_addr = dma_map_page(dev, page, 0, size, PCI_DMA_BIDIRECTIONAL); + *dma_addr = dma_map_page(dev, page, 0, size, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, *dma_addr)) { gvt_vgpu_err("DMA mapping failed for pfn 0x%lx, ret %d\n", page_to_pfn(page), ret); @@ -344,7 +344,7 @@ static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn, { struct device *dev = vgpu->gvt->gt->i915->drm.dev; - dma_unmap_page(dev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); + dma_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL); gvt_unpin_guest_page(vgpu, gfn, size); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 36489be4896b..cd5f2348a187 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,7 +30,7 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, do { if (dma_map_sg_attrs(obj->base.dev->dev, pages->sgl, pages->nents, - PCI_DMA_BIDIRECTIONAL, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN)) @@ -64,7 +64,7 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj, usleep_range(100, 250); dma_unmap_sg(i915->drm.dev, pages->sgl, pages->nents, - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); } /** From 4378daf5d04eed59724e6d0e74755e17dce2e105 Mon Sep 17 00:00:00 2001 From: Lukasz Majczak Date: Thu, 30 Sep 2021 15:46:06 +0200 Subject: [PATCH 146/554] drm/i915/bdb: Fix version check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With patch "drm/i915/vbt: Fix backlight parsing for VBT 234+" the size of bdb_lfp_backlight_data structure has been increased, causing if-statement in the parse_lfp_backlight function that comapres this structure size to the one retrieved from BDB, always to fail for older revisions. This patch calculates expected size of the structure for a given BDB version and compares it with the value gathered from BDB. Tested on Chromebook Pixelbook (Nocturne) (reports bdb->version = 221) Fixes: d381baad29b4 ("drm/i915/vbt: Fix backlight parsing for VBT 234+") Tested-by: Lukasz Majczak Signed-off-by: Lukasz Majczak Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210930134606.227234-1-lma@semihalf.com --- drivers/gpu/drm/i915/display/intel_bios.c | 22 ++++++++++++++----- drivers/gpu/drm/i915/display/intel_vbt_defs.h | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 3c25926092de..f9776ca85de3 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -451,13 +451,23 @@ parse_lfp_backlight(struct drm_i915_private *i915, } i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; - if (bdb->version >= 191 && - get_blocksize(backlight_data) >= sizeof(*backlight_data)) { - const struct lfp_backlight_control_method *method; + if (bdb->version >= 191) { + size_t exp_size; - method = &backlight_data->backlight_control[panel_type]; - i915->vbt.backlight.type = method->type; - i915->vbt.backlight.controller = method->controller; + if (bdb->version >= 236) + exp_size = sizeof(struct bdb_lfp_backlight_data); + else if (bdb->version >= 234) + exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234; + else + exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191; + + if (get_blocksize(backlight_data) >= exp_size) { + const struct lfp_backlight_control_method *method; + + method = &backlight_data->backlight_control[panel_type]; + i915->vbt.backlight.type = method->type; + i915->vbt.backlight.controller = method->controller; + } } i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 330077c2e588..a2108a8f544d 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -814,6 +814,11 @@ struct lfp_brightness_level { u16 reserved; } __packed; +#define EXP_BDB_LFP_BL_DATA_SIZE_REV_191 \ + offsetof(struct bdb_lfp_backlight_data, brightness_level) +#define EXP_BDB_LFP_BL_DATA_SIZE_REV_234 \ + offsetof(struct bdb_lfp_backlight_data, brightness_precision_bits) + struct bdb_lfp_backlight_data { u8 entry_size; struct lfp_backlight_data_entry data[16]; From 1e9ae61d172f92863c84e5745cc59d485f92bdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 16:43:07 +0300 Subject: [PATCH 147/554] drm/i915: Clear leftover DP vswing/preemphasis values before modeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we clear the leftover vswing/preemphasis values only at the start of link training. That means the initial vswing programming performed during modeset is going to use stale values left over from the previous link training sequence, and then at the start of link training we're going to reset the levels back to 0. Seems much better to make sure we start with level 0 from the get go. Additionally if LTTPRs are present the leftover vswing/preemphasis values are those of the last link in the chain, so not the values that our PHY is even using after a successful link training sequence. So let's make sure everything is cleared up before we start programming anything. Suggested-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930134310.31669-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8f5a935b72b6..74a657ae131a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1835,6 +1835,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, void intel_dp_set_link_params(struct intel_dp *intel_dp, int link_rate, int lane_count) { + memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); intel_dp->link_trained = false; intel_dp->link_rate = link_rate; intel_dp->lane_count = lane_count; From 9f620f1dde3e3e984837163d7930dc4b2abffe82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 16:43:08 +0300 Subject: [PATCH 148/554] drm/i915: Call intel_ddi_init_dp_buf_reg() earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I want intel_dp->DP to be fully populated by the time the initial vswing programming happens. To that end move the intel_ddi_init_dp_buf_reg() call to an earlier spot. Additionally we don't want intel_ddi_init_dp_buf_reg() to set DDI_BUF_CTL_ENABLE since the port should only get enabled at the start of link training (see intel_ddi_prepare_link_retrain()). So any earlier write to the register should not set the enable bit. Cc: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930134310.31669-2-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 44 +++++++++++------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 51d07e9af9f3..65e59f16879d 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -282,9 +282,10 @@ static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); enum phy phy = intel_port_to_phy(i915, encoder->port); + /* DDI_BUF_CTL_ENABLE will be set by intel_ddi_prepare_link_retrain() later */ intel_dp->DP = dig_port->saved_port_bits | - DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0); - intel_dp->DP |= DDI_PORT_WIDTH(crtc_state->lane_count); + DDI_PORT_WIDTH(crtc_state->lane_count) | + DDI_BUF_TRANS_SELECT(0); if (IS_ALDERLAKE_P(i915) && intel_phy_is_tc(i915, phy)) { intel_dp->DP |= ddi_buf_phy_link_rate(crtc_state->port_clock); @@ -2360,6 +2361,12 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_link_params(intel_dp, crtc_state->port_clock, crtc_state->lane_count); + /* + * We only configure what the register value will be here. Actual + * enabling happens during link training farther down. + */ + intel_ddi_init_dp_buf_reg(encoder, crtc_state); + /* * 1. Enable Power Wells * @@ -2416,16 +2423,6 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 5.e Configure voltage swing and related IO settings */ intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level); - /* - * 5.f Configure and enable DDI_BUF_CTL - * 5.g Wait for DDI_BUF_CTL DDI Idle Status = 0b (Not Idle), timeout - * after 1200 us. - * - * We only configure what the register value will be here. Actual - * enabling happens during link training farther down. - */ - intel_ddi_init_dp_buf_reg(encoder, crtc_state); - if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); @@ -2473,6 +2470,12 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, crtc_state->port_clock, crtc_state->lane_count); + /* + * We only configure what the register value will be here. Actual + * enabling happens during link training farther down. + */ + intel_ddi_init_dp_buf_reg(encoder, crtc_state); + /* * 1. Enable Power Wells * @@ -2554,16 +2557,6 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, */ intel_ddi_mso_configure(crtc_state); - /* - * 7.g Configure and enable DDI_BUF_CTL - * 7.h Wait for DDI_BUF_CTL DDI Idle Status = 0b (Not Idle), timeout - * after 500 us. - * - * We only configure what the register value will be here. Actual - * enabling happens during link training farther down. - */ - intel_ddi_init_dp_buf_reg(encoder, crtc_state); - if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); @@ -2620,6 +2613,12 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, crtc_state->port_clock, crtc_state->lane_count); + /* + * We only configure what the register value will be here. Actual + * enabling happens during link training farther down. + */ + intel_ddi_init_dp_buf_reg(encoder, crtc_state); + intel_pps_on(intel_dp); intel_ddi_enable_clock(encoder, crtc_state); @@ -2641,7 +2640,6 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_power_up_lanes(encoder, crtc_state); - intel_ddi_init_dp_buf_reg(encoder, crtc_state); if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); From 8a1ec3f3275479292613273a7be2ac87f2a7f6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 16:43:09 +0300 Subject: [PATCH 149/554] drm/i915: Remove DP_PORT_EN stuff from link training code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting DP_PORT_EN in intel_dp->DP is already handled by intel_dp_enable_port() so there is no point in setting it also from the link training code. For DDI platforms a bit with that name doesn't even exist. The counterpart is DDI_BUF_CTL_ENABLE, which is already set up by intel_ddi_prepare_link_retrain(). Fortunately it is the same bit so there was no harm in doing this from the platform independent code as well. But it's just confusing when platform independent code sets platform specific bits in intel_dp->DP. Just get rid of it. Cc: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930134310.31669-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 449499a5c4c1..053ed9302cda 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -499,8 +499,6 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp, DP_SET_ANSI_128B132B : DP_SET_ANSI_8B10B; drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); - intel_dp->DP |= DP_PORT_EN; - return true; } From cbf02c50ea7cdce229cb80218a8ab2ee2b1b9c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 16:43:10 +0300 Subject: [PATCH 150/554] drm/i915: Nuke local copies/pointers of intel_dp->DP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the local copies and pointers of intel_dp->DP and instead just poke at it directly. Makes it much easier to see where it actually gets used/modified. Cc: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930134310.31669-4-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/g4x_dp.c | 45 ++++++++++++--------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 8e0620ae2ed1..69a2e5ad2317 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -426,7 +426,6 @@ intel_dp_link_down(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum port port = encoder->port; - u32 DP = intel_dp->DP; if (drm_WARN_ON(&dev_priv->drm, (intel_de_read(dev_priv, intel_dp->output_reg) & @@ -437,17 +436,17 @@ intel_dp_link_down(struct intel_encoder *encoder, if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) || (HAS_PCH_CPT(dev_priv) && port != PORT_A)) { - DP &= ~DP_LINK_TRAIN_MASK_CPT; - DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; + intel_dp->DP &= ~DP_LINK_TRAIN_MASK_CPT; + intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; } else { - DP &= ~DP_LINK_TRAIN_MASK; - DP |= DP_LINK_TRAIN_PAT_IDLE; + intel_dp->DP &= ~DP_LINK_TRAIN_MASK; + intel_dp->DP |= DP_LINK_TRAIN_PAT_IDLE; } - intel_de_write(dev_priv, intel_dp->output_reg, DP); + intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); - DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE); - intel_de_write(dev_priv, intel_dp->output_reg, DP); + intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE); + intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); /* @@ -464,14 +463,14 @@ intel_dp_link_down(struct intel_encoder *encoder, intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); /* always enable with pattern 1 (as per spec) */ - DP &= ~(DP_PIPE_SEL_MASK | DP_LINK_TRAIN_MASK); - DP |= DP_PORT_EN | DP_PIPE_SEL(PIPE_A) | + intel_dp->DP &= ~(DP_PIPE_SEL_MASK | DP_LINK_TRAIN_MASK); + intel_dp->DP |= DP_PORT_EN | DP_PIPE_SEL(PIPE_A) | DP_LINK_TRAIN_PAT_1; - intel_de_write(dev_priv, intel_dp->output_reg, DP); + intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); - DP &= ~DP_PORT_EN; - intel_de_write(dev_priv, intel_dp->output_reg, DP); + intel_dp->DP &= ~DP_PORT_EN; + intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); intel_wait_for_vblank_if_active(dev_priv, PIPE_A); @@ -481,8 +480,6 @@ intel_dp_link_down(struct intel_encoder *encoder, msleep(intel_dp->pps.panel_power_down_delay); - intel_dp->DP = DP; - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { intel_wakeref_t wakeref; @@ -582,19 +579,18 @@ cpt_set_link_train(struct intel_dp *intel_dp, u8 dp_train_pat) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - u32 *DP = &intel_dp->DP; - *DP &= ~DP_LINK_TRAIN_MASK_CPT; + intel_dp->DP &= ~DP_LINK_TRAIN_MASK_CPT; switch (intel_dp_training_pattern_symbol(dp_train_pat)) { case DP_TRAINING_PATTERN_DISABLE: - *DP |= DP_LINK_TRAIN_OFF_CPT; + intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; break; case DP_TRAINING_PATTERN_1: - *DP |= DP_LINK_TRAIN_PAT_1_CPT; + intel_dp->DP |= DP_LINK_TRAIN_PAT_1_CPT; break; case DP_TRAINING_PATTERN_2: - *DP |= DP_LINK_TRAIN_PAT_2_CPT; + intel_dp->DP |= DP_LINK_TRAIN_PAT_2_CPT; break; default: MISSING_CASE(intel_dp_training_pattern_symbol(dp_train_pat)); @@ -611,19 +607,18 @@ g4x_set_link_train(struct intel_dp *intel_dp, u8 dp_train_pat) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - u32 *DP = &intel_dp->DP; - *DP &= ~DP_LINK_TRAIN_MASK; + intel_dp->DP &= ~DP_LINK_TRAIN_MASK; switch (intel_dp_training_pattern_symbol(dp_train_pat)) { case DP_TRAINING_PATTERN_DISABLE: - *DP |= DP_LINK_TRAIN_OFF; + intel_dp->DP |= DP_LINK_TRAIN_OFF; break; case DP_TRAINING_PATTERN_1: - *DP |= DP_LINK_TRAIN_PAT_1; + intel_dp->DP |= DP_LINK_TRAIN_PAT_1; break; case DP_TRAINING_PATTERN_2: - *DP |= DP_LINK_TRAIN_PAT_2; + intel_dp->DP |= DP_LINK_TRAIN_PAT_2; break; default: MISSING_CASE(intel_dp_training_pattern_symbol(dp_train_pat)); From e505d76404b16646a05ba63ce5b14c1b3e2f52af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 27 Sep 2021 21:24:47 +0300 Subject: [PATCH 151/554] drm/i915: s/ddi_translations/trans/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "ddi_translations" is a bit too long, let's shorten it to just "trans". Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210927182455.27119-2-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 92 +-- .../drm/i915/display/intel_ddi_buf_trans.c | 628 +++++++++--------- drivers/gpu/drm/i915/display/intel_snps_phy.c | 12 +- 3 files changed, 366 insertions(+), 366 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 65e59f16879d..51cd0420e00e 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -104,10 +104,10 @@ void hsw_prepare_dp_ddi_buffers(struct intel_encoder *encoder, u32 iboost_bit = 0; int i, n_entries; enum port port = encoder->port; - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; /* If we're boosting the current, set bit 31 of trans1 */ @@ -117,9 +117,9 @@ void hsw_prepare_dp_ddi_buffers(struct intel_encoder *encoder, for (i = 0; i < n_entries; i++) { intel_de_write(dev_priv, DDI_BUF_TRANS_LO(port, i), - ddi_translations->entries[i].hsw.trans1 | iboost_bit); + trans->entries[i].hsw.trans1 | iboost_bit); intel_de_write(dev_priv, DDI_BUF_TRANS_HI(port, i), - ddi_translations->entries[i].hsw.trans2); + trans->entries[i].hsw.trans2); } } @@ -136,10 +136,10 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, u32 iboost_bit = 0; int n_entries; enum port port = encoder->port; - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; @@ -151,9 +151,9 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, /* Entry 9 is for HDMI: */ intel_de_write(dev_priv, DDI_BUF_TRANS_LO(port, 9), - ddi_translations->entries[level].hsw.trans1 | iboost_bit); + trans->entries[level].hsw.trans1 | iboost_bit); intel_de_write(dev_priv, DDI_BUF_TRANS_HI(port, 9), - ddi_translations->entries[level].hsw.trans2); + trans->entries[level].hsw.trans2); } void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, @@ -971,16 +971,16 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder, iboost = intel_bios_encoder_dp_boost_level(encoder->devdata); if (iboost == 0) { - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; int n_entries; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; - iboost = ddi_translations->entries[level].hsw.i_boost; + iboost = trans->entries[level].hsw.i_boost; } /* Make sure that the requested I_boost is valid */ @@ -1000,21 +1000,21 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder, int level) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; enum port port = encoder->port; int n_entries; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; bxt_ddi_phy_set_signal_level(dev_priv, port, - ddi_translations->entries[level].bxt.margin, - ddi_translations->entries[level].bxt.scale, - ddi_translations->entries[level].bxt.enable, - ddi_translations->entries[level].bxt.deemphasis); + trans->entries[level].bxt.margin, + trans->entries[level].bxt.scale, + trans->entries[level].bxt.enable, + trans->entries[level].bxt.deemphasis); } static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, @@ -1051,13 +1051,13 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, int level) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); int n_entries, ln; u32 val; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; @@ -1066,7 +1066,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); val = EDP4K2K_MODE_OVRD_EN | EDP4K2K_MODE_OVRD_OPTIMIZED; - intel_dp->hobl_active = is_hobl_buf_trans(ddi_translations); + intel_dp->hobl_active = is_hobl_buf_trans(trans); intel_de_rmw(dev_priv, ICL_PORT_CL_DW10(phy), val, intel_dp->hobl_active ? val : 0); } @@ -1084,8 +1084,8 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, val = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN0(phy)); val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | RCOMP_SCALAR_MASK); - val |= SWING_SEL_UPPER(ddi_translations->entries[level].icl.dw2_swing_sel); - val |= SWING_SEL_LOWER(ddi_translations->entries[level].icl.dw2_swing_sel); + val |= SWING_SEL_UPPER(trans->entries[level].icl.dw2_swing_sel); + val |= SWING_SEL_LOWER(trans->entries[level].icl.dw2_swing_sel); /* Program Rcomp scalar for every table entry */ val |= RCOMP_SCALAR(0x98); intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), val); @@ -1096,16 +1096,16 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, val = intel_de_read(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy)); val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | CURSOR_COEFF_MASK); - val |= POST_CURSOR_1(ddi_translations->entries[level].icl.dw4_post_cursor_1); - val |= POST_CURSOR_2(ddi_translations->entries[level].icl.dw4_post_cursor_2); - val |= CURSOR_COEFF(ddi_translations->entries[level].icl.dw4_cursor_coeff); + val |= POST_CURSOR_1(trans->entries[level].icl.dw4_post_cursor_1); + val |= POST_CURSOR_2(trans->entries[level].icl.dw4_post_cursor_2); + val |= CURSOR_COEFF(trans->entries[level].icl.dw4_cursor_coeff); intel_de_write(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy), val); } /* Program PORT_TX_DW7 */ val = intel_de_read(dev_priv, ICL_PORT_TX_DW7_LN0(phy)); val &= ~N_SCALAR_MASK; - val |= N_SCALAR(ddi_translations->entries[level].icl.dw7_n_scalar); + val |= N_SCALAR(trans->entries[level].icl.dw7_n_scalar); intel_de_write(dev_priv, ICL_PORT_TX_DW7_GRP(phy), val); } @@ -1176,15 +1176,15 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; int n_entries, ln; u32 val; if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) return; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; @@ -1205,13 +1205,13 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, val = intel_de_read(dev_priv, MG_TX1_SWINGCTRL(ln, tc_port)); val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK; val |= CRI_TXDEEMPH_OVERRIDE_17_12( - ddi_translations->entries[level].mg.cri_txdeemph_override_17_12); + trans->entries[level].mg.cri_txdeemph_override_17_12); intel_de_write(dev_priv, MG_TX1_SWINGCTRL(ln, tc_port), val); val = intel_de_read(dev_priv, MG_TX2_SWINGCTRL(ln, tc_port)); val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK; val |= CRI_TXDEEMPH_OVERRIDE_17_12( - ddi_translations->entries[level].mg.cri_txdeemph_override_17_12); + trans->entries[level].mg.cri_txdeemph_override_17_12); intel_de_write(dev_priv, MG_TX2_SWINGCTRL(ln, tc_port), val); } @@ -1221,9 +1221,9 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK | CRI_TXDEEMPH_OVERRIDE_5_0_MASK); val |= CRI_TXDEEMPH_OVERRIDE_5_0( - ddi_translations->entries[level].mg.cri_txdeemph_override_5_0) | + trans->entries[level].mg.cri_txdeemph_override_5_0) | CRI_TXDEEMPH_OVERRIDE_11_6( - ddi_translations->entries[level].mg.cri_txdeemph_override_11_6) | + trans->entries[level].mg.cri_txdeemph_override_11_6) | CRI_TXDEEMPH_OVERRIDE_EN; intel_de_write(dev_priv, MG_TX1_DRVCTRL(ln, tc_port), val); @@ -1231,9 +1231,9 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK | CRI_TXDEEMPH_OVERRIDE_5_0_MASK); val |= CRI_TXDEEMPH_OVERRIDE_5_0( - ddi_translations->entries[level].mg.cri_txdeemph_override_5_0) | + trans->entries[level].mg.cri_txdeemph_override_5_0) | CRI_TXDEEMPH_OVERRIDE_11_6( - ddi_translations->entries[level].mg.cri_txdeemph_override_11_6) | + trans->entries[level].mg.cri_txdeemph_override_11_6) | CRI_TXDEEMPH_OVERRIDE_EN; intel_de_write(dev_priv, MG_TX2_DRVCTRL(ln, tc_port), val); @@ -1313,15 +1313,15 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; u32 val, dpcnt_mask, dpcnt_val; int n_entries, ln; if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) return; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) level = n_entries - 1; @@ -1329,9 +1329,9 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, dpcnt_mask = (DKL_TX_PRESHOOT_COEFF_MASK | DKL_TX_DE_EMPAHSIS_COEFF_MASK | DKL_TX_VSWING_CONTROL_MASK); - dpcnt_val = DKL_TX_VSWING_CONTROL(ddi_translations->entries[level].dkl.dkl_vswing_control); - dpcnt_val |= DKL_TX_DE_EMPHASIS_COEFF(ddi_translations->entries[level].dkl.dkl_de_emphasis_control); - dpcnt_val |= DKL_TX_PRESHOOT_COEFF(ddi_translations->entries[level].dkl.dkl_preshoot_control); + dpcnt_val = DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.dkl_vswing_control); + dpcnt_val |= DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.dkl_de_emphasis_control); + dpcnt_val |= DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.dkl_preshoot_control); for (ln = 0; ln < 2; ln++) { intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index 796dd04eae01..449daba7afb3 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -13,7 +13,7 @@ * them for both DP and FDI transports, allowing those ports to * automatically adapt to HDMI connections as well */ -static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _hsw_trans_dp[] = { { .hsw = { 0x00FFFFFF, 0x0006000E, 0x0 } }, { .hsw = { 0x00D75FFF, 0x0005000A, 0x0 } }, { .hsw = { 0x00C30FFF, 0x00040006, 0x0 } }, @@ -25,12 +25,12 @@ static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_dp[] = { { .hsw = { 0x80D75FFF, 0x000B0000, 0x0 } }, }; -static const struct intel_ddi_buf_trans hsw_ddi_translations_dp = { - .entries = _hsw_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_hsw_ddi_translations_dp), +static const struct intel_ddi_buf_trans hsw_trans_dp = { + .entries = _hsw_trans_dp, + .num_entries = ARRAY_SIZE(_hsw_trans_dp), }; -static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_fdi[] = { +static const union intel_ddi_buf_trans_entry _hsw_trans_fdi[] = { { .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } }, { .hsw = { 0x00D75FFF, 0x000F000A, 0x0 } }, { .hsw = { 0x00C30FFF, 0x00060006, 0x0 } }, @@ -42,12 +42,12 @@ static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_fdi[] = { { .hsw = { 0x00D75FFF, 0x001E0000, 0x0 } }, }; -static const struct intel_ddi_buf_trans hsw_ddi_translations_fdi = { - .entries = _hsw_ddi_translations_fdi, - .num_entries = ARRAY_SIZE(_hsw_ddi_translations_fdi), +static const struct intel_ddi_buf_trans hsw_trans_fdi = { + .entries = _hsw_trans_fdi, + .num_entries = ARRAY_SIZE(_hsw_trans_fdi), }; -static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _hsw_trans_hdmi[] = { /* Idx NT mV d T mV d db */ { .hsw = { 0x00FFFFFF, 0x0006000E, 0x0 } }, /* 0: 400 400 0 */ { .hsw = { 0x00E79FFF, 0x000E000C, 0x0 } }, /* 1: 400 500 2 */ @@ -63,13 +63,13 @@ static const union intel_ddi_buf_trans_entry _hsw_ddi_translations_hdmi[] = { { .hsw = { 0x80FFFFFF, 0x00030002, 0x0 } }, /* 11: 1000 1000 0 */ }; -static const struct intel_ddi_buf_trans hsw_ddi_translations_hdmi = { - .entries = _hsw_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_hsw_ddi_translations_hdmi), +static const struct intel_ddi_buf_trans hsw_trans_hdmi = { + .entries = _hsw_trans_hdmi, + .num_entries = ARRAY_SIZE(_hsw_trans_hdmi), .hdmi_default_entry = 6, }; -static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_edp[] = { +static const union intel_ddi_buf_trans_entry _bdw_trans_edp[] = { { .hsw = { 0x00FFFFFF, 0x00000012, 0x0 } }, { .hsw = { 0x00EBAFFF, 0x00020011, 0x0 } }, { .hsw = { 0x00C71FFF, 0x0006000F, 0x0 } }, @@ -81,12 +81,12 @@ static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_edp[] = { { .hsw = { 0x00DB6FFF, 0x000A000C, 0x0 } }, }; -static const struct intel_ddi_buf_trans bdw_ddi_translations_edp = { - .entries = _bdw_ddi_translations_edp, - .num_entries = ARRAY_SIZE(_bdw_ddi_translations_edp), +static const struct intel_ddi_buf_trans bdw_trans_edp = { + .entries = _bdw_trans_edp, + .num_entries = ARRAY_SIZE(_bdw_trans_edp), }; -static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _bdw_trans_dp[] = { { .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } }, { .hsw = { 0x00D75FFF, 0x000E000A, 0x0 } }, { .hsw = { 0x00BEFFFF, 0x00140006, 0x0 } }, @@ -98,12 +98,12 @@ static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_dp[] = { { .hsw = { 0x80D75FFF, 0x001B0002, 0x0 } }, }; -static const struct intel_ddi_buf_trans bdw_ddi_translations_dp = { - .entries = _bdw_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_bdw_ddi_translations_dp), +static const struct intel_ddi_buf_trans bdw_trans_dp = { + .entries = _bdw_trans_dp, + .num_entries = ARRAY_SIZE(_bdw_trans_dp), }; -static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_fdi[] = { +static const union intel_ddi_buf_trans_entry _bdw_trans_fdi[] = { { .hsw = { 0x00FFFFFF, 0x0001000E, 0x0 } }, { .hsw = { 0x00D75FFF, 0x0004000A, 0x0 } }, { .hsw = { 0x00C30FFF, 0x00070006, 0x0 } }, @@ -115,12 +115,12 @@ static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_fdi[] = { { .hsw = { 0x00D75FFF, 0x000C0000, 0x0 } }, }; -static const struct intel_ddi_buf_trans bdw_ddi_translations_fdi = { - .entries = _bdw_ddi_translations_fdi, - .num_entries = ARRAY_SIZE(_bdw_ddi_translations_fdi), +static const struct intel_ddi_buf_trans bdw_trans_fdi = { + .entries = _bdw_trans_fdi, + .num_entries = ARRAY_SIZE(_bdw_trans_fdi), }; -static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _bdw_trans_hdmi[] = { /* Idx NT mV d T mV df db */ { .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } }, /* 0: 400 400 0 */ { .hsw = { 0x00D75FFF, 0x000E000A, 0x0 } }, /* 1: 400 600 3.5 */ @@ -134,14 +134,14 @@ static const union intel_ddi_buf_trans_entry _bdw_ddi_translations_hdmi[] = { { .hsw = { 0x80FFFFFF, 0x001B0002, 0x0 } }, /* 9: 1000 1000 0 */ }; -static const struct intel_ddi_buf_trans bdw_ddi_translations_hdmi = { - .entries = _bdw_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_bdw_ddi_translations_hdmi), +static const struct intel_ddi_buf_trans bdw_trans_hdmi = { + .entries = _bdw_trans_hdmi, + .num_entries = ARRAY_SIZE(_bdw_trans_hdmi), .hdmi_default_entry = 7, }; /* Skylake H and S */ -static const union intel_ddi_buf_trans_entry _skl_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _skl_trans_dp[] = { { .hsw = { 0x00002016, 0x000000A0, 0x0 } }, { .hsw = { 0x00005012, 0x0000009B, 0x0 } }, { .hsw = { 0x00007011, 0x00000088, 0x0 } }, @@ -153,13 +153,13 @@ static const union intel_ddi_buf_trans_entry _skl_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x1 } }, }; -static const struct intel_ddi_buf_trans skl_ddi_translations_dp = { - .entries = _skl_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_skl_ddi_translations_dp), +static const struct intel_ddi_buf_trans skl_trans_dp = { + .entries = _skl_trans_dp, + .num_entries = ARRAY_SIZE(_skl_trans_dp), }; /* Skylake U */ -static const union intel_ddi_buf_trans_entry _skl_u_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _skl_u_trans_dp[] = { { .hsw = { 0x0000201B, 0x000000A2, 0x0 } }, { .hsw = { 0x00005012, 0x00000088, 0x0 } }, { .hsw = { 0x80007011, 0x000000CD, 0x1 } }, @@ -171,13 +171,13 @@ static const union intel_ddi_buf_trans_entry _skl_u_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x1 } }, }; -static const struct intel_ddi_buf_trans skl_u_ddi_translations_dp = { - .entries = _skl_u_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_skl_u_ddi_translations_dp), +static const struct intel_ddi_buf_trans skl_u_trans_dp = { + .entries = _skl_u_trans_dp, + .num_entries = ARRAY_SIZE(_skl_u_trans_dp), }; /* Skylake Y */ -static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _skl_y_trans_dp[] = { { .hsw = { 0x00000018, 0x000000A2, 0x0 } }, { .hsw = { 0x00005012, 0x00000088, 0x0 } }, { .hsw = { 0x80007011, 0x000000CD, 0x3 } }, @@ -189,13 +189,13 @@ static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x3 } }, }; -static const struct intel_ddi_buf_trans skl_y_ddi_translations_dp = { - .entries = _skl_y_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_skl_y_ddi_translations_dp), +static const struct intel_ddi_buf_trans skl_y_trans_dp = { + .entries = _skl_y_trans_dp, + .num_entries = ARRAY_SIZE(_skl_y_trans_dp), }; /* Kabylake H and S */ -static const union intel_ddi_buf_trans_entry _kbl_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _kbl_trans_dp[] = { { .hsw = { 0x00002016, 0x000000A0, 0x0 } }, { .hsw = { 0x00005012, 0x0000009B, 0x0 } }, { .hsw = { 0x00007011, 0x00000088, 0x0 } }, @@ -207,13 +207,13 @@ static const union intel_ddi_buf_trans_entry _kbl_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x1 } }, }; -static const struct intel_ddi_buf_trans kbl_ddi_translations_dp = { - .entries = _kbl_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_kbl_ddi_translations_dp), +static const struct intel_ddi_buf_trans kbl_trans_dp = { + .entries = _kbl_trans_dp, + .num_entries = ARRAY_SIZE(_kbl_trans_dp), }; /* Kabylake U */ -static const union intel_ddi_buf_trans_entry _kbl_u_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _kbl_u_trans_dp[] = { { .hsw = { 0x0000201B, 0x000000A1, 0x0 } }, { .hsw = { 0x00005012, 0x00000088, 0x0 } }, { .hsw = { 0x80007011, 0x000000CD, 0x3 } }, @@ -225,13 +225,13 @@ static const union intel_ddi_buf_trans_entry _kbl_u_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x3 } }, }; -static const struct intel_ddi_buf_trans kbl_u_ddi_translations_dp = { - .entries = _kbl_u_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_kbl_u_ddi_translations_dp), +static const struct intel_ddi_buf_trans kbl_u_trans_dp = { + .entries = _kbl_u_trans_dp, + .num_entries = ARRAY_SIZE(_kbl_u_trans_dp), }; /* Kabylake Y */ -static const union intel_ddi_buf_trans_entry _kbl_y_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _kbl_y_trans_dp[] = { { .hsw = { 0x00001017, 0x000000A1, 0x0 } }, { .hsw = { 0x00005012, 0x00000088, 0x0 } }, { .hsw = { 0x80007011, 0x000000CD, 0x3 } }, @@ -243,16 +243,16 @@ static const union intel_ddi_buf_trans_entry _kbl_y_ddi_translations_dp[] = { { .hsw = { 0x80005012, 0x000000C0, 0x3 } }, }; -static const struct intel_ddi_buf_trans kbl_y_ddi_translations_dp = { - .entries = _kbl_y_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_kbl_y_ddi_translations_dp), +static const struct intel_ddi_buf_trans kbl_y_trans_dp = { + .entries = _kbl_y_trans_dp, + .num_entries = ARRAY_SIZE(_kbl_y_trans_dp), }; /* * Skylake/Kabylake H and S * eDP 1.4 low vswing translation parameters */ -static const union intel_ddi_buf_trans_entry _skl_ddi_translations_edp[] = { +static const union intel_ddi_buf_trans_entry _skl_trans_edp[] = { { .hsw = { 0x00000018, 0x000000A8, 0x0 } }, { .hsw = { 0x00004013, 0x000000A9, 0x0 } }, { .hsw = { 0x00007011, 0x000000A2, 0x0 } }, @@ -265,16 +265,16 @@ static const union intel_ddi_buf_trans_entry _skl_ddi_translations_edp[] = { { .hsw = { 0x00000018, 0x000000DF, 0x0 } }, }; -static const struct intel_ddi_buf_trans skl_ddi_translations_edp = { - .entries = _skl_ddi_translations_edp, - .num_entries = ARRAY_SIZE(_skl_ddi_translations_edp), +static const struct intel_ddi_buf_trans skl_trans_edp = { + .entries = _skl_trans_edp, + .num_entries = ARRAY_SIZE(_skl_trans_edp), }; /* * Skylake/Kabylake U * eDP 1.4 low vswing translation parameters */ -static const union intel_ddi_buf_trans_entry _skl_u_ddi_translations_edp[] = { +static const union intel_ddi_buf_trans_entry _skl_u_trans_edp[] = { { .hsw = { 0x00000018, 0x000000A8, 0x0 } }, { .hsw = { 0x00004013, 0x000000A9, 0x0 } }, { .hsw = { 0x00007011, 0x000000A2, 0x0 } }, @@ -287,16 +287,16 @@ static const union intel_ddi_buf_trans_entry _skl_u_ddi_translations_edp[] = { { .hsw = { 0x00000018, 0x000000DF, 0x0 } }, }; -static const struct intel_ddi_buf_trans skl_u_ddi_translations_edp = { - .entries = _skl_u_ddi_translations_edp, - .num_entries = ARRAY_SIZE(_skl_u_ddi_translations_edp), +static const struct intel_ddi_buf_trans skl_u_trans_edp = { + .entries = _skl_u_trans_edp, + .num_entries = ARRAY_SIZE(_skl_u_trans_edp), }; /* * Skylake/Kabylake Y * eDP 1.4 low vswing translation parameters */ -static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_edp[] = { +static const union intel_ddi_buf_trans_entry _skl_y_trans_edp[] = { { .hsw = { 0x00000018, 0x000000A8, 0x0 } }, { .hsw = { 0x00004013, 0x000000AB, 0x0 } }, { .hsw = { 0x00007011, 0x000000A4, 0x0 } }, @@ -309,13 +309,13 @@ static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_edp[] = { { .hsw = { 0x00000018, 0x0000008A, 0x0 } }, }; -static const struct intel_ddi_buf_trans skl_y_ddi_translations_edp = { - .entries = _skl_y_ddi_translations_edp, - .num_entries = ARRAY_SIZE(_skl_y_ddi_translations_edp), +static const struct intel_ddi_buf_trans skl_y_trans_edp = { + .entries = _skl_y_trans_edp, + .num_entries = ARRAY_SIZE(_skl_y_trans_edp), }; /* Skylake/Kabylake U, H and S */ -static const union intel_ddi_buf_trans_entry _skl_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _skl_trans_hdmi[] = { { .hsw = { 0x00000018, 0x000000AC, 0x0 } }, { .hsw = { 0x00005012, 0x0000009D, 0x0 } }, { .hsw = { 0x00007011, 0x00000088, 0x0 } }, @@ -329,14 +329,14 @@ static const union intel_ddi_buf_trans_entry _skl_ddi_translations_hdmi[] = { { .hsw = { 0x80000018, 0x000000C0, 0x1 } }, }; -static const struct intel_ddi_buf_trans skl_ddi_translations_hdmi = { - .entries = _skl_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_skl_ddi_translations_hdmi), +static const struct intel_ddi_buf_trans skl_trans_hdmi = { + .entries = _skl_trans_hdmi, + .num_entries = ARRAY_SIZE(_skl_trans_hdmi), .hdmi_default_entry = 8, }; /* Skylake/Kabylake Y */ -static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _skl_y_trans_hdmi[] = { { .hsw = { 0x00000018, 0x000000A1, 0x0 } }, { .hsw = { 0x00005012, 0x000000DF, 0x0 } }, { .hsw = { 0x80007011, 0x000000CB, 0x3 } }, @@ -350,13 +350,13 @@ static const union intel_ddi_buf_trans_entry _skl_y_ddi_translations_hdmi[] = { { .hsw = { 0x80000018, 0x000000C0, 0x3 } }, }; -static const struct intel_ddi_buf_trans skl_y_ddi_translations_hdmi = { - .entries = _skl_y_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_skl_y_ddi_translations_hdmi), +static const struct intel_ddi_buf_trans skl_y_trans_hdmi = { + .entries = _skl_y_trans_hdmi, + .num_entries = ARRAY_SIZE(_skl_y_trans_hdmi), .hdmi_default_entry = 8, }; -static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _bxt_trans_dp[] = { /* Idx NT mV diff db */ { .bxt = { 52, 0x9A, 0, 128, } }, /* 0: 400 0 */ { .bxt = { 78, 0x9A, 0, 85, } }, /* 1: 400 3.5 */ @@ -370,12 +370,12 @@ static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_dp[] = { { .bxt = { 154, 0x9A, 1, 128, } }, /* 9: 1200 0 */ }; -static const struct intel_ddi_buf_trans bxt_ddi_translations_dp = { - .entries = _bxt_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_bxt_ddi_translations_dp), +static const struct intel_ddi_buf_trans bxt_trans_dp = { + .entries = _bxt_trans_dp, + .num_entries = ARRAY_SIZE(_bxt_trans_dp), }; -static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_edp[] = { +static const union intel_ddi_buf_trans_entry _bxt_trans_edp[] = { /* Idx NT mV diff db */ { .bxt = { 26, 0, 0, 128, } }, /* 0: 200 0 */ { .bxt = { 38, 0, 0, 112, } }, /* 1: 200 1.5 */ @@ -389,15 +389,15 @@ static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_edp[] = { { .bxt = { 48, 0, 0, 128, } }, /* 9: 300 0 */ }; -static const struct intel_ddi_buf_trans bxt_ddi_translations_edp = { - .entries = _bxt_ddi_translations_edp, - .num_entries = ARRAY_SIZE(_bxt_ddi_translations_edp), +static const struct intel_ddi_buf_trans bxt_trans_edp = { + .entries = _bxt_trans_edp, + .num_entries = ARRAY_SIZE(_bxt_trans_edp), }; /* BSpec has 2 recommended values - entries 0 and 8. * Using the entry with higher vswing. */ -static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _bxt_trans_hdmi[] = { /* Idx NT mV diff db */ { .bxt = { 52, 0x9A, 0, 128, } }, /* 0: 400 0 */ { .bxt = { 52, 0x9A, 0, 85, } }, /* 1: 400 3.5 */ @@ -411,14 +411,14 @@ static const union intel_ddi_buf_trans_entry _bxt_ddi_translations_hdmi[] = { { .bxt = { 154, 0x9A, 1, 128, } }, /* 9: 1200 0 */ }; -static const struct intel_ddi_buf_trans bxt_ddi_translations_hdmi = { - .entries = _bxt_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_bxt_ddi_translations_hdmi), - .hdmi_default_entry = ARRAY_SIZE(_bxt_ddi_translations_hdmi) - 1, +static const struct intel_ddi_buf_trans bxt_trans_hdmi = { + .entries = _bxt_trans_hdmi, + .num_entries = ARRAY_SIZE(_bxt_trans_hdmi), + .hdmi_default_entry = ARRAY_SIZE(_bxt_trans_hdmi) - 1, }; -/* icl_combo_phy_ddi_translations */ -static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3[] = { +/* icl_combo_phy_trans */ +static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_dp_hbr2_edp_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -432,12 +432,12 @@ static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3 = { - .entries = _icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, - .num_entries = ARRAY_SIZE(_icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3), +static const struct intel_ddi_buf_trans icl_combo_phy_trans_dp_hbr2_edp_hbr3 = { + .entries = _icl_combo_phy_trans_dp_hbr2_edp_hbr3, + .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_dp_hbr2_edp_hbr3), }; -static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_edp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_edp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0x0, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 200 0.0 */ { .icl = { 0x8, 0x7F, 0x38, 0x00, 0x07 } }, /* 200 250 1.9 */ @@ -451,12 +451,12 @@ static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_edp { .icl = { 0x9, 0x7F, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ }; -static const struct intel_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2 = { - .entries = _icl_combo_phy_ddi_translations_edp_hbr2, - .num_entries = ARRAY_SIZE(_icl_combo_phy_ddi_translations_edp_hbr2), +static const struct intel_ddi_buf_trans icl_combo_phy_trans_edp_hbr2 = { + .entries = _icl_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_edp_hbr2), }; -static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_hdmi[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x60, 0x3F, 0x00, 0x00 } }, /* 450 450 0.0 */ { .icl = { 0xB, 0x73, 0x36, 0x00, 0x09 } }, /* 450 650 3.2 */ @@ -467,13 +467,13 @@ static const union intel_ddi_buf_trans_entry _icl_combo_phy_ddi_translations_hdm { .icl = { 0x6, 0x7F, 0x35, 0x00, 0x0A } }, /* 600 850 3.0 */ }; -static const struct intel_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi = { - .entries = _icl_combo_phy_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_icl_combo_phy_ddi_translations_hdmi), - .hdmi_default_entry = ARRAY_SIZE(_icl_combo_phy_ddi_translations_hdmi) - 1, +static const struct intel_ddi_buf_trans icl_combo_phy_trans_hdmi = { + .entries = _icl_combo_phy_trans_hdmi, + .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_hdmi), + .hdmi_default_entry = ARRAY_SIZE(_icl_combo_phy_trans_hdmi) - 1, }; -static const union intel_ddi_buf_trans_entry _ehl_combo_phy_ddi_translations_dp[] = { +static const union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_dp[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x33, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x47, 0x36, 0x00, 0x09 } }, /* 350 500 3.1 */ @@ -487,12 +487,12 @@ static const union intel_ddi_buf_trans_entry _ehl_combo_phy_ddi_translations_dp[ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans ehl_combo_phy_ddi_translations_dp = { - .entries = _ehl_combo_phy_ddi_translations_dp, - .num_entries = ARRAY_SIZE(_ehl_combo_phy_ddi_translations_dp), +static const struct intel_ddi_buf_trans ehl_combo_phy_trans_dp = { + .entries = _ehl_combo_phy_trans_dp, + .num_entries = ARRAY_SIZE(_ehl_combo_phy_trans_dp), }; -static const union intel_ddi_buf_trans_entry _ehl_combo_phy_ddi_translations_edp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_edp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 200 0.0 */ { .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 250 1.9 */ @@ -506,12 +506,12 @@ static const union intel_ddi_buf_trans_entry _ehl_combo_phy_ddi_translations_edp { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ }; -static const struct intel_ddi_buf_trans ehl_combo_phy_ddi_translations_edp_hbr2 = { - .entries = _ehl_combo_phy_ddi_translations_edp_hbr2, - .num_entries = ARRAY_SIZE(_ehl_combo_phy_ddi_translations_edp_hbr2), +static const struct intel_ddi_buf_trans ehl_combo_phy_trans_edp_hbr2 = { + .entries = _ehl_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_ehl_combo_phy_trans_edp_hbr2), }; -static const union intel_ddi_buf_trans_entry _jsl_combo_phy_ddi_translations_edp_hbr[] = { +static const union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr[] = { /* NT mV Trans mV db */ { .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 200 0.0 */ { .icl = { 0x8, 0x7F, 0x38, 0x00, 0x07 } }, /* 200 250 1.9 */ @@ -525,12 +525,12 @@ static const union intel_ddi_buf_trans_entry _jsl_combo_phy_ddi_translations_edp { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ }; -static const struct intel_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr = { - .entries = _jsl_combo_phy_ddi_translations_edp_hbr, - .num_entries = ARRAY_SIZE(_jsl_combo_phy_ddi_translations_edp_hbr), +static const struct intel_ddi_buf_trans jsl_combo_phy_trans_edp_hbr = { + .entries = _jsl_combo_phy_trans_edp_hbr, + .num_entries = ARRAY_SIZE(_jsl_combo_phy_trans_edp_hbr), }; -static const union intel_ddi_buf_trans_entry _jsl_combo_phy_ddi_translations_edp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 200 0.0 */ { .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } }, /* 200 250 1.9 */ @@ -544,12 +544,12 @@ static const union intel_ddi_buf_trans_entry _jsl_combo_phy_ddi_translations_edp { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ }; -static const struct intel_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2 = { - .entries = _jsl_combo_phy_ddi_translations_edp_hbr2, - .num_entries = ARRAY_SIZE(_jsl_combo_phy_ddi_translations_edp_hbr2), +static const struct intel_ddi_buf_trans jsl_combo_phy_trans_edp_hbr2 = { + .entries = _jsl_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_jsl_combo_phy_trans_edp_hbr2), }; -static const union intel_ddi_buf_trans_entry _dg1_combo_phy_ddi_translations_dp_rbr_hbr[] = { +static const union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_rbr_hbr[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x48, 0x35, 0x00, 0x0A } }, /* 350 500 3.1 */ @@ -563,12 +563,12 @@ static const union intel_ddi_buf_trans_entry _dg1_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_rbr_hbr = { - .entries = _dg1_combo_phy_ddi_translations_dp_rbr_hbr, - .num_entries = ARRAY_SIZE(_dg1_combo_phy_ddi_translations_dp_rbr_hbr), +static const struct intel_ddi_buf_trans dg1_combo_phy_trans_dp_rbr_hbr = { + .entries = _dg1_combo_phy_trans_dp_rbr_hbr, + .num_entries = ARRAY_SIZE(_dg1_combo_phy_trans_dp_rbr_hbr), }; -static const union intel_ddi_buf_trans_entry _dg1_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_hbr2_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x48, 0x35, 0x00, 0x0A } }, /* 350 500 3.1 */ @@ -582,12 +582,12 @@ static const union intel_ddi_buf_trans_entry _dg1_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_hbr2_hbr3 = { - .entries = _dg1_combo_phy_ddi_translations_dp_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_dg1_combo_phy_ddi_translations_dp_hbr2_hbr3), +static const struct intel_ddi_buf_trans dg1_combo_phy_trans_dp_hbr2_hbr3 = { + .entries = _dg1_combo_phy_trans_dp_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_dg1_combo_phy_trans_dp_hbr2_hbr3), }; -static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_rbr_hbr[] = { +static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_rbr_hbr[] = { /* Voltage swing pre-emphasis */ { .mg = { 0x18, 0x00, 0x00 } }, /* 0 0 */ { .mg = { 0x1D, 0x00, 0x05 } }, /* 0 1 */ @@ -601,12 +601,12 @@ static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_rbr_hb { .mg = { 0x3F, 0x00, 0x00 } }, /* 3 0 */ }; -static const struct intel_ddi_buf_trans icl_mg_phy_ddi_translations_rbr_hbr = { - .entries = _icl_mg_phy_ddi_translations_rbr_hbr, - .num_entries = ARRAY_SIZE(_icl_mg_phy_ddi_translations_rbr_hbr), +static const struct intel_ddi_buf_trans icl_mg_phy_trans_rbr_hbr = { + .entries = _icl_mg_phy_trans_rbr_hbr, + .num_entries = ARRAY_SIZE(_icl_mg_phy_trans_rbr_hbr), }; -static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hbr2_hbr3[] = { /* Voltage swing pre-emphasis */ { .mg = { 0x18, 0x00, 0x00 } }, /* 0 0 */ { .mg = { 0x1D, 0x00, 0x05 } }, /* 0 1 */ @@ -620,12 +620,12 @@ static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_hbr2_h { .mg = { 0x3F, 0x00, 0x00 } }, /* 3 0 */ }; -static const struct intel_ddi_buf_trans icl_mg_phy_ddi_translations_hbr2_hbr3 = { - .entries = _icl_mg_phy_ddi_translations_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_icl_mg_phy_ddi_translations_hbr2_hbr3), +static const struct intel_ddi_buf_trans icl_mg_phy_trans_hbr2_hbr3 = { + .entries = _icl_mg_phy_trans_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_icl_mg_phy_trans_hbr2_hbr3), }; -static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hdmi[] = { /* HDMI Preset VS Pre-emph */ { .mg = { 0x1A, 0x0, 0x0 } }, /* 1 400mV 0dB */ { .mg = { 0x20, 0x0, 0x0 } }, /* 2 500mV 0dB */ @@ -639,13 +639,13 @@ static const union intel_ddi_buf_trans_entry _icl_mg_phy_ddi_translations_hdmi[] { .mg = { 0x36, 0x0, 0x9 } }, /* 10 Full -3 dB */ }; -static const struct intel_ddi_buf_trans icl_mg_phy_ddi_translations_hdmi = { - .entries = _icl_mg_phy_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_icl_mg_phy_ddi_translations_hdmi), - .hdmi_default_entry = ARRAY_SIZE(_icl_mg_phy_ddi_translations_hdmi) - 1, +static const struct intel_ddi_buf_trans icl_mg_phy_trans_hdmi = { + .entries = _icl_mg_phy_trans_hdmi, + .num_entries = ARRAY_SIZE(_icl_mg_phy_trans_hdmi), + .hdmi_default_entry = ARRAY_SIZE(_icl_mg_phy_trans_hdmi) - 1, }; -static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_dp_hbr[] = { +static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr[] = { /* VS pre-emp Non-trans mV Pre-emph dB */ { .dkl = { 0x7, 0x0, 0x00 } }, /* 0 0 400mV 0 dB */ { .dkl = { 0x5, 0x0, 0x05 } }, /* 0 1 400mV 3.5 dB */ @@ -659,12 +659,12 @@ static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_dp_hb { .dkl = { 0x0, 0x0, 0x00 } }, /* 3 0 1200mV 0 dB HDMI default */ }; -static const struct intel_ddi_buf_trans tgl_dkl_phy_ddi_translations_dp_hbr = { - .entries = _tgl_dkl_phy_ddi_translations_dp_hbr, - .num_entries = ARRAY_SIZE(_tgl_dkl_phy_ddi_translations_dp_hbr), +static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_dp_hbr = { + .entries = _tgl_dkl_phy_trans_dp_hbr, + .num_entries = ARRAY_SIZE(_tgl_dkl_phy_trans_dp_hbr), }; -static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_dp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr2[] = { /* VS pre-emp Non-trans mV Pre-emph dB */ { .dkl = { 0x7, 0x0, 0x00 } }, /* 0 0 400mV 0 dB */ { .dkl = { 0x5, 0x0, 0x05 } }, /* 0 1 400mV 3.5 dB */ @@ -678,12 +678,12 @@ static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_dp_hb { .dkl = { 0x0, 0x0, 0x00 } }, /* 3 0 1200mV 0 dB HDMI default */ }; -static const struct intel_ddi_buf_trans tgl_dkl_phy_ddi_translations_dp_hbr2 = { - .entries = _tgl_dkl_phy_ddi_translations_dp_hbr2, - .num_entries = ARRAY_SIZE(_tgl_dkl_phy_ddi_translations_dp_hbr2), +static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_dp_hbr2 = { + .entries = _tgl_dkl_phy_trans_dp_hbr2, + .num_entries = ARRAY_SIZE(_tgl_dkl_phy_trans_dp_hbr2), }; -static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_hdmi[] = { /* HDMI Preset VS Pre-emph */ { .dkl = { 0x7, 0x0, 0x0 } }, /* 1 400mV 0dB */ { .dkl = { 0x6, 0x0, 0x0 } }, /* 2 500mV 0dB */ @@ -697,13 +697,13 @@ static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_ddi_translations_hdmi[ { .dkl = { 0x0, 0x0, 0xA } }, /* 10 Full -3 dB */ }; -static const struct intel_ddi_buf_trans tgl_dkl_phy_ddi_translations_hdmi = { - .entries = _tgl_dkl_phy_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_tgl_dkl_phy_ddi_translations_hdmi), - .hdmi_default_entry = ARRAY_SIZE(_tgl_dkl_phy_ddi_translations_hdmi) - 1, +static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_hdmi = { + .entries = _tgl_dkl_phy_trans_hdmi, + .num_entries = ARRAY_SIZE(_tgl_dkl_phy_trans_hdmi), + .hdmi_default_entry = ARRAY_SIZE(_tgl_dkl_phy_trans_hdmi) - 1, }; -static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_dp_hbr[] = { +static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -717,12 +717,12 @@ static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr = { - .entries = _tgl_combo_phy_ddi_translations_dp_hbr, - .num_entries = ARRAY_SIZE(_tgl_combo_phy_ddi_translations_dp_hbr), +static const struct intel_ddi_buf_trans tgl_combo_phy_trans_dp_hbr = { + .entries = _tgl_combo_phy_trans_dp_hbr, + .num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_dp_hbr), }; -static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_dp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -736,12 +736,12 @@ static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2 = { - .entries = _tgl_combo_phy_ddi_translations_dp_hbr2, - .num_entries = ARRAY_SIZE(_tgl_combo_phy_ddi_translations_dp_hbr2), +static const struct intel_ddi_buf_trans tgl_combo_phy_trans_dp_hbr2 = { + .entries = _tgl_combo_phy_trans_dp_hbr2, + .num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_dp_hbr2), }; -static const union intel_ddi_buf_trans_entry _tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _tgl_uy_combo_phy_trans_dp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x36, 0x00, 0x09 } }, /* 350 500 3.1 */ @@ -755,16 +755,16 @@ static const union intel_ddi_buf_trans_entry _tgl_uy_combo_phy_ddi_translations_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2 = { - .entries = _tgl_uy_combo_phy_ddi_translations_dp_hbr2, - .num_entries = ARRAY_SIZE(_tgl_uy_combo_phy_ddi_translations_dp_hbr2), +static const struct intel_ddi_buf_trans tgl_uy_combo_phy_trans_dp_hbr2 = { + .entries = _tgl_uy_combo_phy_trans_dp_hbr2, + .num_entries = ARRAY_SIZE(_tgl_uy_combo_phy_trans_dp_hbr2), }; /* * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries * that DisplayPort specification requires */ -static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { +static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_edp_hbr2_hobl[] = { /* VS pre-emp */ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 0 0 */ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 0 1 */ @@ -777,12 +777,12 @@ static const union intel_ddi_buf_trans_entry _tgl_combo_phy_ddi_translations_edp { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 2 1 */ }; -static const struct intel_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl = { - .entries = _tgl_combo_phy_ddi_translations_edp_hbr2_hobl, - .num_entries = ARRAY_SIZE(_tgl_combo_phy_ddi_translations_edp_hbr2_hobl), +static const struct intel_ddi_buf_trans tgl_combo_phy_trans_edp_hbr2_hobl = { + .entries = _tgl_combo_phy_trans_edp_hbr2_hobl, + .num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_edp_hbr2_hobl), }; -static const union intel_ddi_buf_trans_entry _rkl_combo_phy_ddi_translations_dp_hbr[] = { +static const union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x2F, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -796,12 +796,12 @@ static const union intel_ddi_buf_trans_entry _rkl_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr = { - .entries = _rkl_combo_phy_ddi_translations_dp_hbr, - .num_entries = ARRAY_SIZE(_rkl_combo_phy_ddi_translations_dp_hbr), +static const struct intel_ddi_buf_trans rkl_combo_phy_trans_dp_hbr = { + .entries = _rkl_combo_phy_trans_dp_hbr, + .num_entries = ARRAY_SIZE(_rkl_combo_phy_trans_dp_hbr), }; -static const union intel_ddi_buf_trans_entry _rkl_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr2_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x50, 0x38, 0x00, 0x07 } }, /* 350 500 3.1 */ @@ -815,12 +815,12 @@ static const union intel_ddi_buf_trans_entry _rkl_combo_phy_ddi_translations_dp_ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr2_hbr3 = { - .entries = _rkl_combo_phy_ddi_translations_dp_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_rkl_combo_phy_ddi_translations_dp_hbr2_hbr3), +static const struct intel_ddi_buf_trans rkl_combo_phy_trans_dp_hbr2_hbr3 = { + .entries = _rkl_combo_phy_trans_dp_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_rkl_combo_phy_trans_dp_hbr2_hbr3), }; -static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_dp_hbr2_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -834,12 +834,12 @@ static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_dp { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans adls_combo_phy_ddi_translations_dp_hbr2_hbr3 = { - .entries = _adls_combo_phy_ddi_translations_dp_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_adls_combo_phy_ddi_translations_dp_hbr2_hbr3), +static const struct intel_ddi_buf_trans adls_combo_phy_trans_dp_hbr2_hbr3 = { + .entries = _adls_combo_phy_trans_dp_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_adls_combo_phy_trans_dp_hbr2_hbr3), }; -static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_edp_hbr2[] = { +static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr2[] = { /* NT mV Trans mV db */ { .icl = { 0x9, 0x73, 0x3D, 0x00, 0x02 } }, /* 200 200 0.0 */ { .icl = { 0x9, 0x7A, 0x3C, 0x00, 0x03 } }, /* 200 250 1.9 */ @@ -853,12 +853,12 @@ static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_ed { .icl = { 0x4, 0x6C, 0x3A, 0x00, 0x05 } }, /* 350 350 0.0 */ }; -static const struct intel_ddi_buf_trans adls_combo_phy_ddi_translations_edp_hbr2 = { - .entries = _adls_combo_phy_ddi_translations_edp_hbr2, - .num_entries = ARRAY_SIZE(_adls_combo_phy_ddi_translations_edp_hbr2), +static const struct intel_ddi_buf_trans adls_combo_phy_trans_edp_hbr2 = { + .entries = _adls_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_adls_combo_phy_trans_edp_hbr2), }; -static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_edp_hbr3[] = { +static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -872,12 +872,12 @@ static const union intel_ddi_buf_trans_entry _adls_combo_phy_ddi_translations_ed { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans adls_combo_phy_ddi_translations_edp_hbr3 = { - .entries = _adls_combo_phy_ddi_translations_edp_hbr3, - .num_entries = ARRAY_SIZE(_adls_combo_phy_ddi_translations_edp_hbr3), +static const struct intel_ddi_buf_trans adls_combo_phy_trans_edp_hbr3 = { + .entries = _adls_combo_phy_trans_edp_hbr3, + .num_entries = ARRAY_SIZE(_adls_combo_phy_trans_edp_hbr3), }; -static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_hdmi[] = { +static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_hdmi[] = { /* NT mV Trans mV db */ { .icl = { 0x6, 0x60, 0x3F, 0x00, 0x00 } }, /* 400 400 0.0 */ { .icl = { 0x6, 0x68, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */ @@ -891,13 +891,13 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_hd { .icl = { 0xB, 0x7F, 0x33, 0x00, 0x0C } }, /* Full Red -3.0 */ }; -static const struct intel_ddi_buf_trans adlp_combo_phy_ddi_translations_hdmi = { - .entries = _adlp_combo_phy_ddi_translations_hdmi, - .num_entries = ARRAY_SIZE(_adlp_combo_phy_ddi_translations_hdmi), - .hdmi_default_entry = ARRAY_SIZE(_adlp_combo_phy_ddi_translations_hdmi) - 1, +static const struct intel_ddi_buf_trans adlp_combo_phy_trans_hdmi = { + .entries = _adlp_combo_phy_trans_hdmi, + .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_hdmi), + .hdmi_default_entry = ARRAY_SIZE(_adlp_combo_phy_trans_hdmi) - 1, }; -static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_dp_hbr[] = { +static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -911,12 +911,12 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_dp { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans adlp_combo_phy_ddi_translations_dp_hbr = { - .entries = _adlp_combo_phy_ddi_translations_dp_hbr, - .num_entries = ARRAY_SIZE(_adlp_combo_phy_ddi_translations_dp_hbr), +static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr = { + .entries = _adlp_combo_phy_trans_dp_hbr, + .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr), }; -static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[] = { /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ @@ -930,22 +930,22 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_ddi_translations_dp { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; -static const struct intel_ddi_buf_trans adlp_combo_phy_ddi_translations_dp_hbr2_hbr3 = { - .entries = _adlp_combo_phy_ddi_translations_dp_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_adlp_combo_phy_ddi_translations_dp_hbr2_hbr3), +static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr2_hbr3 = { + .entries = _adlp_combo_phy_trans_dp_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_hbr3), }; -static const struct intel_ddi_buf_trans adlp_combo_phy_ddi_translations_edp_hbr3 = { - .entries = _icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, - .num_entries = ARRAY_SIZE(_icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3), +static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_hbr3 = { + .entries = _icl_combo_phy_trans_dp_hbr2_edp_hbr3, + .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_dp_hbr2_edp_hbr3), }; -static const struct intel_ddi_buf_trans adlp_combo_phy_ddi_translations_edp_up_to_hbr2 = { - .entries = _icl_combo_phy_ddi_translations_edp_hbr2, - .num_entries = ARRAY_SIZE(_icl_combo_phy_ddi_translations_edp_hbr2), +static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_up_to_hbr2 = { + .entries = _icl_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_edp_hbr2), }; -static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_ddi_translations_dp_hbr[] = { +static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr[] = { /* VS pre-emp Non-trans mV Pre-emph dB */ { .dkl = { 0x7, 0x0, 0x01 } }, /* 0 0 400mV 0 dB */ { .dkl = { 0x5, 0x0, 0x06 } }, /* 0 1 400mV 3.5 dB */ @@ -959,12 +959,12 @@ static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_ddi_translations_dp_h { .dkl = { 0x0, 0x0, 0x00 } }, /* 3 0 1200mV 0 dB */ }; -static const struct intel_ddi_buf_trans adlp_dkl_phy_ddi_translations_dp_hbr = { - .entries = _adlp_dkl_phy_ddi_translations_dp_hbr, - .num_entries = ARRAY_SIZE(_adlp_dkl_phy_ddi_translations_dp_hbr), +static const struct intel_ddi_buf_trans adlp_dkl_phy_trans_dp_hbr = { + .entries = _adlp_dkl_phy_trans_dp_hbr, + .num_entries = ARRAY_SIZE(_adlp_dkl_phy_trans_dp_hbr), }; -static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3[] = { +static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr2_hbr3[] = { /* VS pre-emp Non-trans mV Pre-emph dB */ { .dkl = { 0x7, 0x0, 0x00 } }, /* 0 0 400mV 0 dB */ { .dkl = { 0x5, 0x0, 0x04 } }, /* 0 1 400mV 3.5 dB */ @@ -978,12 +978,12 @@ static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_ddi_translations_dp_h { .dkl = { 0x0, 0x0, 0x00 } }, /* 3 0 1200mV 0 dB */ }; -static const struct intel_ddi_buf_trans adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3 = { - .entries = _adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3, - .num_entries = ARRAY_SIZE(_adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3), +static const struct intel_ddi_buf_trans adlp_dkl_phy_trans_dp_hbr2_hbr3 = { + .entries = _adlp_dkl_phy_trans_dp_hbr2_hbr3, + .num_entries = ARRAY_SIZE(_adlp_dkl_phy_trans_dp_hbr2_hbr3), }; -static const union intel_ddi_buf_trans_entry _dg2_snps_translations[] = { +static const union intel_ddi_buf_trans_entry _dg2_snps_trans[] = { { .snps = { 26, 0, 0 } }, /* VS 0, pre-emph 0 */ { .snps = { 33, 0, 6 } }, /* VS 0, pre-emph 1 */ { .snps = { 38, 0, 12 } }, /* VS 0, pre-emph 2 */ @@ -996,13 +996,13 @@ static const union intel_ddi_buf_trans_entry _dg2_snps_translations[] = { { .snps = { 62, 0, 0 } }, /* VS 3, pre-emph 0 */ }; -static const struct intel_ddi_buf_trans dg2_snps_translations = { - .entries = _dg2_snps_translations, - .num_entries = ARRAY_SIZE(_dg2_snps_translations), - .hdmi_default_entry = ARRAY_SIZE(_dg2_snps_translations) - 1, +static const struct intel_ddi_buf_trans dg2_snps_trans = { + .entries = _dg2_snps_trans, + .num_entries = ARRAY_SIZE(_dg2_snps_trans), + .hdmi_default_entry = ARRAY_SIZE(_dg2_snps_trans) - 1, }; -static const union intel_ddi_buf_trans_entry _dg2_snps_translations_uhbr[] = { +static const union intel_ddi_buf_trans_entry _dg2_snps_trans_uhbr[] = { { .snps = { 62, 0, 0 } }, /* preset 0 */ { .snps = { 56, 0, 6 } }, /* preset 1 */ { .snps = { 51, 0, 11 } }, /* preset 2 */ @@ -1021,21 +1021,21 @@ static const union intel_ddi_buf_trans_entry _dg2_snps_translations_uhbr[] = { { .snps = { 56, 3, 3 } }, /* preset 15 */ }; -static const struct intel_ddi_buf_trans dg2_snps_translations_uhbr = { - .entries = _dg2_snps_translations_uhbr, - .num_entries = ARRAY_SIZE(_dg2_snps_translations_uhbr), +static const struct intel_ddi_buf_trans dg2_snps_trans_uhbr = { + .entries = _dg2_snps_trans_uhbr, + .num_entries = ARRAY_SIZE(_dg2_snps_trans_uhbr), }; bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table) { - return table == &tgl_combo_phy_ddi_translations_edp_hbr2_hobl; + return table == &tgl_combo_phy_trans_edp_hbr2_hobl; } static const struct intel_ddi_buf_trans * -intel_get_buf_trans(const struct intel_ddi_buf_trans *ddi_translations, int *num_entries) +intel_get_buf_trans(const struct intel_ddi_buf_trans *trans, int *num_entries) { - *num_entries = ddi_translations->num_entries; - return ddi_translations; + *num_entries = trans->num_entries; + return trans; } static const struct intel_ddi_buf_trans * @@ -1044,11 +1044,11 @@ hsw_get_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) - return intel_get_buf_trans(&hsw_ddi_translations_fdi, n_entries); + return intel_get_buf_trans(&hsw_trans_fdi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&hsw_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&hsw_trans_hdmi, n_entries); else - return intel_get_buf_trans(&hsw_ddi_translations_dp, n_entries); + return intel_get_buf_trans(&hsw_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1059,14 +1059,14 @@ bdw_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) - return intel_get_buf_trans(&bdw_ddi_translations_fdi, n_entries); + return intel_get_buf_trans(&bdw_trans_fdi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&bdw_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&bdw_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return intel_get_buf_trans(&bdw_ddi_translations_edp, n_entries); + return intel_get_buf_trans(&bdw_trans_edp, n_entries); else - return intel_get_buf_trans(&bdw_ddi_translations_dp, n_entries); + return intel_get_buf_trans(&bdw_trans_dp, n_entries); } static int skl_buf_trans_num_entries(enum port port, int n_entries) @@ -1080,12 +1080,12 @@ static int skl_buf_trans_num_entries(enum port port, int n_entries) static const struct intel_ddi_buf_trans * _skl_get_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_ddi_buf_trans *ddi_translations, + const struct intel_ddi_buf_trans *trans, int *n_entries) { - ddi_translations = intel_get_buf_trans(ddi_translations, n_entries); + trans = intel_get_buf_trans(trans, n_entries); *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; + return trans; } static const struct intel_ddi_buf_trans * @@ -1096,12 +1096,12 @@ skl_y_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_y_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_y_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_y_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_y_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &skl_y_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_y_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1112,12 +1112,12 @@ skl_u_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_u_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_u_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &skl_u_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_u_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1128,12 +1128,12 @@ skl_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &skl_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1144,12 +1144,12 @@ kbl_y_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_y_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_y_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_y_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_y_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &kbl_y_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &kbl_y_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1160,12 +1160,12 @@ kbl_u_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_u_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_u_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &kbl_u_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &kbl_u_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1176,12 +1176,12 @@ kbl_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&skl_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&skl_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return _skl_get_buf_trans_dp(encoder, &skl_ddi_translations_edp, n_entries); + return _skl_get_buf_trans_dp(encoder, &skl_trans_edp, n_entries); else - return _skl_get_buf_trans_dp(encoder, &kbl_ddi_translations_dp, n_entries); + return _skl_get_buf_trans_dp(encoder, &kbl_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1192,12 +1192,12 @@ bxt_get_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&bxt_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&bxt_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && i915->vbt.edp.low_vswing) - return intel_get_buf_trans(&bxt_ddi_translations_edp, n_entries); + return intel_get_buf_trans(&bxt_trans_edp, n_entries); else - return intel_get_buf_trans(&bxt_ddi_translations_dp, n_entries); + return intel_get_buf_trans(&bxt_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1205,7 +1205,7 @@ icl_get_combo_buf_trans_dp(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, int *n_entries) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); } @@ -1217,10 +1217,10 @@ icl_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); if (crtc_state->port_clock > 540000) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); } else if (dev_priv->vbt.edp.low_vswing) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_edp_hbr2, + return intel_get_buf_trans(&icl_combo_phy_trans_edp_hbr2, n_entries); } @@ -1233,7 +1233,7 @@ icl_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1246,10 +1246,10 @@ icl_get_mg_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) { - return intel_get_buf_trans(&icl_mg_phy_ddi_translations_hbr2_hbr3, + return intel_get_buf_trans(&icl_mg_phy_trans_hbr2_hbr3, n_entries); } else { - return intel_get_buf_trans(&icl_mg_phy_ddi_translations_rbr_hbr, + return intel_get_buf_trans(&icl_mg_phy_trans_rbr_hbr, n_entries); } } @@ -1260,7 +1260,7 @@ icl_get_mg_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_mg_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_mg_phy_trans_hdmi, n_entries); else return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries); } @@ -1271,9 +1271,9 @@ ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&ehl_combo_phy_ddi_translations_edp_hbr2, n_entries); + return intel_get_buf_trans(&ehl_combo_phy_trans_edp_hbr2, n_entries); else - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_edp_hbr2, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_edp_hbr2, n_entries); } static const struct intel_ddi_buf_trans * @@ -1284,12 +1284,12 @@ ehl_get_combo_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && dev_priv->vbt.edp.low_vswing) return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else - return intel_get_buf_trans(&ehl_combo_phy_ddi_translations_dp, n_entries); + return intel_get_buf_trans(&ehl_combo_phy_trans_dp, n_entries); } static const struct intel_ddi_buf_trans * @@ -1298,9 +1298,9 @@ jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&jsl_combo_phy_ddi_translations_edp_hbr2, n_entries); + return intel_get_buf_trans(&jsl_combo_phy_trans_edp_hbr2, n_entries); else - return intel_get_buf_trans(&jsl_combo_phy_ddi_translations_edp_hbr, n_entries); + return intel_get_buf_trans(&jsl_combo_phy_trans_edp_hbr, n_entries); } static const struct intel_ddi_buf_trans * @@ -1311,12 +1311,12 @@ jsl_get_combo_buf_trans(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP) && dev_priv->vbt.edp.low_vswing) return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); } static const struct intel_ddi_buf_trans * @@ -1328,14 +1328,14 @@ tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder, if (crtc_state->port_clock > 270000) { if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { - return intel_get_buf_trans(&tgl_uy_combo_phy_ddi_translations_dp_hbr2, + return intel_get_buf_trans(&tgl_uy_combo_phy_trans_dp_hbr2, n_entries); } else { - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_dp_hbr2, + return intel_get_buf_trans(&tgl_combo_phy_trans_dp_hbr2, n_entries); } } else { - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_dp_hbr, + return intel_get_buf_trans(&tgl_combo_phy_trans_dp_hbr, n_entries); } } @@ -1349,13 +1349,13 @@ tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (crtc_state->port_clock > 540000) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_edp_hbr2_hobl, + return intel_get_buf_trans(&tgl_combo_phy_trans_edp_hbr2_hobl, n_entries); } else if (dev_priv->vbt.edp.low_vswing) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_edp_hbr2, + return intel_get_buf_trans(&icl_combo_phy_trans_edp_hbr2, n_entries); } @@ -1368,7 +1368,7 @@ tgl_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1381,10 +1381,10 @@ dg1_get_combo_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&dg1_combo_phy_ddi_translations_dp_hbr2_hbr3, + return intel_get_buf_trans(&dg1_combo_phy_trans_dp_hbr2_hbr3, n_entries); else - return intel_get_buf_trans(&dg1_combo_phy_ddi_translations_dp_rbr_hbr, + return intel_get_buf_trans(&dg1_combo_phy_trans_dp_rbr_hbr, n_entries); } @@ -1397,13 +1397,13 @@ dg1_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (crtc_state->port_clock > 540000) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_edp_hbr2_hobl, + return intel_get_buf_trans(&tgl_combo_phy_trans_edp_hbr2_hobl, n_entries); else if (dev_priv->vbt.edp.low_vswing) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_edp_hbr2, + return intel_get_buf_trans(&icl_combo_phy_trans_edp_hbr2, n_entries); else return dg1_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); @@ -1415,7 +1415,7 @@ dg1_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return dg1_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1428,9 +1428,9 @@ rkl_get_combo_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&rkl_combo_phy_ddi_translations_dp_hbr2_hbr3, n_entries); + return intel_get_buf_trans(&rkl_combo_phy_trans_dp_hbr2_hbr3, n_entries); else - return intel_get_buf_trans(&rkl_combo_phy_ddi_translations_dp_hbr, n_entries); + return intel_get_buf_trans(&rkl_combo_phy_trans_dp_hbr, n_entries); } static const struct intel_ddi_buf_trans * @@ -1442,13 +1442,13 @@ rkl_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (crtc_state->port_clock > 540000) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_dp_hbr2_edp_hbr3, + return intel_get_buf_trans(&icl_combo_phy_trans_dp_hbr2_edp_hbr3, n_entries); } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_edp_hbr2_hobl, + return intel_get_buf_trans(&tgl_combo_phy_trans_edp_hbr2_hobl, n_entries); } else if (dev_priv->vbt.edp.low_vswing) { - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_edp_hbr2, + return intel_get_buf_trans(&icl_combo_phy_trans_edp_hbr2, n_entries); } @@ -1461,7 +1461,7 @@ rkl_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return rkl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1474,9 +1474,9 @@ adls_get_combo_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&adls_combo_phy_ddi_translations_dp_hbr2_hbr3, n_entries); + return intel_get_buf_trans(&adls_combo_phy_trans_dp_hbr2_hbr3, n_entries); else - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_dp_hbr, n_entries); + return intel_get_buf_trans(&tgl_combo_phy_trans_dp_hbr, n_entries); } static const struct intel_ddi_buf_trans * @@ -1488,11 +1488,11 @@ adls_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (crtc_state->port_clock > 540000) - return intel_get_buf_trans(&adls_combo_phy_ddi_translations_edp_hbr3, n_entries); + return intel_get_buf_trans(&adls_combo_phy_trans_edp_hbr3, n_entries); else if (i915->vbt.edp.hobl && !intel_dp->hobl_failed) - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_edp_hbr2_hobl, n_entries); + return intel_get_buf_trans(&tgl_combo_phy_trans_edp_hbr2_hobl, n_entries); else if (i915->vbt.edp.low_vswing) - return intel_get_buf_trans(&adls_combo_phy_ddi_translations_edp_hbr2, n_entries); + return intel_get_buf_trans(&adls_combo_phy_trans_edp_hbr2, n_entries); else return adls_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); } @@ -1503,7 +1503,7 @@ adls_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&icl_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&icl_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return adls_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1516,9 +1516,9 @@ adlp_get_combo_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) - return intel_get_buf_trans(&adlp_combo_phy_ddi_translations_dp_hbr2_hbr3, n_entries); + return intel_get_buf_trans(&adlp_combo_phy_trans_dp_hbr2_hbr3, n_entries); else - return intel_get_buf_trans(&adlp_combo_phy_ddi_translations_dp_hbr, n_entries); + return intel_get_buf_trans(&adlp_combo_phy_trans_dp_hbr, n_entries); } static const struct intel_ddi_buf_trans * @@ -1530,13 +1530,13 @@ adlp_get_combo_buf_trans_edp(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (crtc_state->port_clock > 540000) { - return intel_get_buf_trans(&adlp_combo_phy_ddi_translations_edp_hbr3, + return intel_get_buf_trans(&adlp_combo_phy_trans_edp_hbr3, n_entries); } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { - return intel_get_buf_trans(&tgl_combo_phy_ddi_translations_edp_hbr2_hobl, + return intel_get_buf_trans(&tgl_combo_phy_trans_edp_hbr2_hobl, n_entries); } else if (dev_priv->vbt.edp.low_vswing) { - return intel_get_buf_trans(&adlp_combo_phy_ddi_translations_edp_up_to_hbr2, + return intel_get_buf_trans(&adlp_combo_phy_trans_edp_up_to_hbr2, n_entries); } @@ -1549,7 +1549,7 @@ adlp_get_combo_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&adlp_combo_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&adlp_combo_phy_trans_hdmi, n_entries); else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) return adlp_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); else @@ -1562,10 +1562,10 @@ tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) { - return intel_get_buf_trans(&tgl_dkl_phy_ddi_translations_dp_hbr2, + return intel_get_buf_trans(&tgl_dkl_phy_trans_dp_hbr2, n_entries); } else { - return intel_get_buf_trans(&tgl_dkl_phy_ddi_translations_dp_hbr, + return intel_get_buf_trans(&tgl_dkl_phy_trans_dp_hbr, n_entries); } } @@ -1576,7 +1576,7 @@ tgl_get_dkl_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&tgl_dkl_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&tgl_dkl_phy_trans_hdmi, n_entries); else return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); } @@ -1587,10 +1587,10 @@ adlp_get_dkl_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 270000) { - return intel_get_buf_trans(&adlp_dkl_phy_ddi_translations_dp_hbr2_hbr3, + return intel_get_buf_trans(&adlp_dkl_phy_trans_dp_hbr2_hbr3, n_entries); } else { - return intel_get_buf_trans(&adlp_dkl_phy_ddi_translations_dp_hbr, + return intel_get_buf_trans(&adlp_dkl_phy_trans_dp_hbr, n_entries); } } @@ -1601,7 +1601,7 @@ adlp_get_dkl_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_get_buf_trans(&tgl_dkl_phy_ddi_translations_hdmi, n_entries); + return intel_get_buf_trans(&tgl_dkl_phy_trans_hdmi, n_entries); else return adlp_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); } @@ -1612,9 +1612,9 @@ dg2_get_snps_buf_trans(struct intel_encoder *encoder, int *n_entries) { if (crtc_state->port_clock > 1000000) - return intel_get_buf_trans(&dg2_snps_translations_uhbr, n_entries); + return intel_get_buf_trans(&dg2_snps_trans_uhbr, n_entries); else - return intel_get_buf_trans(&dg2_snps_translations, n_entries); + return intel_get_buf_trans(&dg2_snps_trans, n_entries); } int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, @@ -1622,17 +1622,17 @@ int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, int *default_entry) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; int n_entries; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON(&dev_priv->drm, !ddi_translations)) { + if (drm_WARN_ON(&dev_priv->drm, !trans)) { *default_entry = 0; return 0; } - *default_entry = ddi_translations->hdmi_default_entry; + *default_entry = trans->hdmi_default_entry; return n_entries; } diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 2405f70d82de..3734e349f91d 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -56,12 +56,12 @@ void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int level) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_ddi_buf_trans *ddi_translations; + const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); int n_entries, ln; - ddi_translations = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level < 0 || level >= n_entries)) level = n_entries - 1; @@ -69,9 +69,9 @@ void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder, for (ln = 0; ln < 4; ln++) { u32 val = 0; - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, ddi_translations->entries[level].snps.snps_vswing); - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, ddi_translations->entries[level].snps.snps_pre_cursor); - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, ddi_translations->entries[level].snps.snps_post_cursor); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, trans->entries[level].snps.snps_vswing); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, trans->entries[level].snps.snps_pre_cursor); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, trans->entries[level].snps.snps_post_cursor); intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy), val); } From 241ffeb028e4b1181c0e51e00e553390b42fb1e8 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Mon, 27 Sep 2021 15:23:24 -0400 Subject: [PATCH 152/554] drm/dp: Add Additional DP2 Headers Include FEC, DSC, Link Training related headers. Change since v2 - Align with the spec for DP_DSC_SUPPORT_AND_DSC_DECODER_COUNT Signed-off-by: Fangzhi Zuo Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Link: https://patchwork.freedesktop.org/patch/msgid/20210927192324.5428-1-Jerry.Zuo@amd.com --- include/drm/drm_dp_helper.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 1d5b3dbb6e56..a1df35aa6e68 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -453,6 +453,7 @@ struct drm_panel; # define DP_FEC_UNCORR_BLK_ERROR_COUNT_CAP (1 << 1) # define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) # define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3) +#define DP_FEC_CAPABILITY_1 0x091 /* 2.0 */ /* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */ #define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */ @@ -537,6 +538,9 @@ struct drm_panel; #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 #define DP_DSC_BRANCH_MAX_LINE_WIDTH 0x0a2 +/* DFP Capability Extension */ +#define DP_DFP_CAPABILITY_EXTENSION_SUPPORT 0x0a3 /* 2.0 */ + /* Link Configuration */ #define DP_LINK_BW_SET 0x100 # define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ @@ -688,6 +692,7 @@ struct drm_panel; #define DP_DSC_ENABLE 0x160 /* DP 1.4 */ # define DP_DECOMPRESSION_EN (1 << 0) +#define DP_DSC_CONFIGURATION 0x161 /* DP 2.0 */ #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE BIT(0) @@ -743,6 +748,7 @@ struct drm_panel; # define DP_RECEIVE_PORT_0_STATUS (1 << 0) # define DP_RECEIVE_PORT_1_STATUS (1 << 1) # define DP_STREAM_REGENERATION_STATUS (1 << 2) /* 2.0 */ +# define DP_INTRA_HOP_AUX_REPLY_INDICATION (1 << 3) /* 2.0 */ #define DP_ADJUST_REQUEST_LANE0_1 0x206 #define DP_ADJUST_REQUEST_LANE2_3 0x207 @@ -865,6 +871,8 @@ struct drm_panel; # define DP_PHY_TEST_PATTERN_80BIT_CUSTOM 0x4 # define DP_PHY_TEST_PATTERN_CP2520 0x5 +#define DP_PHY_SQUARE_PATTERN 0x249 + #define DP_TEST_HBR2_SCRAMBLER_RESET 0x24A #define DP_TEST_80BIT_CUSTOM_PATTERN_7_0 0x250 #define DP_TEST_80BIT_CUSTOM_PATTERN_15_8 0x251 @@ -1109,6 +1117,18 @@ struct drm_panel; #define DP_128B132B_TRAINING_AUX_RD_INTERVAL 0x2216 /* 2.0 */ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK 0x7f +#define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0x2230 +#define DP_TEST_264BIT_CUSTOM_PATTERN_263_256 0x2250 + +/* DSC Extended Capability Branch Total DSC Resources */ +#define DP_DSC_SUPPORT_AND_DSC_DECODER_COUNT 0x2260 /* 2.0 */ +# define DP_DSC_DECODER_COUNT_MASK (0b111 << 5) +# define DP_DSC_DECODER_COUNT_SHIFT 5 +#define DP_DSC_MAX_SLICE_COUNT_AND_AGGREGATION_0 0x2270 /* 2.0 */ +# define DP_DSC_DECODER_0_MAXIMUM_SLICE_COUNT_MASK (1 << 0) +# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_MASK (0b111 << 1) +# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_SHIFT 1 + /* Protocol Converter Extension */ /* HDMI CEC tunneling over AUX DP 1.3 section 5.3.3.3.1 DPCD 1.4+ */ #define DP_CEC_TUNNELING_CAPABILITY 0x3000 From ac220f5f754b1d2f4a69428f515c3f1b10d1fad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:01 -0700 Subject: [PATCH 153/554] drm/i915/display/psr: Handle plane and pipe restrictions at every page flip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PSR2 selective is not supported over rotated and scaled planes. We had the rotation check in intel_psr2_sel_fetch_config_valid() but that code path is only execute when a modeset is needed and those plane parameters can change without a modeset. Pipe selective fetch restrictions are also needed, it could be added in intel_psr_compute_config() but pippe scaling is computed after it is executed, so leaving as is for now. There is no much loss in this approach as it would cause selective fetch to not enabled as for alderlake-P and newer will cause it to switch to PSR1 that will have the same power-savings as do full pipe fetch. Also need to check those restricions in the second for_each_oldnew_intel_plane_in_state() loop because the state could only have a plane that is not affected by those restricitons but the damaged area intersect with planes that has those restrictions, so a full pipe fetch is required. v2: - also handling pipe restrictions BSpec: 55229 Reviewed-by: Gwan-gyeong Mun # v1 Cc: Ville Syrjälä Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 65 +++++++++++++++++------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index f489bf9ca096..3cdd193ddb13 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -720,11 +720,7 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { - struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - struct intel_plane_state *plane_state; - struct intel_plane *plane; - int i; if (!dev_priv->params.enable_psr2_sel_fetch && intel_dp->psr.debug != I915_PSR_DEBUG_ENABLE_SEL_FETCH) { @@ -739,14 +735,6 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, return false; } - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane_state->uapi.rotation != DRM_MODE_ROTATE_0) { - drm_dbg_kms(&dev_priv->drm, - "PSR2 sel fetch not enabled, plane rotated\n"); - return false; - } - } - /* Wa_14010254185 Wa_14010103792 */ if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_C0)) { drm_dbg_kms(&dev_priv->drm, @@ -1580,6 +1568,41 @@ static void cursor_area_workaround(const struct intel_plane_state *new_plane_sta clip_area_update(pipe_clip, damaged_area); } +/* + * TODO: Not clear how to handle planes with negative position, + * also planes are not updated if they have a negative X + * position so for now doing a full update in this cases + * + * Plane scaling and rotation is not supported by selective fetch and both + * properties can change without a modeset, so need to be check at every + * atomic commmit. + */ +static bool psr2_sel_fetch_plane_state_supported(const struct intel_plane_state *plane_state) +{ + if (plane_state->uapi.dst.y1 < 0 || + plane_state->uapi.dst.x1 < 0 || + plane_state->scaler_id >= 0 || + plane_state->uapi.rotation != DRM_MODE_ROTATE_0) + return false; + + return true; +} + +/* + * Check for pipe properties that is not supported by selective fetch. + * + * TODO: pipe scaling causes a modeset but skl_update_scaler_crtc() is executed + * after intel_psr_compute_config(), so for now keeping PSR2 selective fetch + * enabled and going to the full update path. + */ +static bool psr2_sel_fetch_pipe_state_supported(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->scaler_state.scaler_id >= 0) + return false; + + return true; +} + int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -1593,6 +1616,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (!crtc_state->enable_psr2_sel_fetch) return 0; + if (!psr2_sel_fetch_pipe_state_supported(crtc_state)) { + full_update = true; + goto skip_sel_fetch_set_loop; + } + /* * Calculate minimal selective fetch area of each plane and calculate * the pipe damaged area. @@ -1612,13 +1640,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, !old_plane_state->uapi.visible) continue; - /* - * TODO: Not clear how to handle planes with negative position, - * also planes are not updated if they have a negative X - * position so for now doing a full update in this cases - */ - if (new_plane_state->uapi.dst.y1 < 0 || - new_plane_state->uapi.dst.x1 < 0) { + if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) { full_update = true; break; } @@ -1697,6 +1719,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) continue; + if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) { + full_update = true; + break; + } + sel_fetch_area = &new_plane_state->psr2_sel_fetch_area; sel_fetch_area->y1 = inter.y1 - new_plane_state->uapi.dst.y1; sel_fetch_area->y2 = inter.y2 - new_plane_state->uapi.dst.y1; From 1f61f0655b95d5b89589390e6f83c4a61d9b1e8d Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Wed, 29 Sep 2021 17:14:02 -0700 Subject: [PATCH 154/554] drm/i915/display/psr: Do full fetch when handling multi-planar formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are still missing the PSR2 selective fetch handling of multi-planar formats but until proper handle is added we can workaround it by doing full frames fetch when state has such formats. Cc: Ville Syrjälä Signed-off-by: Gwan-gyeong Mun Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-2-jose.souza@intel.com Signed-off-by: José Roberto de Souza --- drivers/gpu/drm/i915/display/intel_psr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 3cdd193ddb13..ba1739b5895a 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1573,6 +1573,9 @@ static void cursor_area_workaround(const struct intel_plane_state *new_plane_sta * also planes are not updated if they have a negative X * position so for now doing a full update in this cases * + * TODO: We are missing multi-planar formats handling, until it is + * implemented it will send full frame updates. + * * Plane scaling and rotation is not supported by selective fetch and both * properties can change without a modeset, so need to be check at every * atomic commmit. @@ -1582,6 +1585,7 @@ static bool psr2_sel_fetch_plane_state_supported(const struct intel_plane_state if (plane_state->uapi.dst.y1 < 0 || plane_state->uapi.dst.x1 < 0 || plane_state->scaler_id >= 0 || + plane_state->hw.fb->format->num_planes > 1 || plane_state->uapi.rotation != DRM_MODE_ROTATE_0) return false; From 5da579cff38d64d024c1b99bafa3347c0d5fc107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:03 -0700 Subject: [PATCH 155/554] drm/i915/display: Drop unnecessary frontbuffer flushes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This unnecessary flushes are hurting power-savings are it causes features like PSR, FBC and DRRS to disable it self to handle frontbuffer rendering, below some explanation of why each removed call is not necessary. The flush in intel_prepare_plane_fb() is not required as framebuffer will be flipped and power-saving features do the proper flip handling in hardware. intel_find_initial_plane_obj() flush is not required because it is only executed during driver load and at this point the power-saving features are not even enabled. And the last one intelfb_create(), is also not required as at this point the fbdev was just allocated, userspace will draw on it what will trigger frontbuffer invalidates and flushes later on. Cc: Ville Syrjälä Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-3-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 3 --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a4453dd1bb51..1ce1d46dca5b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1711,8 +1711,6 @@ valid_fb: plane_state->uapi.crtc = &crtc->base; intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); - intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB); - atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); } @@ -10814,7 +10812,6 @@ intel_prepare_plane_fb(struct drm_plane *_plane, return ret; i915_gem_object_wait_priority(obj, 0, &attr); - i915_gem_object_flush_frontbuffer(obj, ORIGIN_DIRTYFB); if (!new_plane_state->uapi.fence) { /* implicit fencing */ struct dma_fence *fence; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 60d3ded27047..53484267b2a4 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -230,8 +230,6 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out_unlock; } - intel_frontbuffer_flush(to_frontbuffer(ifbdev), ORIGIN_DIRTYFB); - info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { drm_err(&dev_priv->drm, "Failed to allocate fb_info\n"); From 34ac6b651f39e63da8d0ae0edd2db32fbb1bc02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:04 -0700 Subject: [PATCH 156/554] drm/i915/display: Handle frontbuffer rendering when PSR2 selective fetch is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When PSR2 selective fetch is enabled writes to CURSURFLIVE alone do not causes the panel to be updated when doing frontbuffer rendering. From what I was able to figure from experiments the writes to CURSURFLIVE takes PSR2 from deep sleep but panel is not updated because PSR2_MAN_TRK_CTL has no start and end region set. As we don't have the dirt area from current flush and invalidate API and even if we did userspace could do several draws to frontbuffer and we would need a way to append all the damaged areas of all the draws that need to be part of next frame. So here only programing PSR2_MAN_TRK_CTL to do a single full frame fetch. It is a safe approach as if scanout is in the visible area the single full frame will only be visible for hardware in the next frame because of the double buffering, and if scanout is in vblank area it will be draw in the current frame. No need to disable PSR and wait a few miliseconds to enable it again. Cc: Gwan-gyeong Mun Cc: Ville Syrjälä Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-4-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index ba1739b5895a..9a5259bbebab 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1397,10 +1397,22 @@ unlock: mutex_unlock(&psr->lock); } +static inline u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv) +{ + return IS_ALDERLAKE_P(dev_priv) ? + ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME : + PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; +} + static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + if (intel_dp->psr.psr2_sel_fetch_enabled) + intel_de_rmw(dev_priv, + PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0, + man_trk_ctl_single_full_frame_bit_get(dev_priv)); + /* * Display WA #0884: skl+ * This documented WA for bxt can be safely applied @@ -1409,6 +1421,10 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) * Workaround tells us to write 0 to CUR_SURFLIVE_A, * but it makes more sense write to the current active * pipe. + * + * This workaround do not exist for platforms with display 10 or newer + * but testing proved that it works for up display 13, for newer + * than that testing will be needed. */ intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); } From ef39826c12b409010b8fb29fc47e2586cd2635ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:05 -0700 Subject: [PATCH 157/554] drm/i915/display: Fix glitches when moving cursor with PSR2 selective fetch enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Legacy cursor APIs are handled by intel_legacy_cursor_update(), that calls drm_atomic_helper_update_plane() when going through the slow/atomic path to update cursor, what was the case for PSR2 selective fetch. drm_atomic_helper_update_plane() sets drm_atomic_state->legacy_cursor_update to true when updating the cursor plane, to allow several cursor updates to happen within the same frame, as userspace does that. If drivers waited for a vblank increment at the end of every cursor movement that would cause a visible lag in the cursor. But this optimization do not properly work with PSR2 selective fetch dirt area calculation, for example if within a single frame the cursor had 3 moves the final dirt area programmed to PSR2_MAN_TRK_CTL would be based in the second movement as old state and third movement as new state, not updating the area where cursor was in the first state. So here switching back to the fast path approach in intel_legacy_cursor_update() and handling cursor movements as frontbuffer rendering(psr_force_hw_tracking_exit()), that is not the most optimal for power-savings but is the solution that we have until mailbox style updates is implemented. Also removing the cursor workaround as not it is properly undestand the issue and is know that it will never cover all the cases. Cc: Ville Syrjälä Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Acked-by: Ville Syrjälä Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-5-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 5 +- drivers/gpu/drm/i915/display/intel_fbc.c | 4 +- .../gpu/drm/i915/display/intel_frontbuffer.h | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 59 +++++-------------- 4 files changed, 20 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 901ad3a4c8c3..f6dcb5aa63f6 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -639,8 +639,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane, * FIXME bigjoiner fastpath would be good */ if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) || - crtc_state->update_pipe || crtc_state->bigjoiner || - crtc_state->enable_psr2_sel_fetch) + crtc_state->update_pipe || crtc_state->bigjoiner) goto slow; /* @@ -698,7 +697,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane, goto out_free; intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb), - ORIGIN_FLIP); + ORIGIN_CURSOR_UPDATE); intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb), to_intel_frontbuffer(new_plane_state->hw.fb), plane->frontbuffer_bit); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 687431faf02f..1f66de77a6b1 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1200,7 +1200,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, if (!HAS_FBC(dev_priv)) return; - if (origin == ORIGIN_FLIP) + if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE) return; mutex_lock(&fbc->lock); @@ -1225,7 +1225,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, fbc->busy_bits &= ~frontbuffer_bits; - if (origin == ORIGIN_FLIP) + if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE) goto out; if (!fbc->busy_bits && fbc->crtc && diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.h b/drivers/gpu/drm/i915/display/intel_frontbuffer.h index 4b977c1e4d52..a88441edc8f9 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.h +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.h @@ -37,6 +37,7 @@ enum fb_op_origin { ORIGIN_CS, ORIGIN_FLIP, ORIGIN_DIRTYFB, + ORIGIN_CURSOR_UPDATE, }; struct intel_frontbuffer { diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 9a5259bbebab..eddf4138b6a8 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1562,28 +1562,6 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c drm_warn(&dev_priv->drm, "Missing PSR2 sel fetch alignment with DSC\n"); } -/* - * FIXME: Not sure why but when moving the cursor fast it causes some artifacts - * of the cursor to be left in the cursor path, adding some pixels above the - * cursor to the damaged area fixes the issue. - */ -static void cursor_area_workaround(const struct intel_plane_state *new_plane_state, - struct drm_rect *damaged_area, - struct drm_rect *pipe_clip) -{ - const struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); - int height; - - if (plane->id != PLANE_CURSOR) - return; - - height = drm_rect_height(&new_plane_state->uapi.dst) / 2; - damaged_area->y1 -= height; - damaged_area->y1 = max(damaged_area->y1, 0); - - clip_area_update(pipe_clip, damaged_area); -} - /* * TODO: Not clear how to handle planes with negative position, * also planes are not updated if they have a negative X @@ -1684,9 +1662,6 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.y2 = new_plane_state->uapi.dst.y2; clip_area_update(&pipe_clip, &damaged_area); } - - cursor_area_workaround(new_plane_state, &damaged_area, - &pipe_clip); continue; } else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha) { /* If alpha changed mark the whole plane area as damaged */ @@ -2120,20 +2095,16 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, /* * When we will be completely rely on PSR2 S/W tracking in future, * intel_psr_flush() will invalidate and flush the PSR for ORIGIN_FLIP - * event also therefore tgl_dc3co_flush() require to be changed + * event also therefore tgl_dc3co_flush_locked() require to be changed * accordingly in future. */ static void -tgl_dc3co_flush(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, - enum fb_op_origin origin) +tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, + enum fb_op_origin origin) { - mutex_lock(&intel_dp->psr.lock); - - if (!intel_dp->psr.dc3co_exitline) - goto unlock; - - if (!intel_dp->psr.psr2_enabled || !intel_dp->psr.active) - goto unlock; + if (!intel_dp->psr.dc3co_exitline || !intel_dp->psr.psr2_enabled || + !intel_dp->psr.active) + return; /* * At every frontbuffer flush flip event modified delay of delayed work, @@ -2141,14 +2112,11 @@ tgl_dc3co_flush(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, */ if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe))) - goto unlock; + return; tgl_psr2_enable_dc3co(intel_dp); mod_delayed_work(system_wq, &intel_dp->psr.dc3co_work, intel_dp->psr.dc3co_exit_delay); - -unlock: - mutex_unlock(&intel_dp->psr.lock); } /** @@ -2173,11 +2141,6 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, unsigned int pipe_frontbuffer_bits = frontbuffer_bits; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - if (origin == ORIGIN_FLIP) { - tgl_dc3co_flush(intel_dp, frontbuffer_bits, origin); - continue; - } - mutex_lock(&intel_dp->psr.lock); if (!intel_dp->psr.enabled) { mutex_unlock(&intel_dp->psr.lock); @@ -2198,6 +2161,14 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, continue; } + if (origin == ORIGIN_FLIP || + (origin == ORIGIN_CURSOR_UPDATE && + !intel_dp->psr.psr2_sel_fetch_enabled)) { + tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin); + mutex_unlock(&intel_dp->psr.lock); + continue; + } + /* By definition flush = invalidate + flush */ if (pipe_frontbuffer_bits) psr_force_hw_tracking_exit(intel_dp); From 1163649a047995c77527023f192d00ae1971965b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:06 -0700 Subject: [PATCH 158/554] drm/i915/display/adlp: Optimize PSR2 power-savings in corner cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Wa_14014971508 is required to fix scanout when a feature that i915 do not support is enabled and this feature is not planned to be enabled for adlp. Keeping this workaround enabled can badly hurt power-savings when a full frame fetch is required(see psr2_sel_fetch_plane_state_supported() and psr2_sel_fetch_pipe_state_supported()). Here a example that could badly hurt power-savings, userspace does a page flip to a rotated plane, so CONTINUOS_FULL_FRAME set. But then for a whole 30 seconds nothing in the screen requires updates but because CONTINUOS_FULL_FRAME is set, it will not go into DC5/DC6. Reverting Wa_14014971508 fixes that, as only a single frame will be sent and then display can go to DC5/DC6 for those 30 seconds of idleness. BSpec: 54369 Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-6-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index eddf4138b6a8..05b9b103a98f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1503,15 +1503,10 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, if (full_update) { /* - * Wa_14014971508:adlp - * SINGLE_FULL_FRAME bit is not hold in register so can not be - * restored by DMC, so using CONTINUOS_FULL_FRAME to mimic that + * Not applying Wa_14014971508:adlp as we do not support the + * feature that requires this workaround. */ - if (IS_ALDERLAKE_P(dev_priv)) - val |= ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME; - else - val |= PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; - + val |= man_trk_ctl_single_full_frame_bit_get(dev_priv); goto exit; } From de572e881b9d7f19da74981dd320699ea796e5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:07 -0700 Subject: [PATCH 159/554] drm/i915/display/adlp: Allow PSR2 to be enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With all the recent fixes PSR2 is properly working in Alderlake-P but due to some issues that don't have software workarounds it will not be supported in display steppings older than B0. Even with this patch PSR2 will no be enabled by default in ADL-P, it still requires enable_psr2_sel_fetch to be set to true, what some of our tests does. Cc: Gwan-gyeong Mun Reviewed-by: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-7-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 05b9b103a98f..7a205fd5023b 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -830,12 +830,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - /* - * We are missing the implementation of some workarounds to enabled PSR2 - * in Alderlake_P, until ready PSR2 should be kept disabled. - */ - if (IS_ALDERLAKE_P(dev_priv)) { - drm_dbg_kms(&dev_priv->drm, "PSR2 is missing the implementation of workarounds\n"); + if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) { + drm_dbg_kms(&dev_priv->drm, "PSR2 not completely functional in this stepping\n"); return false; } From 7f6002e58025cf001e4be34306731f2f8f893638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 29 Sep 2021 17:14:08 -0700 Subject: [PATCH 160/554] drm/i915/display: Enable PSR2 selective fetch by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With all the past fixes now this feature is functional and can be enabled by default in desktop enviroments that uses compositor. Cc: Gwan-gyeong Mun Cc: Ville Syrjälä Reviewed-by: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210930001409.254817-8-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index f27eceb82c0f..8d725b64592d 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -55,7 +55,7 @@ struct drm_printer; param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0400) \ - param(bool, enable_psr2_sel_fetch, false, 0400) \ + param(bool, enable_psr2_sel_fetch, true, 0400) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ From 6b51b02a3a0ac49dfe302818d0746a799545e4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 13:12:33 +0200 Subject: [PATCH 161/554] dma-buf: fix and rework dma_buf_poll v7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Daniel pointed me towards this function and there are multiple obvious problems in the implementation. First of all the retry loop is not working as intended. In general the retry makes only sense if you grab the reference first and then check the sequence values. Then we should always also wait for the exclusive fence. It's also good practice to keep the reference around when installing callbacks to fences you don't own. And last the whole implementation was unnecessary complex and rather hard to understand which could lead to probably unexpected behavior of the IOCTL. Fix all this by reworking the implementation from scratch. Dropping the whole RCU approach and taking the lock instead. Only mildly tested and needs a thoughtful review of the code. Pushing through drm-misc-next to avoid merge conflicts and give the code another round of testing. v2: fix the reference counting as well v3: keep the excl fence handling as is for stable v4: back to testing all fences, drop RCU v5: handle in and out separately v6: add missing clear of events v7: change coding style as suggested by Michel, drop unused variables Signed-off-by: Christian König Reviewed-by: Daniel Vetter Tested-by: Michel Dänzer CC: stable@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20210720131110.88512-1-christian.koenig@amd.com --- drivers/dma-buf/dma-buf.c | 162 ++++++++++++++++++-------------------- include/linux/dma-buf.h | 2 +- 2 files changed, 76 insertions(+), 88 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 474de2d988ca..61e20ae7b08b 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -74,7 +74,7 @@ static void dma_buf_release(struct dentry *dentry) * If you hit this BUG() it means someone dropped their ref to the * dma-buf while still having pending operation to the buffer. */ - BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active); + BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active); dma_buf_stats_teardown(dmabuf); dmabuf->ops->release(dmabuf); @@ -206,16 +206,55 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) wake_up_locked_poll(dcb->poll, dcb->active); dcb->active = 0; spin_unlock_irqrestore(&dcb->poll->lock, flags); + dma_fence_put(fence); +} + +static bool dma_buf_poll_shared(struct dma_resv *resv, + struct dma_buf_poll_cb_t *dcb) +{ + struct dma_resv_list *fobj = dma_resv_shared_list(resv); + struct dma_fence *fence; + int i, r; + + if (!fobj) + return false; + + for (i = 0; i < fobj->shared_count; ++i) { + fence = rcu_dereference_protected(fobj->shared[i], + dma_resv_held(resv)); + dma_fence_get(fence); + r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb); + if (!r) + return true; + dma_fence_put(fence); + } + + return false; +} + +static bool dma_buf_poll_excl(struct dma_resv *resv, + struct dma_buf_poll_cb_t *dcb) +{ + struct dma_fence *fence = dma_resv_excl_fence(resv); + int r; + + if (!fence) + return false; + + dma_fence_get(fence); + r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb); + if (!r) + return true; + dma_fence_put(fence); + + return false; } static __poll_t dma_buf_poll(struct file *file, poll_table *poll) { struct dma_buf *dmabuf; struct dma_resv *resv; - struct dma_resv_list *fobj; - struct dma_fence *fence_excl; __poll_t events; - unsigned shared_count, seq; dmabuf = file->private_data; if (!dmabuf || !dmabuf->resv) @@ -229,61 +268,12 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) if (!events) return 0; -retry: - seq = read_seqcount_begin(&resv->seq); - rcu_read_lock(); + dma_resv_lock(resv, NULL); - fobj = rcu_dereference(resv->fence); - if (fobj) - shared_count = fobj->shared_count; - else - shared_count = 0; - fence_excl = dma_resv_excl_fence(resv); - if (read_seqcount_retry(&resv->seq, seq)) { - rcu_read_unlock(); - goto retry; - } + if (events & EPOLLOUT) { + struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_out; - if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) { - struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl; - __poll_t pevents = EPOLLIN; - - if (shared_count == 0) - pevents |= EPOLLOUT; - - spin_lock_irq(&dmabuf->poll.lock); - if (dcb->active) { - dcb->active |= pevents; - events &= ~pevents; - } else - dcb->active = pevents; - spin_unlock_irq(&dmabuf->poll.lock); - - if (events & pevents) { - if (!dma_fence_get_rcu(fence_excl)) { - /* force a recheck */ - events &= ~pevents; - dma_buf_poll_cb(NULL, &dcb->cb); - } else if (!dma_fence_add_callback(fence_excl, &dcb->cb, - dma_buf_poll_cb)) { - events &= ~pevents; - dma_fence_put(fence_excl); - } else { - /* - * No callback queued, wake up any additional - * waiters. - */ - dma_fence_put(fence_excl); - dma_buf_poll_cb(NULL, &dcb->cb); - } - } - } - - if ((events & EPOLLOUT) && shared_count > 0) { - struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared; - int i; - - /* Only queue a new callback if no event has fired yet */ + /* Check that callback isn't busy */ spin_lock_irq(&dmabuf->poll.lock); if (dcb->active) events &= ~EPOLLOUT; @@ -291,39 +281,37 @@ retry: dcb->active = EPOLLOUT; spin_unlock_irq(&dmabuf->poll.lock); - if (!(events & EPOLLOUT)) - goto out; - - for (i = 0; i < shared_count; ++i) { - struct dma_fence *fence = rcu_dereference(fobj->shared[i]); - - if (!dma_fence_get_rcu(fence)) { - /* - * fence refcount dropped to zero, this means - * that fobj has been freed - * - * call dma_buf_poll_cb and force a recheck! - */ - events &= ~EPOLLOUT; + if (events & EPOLLOUT) { + if (!dma_buf_poll_shared(resv, dcb) && + !dma_buf_poll_excl(resv, dcb)) + /* No callback queued, wake up any other waiters */ dma_buf_poll_cb(NULL, &dcb->cb); - break; - } - if (!dma_fence_add_callback(fence, &dcb->cb, - dma_buf_poll_cb)) { - dma_fence_put(fence); + else events &= ~EPOLLOUT; - break; - } - dma_fence_put(fence); } - - /* No callback queued, wake up any additional waiters. */ - if (i == shared_count) - dma_buf_poll_cb(NULL, &dcb->cb); } -out: - rcu_read_unlock(); + if (events & EPOLLIN) { + struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_in; + + /* Check that callback isn't busy */ + spin_lock_irq(&dmabuf->poll.lock); + if (dcb->active) + events &= ~EPOLLIN; + else + dcb->active = EPOLLIN; + spin_unlock_irq(&dmabuf->poll.lock); + + if (events & EPOLLIN) { + if (!dma_buf_poll_excl(resv, dcb)) + /* No callback queued, wake up any other waiters */ + dma_buf_poll_cb(NULL, &dcb->cb); + else + events &= ~EPOLLIN; + } + } + + dma_resv_unlock(resv); return events; } @@ -566,8 +554,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->owner = exp_info->owner; spin_lock_init(&dmabuf->name_lock); init_waitqueue_head(&dmabuf->poll); - dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll; - dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; + dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll; + dmabuf->cb_in.active = dmabuf->cb_out.active = 0; if (!resv) { resv = (struct dma_resv *)&dmabuf[1]; diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 66470c37e471..02c2eb874da6 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -440,7 +440,7 @@ struct dma_buf { wait_queue_head_t *poll; __poll_t active; - } cb_excl, cb_shared; + } cb_in, cb_out; #ifdef CONFIG_DMABUF_SYSFS_STATS /** * @sysfs_entry: From 606b102876e3741851dfb09d53f3ee57f650a52c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 27 Sep 2021 16:28:02 +0200 Subject: [PATCH 162/554] drm: fb_helper: fix CONFIG_FB dependency With CONFIG_FB=m and CONFIG_DRM=y, we get a link error in the fb helper: aarch64-linux-ld: drivers/gpu/drm/drm_fb_helper.o: in function `drm_fb_helper_alloc_fbi': (.text+0x10cc): undefined reference to `framebuffer_alloc' Tighten the dependency so it is only allowed in the case that DRM can link against FB. Fixes: f611b1e7624c ("drm: Avoid circular dependencies for CONFIG_FB") Link: https://lore.kernel.org/all/20210721152211.2706171-1-arnd@kernel.org/ Signed-off-by: Arnd Bergmann Reviewed-by: Kees Cook Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210927142816.2069269-1-arnd@kernel.org --- drivers/gpu/drm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index b17e231ca6f7..2a926d0de423 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -103,7 +103,7 @@ config DRM_DEBUG_DP_MST_TOPOLOGY_REFS config DRM_FBDEV_EMULATION bool "Enable legacy fbdev support for your modesetting driver" depends on DRM - depends on FB + depends on FB=y || FB=DRM select DRM_KMS_HELPER select FB_CFB_FILLRECT select FB_CFB_COPYAREA From e04a911f436619fff2e57470a50fd2b2436eb6eb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 12:22:58 +0300 Subject: [PATCH 163/554] drm/i915/fdi: move fdi modeset asserts to intel_fdi.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the functionality and the assert code together. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/427d27eb4e5daca208d496d6c2ffc91ed90ba714.1632992608.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 72 ---------------- drivers/gpu/drm/i915/display/intel_display.h | 4 - drivers/gpu/drm/i915/display/intel_fdi.c | 91 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fdi.h | 10 +++ drivers/gpu/drm/i915/display/intel_lvds.c | 1 + 5 files changed, 102 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1ce1d46dca5b..05e42903bde0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -428,78 +428,6 @@ void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) onoff(state), onoff(cur_state)); } -static void assert_fdi_tx(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) -{ - bool cur_state; - - if (HAS_DDI(dev_priv)) { - /* - * DDI does not have a specific FDI_TX register. - * - * FDI is never fed from EDP transcoder - * so pipe->transcoder cast is fine here. - */ - enum transcoder cpu_transcoder = (enum transcoder)pipe; - u32 val = intel_de_read(dev_priv, - TRANS_DDI_FUNC_CTL(cpu_transcoder)); - cur_state = !!(val & TRANS_DDI_FUNC_ENABLE); - } else { - u32 val = intel_de_read(dev_priv, FDI_TX_CTL(pipe)); - cur_state = !!(val & FDI_TX_ENABLE); - } - I915_STATE_WARN(cur_state != state, - "FDI TX state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); -} -#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) -#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) - -static void assert_fdi_rx(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) -{ - u32 val; - bool cur_state; - - val = intel_de_read(dev_priv, FDI_RX_CTL(pipe)); - cur_state = !!(val & FDI_RX_ENABLE); - I915_STATE_WARN(cur_state != state, - "FDI RX state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); -} -#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) -#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) - -static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe) -{ - u32 val; - - /* ILK FDI PLL is always enabled */ - if (IS_IRONLAKE(dev_priv)) - return; - - /* On Haswell, DDI ports are responsible for the FDI PLL setup */ - if (HAS_DDI(dev_priv)) - return; - - val = intel_de_read(dev_priv, FDI_TX_CTL(pipe)); - I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); -} - -void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) -{ - u32 val; - bool cur_state; - - val = intel_de_read(dev_priv, FDI_RX_CTL(pipe)); - cur_state = !!(val & FDI_RX_PLL_ENABLE); - I915_STATE_WARN(cur_state != state, - "FDI RX PLL assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); -} - void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) { i915_reg_t pp_reg; diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 87b96fed5e0b..8cb3bb33cbe0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -654,10 +654,6 @@ void assert_pll(struct drm_i915_private *dev_priv, void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state); #define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true) #define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false) -void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state); -#define assert_fdi_rx_pll_enabled(d, p) assert_fdi_rx_pll(d, p, true) -#define assert_fdi_rx_pll_disabled(d, p) assert_fdi_rx_pll(d, p, false) void assert_transcoder(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, bool state); #define assert_transcoder_enabled(d, t) assert_transcoder(d, t, true) diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index af01d1fa761e..02d3294bad7b 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -10,6 +10,97 @@ #include "intel_fdi.h" #include "intel_sideband.h" +static void assert_fdi_tx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + bool cur_state; + + if (HAS_DDI(dev_priv)) { + /* + * DDI does not have a specific FDI_TX register. + * + * FDI is never fed from EDP transcoder + * so pipe->transcoder cast is fine here. + */ + enum transcoder cpu_transcoder = (enum transcoder)pipe; + cur_state = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder)) & TRANS_DDI_FUNC_ENABLE; + } else { + cur_state = intel_de_read(dev_priv, FDI_TX_CTL(pipe)) & FDI_TX_ENABLE; + } + I915_STATE_WARN(cur_state != state, + "FDI TX state assertion failure (expected %s, current %s)\n", + onoff(state), onoff(cur_state)); +} + +void assert_fdi_tx_enabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_tx(i915, pipe, true); +} + +void assert_fdi_tx_disabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_tx(i915, pipe, false); +} + +static void assert_fdi_rx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + bool cur_state; + + cur_state = intel_de_read(dev_priv, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE; + I915_STATE_WARN(cur_state != state, + "FDI RX state assertion failure (expected %s, current %s)\n", + onoff(state), onoff(cur_state)); +} + +void assert_fdi_rx_enabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_rx(i915, pipe, true); +} + +void assert_fdi_rx_disabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_rx(i915, pipe, false); +} + +void assert_fdi_tx_pll_enabled(struct drm_i915_private *i915, + enum pipe pipe) +{ + bool cur_state; + + /* ILK FDI PLL is always enabled */ + if (IS_IRONLAKE(i915)) + return; + + /* On Haswell, DDI ports are responsible for the FDI PLL setup */ + if (HAS_DDI(i915)) + return; + + cur_state = intel_de_read(i915, FDI_TX_CTL(pipe)) & FDI_TX_PLL_ENABLE; + I915_STATE_WARN(!cur_state, "FDI TX PLL assertion failure, should be active but is disabled\n"); +} + +static void assert_fdi_rx_pll(struct drm_i915_private *i915, + enum pipe pipe, bool state) +{ + bool cur_state; + + cur_state = intel_de_read(i915, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE; + I915_STATE_WARN(cur_state != state, + "FDI RX PLL assertion failure (expected %s, current %s)\n", + onoff(state), onoff(cur_state)); +} + +void assert_fdi_rx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_rx_pll(i915, pipe, true); +} + +void assert_fdi_rx_pll_disabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_fdi_rx_pll(i915, pipe, false); +} + void intel_fdi_link_train(struct intel_crtc *crtc, const struct intel_crtc_state *crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index 61cb216a09f5..d557fc603d7d 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -6,6 +6,7 @@ #ifndef _INTEL_FDI_H_ #define _INTEL_FDI_H_ +enum pipe; struct drm_i915_private; struct intel_crtc; struct intel_crtc_state; @@ -28,4 +29,13 @@ void lpt_fdi_program_mphy(struct drm_i915_private *i915); void intel_fdi_link_train(struct intel_crtc *crtc, const struct intel_crtc_state *crtc_state); + +void assert_fdi_tx_enabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_tx_disabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_rx_enabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_rx_disabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_tx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_rx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_fdi_rx_pll_disabled(struct drm_i915_private *i915, enum pipe pipe); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 130e6ea61e11..6155eb0c0a5c 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -44,6 +44,7 @@ #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_fdi.h" #include "intel_gmbus.h" #include "intel_lvds.h" #include "intel_panel.h" From aa0813b1ba31c345fb745bc8ece6e5b7cbfca71b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 12:22:59 +0300 Subject: [PATCH 164/554] drm/i915/pps: move pps (panel) modeset asserts to intel_pps.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move assert_panel_unlocked() to intel_pps.c and rename assert_pps_unlocked(). Keep the functionality and the assert code together. There's still a bit of a split between the eDP PPS usage in intel_pps.c and all the other PPS usage, and assert_pps_unlocked() is arguably more related to the latter. However, intel_pps.c is the best fit for anything touching the PPS registers. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/a9b77692a145891789eefb0447e082cfc22aaa85.1632992608.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 60 +------------------- drivers/gpu/drm/i915/display/intel_display.h | 2 - drivers/gpu/drm/i915/display/intel_dpll.c | 13 +++-- drivers/gpu/drm/i915/display/intel_pps.c | 59 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_pps.h | 3 + 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 05e42903bde0..34201e71593b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -428,64 +428,6 @@ void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) onoff(state), onoff(cur_state)); } -void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - i915_reg_t pp_reg; - u32 val; - enum pipe panel_pipe = INVALID_PIPE; - bool locked = true; - - if (drm_WARN_ON(&dev_priv->drm, HAS_DDI(dev_priv))) - return; - - if (HAS_PCH_SPLIT(dev_priv)) { - u32 port_sel; - - pp_reg = PP_CONTROL(0); - port_sel = intel_de_read(dev_priv, PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; - - switch (port_sel) { - case PANEL_PORT_SELECT_LVDS: - intel_lvds_port_enabled(dev_priv, PCH_LVDS, &panel_pipe); - break; - case PANEL_PORT_SELECT_DPA: - g4x_dp_port_enabled(dev_priv, DP_A, PORT_A, &panel_pipe); - break; - case PANEL_PORT_SELECT_DPC: - g4x_dp_port_enabled(dev_priv, PCH_DP_C, PORT_C, &panel_pipe); - break; - case PANEL_PORT_SELECT_DPD: - g4x_dp_port_enabled(dev_priv, PCH_DP_D, PORT_D, &panel_pipe); - break; - default: - MISSING_CASE(port_sel); - break; - } - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - /* presumably write lock depends on pipe, not port select */ - pp_reg = PP_CONTROL(pipe); - panel_pipe = pipe; - } else { - u32 port_sel; - - pp_reg = PP_CONTROL(0); - port_sel = intel_de_read(dev_priv, PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; - - drm_WARN_ON(&dev_priv->drm, - port_sel != PANEL_PORT_SELECT_LVDS); - intel_lvds_port_enabled(dev_priv, LVDS, &panel_pipe); - } - - val = intel_de_read(dev_priv, pp_reg); - if (!(val & PANEL_POWER_ON) || - ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS)) - locked = false; - - I915_STATE_WARN(panel_pipe == pipe && locked, - "panel assertion failure, pipe %c regs locked\n", - pipe_name(pipe)); -} - void assert_transcoder(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, bool state) { @@ -2128,7 +2070,7 @@ static void ilk_pch_enable(const struct intel_atomic_state *state, intel_enable_shared_dpll(crtc_state); /* set transcoder timing, panel must allow it */ - assert_panel_unlocked(dev_priv, pipe); + assert_pps_unlocked(dev_priv, pipe); ilk_pch_transcoder_set_timings(crtc_state, pipe); intel_fdi_normal_train(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 8cb3bb33cbe0..5306d119b2c0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -645,8 +645,6 @@ void intel_init_pch_refclk(struct drm_i915_private *dev_priv); int intel_modeset_all_pipes(struct intel_atomic_state *state); /* modesetting asserts */ -void assert_panel_unlocked(struct drm_i915_private *dev_priv, - enum pipe pipe); void assert_pll(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pll_enabled(d, p) assert_pll(d, p, true) diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 784e3ee658b5..66784204f6f7 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -2,16 +2,19 @@ /* * Copyright © 2020 Intel Corporation */ + #include + #include "intel_crtc.h" #include "intel_de.h" -#include "intel_display_types.h" #include "intel_display.h" +#include "intel_display_types.h" #include "intel_dpll.h" #include "intel_lvds.h" #include "intel_panel.h" +#include "intel_pps.h" #include "intel_sideband.h" -#include "display/intel_snps_phy.h" +#include "intel_snps_phy.h" struct intel_limit { struct { @@ -1438,7 +1441,7 @@ void i9xx_enable_pll(const struct intel_crtc_state *crtc_state) /* PLL is protected by panel, make sure we can write it */ if (i9xx_has_pps(dev_priv)) - assert_panel_unlocked(dev_priv, pipe); + assert_pps_unlocked(dev_priv, pipe); intel_de_write(dev_priv, FP0(pipe), crtc_state->dpll_hw_state.fp0); intel_de_write(dev_priv, FP1(pipe), crtc_state->dpll_hw_state.fp1); @@ -1617,7 +1620,7 @@ void vlv_enable_pll(const struct intel_crtc_state *crtc_state) assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); + assert_pps_unlocked(dev_priv, pipe); /* Enable Refclk */ intel_de_write(dev_priv, DPLL(pipe), @@ -1769,7 +1772,7 @@ void chv_enable_pll(const struct intel_crtc_state *crtc_state) assert_transcoder_disabled(dev_priv, crtc_state->cpu_transcoder); /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); + assert_pps_unlocked(dev_priv, pipe); /* Enable Refclk and SSC */ intel_de_write(dev_priv, DPLL(pipe), diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index a36ec4a818ff..e9c679bb1b2e 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -9,6 +9,7 @@ #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dpll.h" +#include "intel_lvds.h" #include "intel_pps.h" static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv, @@ -1408,3 +1409,61 @@ void intel_pps_setup(struct drm_i915_private *i915) else i915->pps_mmio_base = PPS_BASE; } + +void assert_pps_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + i915_reg_t pp_reg; + u32 val; + enum pipe panel_pipe = INVALID_PIPE; + bool locked = true; + + if (drm_WARN_ON(&dev_priv->drm, HAS_DDI(dev_priv))) + return; + + if (HAS_PCH_SPLIT(dev_priv)) { + u32 port_sel; + + pp_reg = PP_CONTROL(0); + port_sel = intel_de_read(dev_priv, PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; + + switch (port_sel) { + case PANEL_PORT_SELECT_LVDS: + intel_lvds_port_enabled(dev_priv, PCH_LVDS, &panel_pipe); + break; + case PANEL_PORT_SELECT_DPA: + g4x_dp_port_enabled(dev_priv, DP_A, PORT_A, &panel_pipe); + break; + case PANEL_PORT_SELECT_DPC: + g4x_dp_port_enabled(dev_priv, PCH_DP_C, PORT_C, &panel_pipe); + break; + case PANEL_PORT_SELECT_DPD: + g4x_dp_port_enabled(dev_priv, PCH_DP_D, PORT_D, &panel_pipe); + break; + default: + MISSING_CASE(port_sel); + break; + } + } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + /* presumably write lock depends on pipe, not port select */ + pp_reg = PP_CONTROL(pipe); + panel_pipe = pipe; + } else { + u32 port_sel; + + pp_reg = PP_CONTROL(0); + port_sel = intel_de_read(dev_priv, PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; + + drm_WARN_ON(&dev_priv->drm, + port_sel != PANEL_PORT_SELECT_LVDS); + intel_lvds_port_enabled(dev_priv, LVDS, &panel_pipe); + } + + val = intel_de_read(dev_priv, pp_reg); + if (!(val & PANEL_POWER_ON) || + ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS)) + locked = false; + + I915_STATE_WARN(panel_pipe == pipe && locked, + "panel assertion failure, pipe %c regs locked\n", + pipe_name(pipe)); +} diff --git a/drivers/gpu/drm/i915/display/intel_pps.h b/drivers/gpu/drm/i915/display/intel_pps.h index fbbcca782e7b..fbb47f6f453e 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.h +++ b/drivers/gpu/drm/i915/display/intel_pps.h @@ -10,6 +10,7 @@ #include "intel_wakeref.h" +enum pipe; struct drm_i915_private; struct intel_connector; struct intel_crtc_state; @@ -49,4 +50,6 @@ void vlv_pps_init(struct intel_encoder *encoder, void intel_pps_unlock_regs_wa(struct drm_i915_private *i915); void intel_pps_setup(struct drm_i915_private *i915); +void assert_pps_unlocked(struct drm_i915_private *i915, enum pipe pipe); + #endif /* __INTEL_PPS_H__ */ From 80e77e30a2126a5d8b5765795c31ee636a660736 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 12:23:00 +0300 Subject: [PATCH 165/554] drm/i915/dpll: move dpll modeset asserts to intel_dpll.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the functionality and the assert code together. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/0229659fb8af6c91c774408c6f7bb8c4ff8735e3.1632992608.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 14 ------------ drivers/gpu/drm/i915/display/intel_display.h | 4 ---- .../drm/i915/display/intel_display_power.c | 3 ++- drivers/gpu/drm/i915/display/intel_dpll.c | 22 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpll.h | 3 +++ drivers/gpu/drm/i915/display/intel_lvds.c | 1 + 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index f5923f1c38bd..34463aeec25c 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -25,6 +25,7 @@ #include "intel_color.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dpll.h" #define CTM_COEFF_SIGN (1ULL << 63) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 34201e71593b..9d2b6bd94d36 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -398,20 +398,6 @@ intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state) } } -/* Only for pre-ILK configs */ -void assert_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) -{ - u32 val; - bool cur_state; - - val = intel_de_read(dev_priv, DPLL(pipe)); - cur_state = !!(val & DPLL_VCO_ENABLE); - I915_STATE_WARN(cur_state != state, - "PLL state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); -} - /* XXX: the dsi pll is shared between MIPI DSI ports */ void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 5306d119b2c0..b3ccec541aa0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -645,10 +645,6 @@ void intel_init_pch_refclk(struct drm_i915_private *dev_priv); int intel_modeset_all_pipes(struct intel_atomic_state *state); /* modesetting asserts */ -void assert_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state); -#define assert_pll_enabled(d, p) assert_pll(d, p, true) -#define assert_pll_disabled(d, p) assert_pll(d, p, false) void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state); #define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true) #define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 2410c1a617ea..06e9879aedd7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -9,11 +9,12 @@ #include "i915_irq.h" #include "intel_cdclk.h" #include "intel_combo_phy.h" -#include "intel_display_power.h" #include "intel_de.h" +#include "intel_display_power.h" #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dpio_phy.h" +#include "intel_dpll.h" #include "intel_hotplug.h" #include "intel_pm.h" #include "intel_pps.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 66784204f6f7..b84ed4a1bd95 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1923,3 +1923,25 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe) else vlv_disable_pll(dev_priv, pipe); } + +/* Only for pre-ILK configs */ +static void assert_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + bool cur_state; + + cur_state = intel_de_read(dev_priv, DPLL(pipe)) & DPLL_VCO_ENABLE; + I915_STATE_WARN(cur_state != state, + "PLL state assertion failure (expected %s, current %s)\n", + onoff(state), onoff(cur_state)); +} + +void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_pll(i915, pipe, true); +} + +void assert_pll_disabled(struct drm_i915_private *i915, enum pipe pipe) +{ + assert_pll(i915, pipe, false); +} diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index db396b3e1141..1af0ac43cca4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -36,4 +36,7 @@ bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, struct dpll *best_clock); int chv_calc_dpll_params(int refclk, struct dpll *pll_clock); +void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe); +void assert_pll_disabled(struct drm_i915_private *i915, enum pipe pipe); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 6155eb0c0a5c..9fced37bed70 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -44,6 +44,7 @@ #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dpll.h" #include "intel_fdi.h" #include "intel_gmbus.h" #include "intel_lvds.h" From e365e4aaa5cc4f7048c73603d7e58accda0ddd3a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 12:23:01 +0300 Subject: [PATCH 166/554] drm/i915/dsi: move dsi pll modeset asserts to vlv_dsi_pll.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the functionality and the assert code together. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/0a5fa9b8d4d4615d4e6503b6bb33541c0bccffbb.1632992608.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 16 -------------- drivers/gpu/drm/i915/display/intel_display.h | 3 --- drivers/gpu/drm/i915/display/intel_dsi.h | 3 +++ drivers/gpu/drm/i915/display/vlv_dsi_pll.c | 23 ++++++++++++++++++++ 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 34463aeec25c..5359b7305a78 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -26,6 +26,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dpll.h" +#include "intel_dsi.h" #define CTM_COEFF_SIGN (1ULL << 63) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9d2b6bd94d36..4e9a6c9c2deb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -398,22 +398,6 @@ intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state) } } -/* XXX: the dsi pll is shared between MIPI DSI ports */ -void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) -{ - u32 val; - bool cur_state; - - vlv_cck_get(dev_priv); - val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); - vlv_cck_put(dev_priv); - - cur_state = val & DSI_PLL_VCO_EN; - I915_STATE_WARN(cur_state != state, - "DSI PLL state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); -} - void assert_transcoder(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, bool state) { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index b3ccec541aa0..3028072c2cf3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -645,9 +645,6 @@ void intel_init_pch_refclk(struct drm_i915_private *dev_priv); int intel_modeset_all_pipes(struct intel_atomic_state *state); /* modesetting asserts */ -void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state); -#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true) -#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false) void assert_transcoder(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, bool state); #define assert_transcoder_enabled(d, t) assert_transcoder(d, t, true) diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h index 50d6da0b2419..fbc40ffdc02e 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.h +++ b/drivers/gpu/drm/i915/display/intel_dsi.h @@ -207,6 +207,9 @@ u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, struct intel_crtc_state *config); void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); +void assert_dsi_pll_enabled(struct drm_i915_private *i915); +void assert_dsi_pll_disabled(struct drm_i915_private *i915); + /* intel_dsi_vbt.c */ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id); void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index 90185b219447..0078973cd219 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -568,3 +568,26 @@ void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) } intel_de_write(dev_priv, MIPI_EOT_DISABLE(port), CLOCKSTOP); } + +static void assert_dsi_pll(struct drm_i915_private *i915, bool state) +{ + bool cur_state; + + vlv_cck_get(i915); + cur_state = vlv_cck_read(i915, CCK_REG_DSI_PLL_CONTROL) & DSI_PLL_VCO_EN; + vlv_cck_put(i915); + + I915_STATE_WARN(cur_state != state, + "DSI PLL state assertion failure (expected %s, current %s)\n", + onoff(state), onoff(cur_state)); +} + +void assert_dsi_pll_enabled(struct drm_i915_private *i915) +{ + assert_dsi_pll(i915, true); +} + +void assert_dsi_pll_disabled(struct drm_i915_private *i915) +{ + assert_dsi_pll(i915, false); +} From 3e2947cd894506c8c0c6cb6ffb704e121e934ae8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:31 +0300 Subject: [PATCH 167/554] drm/i915/dsi: pass struct mipi_dsi_packet pointer, not the entire struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass a const pointer instead of passing 32 bytes of struct mipi_dsi_packet by value. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/c67d2fa0d97bf336a321497775b9717d85d44a51.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index c196993f0d68..11ef40230e8f 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -153,7 +153,8 @@ static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data, } static int dsi_send_pkt_hdr(struct intel_dsi_host *host, - struct mipi_dsi_packet pkt, bool enable_lpdt) + const struct mipi_dsi_packet *packet, + bool enable_lpdt) { struct intel_dsi *intel_dsi = host->intel_dsi; struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); @@ -166,7 +167,7 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host, tmp = intel_de_read(dev_priv, DSI_CMD_TXHDR(dsi_trans)); - if (pkt.payload) + if (packet->payload) tmp |= PAYLOAD_PRESENT; else tmp &= ~PAYLOAD_PRESENT; @@ -177,30 +178,29 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host, tmp |= LP_DATA_TRANSFER; tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK); - tmp |= ((pkt.header[0] & VC_MASK) << VC_SHIFT); - tmp |= ((pkt.header[0] & DT_MASK) << DT_SHIFT); - tmp |= (pkt.header[1] << PARAM_WC_LOWER_SHIFT); - tmp |= (pkt.header[2] << PARAM_WC_UPPER_SHIFT); + tmp |= ((packet->header[0] & VC_MASK) << VC_SHIFT); + tmp |= ((packet->header[0] & DT_MASK) << DT_SHIFT); + tmp |= (packet->header[1] << PARAM_WC_LOWER_SHIFT); + tmp |= (packet->header[2] << PARAM_WC_UPPER_SHIFT); intel_de_write(dev_priv, DSI_CMD_TXHDR(dsi_trans), tmp); return 0; } static int dsi_send_pkt_payld(struct intel_dsi_host *host, - struct mipi_dsi_packet pkt) + const struct mipi_dsi_packet *packet) { struct intel_dsi *intel_dsi = host->intel_dsi; struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); /* payload queue can accept *256 bytes*, check limit */ - if (pkt.payload_length > MAX_PLOAD_CREDIT * 4) { + if (packet->payload_length > MAX_PLOAD_CREDIT * 4) { drm_err(&i915->drm, "payload size exceeds max queue limit\n"); return -1; } /* load data into command payload queue */ - if (!add_payld_to_queue(host, pkt.payload, - pkt.payload_length)) { + if (!add_payld_to_queue(host, packet->payload, packet->payload_length)) { drm_err(&i915->drm, "adding payload to queue failed\n"); return -1; } @@ -1840,13 +1840,13 @@ static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host, /* only long packet contains payload */ if (mipi_dsi_packet_format_is_long(msg->type)) { - ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt); + ret = dsi_send_pkt_payld(intel_dsi_host, &dsi_pkt); if (ret < 0) return ret; } /* send packet header */ - ret = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt); + ret = dsi_send_pkt_hdr(intel_dsi_host, &dsi_pkt, enable_lpdt); if (ret < 0) return ret; From 207ea507a1478dcc7085ce74e15dfc62b67ec11b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:32 +0300 Subject: [PATCH 168/554] drm/i915/dsi: fuse dsi_send_pkt_payld() and add_payld_to_queue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having two functions for this seems like excess duplication and parameter juggling. Merge them together. While at it, drop the extra error message, as wait_for_payload_credits() already prints an error, and switch from incidental -EPERM (i.e. -1) to actual error codes. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/f74f7462a36e76070db6b4c01616d0eb663b9938.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 43 +++++++++----------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 11ef40230e8f..0daa90058ee3 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -129,27 +129,35 @@ static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder) } } -static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data, - u32 len) +static int dsi_send_pkt_payld(struct intel_dsi_host *host, + const struct mipi_dsi_packet *packet) { struct intel_dsi *intel_dsi = host->intel_dsi; - struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); enum transcoder dsi_trans = dsi_port_to_transcoder(host->port); + const u8 *data = packet->payload; + u32 len = packet->payload_length; int i, j; + /* payload queue can accept *256 bytes*, check limit */ + if (len > MAX_PLOAD_CREDIT * 4) { + drm_err(&i915->drm, "payload size exceeds max queue limit\n"); + return -EINVAL; + } + for (i = 0; i < len; i += 4) { u32 tmp = 0; - if (!wait_for_payload_credits(dev_priv, dsi_trans, 1)) - return false; + if (!wait_for_payload_credits(i915, dsi_trans, 1)) + return -EBUSY; for (j = 0; j < min_t(u32, len - i, 4); j++) tmp |= *data++ << 8 * j; - intel_de_write(dev_priv, DSI_CMD_TXPYLD(dsi_trans), tmp); + intel_de_write(i915, DSI_CMD_TXPYLD(dsi_trans), tmp); } - return true; + return 0; } static int dsi_send_pkt_hdr(struct intel_dsi_host *host, @@ -187,27 +195,6 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host, return 0; } -static int dsi_send_pkt_payld(struct intel_dsi_host *host, - const struct mipi_dsi_packet *packet) -{ - struct intel_dsi *intel_dsi = host->intel_dsi; - struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); - - /* payload queue can accept *256 bytes*, check limit */ - if (packet->payload_length > MAX_PLOAD_CREDIT * 4) { - drm_err(&i915->drm, "payload size exceeds max queue limit\n"); - return -1; - } - - /* load data into command payload queue */ - if (!add_payld_to_queue(host, packet->payload, packet->payload_length)) { - drm_err(&i915->drm, "adding payload to queue failed\n"); - return -1; - } - - return 0; -} - void icl_dsi_frame_update(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); From b90acd0987c81e4c8d7b4e7995ff3cecd16b2122 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:33 +0300 Subject: [PATCH 169/554] drm/i915/dsi: return -EBUSY instead of -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using the incidental -EPERM. Also remove useless comment. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/37df1edc6d3745997cec2dfe41520d9f704e14b4.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 0daa90058ee3..9ee62707ec72 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -169,9 +169,8 @@ static int dsi_send_pkt_hdr(struct intel_dsi_host *host, enum transcoder dsi_trans = dsi_port_to_transcoder(host->port); u32 tmp; - /* check if header credit available */ if (!wait_for_header_credits(dev_priv, dsi_trans, 1)) - return -1; + return -EBUSY; tmp = intel_de_read(dev_priv, DSI_CMD_TXHDR(dsi_trans)); From 0743019d540d18e7a5db220bf4c4b95650aa8c9e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:34 +0300 Subject: [PATCH 170/554] drm/i915/hdmi: return -EINVAL instead of -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using the incidental -EPERM. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/8acf7ffe9222d23c7f47dbd95ff1f737221ff72c.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 1bc33766ed39..468a107aaabc 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1703,7 +1703,7 @@ int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port, drm_dbg_kms(&i915->drm, "msg_sz(%zd) is more than exp size(%zu)\n", ret, size); - return -1; + return -EINVAL; } offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET; From 5e9a0200dad83f8620af04c733cd7f93bb0efb8c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:35 +0300 Subject: [PATCH 171/554] drm/i915/drv: return -EIO instead of -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using the incidental -EPERM. Return the -EIO directly from i915_get_bridge_dev() instead of converting return values later. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1ee72c31963d8be98490cd78f7c1182ba4f54c13.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 59fb4c710c8c..d9f208802ae0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -97,7 +97,7 @@ static int i915_get_bridge_dev(struct drm_i915_private *dev_priv) pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0)); if (!dev_priv->bridge_dev) { drm_err(&dev_priv->drm, "bridge device not found\n"); - return -1; + return -EIO; } return 0; } @@ -409,8 +409,9 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv) if (i915_inject_probe_failure(dev_priv)) return -ENODEV; - if (i915_get_bridge_dev(dev_priv)) - return -EIO; + ret = i915_get_bridge_dev(dev_priv); + if (ret < 0) + return ret; ret = intel_uncore_init_mmio(&dev_priv->uncore); if (ret < 0) From 7d8de8cabbba77eb35cdf075ab76a4b994a926ec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 14:24:36 +0300 Subject: [PATCH 172/554] drm/i915/dram: return -EINVAL instead of -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using the incidental -EPERM. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/e2f79220ed2558f615c051e2533275a5dae1a04f.1633000838.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 91866520c173..30a0cab5eff4 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -444,7 +444,7 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv) break; default: MISSING_CASE(val & 0xf); - return -1; + return -EINVAL; } } else { switch (val & 0xf) { @@ -462,7 +462,7 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv) break; default: MISSING_CASE(val & 0xf); - return -1; + return -EINVAL; } } From a23299bb9a49f08e0609b6136b3ee1da5ed486e5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 30 Sep 2021 12:32:29 +0300 Subject: [PATCH 173/554] drm/i915/fdi: use -EAGAIN instead of local special return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using standard -EAGAIN should be perfectly fine instead of using a special case value. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210930093229.28598-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 11 +++++------ drivers/gpu/drm/i915/display/intel_fdi.c | 2 +- drivers/gpu/drm/i915/display/intel_fdi.h | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4e9a6c9c2deb..5f8f233f0e3c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7555,12 +7555,7 @@ encoder_retry: ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config); if (ret == -EDEADLK) return ret; - if (ret < 0) { - drm_dbg_kms(&i915->drm, "CRTC fixup failed\n"); - return ret; - } - - if (ret == I915_DISPLAY_CONFIG_RETRY) { + if (ret == -EAGAIN) { if (drm_WARN(&i915->drm, !retry, "loop in pipe configuration computation\n")) return -EINVAL; @@ -7569,6 +7564,10 @@ encoder_retry: retry = false; goto encoder_retry; } + if (ret < 0) { + drm_dbg_kms(&i915->drm, "CRTC fixup failed\n"); + return ret; + } /* Dithering seems to not pass-through bits correctly when it should, so * only enable it on 6bpc panels and when its not a compliance diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 02d3294bad7b..51d6f810e69b 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -267,7 +267,7 @@ retry: } if (needs_recompute) - return I915_DISPLAY_CONFIG_RETRY; + return -EAGAIN; return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index d557fc603d7d..640d6585c137 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -12,7 +12,6 @@ struct intel_crtc; struct intel_crtc_state; struct intel_encoder; -#define I915_DISPLAY_CONFIG_RETRY 1 int intel_fdi_link_freq(struct drm_i915_private *i915, const struct intel_crtc_state *pipe_config); int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, From 7ceb751b615900086eed1d65955933923f127d99 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 21 Sep 2021 14:02:44 +0300 Subject: [PATCH 174/554] drm/i915/hdmi: convert intel_hdmi_to_dev to intel_hdmi_to_i915 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer i915 over drm pointer. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210921110244.8666-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 468a107aaabc..d2e61f6c6e08 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -53,21 +53,20 @@ #include "intel_panel.h" #include "intel_snps_phy.h" -static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) +static struct drm_i915_private *intel_hdmi_to_i915(struct intel_hdmi *intel_hdmi) { - return hdmi_to_dig_port(intel_hdmi)->base.base.dev; + return to_i915(hdmi_to_dig_port(intel_hdmi)->base.base.dev); } static void assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) { - struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = intel_hdmi_to_i915(intel_hdmi); u32 enabled_bits; enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; - drm_WARN(dev, + drm_WARN(&dev_priv->drm, intel_de_read(dev_priv, intel_hdmi->hdmi_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); } @@ -1246,7 +1245,7 @@ static void hsw_set_infoframes(struct intel_encoder *encoder, void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) { - struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi)); + struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi); struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); @@ -1830,7 +1829,7 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, int clock, bool respect_downstream_limits, bool has_hdmi_sink) { - struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi)); + struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi); if (clock < 25000) return MODE_CLOCK_LOW; @@ -1946,8 +1945,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); - struct drm_device *dev = intel_hdmi_to_dev(hdmi); - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi); enum drm_mode_status status; int clock = mode->clock; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; From 5ec2b4f77e77b747b69afe10a261850a3d3b8e1c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Aug 2021 15:53:42 +0300 Subject: [PATCH 175/554] drm/i915/debugfs: register LPSP capability on all platforms The debugfs file shows it's not capable, don't duplicate the info. Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/939453050a5a5175a12a08f16542c1b40bd726dc.1630327990.git.jani.nikula@intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 68f4ba8c46e7..455283b1a36b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -2485,14 +2485,11 @@ int intel_connector_debugfs_add(struct drm_connector *connector) connector, &i915_dsc_bpp_fops); } - /* Legacy panels doesn't lpsp on any platform */ - if ((DISPLAY_VER(dev_priv) >= 9 || IS_HASWELL(dev_priv) || - IS_BROADWELL(dev_priv)) && - (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP || - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) + if (connector->connector_type == DRM_MODE_CONNECTOR_DSI || + connector->connector_type == DRM_MODE_CONNECTOR_eDP || + connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) debugfs_create_file("i915_lpsp_capability", 0444, root, connector, &i915_lpsp_capability_fops); From fd71fc38da7d5d59e12657c8f2696cda7abd9dda Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Aug 2021 15:53:43 +0300 Subject: [PATCH 176/554] drm/i915/display: stop returning errors from debugfs registration Failures to register debugfs should be ignored anyway, so stop propagating errors altogether for clarity and simplicity. No functional changes. Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/346562ccef2282ccdbdea54409fab1d2b48f313c.1630327990.git.jani.nikula@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 19 +++++-------------- .../drm/i915/display/intel_display_debugfs.h | 8 ++++---- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 455283b1a36b..c4a2ead24b58 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -2442,17 +2442,15 @@ static const struct file_operations i915_dsc_bpp_fops = { * * Cleanup will be done by drm_connector_unregister() through a call to * drm_debugfs_connector_remove(). - * - * Returns 0 on success, negative error codes on error. */ -int intel_connector_debugfs_add(struct drm_connector *connector) +void intel_connector_debugfs_add(struct drm_connector *connector) { struct dentry *root = connector->debugfs_entry; struct drm_i915_private *dev_priv = to_i915(connector->dev); /* The connector must have been registered beforehands. */ if (!root) - return -ENODEV; + return; if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { debugfs_create_file("i915_panel_timings", S_IRUGO, root, @@ -2492,23 +2490,16 @@ int intel_connector_debugfs_add(struct drm_connector *connector) connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) debugfs_create_file("i915_lpsp_capability", 0444, root, connector, &i915_lpsp_capability_fops); - - return 0; } /** * intel_crtc_debugfs_add - add i915 specific crtc debugfs files * @crtc: pointer to a drm_crtc * - * Returns 0 on success, negative error codes on error. - * * Failure to add debugfs entries should generally be ignored. */ -int intel_crtc_debugfs_add(struct drm_crtc *crtc) +void intel_crtc_debugfs_add(struct drm_crtc *crtc) { - if (!crtc->debugfs_entry) - return -ENODEV; - - crtc_updates_add(crtc); - return 0; + if (crtc->debugfs_entry) + crtc_updates_add(crtc); } diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.h b/drivers/gpu/drm/i915/display/intel_display_debugfs.h index 557901f3eb90..c72e35ecba1f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.h +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.h @@ -12,12 +12,12 @@ struct drm_i915_private; #ifdef CONFIG_DEBUG_FS void intel_display_debugfs_register(struct drm_i915_private *i915); -int intel_connector_debugfs_add(struct drm_connector *connector); -int intel_crtc_debugfs_add(struct drm_crtc *crtc); +void intel_connector_debugfs_add(struct drm_connector *connector); +void intel_crtc_debugfs_add(struct drm_crtc *crtc); #else static inline void intel_display_debugfs_register(struct drm_i915_private *i915) {} -static inline int intel_connector_debugfs_add(struct drm_connector *connector) { return 0; } -static inline int intel_crtc_debugfs_add(struct drm_crtc *crtc) { return 0; } +static inline void intel_connector_debugfs_add(struct drm_connector *connector) {} +static inline void intel_crtc_debugfs_add(struct drm_crtc *crtc) {} #endif #endif /* __INTEL_DISPLAY_DEBUGFS_H__ */ From 0f26c8e23ab33fb85a09695771041f5a6a608939 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 30 Aug 2021 17:02:22 +0300 Subject: [PATCH 177/554] drm/i915/debugfs: pass intel_connector to intel_connector_debugfs_add() Prefer the intel_ types. No functional changes. v2: Fix build. Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210830140222.12228-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_connector.c | 2 +- drivers/gpu/drm/i915/display/intel_display_debugfs.c | 3 ++- drivers/gpu/drm/i915/display/intel_display_debugfs.h | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 4f49d782eca2..c65f95a9a1ec 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -124,7 +124,7 @@ int intel_connector_register(struct drm_connector *connector) goto err_backlight; } - intel_connector_debugfs_add(connector); + intel_connector_debugfs_add(intel_connector); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index c4a2ead24b58..309d74fd86ce 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -2443,8 +2443,9 @@ static const struct file_operations i915_dsc_bpp_fops = { * Cleanup will be done by drm_connector_unregister() through a call to * drm_debugfs_connector_remove(). */ -void intel_connector_debugfs_add(struct drm_connector *connector) +void intel_connector_debugfs_add(struct intel_connector *intel_connector) { + struct drm_connector *connector = &intel_connector->base; struct dentry *root = connector->debugfs_entry; struct drm_i915_private *dev_priv = to_i915(connector->dev); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.h b/drivers/gpu/drm/i915/display/intel_display_debugfs.h index c72e35ecba1f..d3a79c07c384 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.h +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.h @@ -6,17 +6,17 @@ #ifndef __INTEL_DISPLAY_DEBUGFS_H__ #define __INTEL_DISPLAY_DEBUGFS_H__ -struct drm_connector; struct drm_crtc; struct drm_i915_private; +struct intel_connector; #ifdef CONFIG_DEBUG_FS void intel_display_debugfs_register(struct drm_i915_private *i915); -void intel_connector_debugfs_add(struct drm_connector *connector); +void intel_connector_debugfs_add(struct intel_connector *connector); void intel_crtc_debugfs_add(struct drm_crtc *crtc); #else static inline void intel_display_debugfs_register(struct drm_i915_private *i915) {} -static inline void intel_connector_debugfs_add(struct drm_connector *connector) {} +static inline void intel_connector_debugfs_add(struct intel_connector *connector) {} static inline void intel_crtc_debugfs_add(struct drm_crtc *crtc) {} #endif From 068396bb21c8aa3b2f797c58eb9e623d7cf271bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Thu, 30 Sep 2021 13:32:36 +0200 Subject: [PATCH 178/554] drm/i915/ttm: Rework object initialization slightly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may end up in i915_ttm_bo_destroy() in an error path before the object is fully initialized. In that case it's not correct to call __i915_gem_free_object(), because that function a) Assumes the gem object refcount is 0, which it isn't. b) frees the placements which are owned by the caller until the init_object() region ops returns successfully. Fix this by providing a lightweight cleanup function __i915_gem_object_fini() which is also called by __i915_gem_free_object(). While doing this, also make sure we call dma_resv_fini() as part of ordinary object destruction and not from the RCU callback that frees the object. This will help track down bugs where the object is incorrectly locked from an RCU lookup. Finally, make sure the object isn't put on the region list until it's either locked or fully initialized in order to block list processing of partially initialized objects. v2: - The TTM object backend memory was freed before the gem pages were put. Separate this functionality into __i915_gem_object_pages_fini() and call it from the TTM delete_mem_notify() callback. v3: - Include i915_gem_object_free_mmaps() in __i915_gem_object_pages_fini() to make sure we don't inadvertedly introduce a race. Fixes: 48b096126954 ("drm/i915: Move __i915_gem_free_object to ttm_bo_destroy") Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20210930113236.583531-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 43 +++++++++++++++++++--- drivers/gpu/drm/i915/gem/i915_gem_object.h | 5 +++ drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 36 +++++++++++------- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 6fb9afb65034..b88b121e244a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -89,6 +89,22 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, mutex_init(&obj->mm.get_dma_page.lock); } +/** + * i915_gem_object_fini - Clean up a GEM object initialization + * @obj: The gem object to cleanup + * + * This function cleans up gem object fields that are set up by + * drm_gem_private_object_init() and i915_gem_object_init(). + * It's primarily intended as a helper for backends that need to + * clean up the gem object in separate steps. + */ +void __i915_gem_object_fini(struct drm_i915_gem_object *obj) +{ + mutex_destroy(&obj->mm.get_page.lock); + mutex_destroy(&obj->mm.get_dma_page.lock); + dma_resv_fini(&obj->base._resv); +} + /** * Mark up the object's coherency levels for a given cache_level * @obj: #drm_i915_gem_object @@ -174,7 +190,6 @@ void __i915_gem_free_object_rcu(struct rcu_head *head) container_of(head, typeof(*obj), rcu); struct drm_i915_private *i915 = to_i915(obj->base.dev); - dma_resv_fini(&obj->base._resv); i915_gem_object_free(obj); GEM_BUG_ON(!atomic_read(&i915->mm.free_count)); @@ -204,10 +219,17 @@ static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj) } } -void __i915_gem_free_object(struct drm_i915_gem_object *obj) +/** + * __i915_gem_object_pages_fini - Clean up pages use of a gem object + * @obj: The gem object to clean up + * + * This function cleans up usage of the object mm.pages member. It + * is intended for backends that need to clean up a gem object in + * separate steps and needs to be called when the object is idle before + * the object's backing memory is freed. + */ +void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj) { - trace_i915_gem_object_destroy(obj); - if (!list_empty(&obj->vma.list)) { struct i915_vma *vma; @@ -233,11 +255,17 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj) __i915_gem_object_free_mmaps(obj); - GEM_BUG_ON(!list_empty(&obj->lut_list)); - atomic_set(&obj->mm.pages_pin_count, 0); __i915_gem_object_put_pages(obj); GEM_BUG_ON(i915_gem_object_has_pages(obj)); +} + +void __i915_gem_free_object(struct drm_i915_gem_object *obj) +{ + trace_i915_gem_object_destroy(obj); + + GEM_BUG_ON(!list_empty(&obj->lut_list)); + bitmap_free(obj->bit_17); if (obj->base.import_attach) @@ -253,6 +281,8 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj) if (obj->shares_resv_from) i915_vm_resv_put(obj->shares_resv_from); + + __i915_gem_object_fini(obj); } static void __i915_gem_free_objects(struct drm_i915_private *i915, @@ -266,6 +296,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915, obj->ops->delayed_free(obj); continue; } + __i915_gem_object_pages_fini(obj); __i915_gem_free_object(obj); /* But keep the pointer alive for RCU-protected lookups */ diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 3043fcbd31bd..7f9f2e5ba0ec 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -58,6 +58,9 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops, struct lock_class_key *key, unsigned alloc_flags); + +void __i915_gem_object_fini(struct drm_i915_gem_object *obj); + struct drm_i915_gem_object * i915_gem_object_create_shmem(struct drm_i915_private *i915, resource_size_t size); @@ -582,6 +585,8 @@ bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj); void __i915_gem_free_object_rcu(struct rcu_head *head); +void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj); + void __i915_gem_free_object(struct drm_i915_gem_object *obj); bool i915_gem_object_evictable(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index bbaaee5668e4..a81bf8b48f79 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -368,8 +368,10 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); - if (likely(obj)) + if (likely(obj)) { + __i915_gem_object_pages_fini(obj); i915_ttm_free_cached_io_st(obj); + } } static struct intel_memory_region * @@ -814,12 +816,9 @@ static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj) */ static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj) { - if (obj->ttm.created) { - ttm_bo_put(i915_gem_to_ttm(obj)); - } else { - __i915_gem_free_object(obj); - call_rcu(&obj->rcu, __i915_gem_free_object_rcu); - } + GEM_BUG_ON(!obj->ttm.created); + + ttm_bo_put(i915_gem_to_ttm(obj)); } static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) @@ -899,16 +898,19 @@ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); - i915_ttm_backup_free(obj); - - /* This releases all gem object bindings to the backend. */ - __i915_gem_free_object(obj); - i915_gem_object_release_memory_region(obj); mutex_destroy(&obj->ttm.get_io_page.lock); - if (obj->ttm.created) + if (obj->ttm.created) { + i915_ttm_backup_free(obj); + + /* This releases all gem object bindings to the backend. */ + __i915_gem_free_object(obj); + call_rcu(&obj->rcu, __i915_gem_free_object_rcu); + } else { + __i915_gem_object_fini(obj); + } } /** @@ -937,7 +939,11 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, drm_gem_private_object_init(&i915->drm, &obj->base, size); i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags); - i915_gem_object_init_memory_region(obj, mem); + + /* Don't put on a region list until we're either locked or fully initialized. */ + obj->mm.region = intel_memory_region_get(mem); + INIT_LIST_HEAD(&obj->mm.region_link); + i915_gem_object_make_unshrinkable(obj); INIT_RADIX_TREE(&obj->ttm.get_io_page.radix, GFP_KERNEL | __GFP_NOWARN); mutex_init(&obj->ttm.get_io_page.lock); @@ -964,6 +970,8 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, return i915_ttm_err_to_gem(ret); obj->ttm.created = true; + i915_gem_object_release_memory_region(obj); + i915_gem_object_init_memory_region(obj, mem); i915_ttm_adjust_domains_after_move(obj); i915_ttm_adjust_gem_after_move(obj); i915_gem_object_unlock(obj); From 048a57fc0d6ab76174eebe7e0c993a370bf516c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 13:41:31 +0300 Subject: [PATCH 179/554] drm/i915: Use standard form -EDEADLK check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify how we check for -EDEADLK vs. other errors from crtc vs. encoder compute_config() calls. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930104133.30854-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5f8f233f0e3c..59bb346aa36e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7537,11 +7537,10 @@ encoder_retry: ret = encoder->compute_config(encoder, pipe_config, connector_state); + if (ret == -EDEADLK) + return ret; if (ret < 0) { - if (ret != -EDEADLK) - drm_dbg_kms(&i915->drm, - "Encoder config failure: %d\n", - ret); + drm_dbg_kms(&i915->drm, "Encoder config failure: %d\n", ret); return ret; } } From 0fb00cc28e1ed1e9052f3231acfd085471d0397b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 13:41:32 +0300 Subject: [PATCH 180/554] drm/i915: Adjust intel_crtc_compute_config() debug message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "CRTC fixup failed" is probably leftovers from pre-atomic days when there was an actual fixup() function. Let's unify the debug messages between encoder vs. crtc compute_config() calls. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930104133.30854-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 59bb346aa36e..27c65c8dc181 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7564,7 +7564,7 @@ encoder_retry: goto encoder_retry; } if (ret < 0) { - drm_dbg_kms(&i915->drm, "CRTC fixup failed\n"); + drm_dbg_kms(&i915->drm, "CRTC config failure: %d\n", ret); return ret; } From ab953f099fd7d0c28d3e35dcd008651aad57db6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 13:41:33 +0300 Subject: [PATCH 181/554] drm/i915: Move WaPruneModeWithIncorrectHsyncOffset into intel_mode_valid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check for the zero length front porch already in intel_mode_valid() so that we get the same validation for both get_modes() and setcrtc()/etc. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930104133.30854-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 27c65c8dc181..583153435ac3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4046,13 +4046,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, } } - /* Cantiga+ cannot handle modes with a hsync front porch of 0. - * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. - */ - if ((DISPLAY_VER(dev_priv) > 4 || IS_G4X(dev_priv)) && - pipe_mode->crtc_hsync_start == pipe_mode->crtc_hdisplay) - return -EINVAL; - intel_crtc_compute_pixel_rate(pipe_config); if (pipe_config->has_pch_encoder) @@ -11159,6 +11152,14 @@ intel_mode_valid(struct drm_device *dev, return MODE_V_ILLEGAL; } + /* + * Cantiga+ cannot handle modes with a hsync front porch of 0. + * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. + */ + if ((DISPLAY_VER(dev_priv) > 4 || IS_G4X(dev_priv)) && + mode->hsync_start == mode->hdisplay) + return MODE_H_ILLEGAL; + return MODE_OK; } From 4bb2d367a5a2807185a04949ae922d247f650576 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Sep 2021 13:00:32 +0000 Subject: [PATCH 182/554] drm/lease: allow empty leases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can be used to create a separate DRM file description, thus creating a new GEM handle namespace. My use-case is wlroots. The library splits responsibilities between separate components: the GBM allocator creates buffers, the GLES2 renderer uses EGL to import them and render to them, the DRM backend imports the buffers and displays them. wlroots has a modular architecture, and any of these components can be swapped and replaced with something else. For instance, the pipeline can be set up so that the DRM dumb buffer allocator is used instead of GBM and the Pixman renderer is used instead of GLES2. Library users can also replace any of these components with their own custom one. DMA-BUFs are used to pass buffer references across components. We could use GEM handles instead, but this would result in pain if multiple GPUs are in use: wlroots copies buffers across GPUs as needed. Importing a GEM handle created on one GPU into a completely different GPU will blow up (fail at best, mix unrelated buffers otherwise). Everything is fine if all components use Mesa. However, this isn't always desirable. For instance when running with DRM dumb buffers and the Pixman software renderer it's unfortunate to depend on GBM in the DRM backend just to turn DMA-BUFs into FB IDs. GBM loads Mesa drivers to perform an action which has nothing driver-specific. Additionally, drivers will fail the import if the 3D engine can't use the imported buffer, for instance amdgpu will refuse to import DRM dumb buffers [1]. We might also want to be running with a Vulkan renderer and a Vulkan allocator in the future, and GBM wouldn't be welcome in this setup. To address this, GBM can be side-stepped in the DRM backend, and can be replaced with drmPrimeFDToHandle calls. However because of GEM handle reference counting issues, care must be taken to avoid double-closing the same GEM handle. In particular, it's not possible to share a DRM FD with GBM or EGL and perform some drmPrimeFDToHandle calls manually. So wlroots needs to re-open the DRM FD to create a new GEM handle namespace. However there's no guarantee that the file-system permissions will be set up so that the primary FD can be opened by the compsoitor. On modern systems seatd or logind is a privileged process responsible for doing this, and other processes aren't expected to do it. For historical reasons systemd still allows physically logged in users to open primary DRM nodes, but this doesn't work on non-systemd setups and it's desirable to lock them down at some point. Some might suggest to open the render node instead of re-opening the primary node. However some systems don't have a render node at all (e.g. no GPU, or a split render/display SoC). Solutions to this issue have been discussed in [2]. One solution would be to open the magic /proc/self/fd/ file, but it's a Linux-specific hack (wlroots supports BSDs too). Another solution is to add support for re-opening a DRM primary node to seatd/logind, but they don't support it now and really haven't been designed for this (logind would need to grow a completely new API, because it assumes unique dev_t IDs). Also this seems like pushing down a kernel limitation to user-space a bit too hard. Another solution is to allow creating empty DRM leases. The lessee FD would have its own GEM handle namespace, so wouldn't conflict wth GBM/EGL. It would have the master bit set, but would be able to manage zero resources. wlroots doesn't intend to share this FD with any other process. All in all IMHO that seems like a pretty reasonable solution to the issue at hand. Note, I've discussed with Jonas Ådahl and Mutter plans to adopt a similar design in the future. Example usage in wlroots is available at [3]. IGT test available at [4]. [1]: https://github.com/swaywm/wlroots/issues/2916 [2]: https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110 [3]: https://github.com/swaywm/wlroots/pull/3158 [4]: https://patchwork.freedesktop.org/series/94323/ Signed-off-by: Simon Ser Cc: Daniel Vetter Cc: Daniel Stone Cc: Pekka Paalanen Cc: Michel Dänzer Cc: Emil Velikov Cc: Keith Packard Cc: Boris Brezillon Cc: Dave Airlie Acked-by: Pekka Paalanen Reviewed-by: Daniel Stone Link: https://patchwork.freedesktop.org/patch/msgid/20210903130000.1590-2-contact@emersion.fr --- drivers/gpu/drm/drm_lease.c | 39 +++++++++++++++++-------------------- include/uapi/drm/drm_mode.h | 3 ++- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index dee4f24a1808..d72c2fac0ff1 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -489,12 +489,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - /* need some objects */ - if (cl->object_count == 0) { - DRM_DEBUG_LEASE("no objects in lease\n"); - return -EINVAL; - } - if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) { DRM_DEBUG_LEASE("invalid flags\n"); return -EINVAL; @@ -510,23 +504,26 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, object_count = cl->object_count; - object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), - array_size(object_count, sizeof(__u32))); - if (IS_ERR(object_ids)) { - ret = PTR_ERR(object_ids); - goto out_lessor; - } - + /* Handle leased objects, if any */ idr_init(&leases); + if (object_count != 0) { + object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), + array_size(object_count, sizeof(__u32))); + if (IS_ERR(object_ids)) { + ret = PTR_ERR(object_ids); + idr_destroy(&leases); + goto out_lessor; + } - /* fill and validate the object idr */ - ret = fill_object_idr(dev, lessor_priv, &leases, - object_count, object_ids); - kfree(object_ids); - if (ret) { - DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret); - idr_destroy(&leases); - goto out_lessor; + /* fill and validate the object idr */ + ret = fill_object_idr(dev, lessor_priv, &leases, + object_count, object_ids); + kfree(object_ids); + if (ret) { + DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret); + idr_destroy(&leases); + goto out_lessor; + } } /* Allocate a file descriptor for the lease */ diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index e4a2570a6058..e1e351682872 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -1112,7 +1112,8 @@ struct drm_mode_destroy_blob { * Lease mode resources, creating another drm_master. * * The @object_ids array must reference at least one CRTC, one connector and - * one plane if &DRM_CLIENT_CAP_UNIVERSAL_PLANES is enabled. + * one plane if &DRM_CLIENT_CAP_UNIVERSAL_PLANES is enabled. Alternatively, + * the lease can be completely empty. */ struct drm_mode_create_lease { /** @object_ids: Pointer to array of object ids (__u32) */ From 21dde40902d2636f70766b3154931de57e1215e9 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:08 +0200 Subject: [PATCH 183/554] drm: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace the boilerplate code surrounding drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-2-greenfoo@u92.eu --- drivers/gpu/drm/drm_client_modeset.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index ced09c7c06f9..5f5184f071ed 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -574,6 +574,7 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, int num_connectors_detected = 0; int num_tiled_conns = 0; struct drm_modeset_acquire_ctx ctx; + int err; if (!drm_drv_uses_atomic_modeset(dev)) return false; @@ -585,10 +586,7 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, if (!save_enabled) return false; - drm_modeset_acquire_init(&ctx, 0); - - while (drm_modeset_lock_all_ctx(dev, &ctx) != 0) - drm_modeset_backoff(&ctx); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); memcpy(save_enabled, enabled, count); mask = GENMASK(count - 1, 0); @@ -743,8 +741,7 @@ bail: ret = false; } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + DRM_MODESET_LOCK_ALL_END(dev, ctx, err); kfree(save_enabled); return ret; From 399190e70816886e2bca1f3f3bc3d9c544af88e7 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:09 +0200 Subject: [PATCH 184/554] drm/i915: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace the boilerplate code surrounding drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-3-greenfoo@u92.eu --- drivers/gpu/drm/i915/display/intel_display.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 134a6acbd8fb..2bf01416d656 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "display/intel_audio.h" #include "display/intel_crt.h" @@ -13476,22 +13477,13 @@ void intel_display_resume(struct drm_device *dev) if (state) state->acquire_ctx = &ctx; - drm_modeset_acquire_init(&ctx, 0); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - while (1) { - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (ret != -EDEADLK) - break; - - drm_modeset_backoff(&ctx); - } - - if (!ret) - ret = __intel_display_resume(dev, state, &ctx); + ret = __intel_display_resume(dev, state, &ctx); intel_enable_ipc(dev_priv); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); if (ret) drm_err(&dev_priv->drm, From 4c048437ef7adb2d81fe4ddc5c04179126eefcf2 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:10 +0200 Subject: [PATCH 185/554] drm/msm: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace the boilerplate code surrounding drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Reported-by: kernel test robot Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-4-greenfoo@u92.eu --- drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index cabe15190ec1..abda52f09b09 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -5,6 +5,8 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include + #include "msm_disp_snapshot.h" static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr) @@ -99,20 +101,18 @@ static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state) { struct drm_device *ddev; struct drm_modeset_acquire_ctx ctx; + int ret; disp_state->timestamp = ktime_get(); ddev = disp_state->drm_dev; - drm_modeset_acquire_init(&ctx, 0); - - while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0) - drm_modeset_backoff(&ctx); + DRM_MODESET_LOCK_ALL_BEGIN(ddev, ctx, 0, ret); disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev, &ctx); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + + DRM_MODESET_LOCK_ALL_END(ddev, ctx, ret); } void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state) From 7c5f2eecc21f44fba1b1f13ce09c2533db9d781a Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:11 +0200 Subject: [PATCH 186/554] drm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-5-greenfoo@u92.eu --- drivers/gpu/drm/drm_client_modeset.c | 5 +++-- drivers/gpu/drm/drm_crtc_helper.c | 18 ++++++++++++------ drivers/gpu/drm/drm_fb_helper.c | 10 ++++++---- drivers/gpu/drm/drm_framebuffer.c | 6 ++++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 5f5184f071ed..43f772543d2a 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -1062,9 +1062,10 @@ static int drm_client_modeset_commit_legacy(struct drm_client_dev *client) struct drm_device *dev = client->dev; struct drm_mode_set *mode_set; struct drm_plane *plane; + struct drm_modeset_acquire_ctx ctx; int ret = 0; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -1093,7 +1094,7 @@ static int drm_client_modeset_commit_legacy(struct drm_client_dev *client) goto out; } out: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); return ret; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index bff917531f33..f3ce073dff79 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -218,11 +218,14 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) */ void drm_helper_disable_unused_functions(struct drm_device *dev) { + struct drm_modeset_acquire_ctx ctx; + int ret; + WARN_ON(drm_drv_uses_atomic_modeset(dev)); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); __drm_helper_disable_unused_functions(dev); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } EXPORT_SYMBOL(drm_helper_disable_unused_functions); @@ -942,12 +945,14 @@ void drm_helper_resume_force_mode(struct drm_device *dev) struct drm_crtc *crtc; struct drm_encoder *encoder; const struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_modeset_acquire_ctx ctx; int encoder_dpms; bool ret; + int err; WARN_ON(drm_drv_uses_atomic_modeset(dev)); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); drm_for_each_crtc(crtc, dev) { if (!crtc->enabled) @@ -982,7 +987,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) /* disable the unused connectors while restoring the modesetting */ __drm_helper_disable_unused_functions(dev); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, err); } EXPORT_SYMBOL(drm_helper_resume_force_mode); @@ -1002,9 +1007,10 @@ EXPORT_SYMBOL(drm_helper_resume_force_mode); int drm_helper_force_disable_all(struct drm_device *dev) { struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; int ret = 0; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); drm_for_each_crtc(crtc, dev) if (crtc->enabled) { struct drm_mode_set set = { @@ -1016,7 +1022,7 @@ int drm_helper_force_disable_all(struct drm_device *dev) goto out; } out: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); return ret; } EXPORT_SYMBOL(drm_helper_force_disable_all); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3ab078321045..6860223f0068 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -940,10 +940,11 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_mode_set *modeset; struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; u16 *r, *g, *b; int ret = 0; - drm_modeset_lock_all(fb_helper->dev); + DRM_MODESET_LOCK_ALL_BEGIN(fb_helper->dev, ctx, 0, ret); drm_client_for_each_modeset(modeset, &fb_helper->client) { crtc = modeset->crtc; if (!crtc->funcs->gamma_set || !crtc->gamma_size) { @@ -970,7 +971,7 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) goto out; } out: - drm_modeset_unlock_all(fb_helper->dev); + DRM_MODESET_LOCK_ALL_END(fb_helper->dev, ctx, ret); return ret; } @@ -1441,10 +1442,11 @@ static int pan_display_legacy(struct fb_var_screeninfo *var, struct drm_fb_helper *fb_helper = info->par; struct drm_client_dev *client = &fb_helper->client; struct drm_mode_set *modeset; + struct drm_modeset_acquire_ctx ctx; int ret = 0; mutex_lock(&client->modeset_mutex); - drm_modeset_lock_all(fb_helper->dev); + DRM_MODESET_LOCK_ALL_BEGIN(fb_helper->dev, ctx, 0, ret); drm_client_for_each_modeset(modeset, client) { modeset->x = var->xoffset; modeset->y = var->yoffset; @@ -1457,7 +1459,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var, } } } - drm_modeset_unlock_all(fb_helper->dev); + DRM_MODESET_LOCK_ALL_END(fb_helper->dev, ctx, ret); mutex_unlock(&client->modeset_mutex); return ret; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 07f5abc875e9..205e9aa9a409 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -1059,8 +1059,10 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) struct drm_device *dev = fb->dev; struct drm_crtc *crtc; struct drm_plane *plane; + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); /* remove from any CRTC */ drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { @@ -1082,7 +1084,7 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) drm_plane_force_disable(plane); } } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } /** From 6b92e77156c5adf6606c8ad825c71404417d88af Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:12 +0200 Subject: [PATCH 187/554] drm/vmwgfx: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-6-greenfoo@u92.eu --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 11 +++++++---- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 28af34ab6ed6..7df35c6f1458 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -28,6 +28,7 @@ #include "vmwgfx_drv.h" #include "vmwgfx_devcaps.h" #include +#include #include "vmwgfx_kms.h" int vmw_getparam_ioctl(struct drm_device *dev, void *data, @@ -172,6 +173,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; + struct drm_modeset_acquire_ctx ctx; struct vmw_framebuffer *vfb; struct vmw_resource *res; uint32_t num_clips; @@ -203,7 +205,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); if (!fb) { @@ -231,7 +233,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, out_no_surface: drm_framebuffer_put(fb); out_no_fb: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); out_no_copy: kfree(clips); out_clips: @@ -250,6 +252,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; + struct drm_modeset_acquire_ctx ctx; struct vmw_framebuffer *vfb; uint32_t num_clips; int ret; @@ -280,7 +283,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); if (!fb) { @@ -303,7 +306,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, out_no_ttm_lock: drm_framebuffer_put(fb); out_no_fb: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); out_no_copy: kfree(clips); out_clips: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 74fa41909213..268095cb8c84 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "vmwgfx_kms.h" @@ -243,15 +244,17 @@ void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv) struct drm_device *dev = &dev_priv->drm; struct vmw_display_unit *du; struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); drm_for_each_crtc(crtc, dev) { du = vmw_crtc_to_du(crtc); du->hotspot_x = 0; du->hotspot_y = 0; } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) @@ -1012,9 +1015,10 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); struct drm_clip_rect norect; + struct drm_modeset_acquire_ctx ctx; int ret, increment = 1; - drm_modeset_lock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); if (!num_clips) { num_clips = 1; @@ -1040,7 +1044,7 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, vmw_cmd_flush(dev_priv, false); - drm_modeset_unlock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); return ret; } From a2cd9947d99b54c959fce20dc19d81af53f4674e Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:13 +0200 Subject: [PATCH 188/554] drm/tegra: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Reported-by: kernel test robot Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-7-greenfoo@u92.eu --- drivers/gpu/drm/tegra/dsi.c | 6 ++++-- drivers/gpu/drm/tegra/hdmi.c | 6 ++++-- drivers/gpu/drm/tegra/sor.c | 11 +++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index f46d377f0c30..28050c188c1c 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "dc.h" #include "drm.h" @@ -202,10 +203,11 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data) struct tegra_dsi *dsi = node->info_ent->data; struct drm_crtc *crtc = dsi->output.encoder.crtc; struct drm_device *drm = node->minor->dev; + struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - drm_modeset_lock_all(drm); + DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -220,7 +222,7 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data) } unlock: - drm_modeset_unlock_all(drm); + DRM_MODESET_LOCK_ALL_END(drm, ctx, err); return err; } diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e5d2a4026028..a62de7f92414 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "hda.h" #include "hdmi.h" @@ -1031,10 +1032,11 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) struct tegra_hdmi *hdmi = node->info_ent->data; struct drm_crtc *crtc = hdmi->output.encoder.crtc; struct drm_device *drm = node->minor->dev; + struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - drm_modeset_lock_all(drm); + DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1049,7 +1051,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) } unlock: - drm_modeset_unlock_all(drm); + DRM_MODESET_LOCK_ALL_END(drm, ctx, err); return err; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 0ea320c1092b..3d1c8b3d1358 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "dc.h" #include "dp.h" @@ -1490,10 +1491,11 @@ static int tegra_sor_show_crc(struct seq_file *s, void *data) struct tegra_sor *sor = node->info_ent->data; struct drm_crtc *crtc = sor->output.encoder.crtc; struct drm_device *drm = node->minor->dev; + struct drm_modeset_acquire_ctx ctx; int err = 0; u32 value; - drm_modeset_lock_all(drm); + DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1522,7 +1524,7 @@ static int tegra_sor_show_crc(struct seq_file *s, void *data) seq_printf(s, "%08x\n", value); unlock: - drm_modeset_unlock_all(drm); + DRM_MODESET_LOCK_ALL_END(drm, ctx, err); return err; } @@ -1652,10 +1654,11 @@ static int tegra_sor_show_regs(struct seq_file *s, void *data) struct tegra_sor *sor = node->info_ent->data; struct drm_crtc *crtc = sor->output.encoder.crtc; struct drm_device *drm = node->minor->dev; + struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - drm_modeset_lock_all(drm); + DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1670,7 +1673,7 @@ static int tegra_sor_show_regs(struct seq_file *s, void *data) } unlock: - drm_modeset_unlock_all(drm); + DRM_MODESET_LOCK_ALL_END(drm, ctx, err); return err; } From 9b8c437ef1a5f34686fc96b391c201a80f1a2ea0 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:14 +0200 Subject: [PATCH 189/554] drm/shmobile: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-8-greenfoo@u92.eu --- drivers/gpu/drm/shmobile/shmob_drm_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 7db01904d18d..8ee215ab614e 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -156,10 +156,12 @@ static int shmob_drm_pm_suspend(struct device *dev) static int shmob_drm_pm_resume(struct device *dev) { struct shmob_drm_device *sdev = dev_get_drvdata(dev); + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(sdev->ddev); + DRM_MODESET_LOCK_ALL_BEGIN(sdev->ddev, ctx, 0, ret); shmob_drm_crtc_resume(&sdev->crtc); - drm_modeset_unlock_all(sdev->ddev); + DRM_MODESET_LOCK_ALL_END(sdev->ddev, ctx, ret); drm_kms_helper_poll_enable(sdev->ddev); return 0; From 26723c3d6b930775f9a85521d09655c533a839e6 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:15 +0200 Subject: [PATCH 190/554] drm/radeon: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-9-greenfoo@u92.eu --- drivers/gpu/drm/radeon/radeon_device.c | 21 +++++++++++++++------ drivers/gpu/drm/radeon/radeon_dp_mst.c | 10 ++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4f0fbf667431..7e31e5ce7f61 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1559,7 +1560,8 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, struct pci_dev *pdev; struct drm_crtc *crtc; struct drm_connector *connector; - int i, r; + struct drm_modeset_acquire_ctx ctx; + int i, r, ret; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1573,12 +1575,15 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, drm_kms_helper_poll_disable(dev); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (ret) + return ret; /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1663,7 +1668,8 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) struct radeon_device *rdev = dev->dev_private; struct pci_dev *pdev = to_pci_dev(dev->dev); struct drm_crtc *crtc; - int r; + struct drm_modeset_acquire_ctx ctx; + int r, ret; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -1741,11 +1747,14 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) if (fbcon) { drm_helper_resume_force_mode(dev); /* turn on display hw */ - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (ret) + return ret; } drm_kms_helper_poll_enable(dev); diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index ec867fa880a4..3f83ee75b100 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "atom.h" #include "ni_reg.h" @@ -737,11 +738,12 @@ static int radeon_debugfs_mst_info_show(struct seq_file *m, void *unused) struct radeon_device *rdev = (struct radeon_device *)m->private; struct drm_device *dev = rdev->ddev; struct drm_connector *connector; + struct drm_modeset_acquire_ctx ctx; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; - int i; + int i, ret; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) continue; @@ -759,8 +761,8 @@ static int radeon_debugfs_mst_info_show(struct seq_file *m, void *unused) radeon_connector->cur_stream_attribs[i].fe, radeon_connector->cur_stream_attribs[i].slots); } - drm_modeset_unlock_all(dev); - return 0; + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + return ret; } DEFINE_SHOW_ATTRIBUTE(radeon_debugfs_mst_info); From 6067fddc1a4fdf155787ab6182c192e4b360b73c Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:16 +0200 Subject: [PATCH 191/554] drm/omapdrm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-10-greenfoo@u92.eu --- drivers/gpu/drm/omapdrm/omap_fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 190afc564914..fa7636c13c19 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "omap_dmm_tiler.h" #include "omap_drv.h" @@ -62,15 +63,17 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb, unsigned num_clips) { struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(fb->dev); + DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, 0, ret); drm_for_each_crtc(crtc, fb->dev) omap_crtc_flush(crtc); - drm_modeset_unlock_all(fb->dev); + DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret); - return 0; + return ret; } static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { From 6aa2daae589b63e8b39fe6f7f2b59fb3063efa05 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:17 +0200 Subject: [PATCH 192/554] drm/nouveau: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-11-greenfoo@u92.eu --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index d7b9f7f8c9e3..86e18a844953 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -667,16 +668,18 @@ nv50_audio_component_bind(struct device *kdev, struct device *hda_kdev, struct drm_device *drm_dev = dev_get_drvdata(kdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct drm_audio_component *acomp = data; + struct drm_modeset_acquire_ctx ctx; + int ret; if (WARN_ON(!device_link_add(hda_kdev, kdev, DL_FLAG_STATELESS))) return -ENOMEM; - drm_modeset_lock_all(drm_dev); + DRM_MODESET_LOCK_ALL_BEGIN(drm_dev, ctx, 0, ret); acomp->ops = &nv50_audio_component_ops; acomp->dev = kdev; drm->audio.component = acomp; - drm_modeset_unlock_all(drm_dev); - return 0; + DRM_MODESET_LOCK_ALL_END(drm_dev, ctx, ret); + return ret; } static void @@ -686,12 +689,14 @@ nv50_audio_component_unbind(struct device *kdev, struct device *hda_kdev, struct drm_device *drm_dev = dev_get_drvdata(kdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct drm_audio_component *acomp = data; + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(drm_dev); + DRM_MODESET_LOCK_ALL_BEGIN(drm_dev, ctx, 0, ret); drm->audio.component = NULL; acomp->ops = NULL; acomp->dev = NULL; - drm_modeset_unlock_all(drm_dev); + DRM_MODESET_LOCK_ALL_END(drm_dev, ctx, ret); } static const struct component_ops nv50_audio_component_bind_ops = { From fd49ef52e2db015ce69ad02bab0702489d141a41 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:18 +0200 Subject: [PATCH 193/554] drm/msm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-12-greenfoo@u92.eu --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 768012243b44..b89687074890 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "dpu_kms.h" #include "dpu_hw_lm.h" @@ -1172,14 +1173,15 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) struct drm_display_mode *mode; struct drm_framebuffer *fb; struct drm_plane_state *state; + struct drm_modeset_acquire_ctx ctx; struct dpu_crtc_state *cstate; - int i, out_width; + int i, out_width, ret; dpu_crtc = s->private; crtc = &dpu_crtc->base; - drm_modeset_lock_all(crtc->dev); + DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret); cstate = to_dpu_crtc_state(crtc->state); mode = &crtc->state->adjusted_mode; @@ -1263,9 +1265,9 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) dpu_crtc->vblank_cb_time = ktime_set(0, 0); } - drm_modeset_unlock_all(crtc->dev); + DRM_MODESET_LOCK_ALL_END(crtc->dev, ctx, ret); - return 0; + return ret; } DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); From 746826bcf8fdf682668ff1c415d6b91dbf5858be Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:19 +0200 Subject: [PATCH 194/554] drm/i915: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-13-greenfoo@u92.eu --- drivers/gpu/drm/i915/display/intel_audio.c | 16 ++++--- drivers/gpu/drm/i915/display/intel_display.c | 5 +- .../drm/i915/display/intel_display_debugfs.c | 46 ++++++++++++------- drivers/gpu/drm/i915/display/intel_overlay.c | 6 ++- drivers/gpu/drm/i915/display/intel_pipe_crc.c | 7 ++- drivers/gpu/drm/i915/i915_drv.c | 13 ++++-- 6 files changed, 61 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 532237588511..c64f738cc062 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -26,6 +26,7 @@ #include #include +#include #include "i915_drv.h" #include "intel_atomic.h" @@ -1214,7 +1215,8 @@ static int i915_audio_component_bind(struct device *i915_kdev, { struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); - int i; + struct drm_modeset_acquire_ctx ctx; + int i, ret; if (drm_WARN_ON(&dev_priv->drm, acomp->base.ops || acomp->base.dev)) return -EEXIST; @@ -1224,16 +1226,16 @@ static int i915_audio_component_bind(struct device *i915_kdev, DL_FLAG_STATELESS))) return -ENOMEM; - drm_modeset_lock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); acomp->base.ops = &i915_audio_component_ops; acomp->base.dev = i915_kdev; BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS); for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++) acomp->aud_sample_rate[i] = 0; dev_priv->audio_component = acomp; - drm_modeset_unlock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); - return 0; + return ret; } static void i915_audio_component_unbind(struct device *i915_kdev, @@ -1241,12 +1243,14 @@ static void i915_audio_component_unbind(struct device *i915_kdev, { struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); + struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_lock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); acomp->base.ops = NULL; acomp->base.dev = NULL; dev_priv->audio_component = NULL; - drm_modeset_unlock_all(&dev_priv->drm); + DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); device_link_remove(hda_kdev, i915_kdev); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 2bf01416d656..297359411c5f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12512,6 +12512,7 @@ cleanup_bios: int intel_modeset_init_nogem(struct drm_i915_private *i915) { struct drm_device *dev = &i915->drm; + struct drm_modeset_acquire_ctx ctx; enum pipe pipe; struct intel_crtc *crtc; int ret; @@ -12563,9 +12564,9 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) intel_vga_disable(i915); intel_setup_outputs(i915); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); intel_modeset_setup_hw_state(dev, dev->mode_config.acquire_ctx); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); for_each_intel_crtc(dev, crtc) { struct intel_initial_plane_config plane_config = {}; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 8fdacb252bb1..e0a6837996e7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -5,6 +5,7 @@ #include #include +#include #include "i915_debugfs.h" #include "intel_display_debugfs.h" @@ -1057,11 +1058,13 @@ static int i915_display_info(struct seq_file *m, void *unused) struct intel_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; + struct drm_modeset_acquire_ctx ctx; intel_wakeref_t wakeref; + int ret; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); seq_printf(m, "CRTC info\n"); seq_printf(m, "---------\n"); @@ -1076,20 +1079,21 @@ static int i915_display_info(struct seq_file *m, void *unused) intel_connector_info(m, connector); drm_connector_list_iter_end(&conn_iter); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - return 0; + return ret; } static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; - int i; + struct drm_modeset_acquire_ctx ctx; + int i, ret; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); seq_printf(m, "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n", dev_priv->dpll.ref_clks.nssc, @@ -1132,9 +1136,9 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, " mg_pll_tdc_coldst_bias: 0x%08x\n", pll->state.hw_state.mg_pll_tdc_coldst_bias); } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - return 0; + return ret; } static int i915_ipc_status_show(struct seq_file *m, void *data) @@ -1193,13 +1197,15 @@ static int i915_ddb_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; struct skl_ddb_entry *entry; struct intel_crtc *crtc; + int ret; if (DISPLAY_VER(dev_priv) < 9) return -ENODEV; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size"); @@ -1223,9 +1229,9 @@ static int i915_ddb_info(struct seq_file *m, void *unused) entry->end, skl_ddb_entry_size(entry)); } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - return 0; + return ret; } static void drrs_status_per_crtc(struct seq_file *m, @@ -1303,10 +1309,12 @@ static int i915_drrs_status(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; struct intel_crtc *crtc; int active_crtc_cnt = 0; + int ret; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for_each_intel_crtc(dev, crtc) { if (crtc->base.state->active) { active_crtc_cnt++; @@ -1315,7 +1323,7 @@ static int i915_drrs_status(struct seq_file *m, void *unused) drrs_status_per_crtc(m, dev, crtc); } } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); if (!active_crtc_cnt) seq_puts(m, "No active crtc found\n"); @@ -1607,8 +1615,10 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) { struct drm_i915_private *dev_priv = m->private; struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; int level; int num_levels; + int ret; if (IS_CHERRYVIEW(dev_priv)) num_levels = 3; @@ -1619,7 +1629,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) else num_levels = ilk_wm_max_level(dev_priv) + 1; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for (level = 0; level < num_levels; level++) { unsigned int latency = wm[level]; @@ -1640,7 +1650,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) level, wm[level], latency / 10, latency % 10); } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } static int pri_wm_latency_show(struct seq_file *m, void *data) @@ -1724,6 +1734,7 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, struct seq_file *m = file->private_data; struct drm_i915_private *dev_priv = m->private; struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; u16 new[8] = { 0 }; int num_levels; int level; @@ -1753,12 +1764,15 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, if (ret != num_levels) return -EINVAL; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for (level = 0; level < num_levels; level++) wm[level] = new[level]; - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (ret) + return ret; return len; } diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 7e3f5c6ca484..c0ee135e5499 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -27,6 +27,7 @@ */ #include +#include #include "gem/i915_gem_pm.h" #include "gt/intel_gpu_commands.h" @@ -1263,6 +1264,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, { struct drm_intel_overlay_attrs *attrs = data; struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_modeset_acquire_ctx ctx; struct intel_overlay *overlay; int ret; @@ -1272,7 +1274,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, return -ENODEV; } - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); ret = -EINVAL; if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { @@ -1329,7 +1331,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, ret = 0; out_unlock: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c index 8ac263f471be..d0bc74904b93 100644 --- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c @@ -29,6 +29,8 @@ #include #include +#include + #include "intel_atomic.h" #include "intel_de.h" #include "intel_display_types.h" @@ -76,6 +78,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, enum intel_pipe_crc_source *source) { struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; struct intel_crtc *crtc; struct intel_digital_port *dig_port; @@ -83,7 +86,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, *source = INTEL_PIPE_CRC_SOURCE_PIPE; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for_each_intel_encoder(dev, encoder) { if (!encoder->base.crtc) continue; @@ -120,7 +123,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, break; } } - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 59fb4c710c8c..e7b763ca6d10 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "display/intel_acpi.h" #include "display/intel_bw.h" @@ -1009,31 +1010,35 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) static void intel_suspend_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; + int ret; if (!HAS_DISPLAY(dev_priv)) return; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for_each_intel_encoder(dev, encoder) if (encoder->suspend) encoder->suspend(encoder); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; + struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; + int ret; if (!HAS_DISPLAY(dev_priv)) return; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); for_each_intel_encoder(dev, encoder) if (encoder->shutdown) encoder->shutdown(encoder); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); } void i915_driver_shutdown(struct drm_i915_private *i915) From 984c9949f1c4cf36c35aa2de5ee2b65c39379fd9 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:20 +0200 Subject: [PATCH 195/554] drm/i915: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() part 2 As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() While the previous commit was a simple "search and replace", this time I had to do a bit of refactoring as only one call to DRM_MODESET_LOCK_ALL_BEGIN() is allowed inside one same function. Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-14-greenfoo@u92.eu --- drivers/gpu/drm/i915/display/intel_overlay.c | 40 ++++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index c0ee135e5499..c623738c59c8 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -1105,6 +1105,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, struct drm_crtc *drmmode_crtc; struct intel_crtc *crtc; struct drm_i915_gem_object *new_bo; + struct drm_modeset_acquire_ctx ctx; int ret; overlay = dev_priv->overlay; @@ -1113,24 +1114,24 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, return -ENODEV; } - if (!(params->flags & I915_OVERLAY_ENABLE)) { - drm_modeset_lock_all(dev); - ret = intel_overlay_switch_off(overlay); - drm_modeset_unlock_all(dev); + if (params->flags & I915_OVERLAY_ENABLE) { - return ret; + drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id); + if (!drmmode_crtc) + return -ENOENT; + crtc = to_intel_crtc(drmmode_crtc); + + new_bo = i915_gem_object_lookup(file_priv, params->bo_handle); + if (!new_bo) + return -ENOENT; } - drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id); - if (!drmmode_crtc) - return -ENOENT; - crtc = to_intel_crtc(drmmode_crtc); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - new_bo = i915_gem_object_lookup(file_priv, params->bo_handle); - if (!new_bo) - return -ENOENT; - - drm_modeset_lock_all(dev); + if (!(params->flags & I915_OVERLAY_ENABLE)) { + ret = intel_overlay_switch_off(overlay); + goto out_unlock; + } if (i915_gem_object_is_tiled(new_bo)) { drm_dbg_kms(&dev_priv->drm, @@ -1195,14 +1196,11 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, if (ret != 0) goto out_unlock; - drm_modeset_unlock_all(dev); - i915_gem_object_put(new_bo); - - return 0; - out_unlock: - drm_modeset_unlock_all(dev); - i915_gem_object_put(new_bo); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (params->flags & I915_OVERLAY_ENABLE) + i915_gem_object_put(new_bo); return ret; } From 4f9e860e6ad65ff4ea8ce165a1407d96ff1b2211 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:21 +0200 Subject: [PATCH 196/554] drm/gma500: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-15-greenfoo@u92.eu --- drivers/gpu/drm/gma500/psb_device.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 3030f18ba022..021a7238508f 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -8,6 +8,7 @@ #include #include +#include #include "gma_device.h" #include "intel_bios.h" @@ -169,8 +170,10 @@ static int psb_save_display_registers(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; struct gma_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; + int ret; /* Display arbitration control + watermarks */ regs->saveDSPARB = PSB_RVDC32(DSPARB); @@ -183,7 +186,7 @@ static int psb_save_display_registers(struct drm_device *dev) regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); /* Save crtc and output state */ - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) dev_priv->ops->save_crtc(crtc); @@ -193,8 +196,9 @@ static int psb_save_display_registers(struct drm_device *dev) if (connector->save) connector->save(&connector->base); - drm_modeset_unlock_all(dev); - return 0; + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + return ret; } /** @@ -207,8 +211,10 @@ static int psb_restore_display_registers(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; struct gma_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; + int ret; /* Display arbitration + watermarks */ PSB_WVDC32(regs->saveDSPARB, DSPARB); @@ -223,7 +229,7 @@ static int psb_restore_display_registers(struct drm_device *dev) /*make sure VGA plane is off. it initializes to on after reset!*/ PSB_WVDC32(0x80000000, VGACNTRL); - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (drm_helper_crtc_in_use(crtc)) dev_priv->ops->restore_crtc(crtc); @@ -232,8 +238,8 @@ static int psb_restore_display_registers(struct drm_device *dev) if (connector->restore) connector->restore(&connector->base); - drm_modeset_unlock_all(dev); - return 0; + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + return ret; } static int psb_power_down(struct drm_device *dev) From 299f040e855b69c29522cde446777902381a07f5 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:22 +0200 Subject: [PATCH 197/554] drm/amd: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() As requested in Documentation/gpu/todo.rst, replace driver calls to drm_modeset_lock_all() with DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-16-greenfoo@u92.eu --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 21 +++++--- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 52 +++++++++---------- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 25 +++++---- 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 7a7316731911..b07e845a2600 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -40,6 +40,7 @@ #include #include #include +#include static void amdgpu_display_flip_callback(struct dma_fence *f, struct dma_fence_cb *cb) @@ -1543,16 +1544,21 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev) struct drm_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter iter; - int r; + struct drm_modeset_acquire_ctx ctx; + int r, ret; /* turn off display hw */ - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); drm_connector_list_iter_end(&iter); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (ret) + return ret; + /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); @@ -1590,7 +1596,8 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) struct drm_connector *connector; struct drm_connector_list_iter iter; struct drm_crtc *crtc; - int r; + struct drm_modeset_acquire_ctx ctx; + int r, ret; /* pin cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1612,7 +1619,7 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) drm_helper_resume_force_mode(dev); /* turn on display hw */ - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) @@ -1620,8 +1627,8 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) DRM_MODE_DPMS_ON); drm_connector_list_iter_end(&iter); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - return 0; + return ret; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 9b1fc54555ee..5196c1d26f87 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -80,6 +80,7 @@ #include #include #include +#include #if defined(CONFIG_DRM_AMD_DC_DCN) #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" @@ -2621,6 +2622,9 @@ static void handle_hpd_irq(void *param) #ifdef CONFIG_DRM_AMD_DC_HDCP struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); #endif + struct drm_modeset_acquire_ctx ctx; + int ret; + if (adev->dm.disable_hpd_irq) return; @@ -2646,14 +2650,6 @@ static void handle_hpd_irq(void *param) if (aconnector->base.force && new_connection_type == dc_connection_none) { emulated_link_detect(aconnector->dc_link); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); - } else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) { if (new_connection_type == dc_connection_none && aconnector->dc_link->type == dc_connection_none) @@ -2661,13 +2657,18 @@ static void handle_hpd_irq(void *param) amdgpu_dm_update_connector_after_detect(aconnector); - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); + } else { + goto out; } + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + dm_restore_drm_connector_state(dev, connector); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) + drm_kms_helper_hotplug_event(dev); + +out: mutex_unlock(&aconnector->hpd_lock); } @@ -2756,12 +2757,14 @@ static void handle_hpd_rx_irq(void *param) struct drm_connector *connector = &aconnector->base; struct drm_device *dev = connector->dev; struct dc_link *dc_link = aconnector->dc_link; + struct drm_modeset_acquire_ctx ctx; bool is_mst_root_connector = aconnector->mst_mgr.mst_state; bool result = false; enum dc_connection_type new_connection_type = dc_connection_none; struct amdgpu_device *adev = drm_to_adev(dev); union hpd_irq_data hpd_irq_data; bool lock_flag = 0; + int ret; memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); @@ -2828,12 +2831,6 @@ out: amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_hotplug_event(dev); } else if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { if (aconnector->fake_enable) @@ -2841,14 +2838,17 @@ out: amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_hotplug_event(dev); + } else { + goto finish; } + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + dm_restore_drm_connector_state(dev, connector); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + drm_kms_helper_hotplug_event(dev); } +finish: #ifdef CONFIG_DRM_AMD_DC_HDCP if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) { if (adev->dm.hdcp_workqueue) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 87daa78a32b8..fb7b56fa2673 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -24,6 +24,7 @@ */ #include +#include #include "dc.h" #include "amdgpu.h" @@ -1191,12 +1192,14 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, struct drm_connector *connector = &aconnector->base; struct dc_link *link = NULL; struct drm_device *dev = connector->dev; + struct drm_modeset_acquire_ctx ctx; enum dc_connection_type new_connection_type = dc_connection_none; char *wr_buf = NULL; uint32_t wr_buf_size = 42; int max_param_num = 1; long param[1] = {0}; uint8_t param_nums = 0; + int ret; if (!aconnector || !aconnector->dc_link) return -EINVAL; @@ -1236,12 +1239,6 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, goto unlock; amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_hotplug_event(dev); } else if (param[0] == 0) { if (!aconnector->dc_link) goto unlock; @@ -1259,13 +1256,19 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, amdgpu_dm_update_connector_after_detect(aconnector); - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_hotplug_event(dev); + } else { + goto unlock; } + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + dm_restore_drm_connector_state(dev, connector); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + if (ret) + return ret; + + drm_kms_helper_hotplug_event(dev); + unlock: mutex_unlock(&aconnector->hpd_lock); From 8d813d1a535c8c7503a5f4061654a73026be8c5e Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:23 +0200 Subject: [PATCH 198/554] drm: cleanup: remove drm_modeset_(un)lock_all() Functions drm_modeset_lock_all() and drm_modeset_unlock_all() are no longer used anywhere and can be removed. Signed-off-by: Fernando Ramos Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-17-greenfoo@u92.eu --- drivers/gpu/drm/drm_modeset_lock.c | 94 +----------------------------- include/drm/drm_modeset_lock.h | 2 - 2 files changed, 3 insertions(+), 93 deletions(-) diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index fcfe1a03c4a1..afd1351749a5 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -77,93 +77,6 @@ static DEFINE_WW_CLASS(crtc_ww_class); -/** - * drm_modeset_lock_all - take all modeset locks - * @dev: DRM device - * - * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. Locks must be dropped by calling the - * drm_modeset_unlock_all() function. - * - * This function is deprecated. It allocates a lock acquisition context and - * stores it in &drm_device.mode_config. This facilitate conversion of - * existing code because it removes the need to manually deal with the - * acquisition context, but it is also brittle because the context is global - * and care must be taken not to nest calls. New code should use the - * drm_modeset_lock_all_ctx() function and pass in the context explicitly. - */ -void drm_modeset_lock_all(struct drm_device *dev) -{ - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL); - if (WARN_ON(!ctx)) - return; - - mutex_lock(&config->mutex); - - drm_modeset_acquire_init(ctx, 0); - -retry: - ret = drm_modeset_lock_all_ctx(dev, ctx); - if (ret < 0) { - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } - - drm_modeset_acquire_fini(ctx); - kfree(ctx); - return; - } - ww_acquire_done(&ctx->ww_ctx); - - WARN_ON(config->acquire_ctx); - - /* - * We hold the locks now, so it is safe to stash the acquisition - * context for drm_modeset_unlock_all(). - */ - config->acquire_ctx = ctx; - - drm_warn_on_modeset_not_all_locked(dev); -} -EXPORT_SYMBOL(drm_modeset_lock_all); - -/** - * drm_modeset_unlock_all - drop all modeset locks - * @dev: DRM device - * - * This function drops all modeset locks taken by a previous call to the - * drm_modeset_lock_all() function. - * - * This function is deprecated. It uses the lock acquisition context stored - * in &drm_device.mode_config. This facilitates conversion of existing - * code because it removes the need to manually deal with the acquisition - * context, but it is also brittle because the context is global and care must - * be taken not to nest calls. New code should pass the acquisition context - * directly to the drm_modeset_drop_locks() function. - */ -void drm_modeset_unlock_all(struct drm_device *dev) -{ - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; - - if (WARN_ON(!ctx)) - return; - - config->acquire_ctx = NULL; - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - - kfree(ctx); - - mutex_unlock(&dev->mode_config.mutex); -} -EXPORT_SYMBOL(drm_modeset_unlock_all); - /** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device @@ -380,10 +293,9 @@ EXPORT_SYMBOL(drm_modeset_unlock); * This function takes all modeset locks, suitable where a more fine-grained * scheme isn't (yet) implemented. * - * Unlike drm_modeset_lock_all(), it doesn't take the &drm_mode_config.mutex - * since that lock isn't required for modeset state changes. Callers which - * need to grab that lock too need to do so outside of the acquire context - * @ctx. + * It doesn't take the &drm_mode_config.mutex since that lock isn't required for + * modeset state changes. Callers which need to grab that lock too need to do so + * outside of the acquire context @ctx. * * Locks acquired with this function should be released by calling the * drm_modeset_drop_locks() function on @ctx. diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index aafd07388eb7..865e64bcc4cb 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -132,8 +132,6 @@ struct drm_device; struct drm_crtc; struct drm_plane; -void drm_modeset_lock_all(struct drm_device *dev); -void drm_modeset_unlock_all(struct drm_device *dev); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); int drm_modeset_lock_all_ctx(struct drm_device *dev, From 18be03ef230f781f34754dbbc642cbe26b44d683 Mon Sep 17 00:00:00 2001 From: Fernando Ramos Date: Fri, 24 Sep 2021 08:43:24 +0200 Subject: [PATCH 199/554] doc: drm: remove TODO entry regarding DRM_MODSET_LOCK_ALL cleanup The previous commits do exactly what this entry in the TODO file asks for, thus we can remove it now as it is no longer applicable. Signed-off-by: Fernando Ramos Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210924064324.229457-18-greenfoo@u92.eu --- Documentation/gpu/todo.rst | 17 ----------------- Documentation/locking/ww-mutex-design.rst | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 12e61869939e..6613543955e9 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -353,23 +353,6 @@ converted, except for struct drm_driver.gem_prime_mmap. Level: Intermediate -Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate ---------------------------------------------------------- - -For cases where drivers are attempting to grab the modeset locks with a local -acquire context. Replace the boilerplate code surrounding -drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and -DRM_MODESET_LOCK_ALL_END() instead. - -This should also be done for all places where drm_modeset_lock_all() is still -used. - -As a reference, take a look at the conversions already completed in drm core. - -Contact: Sean Paul, respective driver maintainers - -Level: Starter - Rename CMA helpers to DMA helpers --------------------------------- diff --git a/Documentation/locking/ww-mutex-design.rst b/Documentation/locking/ww-mutex-design.rst index 6a4d7319f8f0..6a8f8beb9ec4 100644 --- a/Documentation/locking/ww-mutex-design.rst +++ b/Documentation/locking/ww-mutex-design.rst @@ -60,7 +60,7 @@ Concepts Compared to normal mutexes two additional concepts/objects show up in the lock interface for w/w mutexes: -Acquire context: To ensure eventual forward progress it is important the a task +Acquire context: To ensure eventual forward progress it is important that a task trying to acquire locks doesn't grab a new reservation id, but keeps the one it acquired when starting the lock acquisition. This ticket is stored in the acquire context. Furthermore the acquire context keeps track of debugging state From f22f4e5be89c4296d76eaa9ba83dda46bdf11134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 28 Sep 2021 21:51:05 +0300 Subject: [PATCH 200/554] drm/i915: Stop force enabling pipe bottom color gammma/csc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While sanitizing the hardware state we're currently forcing the pipe bottom color legacy csc/gamma bits on. That is not a good idea as BIOSen are likely to leave gabage in the LUTs and so doing this causes ugly visual glitches if and when the planes covering the background get disabled. This was exactly the case on this Dell Precision 5560 tgl laptop. On icl+ we don't normally even use these legacy bits anymore and instead use their GAMMA_MODE counterparts. On earlier platforms the bits are used, but we still shouldn't force them on without knowing what's in the LUT. So two options, get rid of the whole thing, or do what intel_color_commit() does to make sure the bottom color state matches whatever out hardware readout produced. I chose the latter since it'll match what happens on older platforms when the primary plane gets turned off. In fact let's just call intel_color_commit(). It'll also do some CSC programming but since we don't have readout for that it'll actually just set to all zeros. So in the unlikely case of CSC actually being enabld by the BIOS we'll end up with all black until the first atomic commit happens. Still not totally sure what we should do about color management features here in general. Probably the safest thing would be to force everything off exactly at the same time when we disable the primary plane as there is no guarantees that whatever the LUTs/CSCs contain make any sense whatsoever without the specific pixel data in the BIOS fb. And if we preserve the primary plane then we should disable the color management features exactly when the primary plane fb contents first changes since the new content assumes more or less no transformations. But of course synchronizing front buffer rendering with anything else is a bit hard... Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/3534 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210928185105.3030-1-ville.syrjala@linux.intel.com Reviewed-by: Uma Shankar --- drivers/gpu/drm/i915/display/intel_display.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 583153435ac3..873b6b0c0581 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -11996,13 +11996,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc, intel_plane_disable_noatomic(crtc, plane); } - /* - * Disable any background color set by the BIOS, but enable the - * gamma and CSC to match how we program our planes. - */ - if (DISPLAY_VER(dev_priv) >= 9) - intel_de_write(dev_priv, SKL_BOTTOM_COLOR(crtc->pipe), - SKL_BOTTOM_COLOR_GAMMA_ENABLE | SKL_BOTTOM_COLOR_CSC_ENABLE); + /* Disable any background color/etc. set by the BIOS */ + intel_color_commit(crtc_state); } /* Adjust the state of the output pipe according to whether we From 77d40e0176a5b1d9fa26745e485c6e731bdac8e5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Sep 2021 15:57:59 -0700 Subject: [PATCH 201/554] drm/bridge: ti-sn65dsi86: Implement bridge->mode_valid() For the brave new world of bridges not creating their own connectors, we need to implement the max clock limitation via bridge->mode_valid() instead of connector->mode_valid(). v2: Drop unneeded connector->mode_valid() Signed-off-by: Rob Clark Reviewed-by: Douglas Anderson Reviewed-by: Laurent Pinchart Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20210920225801.227211-3-robdclark@gmail.com --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 41d48a393e7f..6154bed0af5b 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -615,20 +615,8 @@ static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector) return drm_bridge_get_modes(pdata->next_bridge, connector); } -static enum drm_mode_status -ti_sn_bridge_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* maximum supported resolution is 4K at 60 fps */ - if (mode->clock > 594000) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - static struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = { .get_modes = ti_sn_bridge_connector_get_modes, - .mode_valid = ti_sn_bridge_connector_mode_valid, }; static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = { @@ -766,6 +754,18 @@ static void ti_sn_bridge_detach(struct drm_bridge *bridge) drm_dp_aux_unregister(&bridge_to_ti_sn65dsi86(bridge)->aux); } +static enum drm_mode_status +ti_sn_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + /* maximum supported resolution is 4K at 60 fps */ + if (mode->clock > 594000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static void ti_sn_bridge_disable(struct drm_bridge *bridge) { struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); @@ -1127,6 +1127,7 @@ static void ti_sn_bridge_post_disable(struct drm_bridge *bridge) static const struct drm_bridge_funcs ti_sn_bridge_funcs = { .attach = ti_sn_bridge_attach, .detach = ti_sn_bridge_detach, + .mode_valid = ti_sn_bridge_mode_valid, .pre_enable = ti_sn_bridge_pre_enable, .enable = ti_sn_bridge_enable, .disable = ti_sn_bridge_disable, From 9eddd5a9a2aee15d4f0c701388cbdea70e49c6a9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 26 Sep 2021 22:10:05 +0200 Subject: [PATCH 202/554] drm/i915: Use fixed offset for PTEs location We assumed that for all modern GENs the PTEs and register space are split in the GTTMMADR BAR, but while it is true, we should rather use fixed offset as it is defined in the specification. Bspec: 4409, 4457, 4604, 11181, 9027, 13246, 13321, 44980 Signed-off-by: Michal Wajdeczko Cc: CQ Tang Cc: Matt Roper Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210926201005.1450-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/gt/intel_ggtt.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 06576fc1310e..f09def2b7090 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -813,6 +813,21 @@ static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) return 0; } +static unsigned int gen6_gttmmadr_size(struct drm_i915_private *i915) +{ + /* + * GEN6: GTTMMADR size is 4MB and GTTADR starts at 2MB offset + * GEN8: GTTMMADR size is 16MB and GTTADR starts at 8MB offset + */ + GEM_BUG_ON(GRAPHICS_VER(i915) < 6); + return (GRAPHICS_VER(i915) < 8) ? SZ_4M : SZ_16M; +} + +static unsigned int gen6_gttadr_offset(struct drm_i915_private *i915) +{ + return gen6_gttmmadr_size(i915) / 2; +} + static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) { struct drm_i915_private *i915 = ggtt->vm.i915; @@ -821,8 +836,8 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) u32 pte_flags; int ret; - /* For Modern GENs the PTEs and register space are split in the BAR */ - phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2; + GEM_WARN_ON(pci_resource_len(pdev, 0) != gen6_gttmmadr_size(i915)); + phys_addr = pci_resource_start(pdev, 0) + gen6_gttadr_offset(i915); /* * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range From 217ecd310d56cca0bfd7c3ee1ff1deafae4ffed1 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 26 Sep 2021 20:45:42 +0200 Subject: [PATCH 203/554] drm/i915/guc: Verify result from CTB (de)register action In commit b839a869dfc9 ("drm/i915/guc: Add support for data reporting in GuC responses") we missed the hypothetical case that GuC might return positive non-zero value as success data. While that would be lucky treated as error case, and at the end will result in reporting valid -EIO, in the meantime this value will be passed to ERR_PTR that could be misleading. v2: rebased Reported-by: Dan Carpenter Signed-off-by: Michal Wajdeczko Cc: Dan Carpenter Reviewed-by: Daniel Vetter Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210926184545.1407-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 20c710a74498..c39abb010181 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -168,12 +168,15 @@ static int guc_action_register_ct_buffer(struct intel_guc *guc, u32 type, FIELD_PREP(HOST2GUC_REGISTER_CTB_REQUEST_MSG_2_DESC_ADDR, desc_addr), FIELD_PREP(HOST2GUC_REGISTER_CTB_REQUEST_MSG_3_BUFF_ADDR, buff_addr), }; + int ret; GEM_BUG_ON(type != GUC_CTB_TYPE_HOST2GUC && type != GUC_CTB_TYPE_GUC2HOST); GEM_BUG_ON(size % SZ_4K); /* CT registration must go over MMIO */ - return intel_guc_send_mmio(guc, request, ARRAY_SIZE(request), NULL, 0); + ret = intel_guc_send_mmio(guc, request, ARRAY_SIZE(request), NULL, 0); + + return ret > 0 ? -EPROTO : ret; } static int ct_register_buffer(struct intel_guc_ct *ct, u32 type, @@ -201,11 +204,14 @@ static int guc_action_deregister_ct_buffer(struct intel_guc *guc, u32 type) FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_HOST2GUC_DEREGISTER_CTB), FIELD_PREP(HOST2GUC_DEREGISTER_CTB_REQUEST_MSG_1_TYPE, type), }; + int ret; GEM_BUG_ON(type != GUC_CTB_TYPE_HOST2GUC && type != GUC_CTB_TYPE_GUC2HOST); /* CT deregistration must go over MMIO */ - return intel_guc_send_mmio(guc, request, ARRAY_SIZE(request), NULL, 0); + ret = intel_guc_send_mmio(guc, request, ARRAY_SIZE(request), NULL, 0); + + return ret > 0 ? -EPROTO : ret; } static int ct_deregister_buffer(struct intel_guc_ct *ct, u32 type) From 0de9765da58f933c32e630ee334752d32139caaa Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 26 Sep 2021 20:45:43 +0200 Subject: [PATCH 204/554] drm/i915/guc: Print error name on CTB (de)registration failure Instead of plain error value (%d) print more user friendly error name (%pe). Signed-off-by: Michal Wajdeczko Reviewed-by: Daniel Vetter Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210926184545.1407-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index c39abb010181..b6c2f2a11dc5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -191,8 +191,8 @@ static int ct_register_buffer(struct intel_guc_ct *ct, u32 type, err = guc_action_register_ct_buffer(ct_to_guc(ct), type, desc_addr, buff_addr, size); if (unlikely(err)) - CT_ERROR(ct, "Failed to register %s buffer (err=%d)\n", - guc_ct_buffer_type_to_str(type), err); + CT_ERROR(ct, "Failed to register %s buffer (%pe)\n", + guc_ct_buffer_type_to_str(type), ERR_PTR(err)); return err; } @@ -219,8 +219,8 @@ static int ct_deregister_buffer(struct intel_guc_ct *ct, u32 type) int err = guc_action_deregister_ct_buffer(ct_to_guc(ct), type); if (unlikely(err)) - CT_ERROR(ct, "Failed to deregister %s buffer (err=%d)\n", - guc_ct_buffer_type_to_str(type), err); + CT_ERROR(ct, "Failed to deregister %s buffer (%pe)\n", + guc_ct_buffer_type_to_str(type), ERR_PTR(err)); return err; } From 0e9deac51337139fc8f8a41c6c9a200944ee7aac Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 26 Sep 2021 20:45:44 +0200 Subject: [PATCH 205/554] drm/i915/guc: Print error name on CTB send failure Instead of plain error value (%d) print more user friendly error name (%pe). Signed-off-by: Michal Wajdeczko Reviewed-by: Daniel Vetter Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210926184545.1407-4-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index b6c2f2a11dc5..e03f86d3b0b9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -781,8 +781,8 @@ int intel_guc_ct_send(struct intel_guc_ct *ct, const u32 *action, u32 len, ret = ct_send(ct, action, len, response_buf, response_buf_size, &status); if (unlikely(ret < 0)) { - CT_ERROR(ct, "Sending action %#x failed (err=%d status=%#X)\n", - action[0], ret, status); + CT_ERROR(ct, "Sending action %#x failed (%pe) status=%#X\n", + action[0], ERR_PTR(ret), status); } else if (unlikely(ret)) { CT_DEBUG(ct, "send action %#x returned %d (%#x)\n", action[0], ret, ret); From fb2d2de3530ab6f93f88aa3b87dfb1382431ca17 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 26 Sep 2021 20:45:45 +0200 Subject: [PATCH 206/554] drm/i915/guc: Move and improve error message for missed CTB reply If we timeout waiting for a CT reply we print very simple error message. Improve that and by moving error reporting to the caller we can use CT_ERROR instead of DRM_ERROR and report just fence as error code will be reported later anyway. Signed-off-by: Michal Wajdeczko Reviewed-by: Daniel Vetter Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210926184545.1407-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index e03f86d3b0b9..0a3504bc0b61 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -528,9 +528,6 @@ static int wait_for_ct_request_update(struct ct_request *req, u32 *status) err = wait_for(done, GUC_CTB_RESPONSE_TIMEOUT_LONG_MS); #undef done - if (unlikely(err)) - DRM_ERROR("CT: fence %u err %d\n", req->fence, err); - *status = req->status; return err; } @@ -728,8 +725,11 @@ retry: err = wait_for_ct_request_update(&request, status); g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); - if (unlikely(err)) + if (unlikely(err)) { + CT_ERROR(ct, "No response for request %#x (fence %u)\n", + action[0], request.fence); goto unlink; + } if (FIELD_GET(GUC_HXG_MSG_0_TYPE, *status) != GUC_HXG_TYPE_RESPONSE_SUCCESS) { err = -EIO; From 5def925dbb60bcdd8ce6f860d80abc749dd5e1ef Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Oct 2021 10:31:33 +1000 Subject: [PATCH 207/554] drm/i915: fix regression with uncore refactoring. This was causing infinite recursion on snb/ivb. Fixes: 5716c8c6f4b6 ("drm/i915/uncore: split the fw get function into separate vfunc") Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211004003133.2279446-1-airlied@gmail.com --- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 2dac69d92c1b..f1b816ebcdf6 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -346,7 +346,7 @@ static void __gen6_gt_wait_for_thread_c0(struct intel_uncore *uncore) static void fw_domains_get_with_thread_status(struct intel_uncore *uncore, enum forcewake_domains fw_domains) { - fw_domains_get(uncore, fw_domains); + fw_domains_get_normal(uncore, fw_domains); /* WaRsForcewakeWaitTC0:snb,ivb,hsw,bdw,vlv */ __gen6_gt_wait_for_thread_c0(uncore); From 7d4fed884484d6631fba759905f0dce308ddb8a4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 1 Oct 2021 13:03:16 +0300 Subject: [PATCH 208/554] drm/i915/reg: add AUD_TCA_DP_2DOT0_CTRL registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For controlling the audio SDP split. Bspec: 63837 Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211001100316.26441-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c78337ab4f7b..c6e883bd4850 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9733,6 +9733,11 @@ enum { #define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4)) #define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4)) +#define _AUD_TCA_DP_2DOT0_CTRL 0x650bc +#define _AUD_TCB_DP_2DOT0_CTRL 0x651bc +#define AUD_DP_2DOT0_CTRL(trans) _MMIO_TRANS(trans, _AUD_TCA_DP_2DOT0_CTRL, _AUD_TCB_DP_2DOT0_CTRL) +#define AUD_ENABLE_SDP_SPLIT REG_BIT(31) + #define HSW_AUD_CHICKENBIT _MMIO(0x65f10) #define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) From 223583dd00a70ae57031c6004948ea177a4745b5 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Sep 2021 17:15:22 +0100 Subject: [PATCH 209/554] drm/v3d: decouple adding job dependencies steps from job init Prep work to enable a job to wait for more than one syncobj before start. Also get rid of old checkpatch warnings in the v3d_gem file. No functional changes. Signed-off-by: Melissa Wen Reviewed-by: Iago Toral Quiroga Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/825f5fdd540b0aa2eb57bd5ff93c0777808b108c.1633016479.git.mwen@igalia.com --- drivers/gpu/drm/v3d/v3d_gem.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index ead0be8d48a7..e60fbc28ef29 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -416,7 +416,7 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data, return -EINVAL; ret = drm_gem_dma_resv_wait(file_priv, args->handle, - true, timeout_jiffies); + true, timeout_jiffies); /* Decrement the user's timeout, in case we got interrupted * such that the ioctl will be restarted. @@ -434,12 +434,25 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data, return ret; } +static int +v3d_job_add_deps(struct drm_file *file_priv, struct v3d_job *job, + u32 in_sync, u32 point) +{ + struct dma_fence *in_fence = NULL; + int ret; + + ret = drm_syncobj_find_fence(file_priv, in_sync, point, 0, &in_fence); + if (ret == -EINVAL) + return ret; + + return drm_sched_job_add_dependency(&job->base, in_fence); +} + static int v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, struct v3d_job *job, void (*free)(struct kref *ref), u32 in_sync, enum v3d_queue queue) { - struct dma_fence *in_fence = NULL; struct v3d_file_priv *v3d_priv = file_priv->driver_priv; int ret; @@ -455,11 +468,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, if (ret) goto fail; - ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence); - if (ret == -EINVAL) - goto fail_job; - - ret = drm_sched_job_add_dependency(&job->base, in_fence); + ret = v3d_job_add_deps(file_priv, job, in_sync, 0); if (ret) goto fail_job; @@ -499,7 +508,7 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, for (i = 0; i < job->bo_count; i++) { /* XXX: Use shared fences for read-only objects. */ dma_resv_add_excl_fence(job->bo[i]->resv, - job->done_fence); + job->done_fence); } drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); @@ -903,8 +912,7 @@ v3d_gem_init(struct drm_device *dev) if (!v3d->pt) { drm_mm_takedown(&v3d->mm); dev_err(v3d->drm.dev, - "Failed to allocate page tables. " - "Please ensure you have CMA enabled.\n"); + "Failed to allocate page tables. Please ensure you have CMA enabled.\n"); return -ENOMEM; } From 07c2a41658c454c8f148c7fd6b0cbcecb78e9829 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Sep 2021 17:17:39 +0100 Subject: [PATCH 210/554] drm/v3d: alloc and init job in one shot Move job memory allocation to v3d_job_init function. This aim to facilitate error handling in job initialization, since cleanup steps are similar for all (struct v3d_job)-based types of job involved in a command submission. To generalize v3d_job_init(), this change takes into account that all job structs have the first element a struct v3d_job (bin, render, tfu, csd) or it is a v3d_job itself (clean_job) for pointer casting. v3: - explicitly init job as NULL (Iago) - fix pm failure handling on v3_job_init (Iago) Suggested-by: Iago Toral Quiroga Signed-off-by: Melissa Wen Reviewed-by: Iago Toral Quiroga Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/4d12e07bd334d2cddb51cabd359e99edde595619.1633016479.git.mwen@igalia.com --- drivers/gpu/drm/v3d/v3d_gem.c | 135 +++++++++++++--------------------- 1 file changed, 53 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index e60fbc28ef29..f932e73fb5c6 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -392,6 +392,9 @@ v3d_render_job_free(struct kref *ref) void v3d_job_cleanup(struct v3d_job *job) { + if (!job) + return; + drm_sched_job_cleanup(&job->base); v3d_job_put(job); } @@ -450,35 +453,48 @@ v3d_job_add_deps(struct drm_file *file_priv, struct v3d_job *job, static int v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, - struct v3d_job *job, void (*free)(struct kref *ref), + void **container, size_t size, void (*free)(struct kref *ref), u32 in_sync, enum v3d_queue queue) { struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct v3d_job *job; int ret; + *container = kcalloc(1, size, GFP_KERNEL); + if (!*container) { + DRM_ERROR("Cannot allocate memory for v3d job."); + return -ENOMEM; + } + + job = *container; job->v3d = v3d; job->free = free; ret = pm_runtime_get_sync(v3d->drm.dev); if (ret < 0) - return ret; + goto fail; ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], v3d_priv); if (ret) - goto fail; + goto fail_job; ret = v3d_job_add_deps(file_priv, job, in_sync, 0); if (ret) - goto fail_job; + goto fail_deps; kref_init(&job->refcount); return 0; -fail_job: + +fail_deps: drm_sched_job_cleanup(&job->base); -fail: +fail_job: pm_runtime_put_autosuspend(v3d->drm.dev); +fail: + kfree(*container); + *container = NULL; + return ret; } @@ -541,7 +557,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct drm_v3d_submit_cl *args = data; struct v3d_bin_job *bin = NULL; - struct v3d_render_job *render; + struct v3d_render_job *render = NULL; struct v3d_job *clean_job = NULL; struct v3d_job *last_job; struct ww_acquire_ctx acquire_ctx; @@ -558,35 +574,20 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - render = kcalloc(1, sizeof(*render), GFP_KERNEL); - if (!render) - return -ENOMEM; + ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), + v3d_render_job_free, args->in_sync_rcl, V3D_RENDER); + if (ret) + goto fail; render->start = args->rcl_start; render->end = args->rcl_end; INIT_LIST_HEAD(&render->unref_list); - ret = v3d_job_init(v3d, file_priv, &render->base, - v3d_render_job_free, args->in_sync_rcl, V3D_RENDER); - if (ret) { - kfree(render); - return ret; - } - if (args->bcl_start != args->bcl_end) { - bin = kcalloc(1, sizeof(*bin), GFP_KERNEL); - if (!bin) { - v3d_job_cleanup(&render->base); - return -ENOMEM; - } - - ret = v3d_job_init(v3d, file_priv, &bin->base, + ret = v3d_job_init(v3d, file_priv, (void *)&bin, sizeof(*bin), v3d_job_free, args->in_sync_bcl, V3D_BIN); - if (ret) { - v3d_job_cleanup(&render->base); - kfree(bin); - return ret; - } + if (ret) + goto fail; bin->start = args->bcl_start; bin->end = args->bcl_end; @@ -597,18 +598,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { - clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); - if (!clean_job) { - ret = -ENOMEM; + ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + v3d_job_free, 0, V3D_CACHE_CLEAN); + if (ret) goto fail; - } - - ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, V3D_CACHE_CLEAN); - if (ret) { - kfree(clean_job); - clean_job = NULL; - goto fail; - } last_job = clean_job; } else { @@ -681,11 +674,9 @@ fail_unreserve: drm_gem_unlock_reservations(last_job->bo, last_job->bo_count, &acquire_ctx); fail: - if (bin) - v3d_job_cleanup(&bin->base); - v3d_job_cleanup(&render->base); - if (clean_job) - v3d_job_cleanup(clean_job); + v3d_job_cleanup((void *)bin); + v3d_job_cleanup((void *)render); + v3d_job_cleanup(clean_job); return ret; } @@ -705,28 +696,22 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, { struct v3d_dev *v3d = to_v3d_dev(dev); struct drm_v3d_submit_tfu *args = data; - struct v3d_tfu_job *job; + struct v3d_tfu_job *job = NULL; struct ww_acquire_ctx acquire_ctx; int ret = 0; trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); - job = kcalloc(1, sizeof(*job), GFP_KERNEL); - if (!job) - return -ENOMEM; - - ret = v3d_job_init(v3d, file_priv, &job->base, + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), v3d_job_free, args->in_sync, V3D_TFU); - if (ret) { - kfree(job); - return ret; - } + if (ret) + goto fail; job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), sizeof(*job->base.bo), GFP_KERNEL); if (!job->base.bo) { - v3d_job_cleanup(&job->base); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } job->args = *args; @@ -773,7 +758,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, return 0; fail: - v3d_job_cleanup(&job->base); + v3d_job_cleanup((void *)job); return ret; } @@ -794,8 +779,8 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct drm_v3d_submit_csd *args = data; - struct v3d_csd_job *job; - struct v3d_job *clean_job; + struct v3d_csd_job *job = NULL; + struct v3d_job *clean_job = NULL; struct ww_acquire_ctx acquire_ctx; int ret; @@ -806,29 +791,15 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - job = kcalloc(1, sizeof(*job), GFP_KERNEL); - if (!job) - return -ENOMEM; - - ret = v3d_job_init(v3d, file_priv, &job->base, + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), v3d_job_free, args->in_sync, V3D_CSD); - if (ret) { - kfree(job); - return ret; - } + if (ret) + goto fail; - clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); - if (!clean_job) { - v3d_job_cleanup(&job->base); - return -ENOMEM; - } - - ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, V3D_CACHE_CLEAN); - if (ret) { - v3d_job_cleanup(&job->base); - kfree(clean_job); - return ret; - } + ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), + v3d_job_free, 0, V3D_CACHE_CLEAN); + if (ret) + goto fail; job->args = *args; @@ -877,7 +848,7 @@ fail_unreserve: drm_gem_unlock_reservations(clean_job->bo, clean_job->bo_count, &acquire_ctx); fail: - v3d_job_cleanup(&job->base); + v3d_job_cleanup((void *)job); v3d_job_cleanup(clean_job); return ret; From bb3425efdcd99f2b4e608e850226f7107b2f993e Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Sep 2021 17:18:50 +0100 Subject: [PATCH 211/554] drm/v3d: add generic ioctl extension Add support to attach generic extensions on job submission. This patch is third prep work to enable multiple syncobjs on job submission. With this work, when the job submission interface needs to be extended to accommodate a new feature, we will use a generic extension struct where an id determines the data type to be pointed. The first application is to enable multiples in/out syncobj (next patch), but the base is already done for future features. Therefore, to attach a new feature, a specific extension struct should subclass drm_v3d_extension and update the list of extensions in a job submission. v2: - remove redundant elements to subclass struct (Daniel) v3: - add comment for v3d_get_extensions Signed-off-by: Melissa Wen Reviewed-by: Iago Toral Quiroga Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/ed53b1cd7e3125b76f18fe3fb995a04393639bc6.1633016479.git.mwen@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.c | 4 +- drivers/gpu/drm/v3d/v3d_gem.c | 74 +++++++++++++++++++++++++++++++++-- include/uapi/drm/v3d_drm.h | 31 +++++++++++++++ 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index c1deab2cf38d..3d6b9bcce2f7 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -83,7 +83,6 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, return 0; } - switch (args->param) { case DRM_V3D_PARAM_SUPPORTS_TFU: args->value = 1; @@ -147,7 +146,7 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) DEFINE_DRM_GEM_FOPS(v3d_drm_fops); /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP - * protection between clients. Note that render nodes would be be + * protection between clients. Note that render nodes would be * able to submit CLs that could access BOs from clients authenticated * with the master node. The TFU doesn't use the GMP, so it would * need to stay DRM_AUTH until we do buffer size/offset validation. @@ -219,7 +218,6 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) u32 mmu_debug; u32 ident1; - v3d = devm_drm_dev_alloc(dev, &v3d_drm_driver, struct v3d_dev, drm); if (IS_ERR(v3d)) return PTR_ERR(v3d); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index f932e73fb5c6..93f130fb3a13 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -537,6 +537,36 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, } } +/* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data + * according to the extension id (name). + */ +static int +v3d_get_extensions(struct drm_file *file_priv, u64 ext_handles) +{ + struct drm_v3d_extension __user *user_ext; + + user_ext = u64_to_user_ptr(ext_handles); + while (user_ext) { + struct drm_v3d_extension ext; + + if (copy_from_user(&ext, user_ext, sizeof(ext))) { + DRM_DEBUG("Failed to copy submit extension\n"); + return -EFAULT; + } + + switch (ext.id) { + case 0: + default: + DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); + return -EINVAL; + } + + user_ext = u64_to_user_ptr(ext.next); + } + + return 0; +} + /** * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D. * @dev: DRM device @@ -565,15 +595,24 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); - if (args->pad != 0) + if (args->pad) return -EINVAL; - if (args->flags != 0 && - args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { + if (args->flags && + args->flags & ~(DRM_V3D_SUBMIT_CL_FLUSH_CACHE | + DRM_V3D_SUBMIT_EXTENSION)) { DRM_INFO("invalid flags: %d\n", args->flags); return -EINVAL; } + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), v3d_render_job_free, args->in_sync_rcl, V3D_RENDER); if (ret) @@ -702,6 +741,19 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_DEBUG("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), v3d_job_free, args->in_sync, V3D_TFU); if (ret) @@ -786,11 +838,27 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]); + if (args->pad) + return -EINVAL; + if (!v3d_has_csd(v3d)) { DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n"); return -EINVAL; } + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_INFO("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + return ret; + } + } + ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), v3d_job_free, args->in_sync, V3D_CSD); if (ret) diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 4104f22fb3d3..55b443ca6c0b 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -58,6 +58,20 @@ extern "C" { struct drm_v3d_perfmon_get_values) #define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 +#define DRM_V3D_SUBMIT_EXTENSION 0x02 + +/* struct drm_v3d_extension - ioctl extensions + * + * Linked-list of generic extensions where the id identify which struct is + * pointed by ext_data. Therefore, DRM_V3D_EXT_ID_* is used on id to identify + * the extension type. + */ +struct drm_v3d_extension { + __u64 next; + __u32 id; +#define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 + __u32 flags; /* mbz */ +}; /** * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D @@ -135,12 +149,16 @@ struct drm_v3d_submit_cl { /* Number of BO handles passed in (size is that times 4). */ __u32 bo_handle_count; + /* DRM_V3D_SUBMIT_* properties */ __u32 flags; /* ID of the perfmon to attach to this job. 0 means no perfmon. */ __u32 perfmon_id; __u32 pad; + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; }; /** @@ -248,6 +266,12 @@ struct drm_v3d_submit_tfu { __u32 in_sync; /* Sync object to signal when the TFU job is done. */ __u32 out_sync; + + __u32 flags; + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; + }; /* Submits a compute shader for dispatch. This job will block on any @@ -276,6 +300,13 @@ struct drm_v3d_submit_csd { /* ID of the perfmon to attach to this job. 0 means no perfmon. */ __u32 perfmon_id; + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; + + __u32 flags; + + __u32 pad; }; enum { From e4165ae8304e5ea822fbe5909dd3be5445c058b7 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 30 Sep 2021 17:19:56 +0100 Subject: [PATCH 212/554] drm/v3d: add multiple syncobjs support Using the generic extension from the previous patch, a specific multisync extension enables more than one in/out binary syncobj per job submission. Arrays of syncobjs are set in struct drm_v3d_multisync, that also cares of determining the stage for sync (wait deps) according to the job queue. v2: - subclass the generic extension struct (Daniel) - simplify adding dependency conditions to make understandable (Iago) v3: - fix conditions to consider single or multiples in/out_syncs (Iago) - remove irrelevant comment (Iago) Signed-off-by: Melissa Wen Reviewed-by: Iago Toral Quiroga Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/ffd8b2e3dd2e0c686db441a0c0a4a0181ff85328.1633016479.git.mwen@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.c | 6 +- drivers/gpu/drm/v3d/v3d_drv.h | 24 +++-- drivers/gpu/drm/v3d/v3d_gem.c | 185 ++++++++++++++++++++++++++++++---- include/uapi/drm/v3d_drm.h | 49 ++++++++- 4 files changed, 232 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 3d6b9bcce2f7..bd46396a1ae0 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -96,6 +96,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, case DRM_V3D_PARAM_SUPPORTS_PERFMON: args->value = (v3d->ver >= 40); return 0; + case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: + args->value = 1; + return 0; default: DRM_DEBUG("Unknown parameter %d\n", args->param); return -EINVAL; @@ -135,9 +138,8 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) struct v3d_file_priv *v3d_priv = file->driver_priv; enum v3d_queue q; - for (q = 0; q < V3D_MAX_QUEUES; q++) { + for (q = 0; q < V3D_MAX_QUEUES; q++) drm_sched_entity_destroy(&v3d_priv->sched_entity[q]); - } v3d_perfmon_close_file(v3d_priv); kfree(v3d_priv); diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index b900a050d5e2..b74b1351bfc8 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -19,15 +19,6 @@ struct reset_control; #define GMP_GRANULARITY (128 * 1024) -/* Enum for each of the V3D queues. */ -enum v3d_queue { - V3D_BIN, - V3D_RENDER, - V3D_TFU, - V3D_CSD, - V3D_CACHE_CLEAN, -}; - #define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) struct v3d_queue_state { @@ -294,6 +285,21 @@ struct v3d_csd_job { struct drm_v3d_submit_csd args; }; +struct v3d_submit_outsync { + struct drm_syncobj *syncobj; +}; + +struct v3d_submit_ext { + u32 flags; + u32 wait_stage; + + u32 in_sync_count; + u64 in_syncs; + + u32 out_sync_count; + struct v3d_submit_outsync *out_syncs; +}; + /** * __wait_for - magic wait macro * diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 93f130fb3a13..6a000d77c568 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -454,11 +454,12 @@ v3d_job_add_deps(struct drm_file *file_priv, struct v3d_job *job, static int v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, void **container, size_t size, void (*free)(struct kref *ref), - u32 in_sync, enum v3d_queue queue) + u32 in_sync, struct v3d_submit_ext *se, enum v3d_queue queue) { struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct v3d_job *job; - int ret; + bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); + int ret, i; *container = kcalloc(1, size, GFP_KERNEL); if (!*container) { @@ -479,9 +480,28 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, if (ret) goto fail_job; - ret = v3d_job_add_deps(file_priv, job, in_sync, 0); - if (ret) - goto fail_deps; + if (has_multisync) { + if (se->in_sync_count && se->wait_stage == queue) { + struct drm_v3d_sem __user *handle = u64_to_user_ptr(se->in_syncs); + + for (i = 0; i < se->in_sync_count; i++) { + struct drm_v3d_sem in; + + ret = copy_from_user(&in, handle++, sizeof(in)); + if (ret) { + DRM_DEBUG("Failed to copy wait dep handle.\n"); + goto fail_deps; + } + ret = v3d_job_add_deps(file_priv, job, in.handle, 0); + if (ret) + goto fail_deps; + } + } + } else { + ret = v3d_job_add_deps(file_priv, job, in_sync, 0); + if (ret) + goto fail_deps; + } kref_init(&job->refcount); @@ -516,9 +536,11 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, struct v3d_job *job, struct ww_acquire_ctx *acquire_ctx, u32 out_sync, + struct v3d_submit_ext *se, struct dma_fence *done_fence) { struct drm_syncobj *sync_out; + bool has_multisync = se && (se->flags & DRM_V3D_EXT_ID_MULTI_SYNC); int i; for (i = 0; i < job->bo_count; i++) { @@ -530,20 +552,130 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); /* Update the return sync object for the job */ - sync_out = drm_syncobj_find(file_priv, out_sync); - if (sync_out) { - drm_syncobj_replace_fence(sync_out, done_fence); - drm_syncobj_put(sync_out); + /* If it only supports a single signal semaphore*/ + if (!has_multisync) { + sync_out = drm_syncobj_find(file_priv, out_sync); + if (sync_out) { + drm_syncobj_replace_fence(sync_out, done_fence); + drm_syncobj_put(sync_out); + } + return; } + + /* If multiple semaphores extension is supported */ + if (se->out_sync_count) { + for (i = 0; i < se->out_sync_count; i++) { + drm_syncobj_replace_fence(se->out_syncs[i].syncobj, + done_fence); + drm_syncobj_put(se->out_syncs[i].syncobj); + } + kvfree(se->out_syncs); + } +} + +static void +v3d_put_multisync_post_deps(struct v3d_submit_ext *se) +{ + unsigned int i; + + if (!(se && se->out_sync_count)) + return; + + for (i = 0; i < se->out_sync_count; i++) + drm_syncobj_put(se->out_syncs[i].syncobj); + kvfree(se->out_syncs); +} + +static int +v3d_get_multisync_post_deps(struct drm_file *file_priv, + struct v3d_submit_ext *se, + u32 count, u64 handles) +{ + struct drm_v3d_sem __user *post_deps; + int i, ret; + + if (!count) + return 0; + + se->out_syncs = (struct v3d_submit_outsync *) + kvmalloc_array(count, + sizeof(struct v3d_submit_outsync), + GFP_KERNEL); + if (!se->out_syncs) + return -ENOMEM; + + post_deps = u64_to_user_ptr(handles); + + for (i = 0; i < count; i++) { + struct drm_v3d_sem out; + + ret = copy_from_user(&out, post_deps++, sizeof(out)); + if (ret) { + DRM_DEBUG("Failed to copy post dep handles\n"); + goto fail; + } + + se->out_syncs[i].syncobj = drm_syncobj_find(file_priv, + out.handle); + if (!se->out_syncs[i].syncobj) { + ret = -EINVAL; + goto fail; + } + } + se->out_sync_count = count; + + return 0; + +fail: + for (i--; i >= 0; i--) + drm_syncobj_put(se->out_syncs[i].syncobj); + kvfree(se->out_syncs); + + return ret; +} + +/* Get data for multiple binary semaphores synchronization. Parse syncobj + * to be signaled when job completes (out_sync). + */ +static int +v3d_get_multisync_submit_deps(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + void *data) +{ + struct drm_v3d_multi_sync multisync; + struct v3d_submit_ext *se = data; + int ret; + + ret = copy_from_user(&multisync, ext, sizeof(multisync)); + if (ret) + return ret; + + if (multisync.pad) + return -EINVAL; + + ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, + multisync.out_syncs); + if (ret) + return ret; + + se->in_sync_count = multisync.in_sync_count; + se->in_syncs = multisync.in_syncs; + se->flags |= DRM_V3D_EXT_ID_MULTI_SYNC; + se->wait_stage = multisync.wait_stage; + + return 0; } /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ static int -v3d_get_extensions(struct drm_file *file_priv, u64 ext_handles) +v3d_get_extensions(struct drm_file *file_priv, + u64 ext_handles, + void *data) { struct drm_v3d_extension __user *user_ext; + int ret; user_ext = u64_to_user_ptr(ext_handles); while (user_ext) { @@ -555,7 +687,11 @@ v3d_get_extensions(struct drm_file *file_priv, u64 ext_handles) } switch (ext.id) { - case 0: + case DRM_V3D_EXT_ID_MULTI_SYNC: + ret = v3d_get_multisync_submit_deps(file_priv, user_ext, data); + if (ret) + return ret; + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -586,6 +722,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct drm_v3d_submit_cl *args = data; + struct v3d_submit_ext se = {0}; struct v3d_bin_job *bin = NULL; struct v3d_render_job *render = NULL; struct v3d_job *clean_job = NULL; @@ -606,7 +743,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions); + ret = v3d_get_extensions(file_priv, args->extensions, &se); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -614,7 +751,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } ret = v3d_job_init(v3d, file_priv, (void *)&render, sizeof(*render), - v3d_render_job_free, args->in_sync_rcl, V3D_RENDER); + v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER); if (ret) goto fail; @@ -624,7 +761,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, if (args->bcl_start != args->bcl_end) { ret = v3d_job_init(v3d, file_priv, (void *)&bin, sizeof(*bin), - v3d_job_free, args->in_sync_bcl, V3D_BIN); + v3d_job_free, args->in_sync_bcl, &se, V3D_BIN); if (ret) goto fail; @@ -638,7 +775,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), - v3d_job_free, 0, V3D_CACHE_CLEAN); + v3d_job_free, 0, 0, V3D_CACHE_CLEAN); if (ret) goto fail; @@ -698,6 +835,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, last_job, &acquire_ctx, args->out_sync, + &se, last_job->done_fence); if (bin) @@ -716,6 +854,7 @@ fail: v3d_job_cleanup((void *)bin); v3d_job_cleanup((void *)render); v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); return ret; } @@ -735,6 +874,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, { struct v3d_dev *v3d = to_v3d_dev(dev); struct drm_v3d_submit_tfu *args = data; + struct v3d_submit_ext se = {0}; struct v3d_tfu_job *job = NULL; struct ww_acquire_ctx acquire_ctx; int ret = 0; @@ -747,7 +887,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions); + ret = v3d_get_extensions(file_priv, args->extensions, &se); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -755,7 +895,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, } ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), - v3d_job_free, args->in_sync, V3D_TFU); + v3d_job_free, args->in_sync, &se, V3D_TFU); if (ret) goto fail; @@ -803,6 +943,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, v3d_attach_fences_and_unlock_reservation(file_priv, &job->base, &acquire_ctx, args->out_sync, + &se, job->base.done_fence); v3d_job_put(&job->base); @@ -811,6 +952,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, fail: v3d_job_cleanup((void *)job); + v3d_put_multisync_post_deps(&se); return ret; } @@ -831,6 +973,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct drm_v3d_submit_csd *args = data; + struct v3d_submit_ext se = {0}; struct v3d_csd_job *job = NULL; struct v3d_job *clean_job = NULL; struct ww_acquire_ctx acquire_ctx; @@ -852,7 +995,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, } if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { - ret = v3d_get_extensions(file_priv, args->extensions); + ret = v3d_get_extensions(file_priv, args->extensions, &se); if (ret) { DRM_DEBUG("Failed to get extensions.\n"); return ret; @@ -860,12 +1003,12 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, } ret = v3d_job_init(v3d, file_priv, (void *)&job, sizeof(*job), - v3d_job_free, args->in_sync, V3D_CSD); + v3d_job_free, args->in_sync, &se, V3D_CSD); if (ret) goto fail; ret = v3d_job_init(v3d, file_priv, (void *)&clean_job, sizeof(*clean_job), - v3d_job_free, 0, V3D_CACHE_CLEAN); + v3d_job_free, 0, 0, V3D_CACHE_CLEAN); if (ret) goto fail; @@ -904,6 +1047,7 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, clean_job, &acquire_ctx, args->out_sync, + &se, clean_job->done_fence); v3d_job_put(&job->base); @@ -918,6 +1062,7 @@ fail_unreserve: fail: v3d_job_cleanup((void *)job); v3d_job_cleanup(clean_job); + v3d_put_multisync_post_deps(&se); return ret; } diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 55b443ca6c0b..3dfc0af8756a 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -73,6 +73,53 @@ struct drm_v3d_extension { __u32 flags; /* mbz */ }; +/* struct drm_v3d_sem - wait/signal semaphore + * + * If binary semaphore, it only takes syncobj handle and ignores flags and + * point fields. Point is defined for timeline syncobj feature. + */ +struct drm_v3d_sem { + __u32 handle; /* syncobj */ + /* rsv below, for future uses */ + __u32 flags; + __u64 point; /* for timeline sem support */ + __u64 mbz[2]; /* must be zero, rsv */ +}; + +/* Enum for each of the V3D queues. */ +enum v3d_queue { + V3D_BIN, + V3D_RENDER, + V3D_TFU, + V3D_CSD, + V3D_CACHE_CLEAN, +}; + +/** + * struct drm_v3d_multi_sync - ioctl extension to add support multiples + * syncobjs for commands submission. + * + * When an extension of DRM_V3D_EXT_ID_MULTI_SYNC id is defined, it points to + * this extension to define wait and signal dependencies, instead of single + * in/out sync entries on submitting commands. The field flags is used to + * determine the stage to set wait dependencies. + */ +struct drm_v3d_multi_sync { + struct drm_v3d_extension base; + /* Array of wait and signal semaphores */ + __u64 in_syncs; + __u64 out_syncs; + + /* Number of entries */ + __u32 in_sync_count; + __u32 out_sync_count; + + /* set the stage (v3d_queue) to sync */ + __u32 wait_stage; + + __u32 pad; /* mbz */ +}; + /** * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D * engine. @@ -228,6 +275,7 @@ enum drm_v3d_param { DRM_V3D_PARAM_SUPPORTS_CSD, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, DRM_V3D_PARAM_SUPPORTS_PERFMON, + DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT, }; struct drm_v3d_get_param { @@ -271,7 +319,6 @@ struct drm_v3d_submit_tfu { /* Pointer to an array of ioctl extensions*/ __u64 extensions; - }; /* Submits a compute shader for dispatch. This job will block on any From f6e3be98654ed1895b105ed0ddf67665ed83dda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 19:08:26 +0300 Subject: [PATCH 213/554] drm/i915: Fix DP clock recovery "voltage_tries" handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP spec says: "If the receiver keeps the same value in the ADJUST_REQUEST_LANEx_y register(s) while the LANEx_CR_DONE bits remain unset, the transmitter must loop four times with the same voltage swing. On the fifth time, the transmitter must down-shift to the lower bit rate and must repeat the CR-lock training sequence as described below." Lets fix the code to follow that instead of terminating after five times of transmitting the same signal levels. The text in spec feels a little bit ambiguous still, but this is my best guess at its meaning. As a bonus this also gets rid of the train_set[0] stuff which would not work for per-lane drive settings anyway. Cc: Imre Deak CC: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001160826.17080-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- .../drm/i915/display/intel_dp_link_training.c | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 053ed9302cda..73a823f1ec22 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -511,6 +511,25 @@ static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_d drm_dp_lttpr_link_train_clock_recovery_delay(); } +static bool intel_dp_adjust_request_changed(int lane_count, + const u8 old_link_status[DP_LINK_STATUS_SIZE], + const u8 new_link_status[DP_LINK_STATUS_SIZE]) +{ + int lane; + + for (lane = 0; lane < lane_count; lane++) { + u8 old = drm_dp_get_adjust_request_voltage(old_link_status, lane) | + drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane); + u8 new = drm_dp_get_adjust_request_voltage(new_link_status, lane) | + drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane); + + if (old != new) + return true; + } + + return false; +} + /* * Perform the link training clock recovery phase on the given DP PHY using * training pattern 1. @@ -521,7 +540,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); - u8 voltage; + u8 old_link_status[DP_LINK_STATUS_SIZE] = {}; int voltage_tries, cr_tries, max_cr_tries; bool max_vswing_reached = false; @@ -574,8 +593,6 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, return false; } - voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - /* Update training set as requested by target */ intel_dp_get_adjust_train(intel_dp, crtc_state, dp_phy, link_status); @@ -585,12 +602,14 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, return false; } - if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == - voltage) + if (!intel_dp_adjust_request_changed(crtc_state->lane_count, + old_link_status, link_status)) ++voltage_tries; else voltage_tries = 1; + memcpy(old_link_status, link_status, sizeof(link_status)); + if (intel_dp_link_max_vswing_reached(intel_dp, crtc_state)) max_vswing_reached = true; From f820693bc2381d73d2769d8b7cc16210f21244a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:00:58 +0300 Subject: [PATCH 214/554] drm/i915: Introduce has_iboost() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suck the "do we have iboost?" platform checks into a small helper. Cc: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-2-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 51cd0420e00e..f6429114ce7c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -92,6 +92,11 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder, return level; } +static bool has_iboost(struct drm_i915_private *i915) +{ + return DISPLAY_VER(i915) == 9 && !IS_BROXTON(i915); +} + /* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. This function programs the correct values for @@ -111,7 +116,7 @@ void hsw_prepare_dp_ddi_buffers(struct intel_encoder *encoder, return; /* If we're boosting the current, set bit 31 of trans1 */ - if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv) && + if (has_iboost(dev_priv) && intel_bios_encoder_dp_boost_level(encoder->devdata)) iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE; @@ -145,7 +150,7 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, level = n_entries - 1; /* If we're boosting the current, set bit 31 of trans1 */ - if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv) && + if (has_iboost(dev_priv) && intel_bios_encoder_hdmi_boost_level(encoder->devdata)) iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE; @@ -1463,7 +1468,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp, intel_dp->DP &= ~DDI_BUF_EMP_MASK; intel_dp->DP |= signal_levels; - if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) + if (has_iboost(dev_priv)) skl_ddi_set_iboost(encoder, crtc_state, level); intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP); @@ -3084,7 +3089,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, else hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state, level); - if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) + if (has_iboost(dev_priv)) skl_ddi_set_iboost(encoder, crtc_state, level); /* Display WA #1143: skl,kbl,cfl */ From 5bafd85dd77080730ca7115ba6b5c4ef88493b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:00:59 +0300 Subject: [PATCH 215/554] drm/i915: Introduce has_buf_trans_select() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a small helper to determine if DDI_BUF_CTL uses the DDI_BUF_TRANS_SELECT field, and whether we have the accompanying DDI_BUF_TRANS table in the hardware. Cc: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f6429114ce7c..dbcf4ddd0f3b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -92,6 +92,11 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder, return level; } +static bool has_buf_trans_select(struct drm_i915_private *i915) +{ + return DISPLAY_VER(i915) < 10 && !IS_BROXTON(i915); +} + static bool has_iboost(struct drm_i915_private *i915) { return DISPLAY_VER(i915) == 9 && !IS_BROXTON(i915); @@ -2640,7 +2645,8 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, icl_ddi_vswing_sequence(encoder, crtc_state, level); else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_ddi_vswing_sequence(encoder, crtc_state, level); - else + + if (has_buf_trans_select(dev_priv)) hsw_prepare_dp_ddi_buffers(encoder, crtc_state); intel_ddi_power_up_lanes(encoder, crtc_state); @@ -3086,7 +3092,8 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, icl_ddi_vswing_sequence(encoder, crtc_state, level); else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_ddi_vswing_sequence(encoder, crtc_state, level); - else + + if (has_buf_trans_select(dev_priv)) hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state, level); if (has_iboost(dev_priv)) From e722ab8b69689cff49f50fcc7c55065615180f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:00 +0300 Subject: [PATCH 216/554] drm/i915: Generalize .set_signal_levels() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently .set_signal_levels() is only used by encoders in DP mode. For most modern platforms there is no essential difference between DP and HDMI, and both codepaths just end up calling the same function under the hood. Let's get remove the need for that extra indirection by moving .set_signal_levels() into the encoder from intel_dp. Since we already plumb the crtc_state/etc. into .set_signal_levels() the code will do the right thing for both DP and HDMI. HSW/BDW/SKL are the only platforms that need a bit of care on account of having to preload the hardware buf_trans register with the full set of values. So we must still remember to call hsw_prepare_{dp,hdmi}_ddi_buffers() to do said preloading, and .set_signal_levels() will just end up selecting the correct entry for DP, and also setting up the iboost magic for both DP and HDMI. Note that previously on HSW/BDW/SKL we did write to DDI_BUF_CTL to select the correct entry until link training started, now that we call .set_signal_levels() already from hsw_ddi_pre_enable_dp() that is no longer the case. But it's all safe now that the intel_ddi_init_dp_buf_reg() call was hoisted up and it no longer sets up the DDI_BUF_CTL_ENABLE bit (that is still deferred until link training). v2: Rebase due to has_{iboost,buf_trans_select}() Add some notes about the DDI_BUF_CTL situation on HSW/BDW/SKL (Imre) Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/g4x_dp.c | 33 +++--- drivers/gpu/drm/i915/display/intel_ddi.c | 104 ++++++++---------- .../drm/i915/display/intel_display_types.h | 5 +- .../drm/i915/display/intel_dp_link_training.c | 5 +- 4 files changed, 71 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 69a2e5ad2317..60ae2ba52006 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -808,10 +808,10 @@ static u8 intel_dp_preemph_max_3(struct intel_dp *intel_dp) return DP_TRAIN_PRE_EMPH_LEVEL_3; } -static void vlv_set_signal_levels(struct intel_dp *intel_dp, +static void vlv_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); unsigned long demph_reg_value, preemph_reg_value, uniqtranscale_reg_value; u8 train_set = intel_dp->train_set[0]; @@ -894,10 +894,10 @@ static void vlv_set_signal_levels(struct intel_dp *intel_dp, uniqtranscale_reg_value, 0); } -static void chv_set_signal_levels(struct intel_dp *intel_dp, +static void chv_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u32 deemph_reg_value, margin_reg_value; bool uniq_trans_scale = false; u8 train_set = intel_dp->train_set[0]; @@ -1015,10 +1015,11 @@ static u32 g4x_signal_levels(u8 train_set) } static void -g4x_set_signal_levels(struct intel_dp *intel_dp, +g4x_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u8 train_set = intel_dp->train_set[0]; u32 signal_levels; @@ -1062,10 +1063,11 @@ static u32 snb_cpu_edp_signal_levels(u8 train_set) } static void -snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp, +snb_cpu_edp_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u8 train_set = intel_dp->train_set[0]; u32 signal_levels; @@ -1113,10 +1115,11 @@ static u32 ivb_cpu_edp_signal_levels(u8 train_set) } static void -ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp, +ivb_cpu_edp_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u8 train_set = intel_dp->train_set[0]; u32 signal_levels; @@ -1359,15 +1362,15 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv, dig_port->dp.set_link_train = g4x_set_link_train; if (IS_CHERRYVIEW(dev_priv)) - dig_port->dp.set_signal_levels = chv_set_signal_levels; + intel_encoder->set_signal_levels = chv_set_signal_levels; else if (IS_VALLEYVIEW(dev_priv)) - dig_port->dp.set_signal_levels = vlv_set_signal_levels; + intel_encoder->set_signal_levels = vlv_set_signal_levels; else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) - dig_port->dp.set_signal_levels = ivb_cpu_edp_set_signal_levels; + intel_encoder->set_signal_levels = ivb_cpu_edp_set_signal_levels; else if (IS_SANDYBRIDGE(dev_priv) && port == PORT_A) - dig_port->dp.set_signal_levels = snb_cpu_edp_set_signal_levels; + intel_encoder->set_signal_levels = snb_cpu_edp_set_signal_levels; else - dig_port->dp.set_signal_levels = g4x_set_signal_levels; + intel_encoder->set_signal_levels = g4x_set_signal_levels; if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) || (HAS_PCH_SPLIT(dev_priv) && port != PORT_A)) { diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index dbcf4ddd0f3b..ad7fe84b6d75 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -139,10 +139,10 @@ void hsw_prepare_dp_ddi_buffers(struct intel_encoder *encoder, * HDMI/DVI use cases. */ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + int level = intel_ddi_hdmi_level(encoder, crtc_state); u32 iboost_bit = 0; int n_entries; enum port port = encoder->port; @@ -1405,8 +1405,7 @@ static int translate_signal_level(struct intel_dp *intel_dp, return 0; } -static int intel_ddi_dp_level(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +static int intel_ddi_dp_level(struct intel_dp *intel_dp) { u8 train_set = intel_dp->train_set[0]; u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | @@ -1415,56 +1414,68 @@ static int intel_ddi_dp_level(struct intel_dp *intel_dp, return translate_signal_level(intel_dp, signal_levels); } +static int intel_ddi_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return intel_ddi_hdmi_level(encoder, crtc_state); + else + return intel_ddi_dp_level(enc_to_intel_dp(encoder)); +} + static void -dg2_set_signal_levels(struct intel_dp *intel_dp, +dg2_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - int level = intel_ddi_dp_level(intel_dp, crtc_state); + int level = intel_ddi_level(encoder, crtc_state); intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level); } static void -tgl_set_signal_levels(struct intel_dp *intel_dp, +tgl_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - int level = intel_ddi_dp_level(intel_dp, crtc_state); + int level = intel_ddi_level(encoder, crtc_state); tgl_ddi_vswing_sequence(encoder, crtc_state, level); } static void -icl_set_signal_levels(struct intel_dp *intel_dp, +icl_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - int level = intel_ddi_dp_level(intel_dp, crtc_state); + int level = intel_ddi_level(encoder, crtc_state); icl_ddi_vswing_sequence(encoder, crtc_state, level); } static void -bxt_set_signal_levels(struct intel_dp *intel_dp, +bxt_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - int level = intel_ddi_dp_level(intel_dp, crtc_state); + int level = intel_ddi_level(encoder, crtc_state); bxt_ddi_vswing_sequence(encoder, crtc_state, level); } static void -hsw_set_signal_levels(struct intel_dp *intel_dp, +hsw_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_dp_level(intel_dp, crtc_state); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int level = intel_ddi_level(encoder, crtc_state); enum port port = encoder->port; u32 signal_levels; + if (has_iboost(dev_priv)) + skl_ddi_set_iboost(encoder, crtc_state, level); + + /* HDMI ignores the rest */ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return; + signal_levels = DDI_BUF_TRANS_SELECT(level); drm_dbg_kms(&dev_priv->drm, "Using signal levels %08x\n", @@ -1473,9 +1484,6 @@ hsw_set_signal_levels(struct intel_dp *intel_dp, intel_dp->DP &= ~DDI_BUF_EMP_MASK; intel_dp->DP |= signal_levels; - if (has_iboost(dev_priv)) - skl_ddi_set_iboost(encoder, crtc_state, level); - intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP); intel_de_posting_read(dev_priv, DDI_BUF_CTL(port)); } @@ -2366,7 +2374,6 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); - int level = intel_ddi_dp_level(intel_dp, crtc_state); intel_dp_set_link_params(intel_dp, crtc_state->port_clock, crtc_state->lane_count); @@ -2431,7 +2438,7 @@ static void dg2_ddi_pre_enable_dp(struct intel_atomic_state *state, */ /* 5.e Configure voltage swing and related IO settings */ - intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level); + encoder->set_signal_levels(encoder, crtc_state); if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); @@ -2474,7 +2481,6 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); - int level = intel_ddi_dp_level(intel_dp, crtc_state); intel_dp_set_link_params(intel_dp, crtc_state->port_clock, @@ -2554,7 +2560,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, */ /* 7.e Configure voltage swing and related IO settings */ - tgl_ddi_vswing_sequence(encoder, crtc_state, level); + encoder->set_signal_levels(encoder, crtc_state); /* * 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up @@ -2611,7 +2617,6 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, enum port port = encoder->port; struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); - int level = intel_ddi_dp_level(intel_dp, crtc_state); if (DISPLAY_VER(dev_priv) < 11) drm_WARN_ON(&dev_priv->drm, @@ -2641,14 +2646,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, icl_program_mg_dp_mode(dig_port, crtc_state); - if (DISPLAY_VER(dev_priv) >= 11) - icl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - bxt_ddi_vswing_sequence(encoder, crtc_state, level); - if (has_buf_trans_select(dev_priv)) hsw_prepare_dp_ddi_buffers(encoder, crtc_state); + encoder->set_signal_levels(encoder, crtc_state); + intel_ddi_power_up_lanes(encoder, crtc_state); if (!is_mst) @@ -3074,7 +3076,6 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct drm_connector *connector = conn_state->connector; - int level = intel_ddi_hdmi_level(encoder, crtc_state); enum port port = encoder->port; if (!intel_hdmi_handle_sink_scrambling(encoder, connector, @@ -3084,20 +3085,10 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, "[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n", connector->base.id, connector->name); - if (IS_DG2(dev_priv)) - intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level); - else if (DISPLAY_VER(dev_priv) >= 12) - tgl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (DISPLAY_VER(dev_priv) == 11) - icl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - bxt_ddi_vswing_sequence(encoder, crtc_state, level); - if (has_buf_trans_select(dev_priv)) - hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state, level); + hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state); - if (has_iboost(dev_priv)) - skl_ddi_set_iboost(encoder, crtc_state, level); + encoder->set_signal_levels(encoder, crtc_state); /* Display WA #1143: skl,kbl,cfl */ if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) { @@ -4057,7 +4048,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = { static struct intel_connector * intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) { - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); struct intel_connector *connector; enum port port = dig_port->base.port; @@ -4070,17 +4060,6 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) dig_port->dp.set_link_train = intel_ddi_set_link_train; dig_port->dp.set_idle_link_train = intel_ddi_set_idle_link_train; - if (IS_DG2(dev_priv)) - dig_port->dp.set_signal_levels = dg2_set_signal_levels; - else if (DISPLAY_VER(dev_priv) >= 12) - dig_port->dp.set_signal_levels = tgl_set_signal_levels; - else if (DISPLAY_VER(dev_priv) >= 11) - dig_port->dp.set_signal_levels = icl_set_signal_levels; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - dig_port->dp.set_signal_levels = bxt_set_signal_levels; - else - dig_port->dp.set_signal_levels = hsw_set_signal_levels; - dig_port->dp.voltage_max = intel_ddi_dp_voltage_max; dig_port->dp.preemph_max = intel_ddi_dp_preemph_max; @@ -4652,6 +4631,17 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->get_config = hsw_ddi_get_config; } + if (IS_DG2(dev_priv)) + encoder->set_signal_levels = dg2_set_signal_levels; + else if (DISPLAY_VER(dev_priv) >= 12) + encoder->set_signal_levels = tgl_set_signal_levels; + else if (DISPLAY_VER(dev_priv) >= 11) + encoder->set_signal_levels = icl_set_signal_levels; + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + encoder->set_signal_levels = bxt_set_signal_levels; + else + encoder->set_signal_levels = hsw_set_signal_levels; + intel_ddi_buf_trans_init(encoder); if (DISPLAY_VER(dev_priv) >= 13) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 632391197937..a811e13720bf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -269,6 +269,9 @@ struct intel_encoder { const struct intel_ddi_buf_trans *(*get_buf_trans)(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, int *n_entries); + void (*set_signal_levels)(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); + enum hpd_pin hpd_pin; enum intel_display_power_domain power_domain; /* for communication with audio component; protected by av_mutex */ @@ -1601,8 +1604,6 @@ struct intel_dp { u8 dp_train_pat); void (*set_idle_link_train)(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); - void (*set_signal_levels)(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); u8 (*preemph_max)(struct intel_dp *intel_dp); u8 (*voltage_max)(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 73a823f1ec22..cc4d8b3a2264 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -398,7 +398,8 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u8 train_set = intel_dp->train_set[0]; char phy_name[10]; @@ -412,7 +413,7 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp, intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy)) - intel_dp->set_signal_levels(intel_dp, crtc_state); + encoder->set_signal_levels(encoder, crtc_state); } static bool From 193299ad9d8579ba1f468e32870c9a52688f0872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:01 +0300 Subject: [PATCH 217/554] drm/i915: Nuke useless .set_signal_levels() wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that .set_signal_levels() is used for HDMI as well, we can remove the extra level of indirection and just plug the correct stuff straight into .set_signal_levels(). Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 119 +++++------------- drivers/gpu/drm/i915/display/intel_ddi.h | 6 +- drivers/gpu/drm/i915/display/intel_snps_phy.c | 7 +- drivers/gpu/drm/i915/display/intel_snps_phy.h | 5 +- 4 files changed, 39 insertions(+), 98 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ad7fe84b6d75..accdf456b1d0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1005,11 +1005,11 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder, _skl_ddi_set_iboost(dev_priv, PORT_E, iboost); } -static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) +static void bxt_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + int level = intel_ddi_level(encoder, crtc_state); const struct intel_ddi_buf_trans *trans; enum port port = encoder->port; int n_entries; @@ -1057,10 +1057,10 @@ static u8 intel_ddi_dp_preemph_max(struct intel_dp *intel_dp) } static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + int level = intel_ddi_level(encoder, crtc_state); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); int n_entries, ln; @@ -1119,9 +1119,8 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, intel_de_write(dev_priv, ICL_PORT_TX_DW7_GRP(phy), val); } -static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) +static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); @@ -1172,7 +1171,7 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val); /* 5. Program swing and de-emphasis */ - icl_ddi_combo_vswing_program(encoder, crtc_state, level); + icl_ddi_combo_vswing_program(encoder, crtc_state); /* 6. Set training enable to trigger update */ val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); @@ -1180,12 +1179,12 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val); } -static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) +static void icl_mg_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); + int level = intel_ddi_level(encoder, crtc_state); const struct intel_ddi_buf_trans *trans; int n_entries, ln; u32 val; @@ -1303,26 +1302,12 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, } } -static void icl_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - - if (intel_phy_is_combo(dev_priv, phy)) - icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level); - else - icl_mg_phy_ddi_vswing_sequence(encoder, crtc_state, level); -} - -static void -tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) +static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); + int level = intel_ddi_level(encoder, crtc_state); const struct intel_ddi_buf_trans *trans; u32 val, dpcnt_mask, dpcnt_val; int n_entries, ln; @@ -1374,19 +1359,6 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, } } -static void tgl_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - - if (intel_phy_is_combo(dev_priv, phy)) - icl_combo_phy_ddi_vswing_sequence(encoder, crtc_state, level); - else - tgl_dkl_phy_ddi_vswing_sequence(encoder, crtc_state, level); -} - static int translate_signal_level(struct intel_dp *intel_dp, u8 signal_levels) { @@ -1414,8 +1386,8 @@ static int intel_ddi_dp_level(struct intel_dp *intel_dp) return translate_signal_level(intel_dp, signal_levels); } -static int intel_ddi_level(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +int intel_ddi_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) return intel_ddi_hdmi_level(encoder, crtc_state); @@ -1423,42 +1395,6 @@ static int intel_ddi_level(struct intel_encoder *encoder, return intel_ddi_dp_level(enc_to_intel_dp(encoder)); } -static void -dg2_set_signal_levels(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - int level = intel_ddi_level(encoder, crtc_state); - - intel_snps_phy_ddi_vswing_sequence(encoder, crtc_state, level); -} - -static void -tgl_set_signal_levels(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - int level = intel_ddi_level(encoder, crtc_state); - - tgl_ddi_vswing_sequence(encoder, crtc_state, level); -} - -static void -icl_set_signal_levels(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - int level = intel_ddi_level(encoder, crtc_state); - - icl_ddi_vswing_sequence(encoder, crtc_state, level); -} - -static void -bxt_set_signal_levels(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - int level = intel_ddi_level(encoder, crtc_state); - - bxt_ddi_vswing_sequence(encoder, crtc_state, level); -} - static void hsw_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) @@ -4631,16 +4567,23 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->get_config = hsw_ddi_get_config; } - if (IS_DG2(dev_priv)) - encoder->set_signal_levels = dg2_set_signal_levels; - else if (DISPLAY_VER(dev_priv) >= 12) - encoder->set_signal_levels = tgl_set_signal_levels; - else if (DISPLAY_VER(dev_priv) >= 11) - encoder->set_signal_levels = icl_set_signal_levels; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + if (IS_DG2(dev_priv)) { + encoder->set_signal_levels = intel_snps_phy_set_signal_levels; + } else if (DISPLAY_VER(dev_priv) >= 12) { + if (intel_phy_is_combo(dev_priv, phy)) + encoder->set_signal_levels = icl_combo_phy_set_signal_levels; + else + encoder->set_signal_levels = tgl_dkl_phy_set_signal_levels; + } else if (DISPLAY_VER(dev_priv) >= 11) { + if (intel_phy_is_combo(dev_priv, phy)) + encoder->set_signal_levels = icl_combo_phy_set_signal_levels; + else + encoder->set_signal_levels = icl_mg_phy_set_signal_levels; + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { encoder->set_signal_levels = bxt_set_signal_levels; - else + } else { encoder->set_signal_levels = hsw_set_signal_levels; + } intel_ddi_buf_trans_init(encoder); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 7d448485d887..d6947c06a455 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -59,13 +59,11 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state, bool state); void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, struct intel_crtc_state *crtc_state); -u32 bxt_signal_levels(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); -u32 ddi_signal_levels(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder, enum transcoder cpu_transcoder, bool enable, u32 hdcp_mask); void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); +int intel_ddi_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); #endif /* __INTEL_DDI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 3734e349f91d..f59cc320ce9c 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -5,6 +5,7 @@ #include +#include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display_types.h" @@ -51,13 +52,13 @@ void intel_snps_phy_update_psr_power_state(struct drm_i915_private *dev_priv, SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val); } -void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level) +void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + int level = intel_ddi_level(encoder, crtc_state); int n_entries, ln; trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.h b/drivers/gpu/drm/i915/display/intel_snps_phy.h index a68547a6fee5..11dcd6deb070 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.h +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.h @@ -29,8 +29,7 @@ int intel_mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_mpllb_state *pll_state); int intel_snps_phy_check_hdmi_link_rate(int clock); -void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int level); +void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); #endif /* __INTEL_SNPS_PHY_H__ */ From 5f5ada0bae454aababf83b9fde3ae6b8df73afe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:02 +0300 Subject: [PATCH 218/554] drm/i915: De-wrapper bxt_ddi_phy_set_signal_levels() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert bxt_ddi_phy_set_signal_levels() to act as the full .set_signal_levels() hook instead of going through a pointless wrapper. Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 24 +-------------- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 30 +++++++++++++------ drivers/gpu/drm/i915/display/intel_dpio_phy.h | 5 ++-- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index accdf456b1d0..e6dd8ca36e44 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1005,28 +1005,6 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder, _skl_ddi_set_iboost(dev_priv, PORT_E, iboost); } -static void bxt_set_signal_levels(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_level(encoder, crtc_state); - const struct intel_ddi_buf_trans *trans; - enum port port = encoder->port; - int n_entries; - - trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) - return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; - - bxt_ddi_phy_set_signal_level(dev_priv, port, - trans->entries[level].bxt.margin, - trans->entries[level].bxt.scale, - trans->entries[level].bxt.enable, - trans->entries[level].bxt.deemphasis); -} - static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { @@ -4580,7 +4558,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) else encoder->set_signal_levels = icl_mg_phy_set_signal_levels; } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - encoder->set_signal_levels = bxt_set_signal_levels; + encoder->set_signal_levels = bxt_ddi_phy_set_signal_levels; } else { encoder->set_signal_levels = hsw_set_signal_levels; } diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 48507ed79950..4d604e4cfa5d 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -23,6 +23,8 @@ #include "display/intel_dp.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" @@ -266,15 +268,24 @@ void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, *ch = DPIO_CH0; } -void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv, - enum port port, u32 margin, u32 scale, - u32 enable, u32 deemphasis) +void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { - u32 val; - enum dpio_phy phy; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + int level = intel_ddi_level(encoder, crtc_state); + const struct intel_ddi_buf_trans *trans; enum dpio_channel ch; + enum dpio_phy phy; + int n_entries; + u32 val; - bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) + return; + if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) + level = n_entries - 1; + + bxt_port_to_phy_channel(dev_priv, encoder->port, &phy, &ch); /* * While we write to the group register to program all lanes at once we @@ -286,12 +297,13 @@ void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv, val = intel_de_read(dev_priv, BXT_PORT_TX_DW2_LN0(phy, ch)); val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE); - val |= margin << MARGIN_000_SHIFT | scale << UNIQ_TRANS_SCALE_SHIFT; + val |= trans->entries[level].bxt.margin << MARGIN_000_SHIFT | + trans->entries[level].bxt.scale << UNIQ_TRANS_SCALE_SHIFT; intel_de_write(dev_priv, BXT_PORT_TX_DW2_GRP(phy, ch), val); val = intel_de_read(dev_priv, BXT_PORT_TX_DW3_LN0(phy, ch)); val &= ~SCALE_DCOMP_METHOD; - if (enable) + if (trans->entries[level].bxt.enable) val |= SCALE_DCOMP_METHOD; if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD)) @@ -302,7 +314,7 @@ void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv, val = intel_de_read(dev_priv, BXT_PORT_TX_DW4_LN0(phy, ch)); val &= ~DE_EMPHASIS; - val |= deemphasis << DEEMPH_SHIFT; + val |= trans->entries[level].bxt.deemphasis << DEEMPH_SHIFT; intel_de_write(dev_priv, BXT_PORT_TX_DW4_GRP(phy, ch), val); val = intel_de_read(dev_priv, BXT_PORT_PCS_DW10_LN01(phy, ch)); diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 6473440e7457..9c3d008e8e1a 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -17,9 +17,8 @@ struct intel_encoder; void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, enum dpio_phy *phy, enum dpio_channel *ch); -void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv, - enum port port, u32 margin, u32 scale, - u32 enable, u32 deemphasis); +void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy); void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy); bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv, From 2c63e0f92e2fe3400ebfec7952f9dcbff6a583a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:03 +0300 Subject: [PATCH 219/554] drm/i915: Hoover the level>=n_entries WARN into intel_ddi_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers of intel_ddi_level() duplicate the check+WARN to make sure the returned level is actually present in the appropriate buf_trans table. Let's push that stuff into intel_ddi_level() so the callers don't have to worry about it. Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 27 ++++++++++--------- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 2 -- drivers/gpu/drm/i915/display/intel_snps_phy.c | 2 -- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e6dd8ca36e44..2b192694f484 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -151,8 +151,6 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; /* If we're boosting the current, set bit 31 of trans1 */ if (has_iboost(dev_priv) && @@ -987,8 +985,6 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; iboost = trans->entries[level].hsw.i_boost; } @@ -1047,8 +1043,6 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1173,8 +1167,6 @@ static void icl_mg_phy_set_signal_levels(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; /* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */ for (ln = 0; ln < 2; ln++) { @@ -1296,8 +1288,6 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; dpcnt_mask = (DKL_TX_PRESHOOT_COEFF_MASK | DKL_TX_DE_EMPAHSIS_COEFF_MASK | @@ -1367,10 +1357,23 @@ static int intel_ddi_dp_level(struct intel_dp *intel_dp) int intel_ddi_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_ddi_buf_trans *trans; + int level, n_entries; + + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&i915->drm, !trans)) + return 0; + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return intel_ddi_hdmi_level(encoder, crtc_state); + level = intel_ddi_hdmi_level(encoder, crtc_state); else - return intel_ddi_dp_level(enc_to_intel_dp(encoder)); + level = intel_ddi_dp_level(enc_to_intel_dp(encoder)); + + if (drm_WARN_ON_ONCE(&i915->drm, level >= n_entries)) + level = n_entries - 1; + + return level; } static void diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 4d604e4cfa5d..96650369164d 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -282,8 +282,6 @@ void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; bxt_port_to_phy_channel(dev_priv, encoder->port, &phy, &ch); diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index f59cc320ce9c..7a9771dbb63f 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -64,8 +64,6 @@ void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !trans)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, level < 0 || level >= n_entries)) - level = n_entries - 1; for (ln = 0; ln < 4; ln++) { u32 val = 0; From 3e022c1f0a5fcdc0192fc497c63efdadd8c5b3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:04 +0300 Subject: [PATCH 220/554] drm/i915: Nuke intel_ddi_hdmi_num_entries() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since intel_ddi_level() now looks at the buf_trans table there's no point in having intel_ddi_hdmi_num_entries() around. Just roll the necessary bits of locic into intel_ddi_hdmi_level()/intel_ddi_level(). Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 17 +++++----------- .../drm/i915/display/intel_ddi_buf_trans.c | 20 ------------------- .../drm/i915/display/intel_ddi_buf_trans.h | 4 ---- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2b192694f484..4e9a6f30f524 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -74,20 +74,13 @@ static const u8 index_to_dp_signal_levels[] = { }; static int intel_ddi_hdmi_level(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_ddi_buf_trans *trans) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int n_entries, level, default_entry; + int level; - n_entries = intel_ddi_hdmi_num_entries(encoder, crtc_state, &default_entry); - if (n_entries == 0) - return 0; level = intel_bios_hdmi_level_shift(encoder); if (level < 0) - level = default_entry; - - if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) - level = n_entries - 1; + level = trans->hdmi_default_entry; return level; } @@ -142,7 +135,7 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_hdmi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state); u32 iboost_bit = 0; int n_entries; enum port port = encoder->port; @@ -1366,7 +1359,7 @@ int intel_ddi_level(struct intel_encoder *encoder, return 0; if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - level = intel_ddi_hdmi_level(encoder, crtc_state); + level = intel_ddi_hdmi_level(encoder, trans); else level = intel_ddi_dp_level(enc_to_intel_dp(encoder)); diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index 449daba7afb3..a2d39131ea53 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -1617,26 +1617,6 @@ dg2_get_snps_buf_trans(struct intel_encoder *encoder, return intel_get_buf_trans(&dg2_snps_trans, n_entries); } -int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *default_entry) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_ddi_buf_trans *trans; - int n_entries; - - trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); - - if (drm_WARN_ON(&dev_priv->drm, !trans)) { - *default_entry = 0; - return 0; - } - - *default_entry = trans->hdmi_default_entry; - - return n_entries; -} - void intel_ddi_buf_trans_init(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h index 94d338287f61..6cdb8e9073c7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -68,10 +68,6 @@ struct intel_ddi_buf_trans { bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table); -int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *default_entry); - void intel_ddi_buf_trans_init(struct intel_encoder *encoder); #endif From a0b1d355b9b4e24833f6d5c0e03bdf61a34b9963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:11:56 +0200 Subject: [PATCH 221/554] drm/fourcc: Add R8 to drm_format_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an entry in drm_format_info for the existing format DRM_FORMAT_R8. Reviewed-by: Daniel Vetter Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-2-noralf@tronnes.org --- drivers/gpu/drm/drm_fourcc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index eda832f9200d..783844bfecc1 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -133,6 +133,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { static const struct drm_format_info formats[] = { { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, From cee0b7cbf1c02fc1e32a9eda6a66f1a4f85adae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:11:57 +0200 Subject: [PATCH 222/554] drm/format-helper: Add drm_fb_xrgb8888_to_rgb332() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add XRGB8888 emulation support for devices that can only do RGB332. v2: - Support Big Endian (Daniel) Reviewed-by: Daniel Vetter Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-3-noralf@tronnes.org --- drivers/gpu/drm/drm_format_helper.c | 50 +++++++++++++++++++++++++++++ include/drm/drm_format_helper.h | 2 ++ 2 files changed, 52 insertions(+) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 5231104b1498..dab4f382d469 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -135,6 +135,56 @@ void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_fb_swab); +static void drm_fb_xrgb8888_to_rgb332_line(u8 *dbuf, __le32 *sbuf, unsigned int pixels) +{ + unsigned int x; + u32 pix; + + for (x = 0; x < pixels; x++) { + pix = le32_to_cpu(sbuf[x]); + dbuf[x] = ((pix & 0x00e00000) >> 16) | + ((pix & 0x0000e000) >> 11) | + ((pix & 0x000000c0) >> 6); + } +} + +/** + * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer + * @dst: RGB332 destination buffer + * @src: XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * + * Drivers can use this function for RGB332 devices that don't natively support XRGB8888. + * + * This function does not apply clipping on dst, i.e. the destination is a small buffer + * containing the clip rect only. + */ +void drm_fb_xrgb8888_to_rgb332(void *dst, void *src, struct drm_framebuffer *fb, + struct drm_rect *clip) +{ + size_t width = drm_rect_width(clip); + size_t src_len = width * sizeof(u32); + unsigned int y; + void *sbuf; + + /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ + sbuf = kmalloc(src_len, GFP_KERNEL); + if (!sbuf) + return; + + src += clip_offset(clip, fb->pitches[0], sizeof(u32)); + for (y = 0; y < drm_rect_height(clip); y++) { + memcpy(sbuf, src, src_len); + drm_fb_xrgb8888_to_rgb332_line(dst, sbuf, width); + src += fb->pitches[0]; + dst += width; + } + + kfree(sbuf); +} +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); + static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf, unsigned int pixels, bool swab) diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index 4e0258a61311..d0809aff5cf8 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -16,6 +16,8 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vadd struct drm_rect *clip); void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb, struct drm_rect *clip, bool cached); +void drm_fb_xrgb8888_to_rgb332(void *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip); void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip, bool swab); From bcf80d6ef17c97ca7a712d8e6b065910b406e3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:11:58 +0200 Subject: [PATCH 223/554] drm/format-helper: Add drm_fb_xrgb8888_to_rgb888() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add XRGB8888 emulation support for devices that can only do RGB888. Reviewed-by: Daniel Vetter Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-4-noralf@tronnes.org --- drivers/gpu/drm/drm_format_helper.c | 38 +++++++++++++++++++++++++++++ include/drm/drm_format_helper.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index dab4f382d469..69fde60e36b3 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -300,6 +300,44 @@ static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf, } } +/** + * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer + * @dst: RGB888 destination buffer + * @src: XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * + * Drivers can use this function for RGB888 devices that don't natively + * support XRGB8888. + * + * This function does not apply clipping on dst, i.e. the destination + * is a small buffer containing the clip rect only. + */ +void drm_fb_xrgb8888_to_rgb888(void *dst, void *src, struct drm_framebuffer *fb, + struct drm_rect *clip) +{ + size_t width = drm_rect_width(clip); + size_t src_len = width * sizeof(u32); + unsigned int y; + void *sbuf; + + /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ + sbuf = kmalloc(src_len, GFP_KERNEL); + if (!sbuf) + return; + + src += clip_offset(clip, fb->pitches[0], sizeof(u32)); + for (y = 0; y < drm_rect_height(clip); y++) { + memcpy(sbuf, src, src_len); + drm_fb_xrgb8888_to_rgb888_line(dst, sbuf, width); + src += fb->pitches[0]; + dst += width * 3; + } + + kfree(sbuf); +} +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); + /** * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer * @dst: RGB565 destination buffer (iomem) diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index d0809aff5cf8..e86925cf07b9 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -24,6 +24,8 @@ void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip, bool swab); +void drm_fb_xrgb8888_to_rgb888(void *dst, void *src, struct drm_framebuffer *fb, + struct drm_rect *clip); void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip); From d0920a45574c15a8fc00ccdff65da3b801438757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:05 +0300 Subject: [PATCH 224/554] drm/i915: Pass the lane to intel_ddi_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to have per-lane drive settings we need intel_ddi_level() to accept the lane as a parameter. That is, the eventual goal is to call intel_ddi_level() once for each lane. For now we just pass in a hardcoded 0 and use the same settings for every lane. Ie. no change in behaviour yet. Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 19 ++++++++++--------- drivers/gpu/drm/i915/display/intel_ddi.h | 3 ++- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 2 +- drivers/gpu/drm/i915/display/intel_snps_phy.c | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 4e9a6f30f524..0d4cf7fa8720 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -135,7 +135,7 @@ static void hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); u32 iboost_bit = 0; int n_entries; enum port port = encoder->port; @@ -1027,7 +1027,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); int n_entries, ln; @@ -1149,7 +1149,7 @@ static void icl_mg_phy_set_signal_levels(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); const struct intel_ddi_buf_trans *trans; int n_entries, ln; u32 val; @@ -1270,7 +1270,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, encoder->port); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); const struct intel_ddi_buf_trans *trans; u32 val, dpcnt_mask, dpcnt_val; int n_entries, ln; @@ -1338,9 +1338,9 @@ static int translate_signal_level(struct intel_dp *intel_dp, return 0; } -static int intel_ddi_dp_level(struct intel_dp *intel_dp) +static int intel_ddi_dp_level(struct intel_dp *intel_dp, int lane) { - u8 train_set = intel_dp->train_set[0]; + u8 train_set = intel_dp->train_set[lane]; u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | DP_TRAIN_PRE_EMPHASIS_MASK); @@ -1348,7 +1348,8 @@ static int intel_ddi_dp_level(struct intel_dp *intel_dp) } int intel_ddi_level(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + int lane) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; @@ -1361,7 +1362,7 @@ int intel_ddi_level(struct intel_encoder *encoder, if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) level = intel_ddi_hdmi_level(encoder, trans); else - level = intel_ddi_dp_level(enc_to_intel_dp(encoder)); + level = intel_ddi_dp_level(enc_to_intel_dp(encoder), lane); if (drm_WARN_ON_ONCE(&i915->drm, level >= n_entries)) level = n_entries - 1; @@ -1375,7 +1376,7 @@ hsw_set_signal_levels(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); enum port port = encoder->port; u32 signal_levels; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index d6947c06a455..d6971717ef9c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -64,6 +64,7 @@ int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder, bool enable, u32 hdcp_mask); void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); int intel_ddi_level(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); + const struct intel_crtc_state *crtc_state, + int lane); #endif /* __INTEL_DDI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 96650369164d..5a2eccb12fe4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -272,7 +272,7 @@ void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); const struct intel_ddi_buf_trans *trans; enum dpio_channel ch; enum dpio_phy phy; diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 7a9771dbb63f..b18f08c851dc 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -58,7 +58,7 @@ void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - int level = intel_ddi_level(encoder, crtc_state); + int level = intel_ddi_level(encoder, crtc_state, 0); int n_entries, ln; trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); From c6921d484d3f986f3bed3372ac22574b42e2589f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:06 +0300 Subject: [PATCH 225/554] drm/i915: Prepare link training for per-lane drive settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the link training code to accommodate per-lane drive settings, if supported by the platform. Actually enabling this will involve some changes to each platform's .set_signal_level() implementation, so for the moment all supported platforms will keep using the current codepath that just uses the same drive settings for all the lanes. v2: Fix min() vs. max() fumble v3: Compact the debug print to a single line Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-10-ville.syrjala@linux.intel.com --- .../drm/i915/display/intel_dp_link_training.c | 78 ++++++++++++++----- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index cc4d8b3a2264..6e54de5db183 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -301,21 +301,33 @@ static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp, return preemph_max; } -void -intel_dp_get_adjust_train(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - enum drm_dp_phy dp_phy, - const u8 link_status[DP_LINK_STATUS_SIZE]) +static bool has_per_lane_signal_levels(struct intel_dp *intel_dp, + enum drm_dp_phy dp_phy) +{ + return false; +} + +static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) { u8 v = 0; u8 p = 0; - int lane; u8 voltage_max; u8 preemph_max; - for (lane = 0; lane < crtc_state->lane_count; lane++) { - v = max(v, drm_dp_get_adjust_request_voltage(link_status, lane)); - p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane)); + if (has_per_lane_signal_levels(intel_dp, dp_phy)) { + lane = min(lane, crtc_state->lane_count - 1); + + v = drm_dp_get_adjust_request_voltage(link_status, lane); + p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); + } else { + for (lane = 0; lane < crtc_state->lane_count; lane++) { + v = max(v, drm_dp_get_adjust_request_voltage(link_status, lane)); + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane)); + } } preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy); @@ -328,8 +340,21 @@ intel_dp_get_adjust_train(struct intel_dp *intel_dp, if (v >= voltage_max) v = voltage_max | DP_TRAIN_MAX_SWING_REACHED; + return v | p; +} + +void +intel_dp_get_adjust_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE]) +{ + int lane; + for (lane = 0; lane < 4; lane++) - intel_dp->train_set[lane] = v | p; + intel_dp->train_set[lane] = + intel_dp_get_lane_adjust_train(intel_dp, crtc_state, + dp_phy, link_status, lane); } static int intel_dp_training_pattern_set_reg(struct intel_dp *intel_dp, @@ -394,22 +419,39 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat); } +#define TRAIN_SET_FMT "%d%s/%d%s/%d%s/%d%s" +#define _TRAIN_SET_VSWING_ARGS(train_set) \ + ((train_set) & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT, \ + (train_set) & DP_TRAIN_MAX_SWING_REACHED ? "(max)" : "" +#define TRAIN_SET_VSWING_ARGS(train_set) \ + _TRAIN_SET_VSWING_ARGS((train_set)[0]), \ + _TRAIN_SET_VSWING_ARGS((train_set)[1]), \ + _TRAIN_SET_VSWING_ARGS((train_set)[2]), \ + _TRAIN_SET_VSWING_ARGS((train_set)[3]) +#define _TRAIN_SET_PREEMPH_ARGS(train_set) \ + ((train_set) & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT, \ + (train_set) & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ? "(max)" : "" +#define TRAIN_SET_PREEMPH_ARGS(train_set) \ + _TRAIN_SET_PREEMPH_ARGS((train_set)[0]), \ + _TRAIN_SET_PREEMPH_ARGS((train_set)[1]), \ + _TRAIN_SET_PREEMPH_ARGS((train_set)[2]), \ + _TRAIN_SET_PREEMPH_ARGS((train_set)[3]) + void intel_dp_set_signal_levels(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u8 train_set = intel_dp->train_set[0]; char phy_name[10]; - drm_dbg_kms(&dev_priv->drm, "Using vswing level %d%s, pre-emphasis level %d%s, at %s\n", - train_set & DP_TRAIN_VOLTAGE_SWING_MASK, - train_set & DP_TRAIN_MAX_SWING_REACHED ? " (max)" : "", - (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >> - DP_TRAIN_PRE_EMPHASIS_SHIFT, - train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ? - " (max)" : "", + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] lanes: %d, " + "vswing levels: " TRAIN_SET_FMT ", " + "pre-emphasis levels: " TRAIN_SET_FMT ", at %s\n", + encoder->base.base.id, encoder->base.name, + crtc_state->lane_count, + TRAIN_SET_VSWING_ARGS(intel_dp->train_set), + TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set), intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy)) From 104c1b3d6fb6a794babd5e2ffd6a5183b5a3d6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Oct 2021 16:01:07 +0300 Subject: [PATCH 226/554] drm/i915: Allow per-lane drive settings with LTTPRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LTTPRs should support per-lane drive settings I think, and even if they don't they should implement their own fallback logic to determine suitable common drive settings to use for all the lanes. v2: Actually check the correct thing Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001130107.1746-11-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 6e54de5db183..c052ce14894d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -304,7 +304,7 @@ static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp, static bool has_per_lane_signal_levels(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { - return false; + return !intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy); } static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, From 4cabfedc096b14336fac1d42bec5cb8ff5090527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:11:59 +0200 Subject: [PATCH 227/554] drm/gud: Add GUD_PIXEL_FORMAT_R8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for 8-bit greyscale format. Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-5-noralf@tronnes.org --- drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/gud/gud_internal.h | 4 ++++ drivers/gpu/drm/gud/gud_pipe.c | 2 ++ include/drm/gud.h | 4 ++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index eb4e08846da4..a8d76c76e868 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -523,6 +523,8 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id) switch (format) { case GUD_DRM_FORMAT_R1: fallthrough; + case DRM_FORMAT_R8: + fallthrough; case GUD_DRM_FORMAT_XRGB1111: if (!xrgb8888_emulation_format) xrgb8888_emulation_format = info; diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h index 2a388e27d5d7..8499e713dbbc 100644 --- a/drivers/gpu/drm/gud/gud_internal.h +++ b/drivers/gpu/drm/gud/gud_internal.h @@ -80,6 +80,8 @@ static inline u8 gud_from_fourcc(u32 fourcc) switch (fourcc) { case GUD_DRM_FORMAT_R1: return GUD_PIXEL_FORMAT_R1; + case DRM_FORMAT_R8: + return GUD_PIXEL_FORMAT_R8; case GUD_DRM_FORMAT_XRGB1111: return GUD_PIXEL_FORMAT_XRGB1111; case DRM_FORMAT_RGB565: @@ -98,6 +100,8 @@ static inline u32 gud_to_fourcc(u8 format) switch (format) { case GUD_PIXEL_FORMAT_R1: return GUD_DRM_FORMAT_R1; + case GUD_PIXEL_FORMAT_R8: + return DRM_FORMAT_R8; case GUD_PIXEL_FORMAT_XRGB1111: return GUD_DRM_FORMAT_XRGB1111; case GUD_PIXEL_FORMAT_RGB565: diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index b9b0e435ea0f..be4f95b2d59c 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -189,6 +189,8 @@ retry: ret = -ENOMEM; goto end_cpu_access; } + } else if (format->format == DRM_FORMAT_R8) { + drm_fb_xrgb8888_to_gray8(buf, vaddr, fb, rect); } else if (format->format == DRM_FORMAT_RGB565) { drm_fb_xrgb8888_to_rgb565(buf, vaddr, fb, rect, gud_is_big_endian()); } else { diff --git a/include/drm/gud.h b/include/drm/gud.h index 0b46b54fe56e..1dc781009e62 100644 --- a/include/drm/gud.h +++ b/include/drm/gud.h @@ -246,8 +246,8 @@ struct gud_state_req { /* Get supported pixel formats as a byte array of GUD_PIXEL_FORMAT_* */ #define GUD_REQ_GET_FORMATS 0x40 #define GUD_FORMATS_MAX_NUM 32 - /* R1 is a 1-bit monochrome transfer format presented to userspace as XRGB8888 */ - #define GUD_PIXEL_FORMAT_R1 0x01 + #define GUD_PIXEL_FORMAT_R1 0x01 /* 1-bit monochrome */ + #define GUD_PIXEL_FORMAT_R8 0x08 /* 8-bit greyscale */ #define GUD_PIXEL_FORMAT_XRGB1111 0x20 #define GUD_PIXEL_FORMAT_RGB565 0x40 #define GUD_PIXEL_FORMAT_XRGB8888 0x80 From 1f25d0054258df239ffa420606466fd9b14e06d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:12:00 +0200 Subject: [PATCH 228/554] drm/gud: Add GUD_PIXEL_FORMAT_RGB332 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the RGB332 pixel format. Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-6-noralf@tronnes.org --- drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/gud/gud_internal.h | 4 ++++ drivers/gpu/drm/gud/gud_pipe.c | 2 ++ include/drm/gud.h | 1 + 4 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index a8d76c76e868..e571ad10a12b 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -526,6 +526,8 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id) case DRM_FORMAT_R8: fallthrough; case GUD_DRM_FORMAT_XRGB1111: + fallthrough; + case DRM_FORMAT_RGB332: if (!xrgb8888_emulation_format) xrgb8888_emulation_format = info; break; diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h index 8499e713dbbc..249e02d1f5ed 100644 --- a/drivers/gpu/drm/gud/gud_internal.h +++ b/drivers/gpu/drm/gud/gud_internal.h @@ -84,6 +84,8 @@ static inline u8 gud_from_fourcc(u32 fourcc) return GUD_PIXEL_FORMAT_R8; case GUD_DRM_FORMAT_XRGB1111: return GUD_PIXEL_FORMAT_XRGB1111; + case DRM_FORMAT_RGB332: + return GUD_PIXEL_FORMAT_RGB332; case DRM_FORMAT_RGB565: return GUD_PIXEL_FORMAT_RGB565; case DRM_FORMAT_XRGB8888: @@ -104,6 +106,8 @@ static inline u32 gud_to_fourcc(u8 format) return DRM_FORMAT_R8; case GUD_PIXEL_FORMAT_XRGB1111: return GUD_DRM_FORMAT_XRGB1111; + case GUD_PIXEL_FORMAT_RGB332: + return DRM_FORMAT_RGB332; case GUD_PIXEL_FORMAT_RGB565: return DRM_FORMAT_RGB565; case GUD_PIXEL_FORMAT_XRGB8888: diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index be4f95b2d59c..868a0b8a1f3e 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -191,6 +191,8 @@ retry: } } else if (format->format == DRM_FORMAT_R8) { drm_fb_xrgb8888_to_gray8(buf, vaddr, fb, rect); + } else if (format->format == DRM_FORMAT_RGB332) { + drm_fb_xrgb8888_to_rgb332(buf, vaddr, fb, rect); } else if (format->format == DRM_FORMAT_RGB565) { drm_fb_xrgb8888_to_rgb565(buf, vaddr, fb, rect, gud_is_big_endian()); } else { diff --git a/include/drm/gud.h b/include/drm/gud.h index 1dc781009e62..4118dce2fcec 100644 --- a/include/drm/gud.h +++ b/include/drm/gud.h @@ -249,6 +249,7 @@ struct gud_state_req { #define GUD_PIXEL_FORMAT_R1 0x01 /* 1-bit monochrome */ #define GUD_PIXEL_FORMAT_R8 0x08 /* 8-bit greyscale */ #define GUD_PIXEL_FORMAT_XRGB1111 0x20 + #define GUD_PIXEL_FORMAT_RGB332 0x30 #define GUD_PIXEL_FORMAT_RGB565 0x40 #define GUD_PIXEL_FORMAT_XRGB8888 0x80 #define GUD_PIXEL_FORMAT_ARGB8888 0x81 From 83d7b6d54b8e8a3a487c8a4066e33e6bdd255c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 29 Sep 2021 21:12:01 +0200 Subject: [PATCH 229/554] drm/gud: Add GUD_PIXEL_FORMAT_RGB888 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the RGB888 pixel format. Acked-by: Thomas Zimmermann Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210929191201.34456-7-noralf@tronnes.org --- drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/gud/gud_internal.h | 4 ++++ drivers/gpu/drm/gud/gud_pipe.c | 2 ++ include/drm/gud.h | 1 + 4 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index e571ad10a12b..3f9d4b9a1e3d 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -528,6 +528,8 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id) case GUD_DRM_FORMAT_XRGB1111: fallthrough; case DRM_FORMAT_RGB332: + fallthrough; + case DRM_FORMAT_RGB888: if (!xrgb8888_emulation_format) xrgb8888_emulation_format = info; break; diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h index 249e02d1f5ed..e351a1f1420d 100644 --- a/drivers/gpu/drm/gud/gud_internal.h +++ b/drivers/gpu/drm/gud/gud_internal.h @@ -88,6 +88,8 @@ static inline u8 gud_from_fourcc(u32 fourcc) return GUD_PIXEL_FORMAT_RGB332; case DRM_FORMAT_RGB565: return GUD_PIXEL_FORMAT_RGB565; + case DRM_FORMAT_RGB888: + return GUD_PIXEL_FORMAT_RGB888; case DRM_FORMAT_XRGB8888: return GUD_PIXEL_FORMAT_XRGB8888; case DRM_FORMAT_ARGB8888: @@ -110,6 +112,8 @@ static inline u32 gud_to_fourcc(u8 format) return DRM_FORMAT_RGB332; case GUD_PIXEL_FORMAT_RGB565: return DRM_FORMAT_RGB565; + case GUD_PIXEL_FORMAT_RGB888: + return DRM_FORMAT_RGB888; case GUD_PIXEL_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; case GUD_PIXEL_FORMAT_ARGB8888: diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 868a0b8a1f3e..daf75c178c2b 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -195,6 +195,8 @@ retry: drm_fb_xrgb8888_to_rgb332(buf, vaddr, fb, rect); } else if (format->format == DRM_FORMAT_RGB565) { drm_fb_xrgb8888_to_rgb565(buf, vaddr, fb, rect, gud_is_big_endian()); + } else if (format->format == DRM_FORMAT_RGB888) { + drm_fb_xrgb8888_to_rgb888(buf, vaddr, fb, rect); } else { len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect); } diff --git a/include/drm/gud.h b/include/drm/gud.h index 4118dce2fcec..c52a8ba4ae4e 100644 --- a/include/drm/gud.h +++ b/include/drm/gud.h @@ -251,6 +251,7 @@ struct gud_state_req { #define GUD_PIXEL_FORMAT_XRGB1111 0x20 #define GUD_PIXEL_FORMAT_RGB332 0x30 #define GUD_PIXEL_FORMAT_RGB565 0x40 + #define GUD_PIXEL_FORMAT_RGB888 0x50 #define GUD_PIXEL_FORMAT_XRGB8888 0x80 #define GUD_PIXEL_FORMAT_ARGB8888 0x81 From 294a0d9524b1b814499140d79b9127fb581acc9c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:27 -0400 Subject: [PATCH 230/554] Revert "drm: cleanup: remove drm_modeset_(un)lock_all()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8d813d1a535c8c7503a5f4061654a73026be8c5e. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-1-sean@poorly.run --- drivers/gpu/drm/drm_modeset_lock.c | 94 +++++++++++++++++++++++++++++- include/drm/drm_modeset_lock.h | 2 + 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index afd1351749a5..fcfe1a03c4a1 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -77,6 +77,93 @@ static DEFINE_WW_CLASS(crtc_ww_class); +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: DRM device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. Locks must be dropped by calling the + * drm_modeset_unlock_all() function. + * + * This function is deprecated. It allocates a lock acquisition context and + * stores it in &drm_device.mode_config. This facilitate conversion of + * existing code because it removes the need to manually deal with the + * acquisition context, but it is also brittle because the context is global + * and care must be taken not to nest calls. New code should use the + * drm_modeset_lock_all_ctx() function and pass in the context explicitly. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL); + if (WARN_ON(!ctx)) + return; + + mutex_lock(&config->mutex); + + drm_modeset_acquire_init(ctx, 0); + +retry: + ret = drm_modeset_lock_all_ctx(dev, ctx); + if (ret < 0) { + if (ret == -EDEADLK) { + drm_modeset_backoff(ctx); + goto retry; + } + + drm_modeset_acquire_fini(ctx); + kfree(ctx); + return; + } + ww_acquire_done(&ctx->ww_ctx); + + WARN_ON(config->acquire_ctx); + + /* + * We hold the locks now, so it is safe to stash the acquisition + * context for drm_modeset_unlock_all(). + */ + config->acquire_ctx = ctx; + + drm_warn_on_modeset_not_all_locked(dev); +} +EXPORT_SYMBOL(drm_modeset_lock_all); + +/** + * drm_modeset_unlock_all - drop all modeset locks + * @dev: DRM device + * + * This function drops all modeset locks taken by a previous call to the + * drm_modeset_lock_all() function. + * + * This function is deprecated. It uses the lock acquisition context stored + * in &drm_device.mode_config. This facilitates conversion of existing + * code because it removes the need to manually deal with the acquisition + * context, but it is also brittle because the context is global and care must + * be taken not to nest calls. New code should pass the acquisition context + * directly to the drm_modeset_drop_locks() function. + */ +void drm_modeset_unlock_all(struct drm_device *dev) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + + if (WARN_ON(!ctx)) + return; + + config->acquire_ctx = NULL; + drm_modeset_drop_locks(ctx); + drm_modeset_acquire_fini(ctx); + + kfree(ctx); + + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_unlock_all); + /** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device @@ -293,9 +380,10 @@ EXPORT_SYMBOL(drm_modeset_unlock); * This function takes all modeset locks, suitable where a more fine-grained * scheme isn't (yet) implemented. * - * It doesn't take the &drm_mode_config.mutex since that lock isn't required for - * modeset state changes. Callers which need to grab that lock too need to do so - * outside of the acquire context @ctx. + * Unlike drm_modeset_lock_all(), it doesn't take the &drm_mode_config.mutex + * since that lock isn't required for modeset state changes. Callers which + * need to grab that lock too need to do so outside of the acquire context + * @ctx. * * Locks acquired with this function should be released by calling the * drm_modeset_drop_locks() function on @ctx. diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 865e64bcc4cb..aafd07388eb7 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -132,6 +132,8 @@ struct drm_device; struct drm_crtc; struct drm_plane; +void drm_modeset_lock_all(struct drm_device *dev); +void drm_modeset_unlock_all(struct drm_device *dev); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); int drm_modeset_lock_all_ctx(struct drm_device *dev, From 6f67e6fd4dc022265fb1b7bb26ef955d8d9e6540 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:28 -0400 Subject: [PATCH 231/554] Revert "drm/amd: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 299f040e855b69c29522cde446777902381a07f5. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-2-sean@poorly.run --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 21 +++----- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 52 +++++++++---------- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 25 ++++----- 3 files changed, 44 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index b07e845a2600..7a7316731911 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -40,7 +40,6 @@ #include #include #include -#include static void amdgpu_display_flip_callback(struct dma_fence *f, struct dma_fence_cb *cb) @@ -1544,21 +1543,16 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev) struct drm_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter iter; - struct drm_modeset_acquire_ctx ctx; - int r, ret; + int r; /* turn off display hw */ - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); drm_connector_list_iter_end(&iter); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (ret) - return ret; - + drm_modeset_unlock_all(dev); /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); @@ -1596,8 +1590,7 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) struct drm_connector *connector; struct drm_connector_list_iter iter; struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; - int r, ret; + int r; /* pin cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1619,7 +1612,7 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) drm_helper_resume_force_mode(dev); /* turn on display hw */ - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) @@ -1627,8 +1620,8 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev) DRM_MODE_DPMS_ON); drm_connector_list_iter_end(&iter); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); - return ret; + return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5196c1d26f87..9b1fc54555ee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -80,7 +80,6 @@ #include #include #include -#include #if defined(CONFIG_DRM_AMD_DC_DCN) #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" @@ -2622,9 +2621,6 @@ static void handle_hpd_irq(void *param) #ifdef CONFIG_DRM_AMD_DC_HDCP struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); #endif - struct drm_modeset_acquire_ctx ctx; - int ret; - if (adev->dm.disable_hpd_irq) return; @@ -2650,6 +2646,14 @@ static void handle_hpd_irq(void *param) if (aconnector->base.force && new_connection_type == dc_connection_none) { emulated_link_detect(aconnector->dc_link); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) + drm_kms_helper_hotplug_event(dev); + } else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) { if (new_connection_type == dc_connection_none && aconnector->dc_link->type == dc_connection_none) @@ -2657,18 +2661,13 @@ static void handle_hpd_irq(void *param) amdgpu_dm_update_connector_after_detect(aconnector); - } else { - goto out; + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) + drm_kms_helper_hotplug_event(dev); } - - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - dm_restore_drm_connector_state(dev, connector); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); - -out: mutex_unlock(&aconnector->hpd_lock); } @@ -2757,14 +2756,12 @@ static void handle_hpd_rx_irq(void *param) struct drm_connector *connector = &aconnector->base; struct drm_device *dev = connector->dev; struct dc_link *dc_link = aconnector->dc_link; - struct drm_modeset_acquire_ctx ctx; bool is_mst_root_connector = aconnector->mst_mgr.mst_state; bool result = false; enum dc_connection_type new_connection_type = dc_connection_none; struct amdgpu_device *adev = drm_to_adev(dev); union hpd_irq_data hpd_irq_data; bool lock_flag = 0; - int ret; memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); @@ -2831,6 +2828,12 @@ out: amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_hotplug_event(dev); } else if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { if (aconnector->fake_enable) @@ -2838,17 +2841,14 @@ out: amdgpu_dm_update_connector_after_detect(aconnector); - } else { - goto finish; + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_hotplug_event(dev); } - - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - dm_restore_drm_connector_state(dev, connector); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - drm_kms_helper_hotplug_event(dev); } -finish: #ifdef CONFIG_DRM_AMD_DC_HDCP if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) { if (adev->dm.hdcp_workqueue) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index fb7b56fa2673..87daa78a32b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -24,7 +24,6 @@ */ #include -#include #include "dc.h" #include "amdgpu.h" @@ -1192,14 +1191,12 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, struct drm_connector *connector = &aconnector->base; struct dc_link *link = NULL; struct drm_device *dev = connector->dev; - struct drm_modeset_acquire_ctx ctx; enum dc_connection_type new_connection_type = dc_connection_none; char *wr_buf = NULL; uint32_t wr_buf_size = 42; int max_param_num = 1; long param[1] = {0}; uint8_t param_nums = 0; - int ret; if (!aconnector || !aconnector->dc_link) return -EINVAL; @@ -1239,6 +1236,12 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, goto unlock; amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_hotplug_event(dev); } else if (param[0] == 0) { if (!aconnector->dc_link) goto unlock; @@ -1256,19 +1259,13 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, amdgpu_dm_update_connector_after_detect(aconnector); - } else { - goto unlock; + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_hotplug_event(dev); } - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - dm_restore_drm_connector_state(dev, connector); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (ret) - return ret; - - drm_kms_helper_hotplug_event(dev); - unlock: mutex_unlock(&aconnector->hpd_lock); From 1f9e2f442151b07c5a1fb135db60450f9785ab62 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:29 -0400 Subject: [PATCH 232/554] Revert "drm/gma500: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 4f9e860e6ad65ff4ea8ce165a1407d96ff1b2211. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-3-sean@poorly.run --- drivers/gpu/drm/gma500/psb_device.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 021a7238508f..3030f18ba022 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -8,7 +8,6 @@ #include #include -#include #include "gma_device.h" #include "intel_bios.h" @@ -170,10 +169,8 @@ static int psb_save_display_registers(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; struct gma_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; - int ret; /* Display arbitration control + watermarks */ regs->saveDSPARB = PSB_RVDC32(DSPARB); @@ -186,7 +183,7 @@ static int psb_save_display_registers(struct drm_device *dev) regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); /* Save crtc and output state */ - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) dev_priv->ops->save_crtc(crtc); @@ -196,9 +193,8 @@ static int psb_save_display_registers(struct drm_device *dev) if (connector->save) connector->save(&connector->base); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - return ret; + drm_modeset_unlock_all(dev); + return 0; } /** @@ -211,10 +207,8 @@ static int psb_restore_display_registers(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; struct gma_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; - int ret; /* Display arbitration + watermarks */ PSB_WVDC32(regs->saveDSPARB, DSPARB); @@ -229,7 +223,7 @@ static int psb_restore_display_registers(struct drm_device *dev) /*make sure VGA plane is off. it initializes to on after reset!*/ PSB_WVDC32(0x80000000, VGACNTRL); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (drm_helper_crtc_in_use(crtc)) dev_priv->ops->restore_crtc(crtc); @@ -238,8 +232,8 @@ static int psb_restore_display_registers(struct drm_device *dev) if (connector->restore) connector->restore(&connector->base); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - return ret; + drm_modeset_unlock_all(dev); + return 0; } static int psb_power_down(struct drm_device *dev) From 91a8fb071f7eb09374c60d15e7d1bb0b1c1d1afc Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:30 -0400 Subject: [PATCH 233/554] Revert "drm/i915: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN() part 2" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 984c9949f1c4cf36c35aa2de5ee2b65c39379fd9. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-4-sean@poorly.run --- drivers/gpu/drm/i915/display/intel_overlay.c | 42 ++++++++++---------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index c623738c59c8..c0ee135e5499 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -1105,7 +1105,6 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, struct drm_crtc *drmmode_crtc; struct intel_crtc *crtc; struct drm_i915_gem_object *new_bo; - struct drm_modeset_acquire_ctx ctx; int ret; overlay = dev_priv->overlay; @@ -1114,25 +1113,25 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, return -ENODEV; } - if (params->flags & I915_OVERLAY_ENABLE) { - - drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id); - if (!drmmode_crtc) - return -ENOENT; - crtc = to_intel_crtc(drmmode_crtc); - - new_bo = i915_gem_object_lookup(file_priv, params->bo_handle); - if (!new_bo) - return -ENOENT; - } - - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - if (!(params->flags & I915_OVERLAY_ENABLE)) { + drm_modeset_lock_all(dev); ret = intel_overlay_switch_off(overlay); - goto out_unlock; + drm_modeset_unlock_all(dev); + + return ret; } + drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id); + if (!drmmode_crtc) + return -ENOENT; + crtc = to_intel_crtc(drmmode_crtc); + + new_bo = i915_gem_object_lookup(file_priv, params->bo_handle); + if (!new_bo) + return -ENOENT; + + drm_modeset_lock_all(dev); + if (i915_gem_object_is_tiled(new_bo)) { drm_dbg_kms(&dev_priv->drm, "buffer used for overlay image can not be tiled\n"); @@ -1196,11 +1195,14 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, if (ret != 0) goto out_unlock; -out_unlock: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); + i915_gem_object_put(new_bo); - if (params->flags & I915_OVERLAY_ENABLE) - i915_gem_object_put(new_bo); + return 0; + +out_unlock: + drm_modeset_unlock_all(dev); + i915_gem_object_put(new_bo); return ret; } From 077b3191461c4029e9bd6fbb3769fef0a9633e5f Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:31 -0400 Subject: [PATCH 234/554] Revert "drm/i915: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 746826bcf8fdf682668ff1c415d6b91dbf5858be. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-5-sean@poorly.run --- drivers/gpu/drm/i915/display/intel_audio.c | 16 +++---- drivers/gpu/drm/i915/display/intel_display.c | 5 +- .../drm/i915/display/intel_display_debugfs.c | 46 +++++++------------ drivers/gpu/drm/i915/display/intel_overlay.c | 6 +-- drivers/gpu/drm/i915/display/intel_pipe_crc.c | 7 +-- drivers/gpu/drm/i915/i915_drv.c | 13 ++---- 6 files changed, 32 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index c64f738cc062..532237588511 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -26,7 +26,6 @@ #include #include -#include #include "i915_drv.h" #include "intel_atomic.h" @@ -1215,8 +1214,7 @@ static int i915_audio_component_bind(struct device *i915_kdev, { struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); - struct drm_modeset_acquire_ctx ctx; - int i, ret; + int i; if (drm_WARN_ON(&dev_priv->drm, acomp->base.ops || acomp->base.dev)) return -EEXIST; @@ -1226,16 +1224,16 @@ static int i915_audio_component_bind(struct device *i915_kdev, DL_FLAG_STATELESS))) return -ENOMEM; - DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); + drm_modeset_lock_all(&dev_priv->drm); acomp->base.ops = &i915_audio_component_ops; acomp->base.dev = i915_kdev; BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS); for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++) acomp->aud_sample_rate[i] = 0; dev_priv->audio_component = acomp; - DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); + drm_modeset_unlock_all(&dev_priv->drm); - return ret; + return 0; } static void i915_audio_component_unbind(struct device *i915_kdev, @@ -1243,14 +1241,12 @@ static void i915_audio_component_unbind(struct device *i915_kdev, { struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); + drm_modeset_lock_all(&dev_priv->drm); acomp->base.ops = NULL; acomp->base.dev = NULL; dev_priv->audio_component = NULL; - DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); + drm_modeset_unlock_all(&dev_priv->drm); device_link_remove(hda_kdev, i915_kdev); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 297359411c5f..2bf01416d656 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12512,7 +12512,6 @@ cleanup_bios: int intel_modeset_init_nogem(struct drm_i915_private *i915) { struct drm_device *dev = &i915->drm; - struct drm_modeset_acquire_ctx ctx; enum pipe pipe; struct intel_crtc *crtc; int ret; @@ -12564,9 +12563,9 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) intel_vga_disable(i915); intel_setup_outputs(i915); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, dev->mode_config.acquire_ctx); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { struct intel_initial_plane_config plane_config = {}; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index e0a6837996e7..8fdacb252bb1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -5,7 +5,6 @@ #include #include -#include #include "i915_debugfs.h" #include "intel_display_debugfs.h" @@ -1058,13 +1057,11 @@ static int i915_display_info(struct seq_file *m, void *unused) struct intel_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - struct drm_modeset_acquire_ctx ctx; intel_wakeref_t wakeref; - int ret; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); seq_printf(m, "CRTC info\n"); seq_printf(m, "---------\n"); @@ -1079,21 +1076,20 @@ static int i915_display_info(struct seq_file *m, void *unused) intel_connector_info(m, connector); drm_connector_list_iter_end(&conn_iter); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - return ret; + return 0; } static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; - int i, ret; + int i; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); seq_printf(m, "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n", dev_priv->dpll.ref_clks.nssc, @@ -1136,9 +1132,9 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, " mg_pll_tdc_coldst_bias: 0x%08x\n", pll->state.hw_state.mg_pll_tdc_coldst_bias); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); - return ret; + return 0; } static int i915_ipc_status_show(struct seq_file *m, void *data) @@ -1197,15 +1193,13 @@ static int i915_ddb_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; struct skl_ddb_entry *entry; struct intel_crtc *crtc; - int ret; if (DISPLAY_VER(dev_priv) < 9) return -ENODEV; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size"); @@ -1229,9 +1223,9 @@ static int i915_ddb_info(struct seq_file *m, void *unused) entry->end, skl_ddb_entry_size(entry)); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); - return ret; + return 0; } static void drrs_status_per_crtc(struct seq_file *m, @@ -1309,12 +1303,10 @@ static int i915_drrs_status(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; struct intel_crtc *crtc; int active_crtc_cnt = 0; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for_each_intel_crtc(dev, crtc) { if (crtc->base.state->active) { active_crtc_cnt++; @@ -1323,7 +1315,7 @@ static int i915_drrs_status(struct seq_file *m, void *unused) drrs_status_per_crtc(m, dev, crtc); } } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); if (!active_crtc_cnt) seq_puts(m, "No active crtc found\n"); @@ -1615,10 +1607,8 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) { struct drm_i915_private *dev_priv = m->private; struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; int level; int num_levels; - int ret; if (IS_CHERRYVIEW(dev_priv)) num_levels = 3; @@ -1629,7 +1619,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) else num_levels = ilk_wm_max_level(dev_priv) + 1; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for (level = 0; level < num_levels; level++) { unsigned int latency = wm[level]; @@ -1650,7 +1640,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) level, wm[level], latency / 10, latency % 10); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } static int pri_wm_latency_show(struct seq_file *m, void *data) @@ -1734,7 +1724,6 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, struct seq_file *m = file->private_data; struct drm_i915_private *dev_priv = m->private; struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; u16 new[8] = { 0 }; int num_levels; int level; @@ -1764,15 +1753,12 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, if (ret != num_levels) return -EINVAL; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for (level = 0; level < num_levels; level++) wm[level] = new[level]; - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (ret) - return ret; + drm_modeset_unlock_all(dev); return len; } diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index c0ee135e5499..7e3f5c6ca484 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -27,7 +27,6 @@ */ #include -#include #include "gem/i915_gem_pm.h" #include "gt/intel_gpu_commands.h" @@ -1264,7 +1263,6 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, { struct drm_intel_overlay_attrs *attrs = data; struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_modeset_acquire_ctx ctx; struct intel_overlay *overlay; int ret; @@ -1274,7 +1272,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, return -ENODEV; } - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); ret = -EINVAL; if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { @@ -1331,7 +1329,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, ret = 0; out_unlock: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c index d0bc74904b93..8ac263f471be 100644 --- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c @@ -29,8 +29,6 @@ #include #include -#include - #include "intel_atomic.h" #include "intel_de.h" #include "intel_display_types.h" @@ -78,7 +76,6 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, enum intel_pipe_crc_source *source) { struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; struct intel_crtc *crtc; struct intel_digital_port *dig_port; @@ -86,7 +83,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, *source = INTEL_PIPE_CRC_SOURCE_PIPE; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for_each_intel_encoder(dev, encoder) { if (!encoder->base.crtc) continue; @@ -123,7 +120,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, break; } } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e7b763ca6d10..59fb4c710c8c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -44,7 +44,6 @@ #include #include #include -#include #include "display/intel_acpi.h" #include "display/intel_bw.h" @@ -1010,35 +1009,31 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) static void intel_suspend_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; - int ret; if (!HAS_DISPLAY(dev_priv)) return; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for_each_intel_encoder(dev, encoder) if (encoder->suspend) encoder->suspend(encoder); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; - struct drm_modeset_acquire_ctx ctx; struct intel_encoder *encoder; - int ret; if (!HAS_DISPLAY(dev_priv)) return; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); for_each_intel_encoder(dev, encoder) if (encoder->shutdown) encoder->shutdown(encoder); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } void i915_driver_shutdown(struct drm_i915_private *i915) From fcae996e56cbbad714bde11fc2963e2bb7b74364 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:32 -0400 Subject: [PATCH 235/554] Revert "drm/msm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fd49ef52e2db015ce69ad02bab0702489d141a41. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-6-sean@poorly.run --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b89687074890..768012243b44 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "dpu_kms.h" #include "dpu_hw_lm.h" @@ -1173,15 +1172,14 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) struct drm_display_mode *mode; struct drm_framebuffer *fb; struct drm_plane_state *state; - struct drm_modeset_acquire_ctx ctx; struct dpu_crtc_state *cstate; - int i, out_width, ret; + int i, out_width; dpu_crtc = s->private; crtc = &dpu_crtc->base; - DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret); + drm_modeset_lock_all(crtc->dev); cstate = to_dpu_crtc_state(crtc->state); mode = &crtc->state->adjusted_mode; @@ -1265,9 +1263,9 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) dpu_crtc->vblank_cb_time = ktime_set(0, 0); } - DRM_MODESET_LOCK_ALL_END(crtc->dev, ctx, ret); + drm_modeset_unlock_all(crtc->dev); - return ret; + return 0; } DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); From 7a154d5bbcd725e80f45266e05ce8b010aec086a Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:33 -0400 Subject: [PATCH 236/554] Revert "drm/nouveau: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6aa2daae589b63e8b39fe6f7f2b59fb3063efa05. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-7-sean@poorly.run --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 86e18a844953..d7b9f7f8c9e3 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -42,7 +42,6 @@ #include #include #include -#include #include @@ -668,18 +667,16 @@ nv50_audio_component_bind(struct device *kdev, struct device *hda_kdev, struct drm_device *drm_dev = dev_get_drvdata(kdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct drm_audio_component *acomp = data; - struct drm_modeset_acquire_ctx ctx; - int ret; if (WARN_ON(!device_link_add(hda_kdev, kdev, DL_FLAG_STATELESS))) return -ENOMEM; - DRM_MODESET_LOCK_ALL_BEGIN(drm_dev, ctx, 0, ret); + drm_modeset_lock_all(drm_dev); acomp->ops = &nv50_audio_component_ops; acomp->dev = kdev; drm->audio.component = acomp; - DRM_MODESET_LOCK_ALL_END(drm_dev, ctx, ret); - return ret; + drm_modeset_unlock_all(drm_dev); + return 0; } static void @@ -689,14 +686,12 @@ nv50_audio_component_unbind(struct device *kdev, struct device *hda_kdev, struct drm_device *drm_dev = dev_get_drvdata(kdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct drm_audio_component *acomp = data; - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(drm_dev, ctx, 0, ret); + drm_modeset_lock_all(drm_dev); drm->audio.component = NULL; acomp->ops = NULL; acomp->dev = NULL; - DRM_MODESET_LOCK_ALL_END(drm_dev, ctx, ret); + drm_modeset_unlock_all(drm_dev); } static const struct component_ops nv50_audio_component_bind_ops = { From ff6c898f2e73a68626ded79bd4a831f5a25b7598 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:34 -0400 Subject: [PATCH 237/554] Revert "drm/omapdrm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6067fddc1a4fdf155787ab6182c192e4b360b73c. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-8-sean@poorly.run --- drivers/gpu/drm/omapdrm/omap_fb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index fa7636c13c19..190afc564914 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -9,7 +9,6 @@ #include #include #include -#include #include "omap_dmm_tiler.h" #include "omap_drv.h" @@ -63,17 +62,15 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb, unsigned num_clips) { struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, 0, ret); + drm_modeset_lock_all(fb->dev); drm_for_each_crtc(crtc, fb->dev) omap_crtc_flush(crtc); - DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret); + drm_modeset_unlock_all(fb->dev); - return ret; + return 0; } static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { From d91a342eb6310a1a35f07eb4440c484fbd43b16b Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:35 -0400 Subject: [PATCH 238/554] Revert "drm/radeon: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 26723c3d6b930775f9a85521d09655c533a839e6. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-9-sean@poorly.run --- drivers/gpu/drm/radeon/radeon_device.c | 21 ++++++--------------- drivers/gpu/drm/radeon/radeon_dp_mst.c | 10 ++++------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7e31e5ce7f61..4f0fbf667431 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -1560,8 +1559,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, struct pci_dev *pdev; struct drm_crtc *crtc; struct drm_connector *connector; - struct drm_modeset_acquire_ctx ctx; - int i, r, ret; + int i, r; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1575,15 +1573,12 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, drm_kms_helper_poll_disable(dev); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (ret) - return ret; + drm_modeset_unlock_all(dev); /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1668,8 +1663,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) struct radeon_device *rdev = dev->dev_private; struct pci_dev *pdev = to_pci_dev(dev->dev); struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; - int r, ret; + int r; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -1747,14 +1741,11 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) if (fbcon) { drm_helper_resume_force_mode(dev); /* turn on display hw */ - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - - if (ret) - return ret; + drm_modeset_unlock_all(dev); } drm_kms_helper_poll_enable(dev); diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 3f83ee75b100..ec867fa880a4 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "atom.h" #include "ni_reg.h" @@ -738,12 +737,11 @@ static int radeon_debugfs_mst_info_show(struct seq_file *m, void *unused) struct radeon_device *rdev = (struct radeon_device *)m->private; struct drm_device *dev = rdev->ddev; struct drm_connector *connector; - struct drm_modeset_acquire_ctx ctx; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; - int i, ret; + int i; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) continue; @@ -761,8 +759,8 @@ static int radeon_debugfs_mst_info_show(struct seq_file *m, void *unused) radeon_connector->cur_stream_attribs[i].fe, radeon_connector->cur_stream_attribs[i].slots); } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); - return ret; + drm_modeset_unlock_all(dev); + return 0; } DEFINE_SHOW_ATTRIBUTE(radeon_debugfs_mst_info); From 03b476fa45956f0429e6cf6aa2770f7bb6f15de2 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:36 -0400 Subject: [PATCH 239/554] Revert "drm/shmobile: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9b8c437ef1a5f34686fc96b391c201a80f1a2ea0. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-10-sean@poorly.run --- drivers/gpu/drm/shmobile/shmob_drm_drv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 8ee215ab614e..7db01904d18d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -156,12 +156,10 @@ static int shmob_drm_pm_suspend(struct device *dev) static int shmob_drm_pm_resume(struct device *dev) { struct shmob_drm_device *sdev = dev_get_drvdata(dev); - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(sdev->ddev, ctx, 0, ret); + drm_modeset_lock_all(sdev->ddev); shmob_drm_crtc_resume(&sdev->crtc); - DRM_MODESET_LOCK_ALL_END(sdev->ddev, ctx, ret); + drm_modeset_unlock_all(sdev->ddev); drm_kms_helper_poll_enable(sdev->ddev); return 0; From 86e7786e97c84d75b06ed6ff7f773d3b7bdd3447 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:37 -0400 Subject: [PATCH 240/554] Revert "drm/tegra: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a2cd9947d99b54c959fce20dc19d81af53f4674e. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-11-sean@poorly.run --- drivers/gpu/drm/tegra/dsi.c | 6 ++---- drivers/gpu/drm/tegra/hdmi.c | 6 ++---- drivers/gpu/drm/tegra/sor.c | 11 ++++------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 28050c188c1c..f46d377f0c30 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "dc.h" #include "drm.h" @@ -203,11 +202,10 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data) struct tegra_dsi *dsi = node->info_ent->data; struct drm_crtc *crtc = dsi->output.encoder.crtc; struct drm_device *drm = node->minor->dev; - struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); + drm_modeset_lock_all(drm); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -222,7 +220,7 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data) } unlock: - DRM_MODESET_LOCK_ALL_END(drm, ctx, err); + drm_modeset_unlock_all(drm); return err; } diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index a62de7f92414..e5d2a4026028 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "hda.h" #include "hdmi.h" @@ -1032,11 +1031,10 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) struct tegra_hdmi *hdmi = node->info_ent->data; struct drm_crtc *crtc = hdmi->output.encoder.crtc; struct drm_device *drm = node->minor->dev; - struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); + drm_modeset_lock_all(drm); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1051,7 +1049,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) } unlock: - DRM_MODESET_LOCK_ALL_END(drm, ctx, err); + drm_modeset_unlock_all(drm); return err; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 3d1c8b3d1358..0ea320c1092b 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "dc.h" #include "dp.h" @@ -1491,11 +1490,10 @@ static int tegra_sor_show_crc(struct seq_file *s, void *data) struct tegra_sor *sor = node->info_ent->data; struct drm_crtc *crtc = sor->output.encoder.crtc; struct drm_device *drm = node->minor->dev; - struct drm_modeset_acquire_ctx ctx; int err = 0; u32 value; - DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); + drm_modeset_lock_all(drm); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1524,7 +1522,7 @@ static int tegra_sor_show_crc(struct seq_file *s, void *data) seq_printf(s, "%08x\n", value); unlock: - DRM_MODESET_LOCK_ALL_END(drm, ctx, err); + drm_modeset_unlock_all(drm); return err; } @@ -1654,11 +1652,10 @@ static int tegra_sor_show_regs(struct seq_file *s, void *data) struct tegra_sor *sor = node->info_ent->data; struct drm_crtc *crtc = sor->output.encoder.crtc; struct drm_device *drm = node->minor->dev; - struct drm_modeset_acquire_ctx ctx; unsigned int i; int err = 0; - DRM_MODESET_LOCK_ALL_BEGIN(drm, ctx, 0, err); + drm_modeset_lock_all(drm); if (!crtc || !crtc->state->active) { err = -EBUSY; @@ -1673,7 +1670,7 @@ static int tegra_sor_show_regs(struct seq_file *s, void *data) } unlock: - DRM_MODESET_LOCK_ALL_END(drm, ctx, err); + drm_modeset_unlock_all(drm); return err; } From e7b481857bcadfd2bc17eb8610ab4bf113be8662 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:38 -0400 Subject: [PATCH 241/554] Revert "drm/vmwgfx: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6b92e77156c5adf6606c8ad825c71404417d88af. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-12-sean@poorly.run --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 11 ++++------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 ++++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 7df35c6f1458..28af34ab6ed6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -28,7 +28,6 @@ #include "vmwgfx_drv.h" #include "vmwgfx_devcaps.h" #include -#include #include "vmwgfx_kms.h" int vmw_getparam_ioctl(struct drm_device *dev, void *data, @@ -173,7 +172,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; - struct drm_modeset_acquire_ctx ctx; struct vmw_framebuffer *vfb; struct vmw_resource *res; uint32_t num_clips; @@ -205,7 +203,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); if (!fb) { @@ -233,7 +231,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, out_no_surface: drm_framebuffer_put(fb); out_no_fb: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: @@ -252,7 +250,6 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; - struct drm_modeset_acquire_ctx ctx; struct vmw_framebuffer *vfb; uint32_t num_clips; int ret; @@ -283,7 +280,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id); if (!fb) { @@ -306,7 +303,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, out_no_ttm_lock: drm_framebuffer_put(fb); out_no_fb: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 268095cb8c84..74fa41909213 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "vmwgfx_kms.h" @@ -244,17 +243,15 @@ void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv) struct drm_device *dev = &dev_priv->drm; struct vmw_display_unit *du; struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); drm_for_each_crtc(crtc, dev) { du = vmw_crtc_to_du(crtc); du->hotspot_x = 0; du->hotspot_y = 0; } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) @@ -1015,10 +1012,9 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); struct drm_clip_rect norect; - struct drm_modeset_acquire_ctx ctx; int ret, increment = 1; - DRM_MODESET_LOCK_ALL_BEGIN((&dev_priv->drm), ctx, 0, ret); + drm_modeset_lock_all(&dev_priv->drm); if (!num_clips) { num_clips = 1; @@ -1044,7 +1040,7 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, vmw_cmd_flush(dev_priv, false); - DRM_MODESET_LOCK_ALL_END((&dev_priv->drm), ctx, ret); + drm_modeset_unlock_all(&dev_priv->drm); return ret; } From 76fd2c379e654aaa6ab3435a5c6bdd7dc4c1d28c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:39 -0400 Subject: [PATCH 242/554] Revert "drm: cleanup: drm_modeset_lock_all() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7c5f2eecc21f44fba1b1f13ce09c2533db9d781a. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-13-sean@poorly.run --- drivers/gpu/drm/drm_client_modeset.c | 5 ++--- drivers/gpu/drm/drm_crtc_helper.c | 18 ++++++------------ drivers/gpu/drm/drm_fb_helper.c | 10 ++++------ drivers/gpu/drm/drm_framebuffer.c | 6 ++---- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 43f772543d2a..5f5184f071ed 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -1062,10 +1062,9 @@ static int drm_client_modeset_commit_legacy(struct drm_client_dev *client) struct drm_device *dev = client->dev; struct drm_mode_set *mode_set; struct drm_plane *plane; - struct drm_modeset_acquire_ctx ctx; int ret = 0; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -1094,7 +1093,7 @@ static int drm_client_modeset_commit_legacy(struct drm_client_dev *client) goto out; } out: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f3ce073dff79..bff917531f33 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -218,14 +218,11 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) */ void drm_helper_disable_unused_functions(struct drm_device *dev) { - struct drm_modeset_acquire_ctx ctx; - int ret; - WARN_ON(drm_drv_uses_atomic_modeset(dev)); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); __drm_helper_disable_unused_functions(dev); - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_helper_disable_unused_functions); @@ -945,14 +942,12 @@ void drm_helper_resume_force_mode(struct drm_device *dev) struct drm_crtc *crtc; struct drm_encoder *encoder; const struct drm_crtc_helper_funcs *crtc_funcs; - struct drm_modeset_acquire_ctx ctx; int encoder_dpms; bool ret; - int err; WARN_ON(drm_drv_uses_atomic_modeset(dev)); - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); + drm_modeset_lock_all(dev); drm_for_each_crtc(crtc, dev) { if (!crtc->enabled) @@ -987,7 +982,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) /* disable the unused connectors while restoring the modesetting */ __drm_helper_disable_unused_functions(dev); - DRM_MODESET_LOCK_ALL_END(dev, ctx, err); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_helper_resume_force_mode); @@ -1007,10 +1002,9 @@ EXPORT_SYMBOL(drm_helper_resume_force_mode); int drm_helper_force_disable_all(struct drm_device *dev) { struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; int ret = 0; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); drm_for_each_crtc(crtc, dev) if (crtc->enabled) { struct drm_mode_set set = { @@ -1022,7 +1016,7 @@ int drm_helper_force_disable_all(struct drm_device *dev) goto out; } out: - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); return ret; } EXPORT_SYMBOL(drm_helper_force_disable_all); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 6860223f0068..3ab078321045 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -940,11 +940,10 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_mode_set *modeset; struct drm_crtc *crtc; - struct drm_modeset_acquire_ctx ctx; u16 *r, *g, *b; int ret = 0; - DRM_MODESET_LOCK_ALL_BEGIN(fb_helper->dev, ctx, 0, ret); + drm_modeset_lock_all(fb_helper->dev); drm_client_for_each_modeset(modeset, &fb_helper->client) { crtc = modeset->crtc; if (!crtc->funcs->gamma_set || !crtc->gamma_size) { @@ -971,7 +970,7 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) goto out; } out: - DRM_MODESET_LOCK_ALL_END(fb_helper->dev, ctx, ret); + drm_modeset_unlock_all(fb_helper->dev); return ret; } @@ -1442,11 +1441,10 @@ static int pan_display_legacy(struct fb_var_screeninfo *var, struct drm_fb_helper *fb_helper = info->par; struct drm_client_dev *client = &fb_helper->client; struct drm_mode_set *modeset; - struct drm_modeset_acquire_ctx ctx; int ret = 0; mutex_lock(&client->modeset_mutex); - DRM_MODESET_LOCK_ALL_BEGIN(fb_helper->dev, ctx, 0, ret); + drm_modeset_lock_all(fb_helper->dev); drm_client_for_each_modeset(modeset, client) { modeset->x = var->xoffset; modeset->y = var->yoffset; @@ -1459,7 +1457,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var, } } } - DRM_MODESET_LOCK_ALL_END(fb_helper->dev, ctx, ret); + drm_modeset_unlock_all(fb_helper->dev); mutex_unlock(&client->modeset_mutex); return ret; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 205e9aa9a409..07f5abc875e9 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -1059,10 +1059,8 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) struct drm_device *dev = fb->dev; struct drm_crtc *crtc; struct drm_plane *plane; - struct drm_modeset_acquire_ctx ctx; - int ret; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_lock_all(dev); /* remove from any CRTC */ drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { @@ -1084,7 +1082,7 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) drm_plane_force_disable(plane); } } - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_unlock_all(dev); } /** From f505495d246a3c733f973d60c98f754890ddb962 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:40 -0400 Subject: [PATCH 243/554] Revert "drm/msm: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 4c048437ef7adb2d81fe4ddc5c04179126eefcf2. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-14-sean@poorly.run --- drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index abda52f09b09..cabe15190ec1 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -5,8 +5,6 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include - #include "msm_disp_snapshot.h" static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr) @@ -101,18 +99,20 @@ static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state) { struct drm_device *ddev; struct drm_modeset_acquire_ctx ctx; - int ret; disp_state->timestamp = ktime_get(); ddev = disp_state->drm_dev; - DRM_MODESET_LOCK_ALL_BEGIN(ddev, ctx, 0, ret); + drm_modeset_acquire_init(&ctx, 0); + + while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0) + drm_modeset_backoff(&ctx); disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev, &ctx); - - DRM_MODESET_LOCK_ALL_END(ddev, ctx, ret); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); } void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state) From 369de54eecd1127cb512975cc91b95c0fecd2cad Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:41 -0400 Subject: [PATCH 244/554] Revert "drm/i915: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 399190e70816886e2bca1f3f3bc3d9c544af88e7. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-15-sean@poorly.run --- drivers/gpu/drm/i915/display/intel_display.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 2bf01416d656..134a6acbd8fb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -43,7 +43,6 @@ #include #include #include -#include #include "display/intel_audio.h" #include "display/intel_crt.h" @@ -13477,13 +13476,22 @@ void intel_display_resume(struct drm_device *dev) if (state) state->acquire_ctx = &ctx; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + drm_modeset_acquire_init(&ctx, 0); - ret = __intel_display_resume(dev, state, &ctx); + while (1) { + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + if (!ret) + ret = __intel_display_resume(dev, state, &ctx); intel_enable_ipc(dev_priv); - - DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); if (ret) drm_err(&dev_priv->drm, From 61bae132030af4e9aaebe801e547da4a41803d3c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Sat, 2 Oct 2021 11:45:42 -0400 Subject: [PATCH 245/554] Revert "drm: cleanup: drm_modeset_lock_all_ctx() --> DRM_MODESET_LOCK_ALL_BEGIN()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 21dde40902d2636f70766b3154931de57e1215e9. This patchset breaks on intel platforms and was previously NACK'd by Ville. Cc: Ville Syrjälä Cc: Fernando Ramos Acked-by: Ville Syrjälä Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211002154542.15800-16-sean@poorly.run --- drivers/gpu/drm/drm_client_modeset.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 5f5184f071ed..ced09c7c06f9 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -574,7 +574,6 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, int num_connectors_detected = 0; int num_tiled_conns = 0; struct drm_modeset_acquire_ctx ctx; - int err; if (!drm_drv_uses_atomic_modeset(dev)) return false; @@ -586,7 +585,10 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, if (!save_enabled) return false; - DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); + drm_modeset_acquire_init(&ctx, 0); + + while (drm_modeset_lock_all_ctx(dev, &ctx) != 0) + drm_modeset_backoff(&ctx); memcpy(save_enabled, enabled, count); mask = GENMASK(count - 1, 0); @@ -741,7 +743,8 @@ bail: ret = false; } - DRM_MODESET_LOCK_ALL_END(dev, ctx, err); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); kfree(save_enabled); return ret; From 288f1068975583bc63e68a61731453b0f07a46af Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:36 -0700 Subject: [PATCH 246/554] drm/i915/pxp: Define PXP component interface This will be used for communication between the i915 driver and the mei one. Defining it in a stand-alone patch to avoid circualr dependedencies between the patches modifying the 2 drivers. Split out from an original patch from Huang, Sean Z v2: rename the component struct (Rodrigo) Signed-off-by: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-2-alan.previn.teres.alexis@intel.com --- include/drm/i915_component.h | 1 + include/drm/i915_pxp_tee_interface.h | 42 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 include/drm/i915_pxp_tee_interface.h diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index 55c3b123581b..c1e2a43d2d1e 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -29,6 +29,7 @@ enum i915_component_type { I915_COMPONENT_AUDIO = 1, I915_COMPONENT_HDCP, + I915_COMPONENT_PXP }; /* MAX_PORT is the number of port diff --git a/include/drm/i915_pxp_tee_interface.h b/include/drm/i915_pxp_tee_interface.h new file mode 100644 index 000000000000..af593ec64469 --- /dev/null +++ b/include/drm/i915_pxp_tee_interface.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#ifndef _I915_PXP_TEE_INTERFACE_H_ +#define _I915_PXP_TEE_INTERFACE_H_ + +#include +#include + +/** + * struct i915_pxp_component_ops - ops for PXP services. + * @owner: Module providing the ops + * @send: sends data to PXP + * @receive: receives data from PXP + */ +struct i915_pxp_component_ops { + /** + * @owner: owner of the module provding the ops + */ + struct module *owner; + + int (*send)(struct device *dev, const void *message, size_t size); + int (*recv)(struct device *dev, void *buffer, size_t size); +}; + +/** + * struct i915_pxp_component - Used for communication between i915 and TEE + * drivers for the PXP services + * @tee_dev: device that provide the PXP service from TEE Bus. + * @pxp_ops: Ops implemented by TEE driver, used by i915 driver. + */ +struct i915_pxp_component { + struct device *tee_dev; + const struct i915_pxp_component_ops *ops; + + /* To protect the above members. */ + struct mutex mutex; +}; + +#endif /* _I915_TEE_PXP_INTERFACE_H_ */ From c2004ce99ed73788755d61b7b691ff072fdada20 Mon Sep 17 00:00:00 2001 From: Vitaly Lubart Date: Fri, 24 Sep 2021 12:14:37 -0700 Subject: [PATCH 247/554] mei: pxp: export pavp client to me client bus Export PAVP client to work with i915 driver, for binding it uses kernel component framework. v2:drop debug prints, refactor match code to match mei_hdcp (Tomas) Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-3-alan.previn.teres.alexis@intel.com --- drivers/misc/mei/Kconfig | 2 + drivers/misc/mei/Makefile | 1 + drivers/misc/mei/pxp/Kconfig | 13 ++ drivers/misc/mei/pxp/Makefile | 7 + drivers/misc/mei/pxp/mei_pxp.c | 229 +++++++++++++++++++++++++++++++++ drivers/misc/mei/pxp/mei_pxp.h | 18 +++ 6 files changed, 270 insertions(+) create mode 100644 drivers/misc/mei/pxp/Kconfig create mode 100644 drivers/misc/mei/pxp/Makefile create mode 100644 drivers/misc/mei/pxp/mei_pxp.c create mode 100644 drivers/misc/mei/pxp/mei_pxp.h diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index f5fd5b786607..0e0bcd0da852 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -47,3 +47,5 @@ config INTEL_MEI_TXE Intel Bay Trail source "drivers/misc/mei/hdcp/Kconfig" +source "drivers/misc/mei/pxp/Kconfig" + diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index f1c76f7ee804..d8e5165917f2 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -26,3 +26,4 @@ mei-$(CONFIG_EVENT_TRACING) += mei-trace.o CFLAGS_mei-trace.o = -I$(src) obj-$(CONFIG_INTEL_MEI_HDCP) += hdcp/ +obj-$(CONFIG_INTEL_MEI_PXP) += pxp/ diff --git a/drivers/misc/mei/pxp/Kconfig b/drivers/misc/mei/pxp/Kconfig new file mode 100644 index 000000000000..4029b96afc04 --- /dev/null +++ b/drivers/misc/mei/pxp/Kconfig @@ -0,0 +1,13 @@ + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2020, Intel Corporation. All rights reserved. +# +config INTEL_MEI_PXP + tristate "Intel PXP services of ME Interface" + select INTEL_MEI_ME + depends on DRM_I915 + help + MEI Support for PXP Services on Intel platforms. + + Enables the ME FW services required for PXP support through + I915 display driver of Intel. diff --git a/drivers/misc/mei/pxp/Makefile b/drivers/misc/mei/pxp/Makefile new file mode 100644 index 000000000000..0329950d5794 --- /dev/null +++ b/drivers/misc/mei/pxp/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2020, Intel Corporation. All rights reserved. +# +# Makefile - PXP client driver for Intel MEI Bus Driver. + +obj-$(CONFIG_INTEL_MEI_PXP) += mei_pxp.o diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c new file mode 100644 index 000000000000..f7380d387bab --- /dev/null +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2020 - 2021 Intel Corporation + */ + +/** + * DOC: MEI_PXP Client Driver + * + * The mei_pxp driver acts as a translation layer between PXP + * protocol implementer (I915) and ME FW by translating PXP + * negotiation messages to ME FW command payloads and vice versa. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mei_pxp.h" + +/** + * mei_pxp_send_message() - Sends a PXP message to ME FW. + * @dev: device corresponding to the mei_cl_device + * @message: a message buffer to send + * @size: size of the message + * Return: 0 on Success, <0 on Failure + */ +static int +mei_pxp_send_message(struct device *dev, const void *message, size_t size) +{ + struct mei_cl_device *cldev; + ssize_t byte; + + if (!dev || !message) + return -EINVAL; + + cldev = to_mei_cl_device(dev); + + /* temporary drop const qualifier till the API is fixed */ + byte = mei_cldev_send(cldev, (u8 *)message, size); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + return 0; +} + +/** + * mei_pxp_receive_message() - Receives a PXP message from ME FW. + * @dev: device corresponding to the mei_cl_device + * @buffer: a message buffer to contain the received message + * @size: size of the buffer + * Return: bytes sent on Success, <0 on Failure + */ +static int +mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) +{ + struct mei_cl_device *cldev; + ssize_t byte; + + if (!dev || !buffer) + return -EINVAL; + + cldev = to_mei_cl_device(dev); + + byte = mei_cldev_recv(cldev, buffer, size); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + return byte; +} + +static const struct i915_pxp_component_ops mei_pxp_ops = { + .owner = THIS_MODULE, + .send = mei_pxp_send_message, + .recv = mei_pxp_receive_message, +}; + +static int mei_component_master_bind(struct device *dev) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev); + int ret; + + comp_master->ops = &mei_pxp_ops; + comp_master->tee_dev = dev; + ret = component_bind_all(dev, comp_master); + if (ret < 0) + return ret; + + return 0; +} + +static void mei_component_master_unbind(struct device *dev) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev); + + component_unbind_all(dev, comp_master); +} + +static const struct component_master_ops mei_component_master_ops = { + .bind = mei_component_master_bind, + .unbind = mei_component_master_unbind, +}; + +/** + * mei_pxp_component_match - compare function for matching mei pxp. + * + * The function checks if the driver is i915, the subcomponent is PXP + * and the grand parent of pxp and the parent of i915 are the same + * PCH device. + * + * @dev: master device + * @subcomponent: subcomponent to match (I915_COMPONENT_PXP) + * @data: compare data (mei pxp device) + * + * Return: + * * 1 - if components match + * * 0 - otherwise + */ +static int mei_pxp_component_match(struct device *dev, int subcomponent, + void *data) +{ + struct device *base = data; + + if (strcmp(dev->driver->name, "i915") || + subcomponent != I915_COMPONENT_PXP) + return 0; + + base = base->parent; + if (!base) + return 0; + + base = base->parent; + dev = dev->parent; + + return (base && dev && dev == base); +} + +static int mei_pxp_probe(struct mei_cl_device *cldev, + const struct mei_cl_device_id *id) +{ + struct i915_pxp_component *comp_master; + struct component_match *master_match; + int ret; + + ret = mei_cldev_enable(cldev); + if (ret < 0) { + dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); + goto enable_err_exit; + } + + comp_master = kzalloc(sizeof(*comp_master), GFP_KERNEL); + if (!comp_master) { + ret = -ENOMEM; + goto err_exit; + } + + master_match = NULL; + component_match_add_typed(&cldev->dev, &master_match, + mei_pxp_component_match, &cldev->dev); + if (IS_ERR_OR_NULL(master_match)) { + ret = -ENOMEM; + goto err_exit; + } + + mei_cldev_set_drvdata(cldev, comp_master); + ret = component_master_add_with_match(&cldev->dev, + &mei_component_master_ops, + master_match); + if (ret < 0) { + dev_err(&cldev->dev, "Master comp add failed %d\n", ret); + goto err_exit; + } + + return 0; + +err_exit: + mei_cldev_set_drvdata(cldev, NULL); + kfree(comp_master); + mei_cldev_disable(cldev); +enable_err_exit: + return ret; +} + +static void mei_pxp_remove(struct mei_cl_device *cldev) +{ + struct i915_pxp_component *comp_master = mei_cldev_get_drvdata(cldev); + int ret; + + component_master_del(&cldev->dev, &mei_component_master_ops); + kfree(comp_master); + mei_cldev_set_drvdata(cldev, NULL); + + ret = mei_cldev_disable(cldev); + if (ret) + dev_warn(&cldev->dev, "mei_cldev_disable() failed\n"); +} + +/* fbf6fcf1-96cf-4e2e-a6a6-1bab8cbe36b1 : PAVP GUID*/ +#define MEI_GUID_PXP GUID_INIT(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \ + 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1) + +static struct mei_cl_device_id mei_pxp_tbl[] = { + { .uuid = MEI_GUID_PXP, .version = MEI_CL_VERSION_ANY }, + { } +}; +MODULE_DEVICE_TABLE(mei, mei_pxp_tbl); + +static struct mei_cl_driver mei_pxp_driver = { + .id_table = mei_pxp_tbl, + .name = KBUILD_MODNAME, + .probe = mei_pxp_probe, + .remove = mei_pxp_remove, +}; + +module_mei_cl_driver(mei_pxp_driver); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MEI PXP"); diff --git a/drivers/misc/mei/pxp/mei_pxp.h b/drivers/misc/mei/pxp/mei_pxp.h new file mode 100644 index 000000000000..e7b15373fefd --- /dev/null +++ b/drivers/misc/mei/pxp/mei_pxp.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright © 2020 Intel Corporation + * + * Authors: + * Vitaly Lubart + */ + +#ifndef __MEI_PXP_H__ +#define __MEI_PXP_H__ + +/* me_pxp_status: Enumeration of all PXP Status Codes */ +enum me_pxp_status { + ME_PXP_STATUS_SUCCESS = 0x0000, + +}; + +#endif /* __MEI_PXP_H__ */ From e6aa71361bb9a40cb69376657afbbe32aa777d2a Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:38 -0700 Subject: [PATCH 248/554] drm/i915/pxp: define PXP device flag and kconfig Ahead of the PXP implementation, define the relevant define flag and kconfig option. v2: flip kconfig default to N. Some machines have IFWIs that do not support PXP, so we need it to be an opt-in until we add support to query the caps from the mei device. v10: change comments from "Gen12+" to "Gen12 and newer" Signed-off-by: Alan Previn Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-4-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Kconfig | 11 +++++++++++ drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_device_info.h | 1 + 3 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index f960f5d7664e..8859444943a0 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -131,6 +131,17 @@ config DRM_I915_GVT_KVMGT Choose this option if you want to enable KVMGT support for Intel GVT-g. +config DRM_I915_PXP + bool "Enable Intel PXP support for Intel Gen12 and newer platform" + depends on DRM_I915 + depends on INTEL_MEI && INTEL_MEI_PXP + default n + help + PXP (Protected Xe Path) is an i915 component, available on GEN12 and + newer GPUs, that helps to establish the hardware protected session and + manage the status of the alive software session, as well as its life + cycle. + menu "drm/i915 Debugging" depends on DRM_I915 depends on EXPERT diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 93d13aba6a85..357faa043b3a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1700,6 +1700,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_GLOBAL_MOCS_REGISTERS(dev_priv) (INTEL_INFO(dev_priv)->has_global_mocs) +#define HAS_PXP(dev_priv) ((IS_ENABLED(CONFIG_DRM_I915_PXP) && \ + INTEL_INFO(dev_priv)->has_pxp) && \ + VDBOX_MASK(&dev_priv->gt)) #define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch) diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index d328bb95c49b..8e6f48d1eb7b 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -133,6 +133,7 @@ enum intel_ppgtt_type { func(has_logical_ring_elsq); \ func(has_mslices); \ func(has_pooled_eu); \ + func(has_pxp); \ func(has_rc6); \ func(has_rc6p); \ func(has_rps); \ From 3ad2dd9c4caa7330dd08244e94bec49a62fee6e4 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:39 -0700 Subject: [PATCH 249/554] drm/i915/pxp: allocate a vcs context for pxp usage The context is required to send the session termination commands to the VCS, which will be implemented in a follow-up patch. We can also use the presence of the context as a check of pxp initialization completion. v2: use perma-pinned context (Chris) v3: rename pinned_context functions (Chris) v4: split export of pinned_context functions to a separate patch (Rodrigo) v10: remove inclusion of intel_gt_types.h from intel_pxp.h (Jani) v13: fixed for loop pointer dereference (Vinay) Signed-off-by: Alan Previn Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-5-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 4 ++ drivers/gpu/drm/i915/gt/intel_engine.h | 2 + drivers/gpu/drm/i915/gt/intel_gt.c | 5 ++ drivers/gpu/drm/i915/gt/intel_gt_types.h | 3 + drivers/gpu/drm/i915/pxp/intel_pxp.c | 70 ++++++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp.h | 30 ++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 17 ++++++ 7 files changed, 131 insertions(+) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp.h create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_types.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3b9a60adfe57..d480c9d3ef8c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -278,6 +278,10 @@ i915-y += \ i915-y += i915_perf.o +# Protected execution platform (PXP) support +i915-$(CONFIG_DRM_I915_PXP) += \ + pxp/intel_pxp.o + # Post-mortem debug and GPU hang state capture i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o i915-$(CONFIG_DRM_I915_SELFTEST) += \ diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 87579affb952..eed4634c08cd 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -175,6 +175,8 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value) #define I915_GEM_HWS_SEQNO 0x40 #define I915_GEM_HWS_SEQNO_ADDR (I915_GEM_HWS_SEQNO * sizeof(u32)) #define I915_GEM_HWS_MIGRATE (0x42 * sizeof(u32)) +#define I915_GEM_HWS_PXP 0x60 +#define I915_GEM_HWS_PXP_ADDR (I915_GEM_HWS_PXP * sizeof(u32)) #define I915_GEM_HWS_SCRATCH 0x80 #define I915_HWS_CSB_BUF0_INDEX 0x10 diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 5b3acf2b064e..1cb1948ac959 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -21,6 +21,7 @@ #include "intel_rps.h" #include "intel_uncore.h" #include "shmem_utils.h" +#include "pxp/intel_pxp.h" void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915) { @@ -714,6 +715,8 @@ int intel_gt_init(struct intel_gt *gt) intel_migrate_init(>->migrate, gt); + intel_pxp_init(>->pxp); + goto out_fw; err_gt: __intel_gt_disable(gt); @@ -751,6 +754,8 @@ void intel_gt_driver_unregister(struct intel_gt *gt) intel_rps_driver_unregister(>->rps); + intel_pxp_fini(>->pxp); + /* * Upon unregistering the device to prevent any new users, cancel * all in-flight requests so that we can quickly unbind the active diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 9f711ee0d42c..14216cc471b1 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -26,6 +26,7 @@ #include "intel_rps_types.h" #include "intel_migrate_types.h" #include "intel_wakeref.h" +#include "pxp/intel_pxp_types.h" struct drm_i915_private; struct i915_ggtt; @@ -201,6 +202,8 @@ struct intel_gt { struct { u8 uc_index; } mocs; + + struct intel_pxp pxp; }; enum intel_gt_scratch_field { diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c new file mode 100644 index 000000000000..9258e0ddd0d5 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020 Intel Corporation. + */ +#include "intel_pxp.h" +#include "gt/intel_context.h" +#include "i915_drv.h" + +struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp) +{ + return container_of(pxp, struct intel_gt, pxp); +} + +static int create_vcs_context(struct intel_pxp *pxp) +{ + static struct lock_class_key pxp_lock; + struct intel_gt *gt = pxp_to_gt(pxp); + struct intel_engine_cs *engine; + struct intel_context *ce; + int i; + + /* + * Find the first VCS engine present. We're guaranteed there is one + * if we're in this function due to the check in has_pxp + */ + for (i = 0, engine = NULL; !engine; i++) + engine = gt->engine_class[VIDEO_DECODE_CLASS][i]; + + GEM_BUG_ON(!engine || engine->class != VIDEO_DECODE_CLASS); + + ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K, + I915_GEM_HWS_PXP_ADDR, + &pxp_lock, "pxp_context"); + if (IS_ERR(ce)) { + drm_err(>->i915->drm, "failed to create VCS ctx for PXP\n"); + return PTR_ERR(ce); + } + + pxp->ce = ce; + + return 0; +} + +static void destroy_vcs_context(struct intel_pxp *pxp) +{ + intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce)); +} + +void intel_pxp_init(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + int ret; + + if (!HAS_PXP(gt->i915)) + return; + + ret = create_vcs_context(pxp); + if (ret) + return; + + drm_info(>->i915->drm, "Protected Xe Path (PXP) protected content support initialized\n"); +} + +void intel_pxp_fini(struct intel_pxp *pxp) +{ + if (!intel_pxp_is_enabled(pxp)) + return; + + destroy_vcs_context(pxp); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h new file mode 100644 index 000000000000..73acd879f2fb --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_H__ +#define __INTEL_PXP_H__ + +#include "intel_pxp_types.h" + +static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp) +{ + return pxp->ce; +} + +#ifdef CONFIG_DRM_I915_PXP +struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp); +void intel_pxp_init(struct intel_pxp *pxp); +void intel_pxp_fini(struct intel_pxp *pxp); +#else +static inline void intel_pxp_init(struct intel_pxp *pxp) +{ +} + +static inline void intel_pxp_fini(struct intel_pxp *pxp) +{ +} +#endif + +#endif /* __INTEL_PXP_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h new file mode 100644 index 000000000000..db98df723dbb --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_TYPES_H__ +#define __INTEL_PXP_TYPES_H__ + +#include + +struct intel_context; + +struct intel_pxp { + struct intel_context *ce; +}; + +#endif /* __INTEL_PXP_TYPES_H__ */ From 0436ac1b008d48613af26da7053573086827613b Mon Sep 17 00:00:00 2001 From: "Huang, Sean Z" Date: Fri, 24 Sep 2021 12:14:40 -0700 Subject: [PATCH 250/554] drm/i915/pxp: Implement funcs to create the TEE channel Implement the funcs to create the TEE channel, so kernel can send the TEE commands directly to TEE for creating the arbitrary (default) session. v2: fix locking, don't pollute dev_priv (Chris) v3: wait for mei PXP component to be bound. v4: drop the wait, as the component might be bound after i915 load completes. We'll instead check when sending a tee message. v5: fix an issue with mei_pxp module removal v6: don't use fetch_and_zero in fini (Rodrigo) Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-6-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/pxp/intel_pxp.c | 13 ++++ drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 79 ++++++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_tee.h | 14 ++++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 4 ++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_tee.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_tee.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d480c9d3ef8c..d790b603fbdd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -280,7 +280,8 @@ i915-y += i915_perf.o # Protected execution platform (PXP) support i915-$(CONFIG_DRM_I915_PXP) += \ - pxp/intel_pxp.o + pxp/intel_pxp.o \ + pxp/intel_pxp_tee.o # Post-mortem debug and GPU hang state capture i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 9258e0ddd0d5..14ab7c97800e 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -3,6 +3,7 @@ * Copyright(c) 2020 Intel Corporation. */ #include "intel_pxp.h" +#include "intel_pxp_tee.h" #include "gt/intel_context.h" #include "i915_drv.h" @@ -58,7 +59,16 @@ void intel_pxp_init(struct intel_pxp *pxp) if (ret) return; + ret = intel_pxp_tee_component_init(pxp); + if (ret) + goto out_context; + drm_info(>->i915->drm, "Protected Xe Path (PXP) protected content support initialized\n"); + + return; + +out_context: + destroy_vcs_context(pxp); } void intel_pxp_fini(struct intel_pxp *pxp) @@ -66,5 +76,8 @@ void intel_pxp_fini(struct intel_pxp *pxp) if (!intel_pxp_is_enabled(pxp)) return; + intel_pxp_tee_component_fini(pxp); + destroy_vcs_context(pxp); + } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c new file mode 100644 index 000000000000..f1d8de832653 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020 Intel Corporation. + */ + +#include +#include "drm/i915_pxp_tee_interface.h" +#include "drm/i915_component.h" +#include "i915_drv.h" +#include "intel_pxp.h" +#include "intel_pxp_tee.h" + +static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev) +{ + return &kdev_to_i915(i915_kdev)->gt.pxp; +} + +/** + * i915_pxp_tee_component_bind - bind function to pass the function pointers to pxp_tee + * @i915_kdev: pointer to i915 kernel device + * @tee_kdev: pointer to tee kernel device + * @data: pointer to pxp_tee_master containing the function pointers + * + * This bind function is called during the system boot or resume from system sleep. + * + * Return: return 0 if successful. + */ +static int i915_pxp_tee_component_bind(struct device *i915_kdev, + struct device *tee_kdev, void *data) +{ + struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + + pxp->pxp_component = data; + pxp->pxp_component->tee_dev = tee_kdev; + + return 0; +} + +static void i915_pxp_tee_component_unbind(struct device *i915_kdev, + struct device *tee_kdev, void *data) +{ + struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + + pxp->pxp_component = NULL; +} + +static const struct component_ops i915_pxp_tee_component_ops = { + .bind = i915_pxp_tee_component_bind, + .unbind = i915_pxp_tee_component_unbind, +}; + +int intel_pxp_tee_component_init(struct intel_pxp *pxp) +{ + int ret; + struct intel_gt *gt = pxp_to_gt(pxp); + struct drm_i915_private *i915 = gt->i915; + + ret = component_add_typed(i915->drm.dev, &i915_pxp_tee_component_ops, + I915_COMPONENT_PXP); + if (ret < 0) { + drm_err(&i915->drm, "Failed to add PXP component (%d)\n", ret); + return ret; + } + + pxp->pxp_component_added = true; + + return 0; +} + +void intel_pxp_tee_component_fini(struct intel_pxp *pxp) +{ + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + + if (!pxp->pxp_component_added) + return; + + component_del(i915->drm.dev, &i915_pxp_tee_component_ops); + pxp->pxp_component_added = false; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h new file mode 100644 index 000000000000..23d050a5d3e7 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_TEE_H__ +#define __INTEL_PXP_TEE_H__ + +#include "intel_pxp.h" + +int intel_pxp_tee_component_init(struct intel_pxp *pxp); +void intel_pxp_tee_component_fini(struct intel_pxp *pxp); + +#endif /* __INTEL_PXP_TEE_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index db98df723dbb..3a8e17e591bd 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -9,8 +9,12 @@ #include struct intel_context; +struct i915_pxp_component; struct intel_pxp { + struct i915_pxp_component *pxp_component; + bool pxp_component_added; + struct intel_context *ce; }; From e0111ce0f5cbd2428333c3d3cd33ba42f1e148ad Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:41 -0700 Subject: [PATCH 251/554] drm/i915/pxp: set KCR reg init The setting is required by hardware to allow us doing further protection operation such as sending commands to GPU or TEE. The register needs to be re-programmed on resume, so for simplicitly we bundle the programming with the component binding, which is automatically called on resume. Further HW set-up operations will be added in the same location in follow-up patches, so get ready for them by using a couple of init/fini_hw wrappers instead of calling the KCR funcs directly. v3: move programming to component binding function, rework commit msg Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-7-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/pxp/intel_pxp.c | 28 +++++++++++++++++++++++- drivers/gpu/drm/i915/pxp/intel_pxp.h | 3 +++ drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 5 +++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 14ab7c97800e..f7166dd71d8f 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -12,6 +12,23 @@ struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp) return container_of(pxp, struct intel_gt, pxp); } +/* KCR register definitions */ +#define KCR_INIT _MMIO(0x320f0) +/* Setting KCR Init bit is required after system boot */ +#define KCR_INIT_ALLOW_DISPLAY_ME_WRITES REG_BIT(14) + +static void kcr_pxp_enable(struct intel_gt *gt) +{ + intel_uncore_write(gt->uncore, KCR_INIT, + _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES)); +} + +static void kcr_pxp_disable(struct intel_gt *gt) +{ + intel_uncore_write(gt->uncore, KCR_INIT, + _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES)); +} + static int create_vcs_context(struct intel_pxp *pxp) { static struct lock_class_key pxp_lock; @@ -79,5 +96,14 @@ void intel_pxp_fini(struct intel_pxp *pxp) intel_pxp_tee_component_fini(pxp); destroy_vcs_context(pxp); - +} + +void intel_pxp_init_hw(struct intel_pxp *pxp) +{ + kcr_pxp_enable(pxp_to_gt(pxp)); +} + +void intel_pxp_fini_hw(struct intel_pxp *pxp) +{ + kcr_pxp_disable(pxp_to_gt(pxp)); } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 73acd879f2fb..cd6560b2605c 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -17,6 +17,9 @@ static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp) struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp); void intel_pxp_init(struct intel_pxp *pxp); void intel_pxp_fini(struct intel_pxp *pxp); + +void intel_pxp_init_hw(struct intel_pxp *pxp); +void intel_pxp_fini_hw(struct intel_pxp *pxp); #else static inline void intel_pxp_init(struct intel_pxp *pxp) { diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index f1d8de832653..0c0c7946e6a0 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -33,6 +33,9 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, pxp->pxp_component = data; pxp->pxp_component->tee_dev = tee_kdev; + /* the component is required to fully start the PXP HW */ + intel_pxp_init_hw(pxp); + return 0; } @@ -41,6 +44,8 @@ static void i915_pxp_tee_component_unbind(struct device *i915_kdev, { struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + intel_pxp_fini_hw(pxp); + pxp->pxp_component = NULL; } From cbbd3764b2399ad882cda98435b25144e9ea2124 Mon Sep 17 00:00:00 2001 From: "Huang, Sean Z" Date: Fri, 24 Sep 2021 12:14:42 -0700 Subject: [PATCH 252/554] drm/i915/pxp: Create the arbitrary session after boot Create the arbitrary session, with the fixed session id 0xf, after system boot, for the case that application allocates the protected buffer without establishing any protection session. Because the hardware requires at least one alive session for protected buffer creation. This arbitrary session will need to be re-created after teardown or power event because hardware encryption key won't be valid after such cases. The session ID is exposed as part of the uapi so it can be used as part of userspace commands. v2: use gt->uncore->rpm (Chris) v3: s/arb_is_in_play/arb_is_valid (Chris), move set-up to the new init_hw function v4: move interface defs to separate header, set arb_is valid to false on fini (Rodrigo) v5: handle async component binding Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-8-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/pxp/intel_pxp.c | 12 +++ drivers/gpu/drm/i915/pxp/intel_pxp.h | 2 + drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 74 ++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_session.h | 15 ++++ drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 87 +++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_tee.h | 3 + .../drm/i915/pxp/intel_pxp_tee_interface.h | 36 ++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 10 +++ include/uapi/drm/i915_drm.h | 3 + 10 files changed, 243 insertions(+) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_session.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_session.h create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d790b603fbdd..1152348c04a9 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -281,6 +281,7 @@ i915-y += i915_perf.o # Protected execution platform (PXP) support i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp.o \ + pxp/intel_pxp_session.o \ pxp/intel_pxp_tee.o # Post-mortem debug and GPU hang state capture diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index f7166dd71d8f..65598487a7b2 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -3,6 +3,7 @@ * Copyright(c) 2020 Intel Corporation. */ #include "intel_pxp.h" +#include "intel_pxp_session.h" #include "intel_pxp_tee.h" #include "gt/intel_context.h" #include "i915_drv.h" @@ -12,6 +13,11 @@ struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp) return container_of(pxp, struct intel_gt, pxp); } +bool intel_pxp_is_active(const struct intel_pxp *pxp) +{ + return pxp->arb_is_valid; +} + /* KCR register definitions */ #define KCR_INIT _MMIO(0x320f0) /* Setting KCR Init bit is required after system boot */ @@ -72,6 +78,8 @@ void intel_pxp_init(struct intel_pxp *pxp) if (!HAS_PXP(gt->i915)) return; + mutex_init(&pxp->tee_mutex); + ret = create_vcs_context(pxp); if (ret) return; @@ -93,6 +101,8 @@ void intel_pxp_fini(struct intel_pxp *pxp) if (!intel_pxp_is_enabled(pxp)) return; + pxp->arb_is_valid = false; + intel_pxp_tee_component_fini(pxp); destroy_vcs_context(pxp); @@ -101,6 +111,8 @@ void intel_pxp_fini(struct intel_pxp *pxp) void intel_pxp_init_hw(struct intel_pxp *pxp) { kcr_pxp_enable(pxp_to_gt(pxp)); + + intel_pxp_create_arb_session(pxp); } void intel_pxp_fini_hw(struct intel_pxp *pxp) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index cd6560b2605c..2960e8338c82 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -15,6 +15,8 @@ static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp) #ifdef CONFIG_DRM_I915_PXP struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp); +bool intel_pxp_is_active(const struct intel_pxp *pxp); + void intel_pxp_init(struct intel_pxp *pxp); void intel_pxp_fini(struct intel_pxp *pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c new file mode 100644 index 000000000000..3331868f354c --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#include "drm/i915_drm.h" +#include "i915_drv.h" + +#include "intel_pxp.h" +#include "intel_pxp_session.h" +#include "intel_pxp_tee.h" +#include "intel_pxp_types.h" + +#define ARB_SESSION I915_PROTECTED_CONTENT_DEFAULT_SESSION /* shorter define */ + +#define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */ + +static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + intel_wakeref_t wakeref; + u32 sip = 0; + + with_intel_runtime_pm(gt->uncore->rpm, wakeref) + sip = intel_uncore_read(gt->uncore, GEN12_KCR_SIP); + + return sip & BIT(id); +} + +static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + intel_wakeref_t wakeref; + u32 mask = BIT(id); + int ret; + + with_intel_runtime_pm(gt->uncore->rpm, wakeref) + ret = intel_wait_for_register(gt->uncore, + GEN12_KCR_SIP, + mask, + in_play ? mask : 0, + 100); + + return ret; +} + +int intel_pxp_create_arb_session(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + int ret; + + pxp->arb_is_valid = false; + + if (intel_pxp_session_is_in_play(pxp, ARB_SESSION)) { + drm_err(>->i915->drm, "arb session already in play at creation time\n"); + return -EEXIST; + } + + ret = intel_pxp_tee_cmd_create_arb_session(pxp, ARB_SESSION); + if (ret) { + drm_err(>->i915->drm, "tee cmd for arb session creation failed\n"); + return ret; + } + + ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true); + if (ret) { + drm_err(>->i915->drm, "arb session failed to go in play\n"); + return ret; + } + + pxp->arb_is_valid = true; + + return 0; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h new file mode 100644 index 000000000000..316c3bebed9c --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_SESSION_H__ +#define __INTEL_PXP_SESSION_H__ + +#include + +struct intel_pxp; + +int intel_pxp_create_arb_session(struct intel_pxp *pxp); + +#endif /* __INTEL_PXP_SESSION_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 0c0c7946e6a0..accbbf9aa6d1 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -8,13 +8,63 @@ #include "drm/i915_component.h" #include "i915_drv.h" #include "intel_pxp.h" +#include "intel_pxp_session.h" #include "intel_pxp_tee.h" +#include "intel_pxp_tee_interface.h" static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev) { return &kdev_to_i915(i915_kdev)->gt.pxp; } +static int intel_pxp_tee_io_message(struct intel_pxp *pxp, + void *msg_in, u32 msg_in_size, + void *msg_out, u32 msg_out_max_size, + u32 *msg_out_rcv_size) +{ + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + struct i915_pxp_component *pxp_component = pxp->pxp_component; + int ret = 0; + + mutex_lock(&pxp->tee_mutex); + + /* + * The binding of the component is asynchronous from i915 probe, so we + * can't be sure it has happened. + */ + if (!pxp_component) { + ret = -ENODEV; + goto unlock; + } + + ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size); + if (ret) { + drm_err(&i915->drm, "Failed to send PXP TEE message\n"); + goto unlock; + } + + ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size); + if (ret < 0) { + drm_err(&i915->drm, "Failed to receive PXP TEE message\n"); + goto unlock; + } + + if (ret > msg_out_max_size) { + drm_err(&i915->drm, + "Failed to receive PXP TEE message due to unexpected output size\n"); + ret = -ENOSPC; + goto unlock; + } + + if (msg_out_rcv_size) + *msg_out_rcv_size = ret; + + ret = 0; +unlock: + mutex_unlock(&pxp->tee_mutex); + return ret; +} + /** * i915_pxp_tee_component_bind - bind function to pass the function pointers to pxp_tee * @i915_kdev: pointer to i915 kernel device @@ -28,14 +78,24 @@ static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev) static int i915_pxp_tee_component_bind(struct device *i915_kdev, struct device *tee_kdev, void *data) { + struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + mutex_lock(&pxp->tee_mutex); pxp->pxp_component = data; pxp->pxp_component->tee_dev = tee_kdev; + mutex_unlock(&pxp->tee_mutex); /* the component is required to fully start the PXP HW */ intel_pxp_init_hw(pxp); + if (!pxp->arb_is_valid) { + drm_err(&i915->drm, "Failed to create arb session during bind\n"); + intel_pxp_fini_hw(pxp); + pxp->pxp_component = NULL; + return -EIO; + } + return 0; } @@ -46,7 +106,9 @@ static void i915_pxp_tee_component_unbind(struct device *i915_kdev, intel_pxp_fini_hw(pxp); + mutex_lock(&pxp->tee_mutex); pxp->pxp_component = NULL; + mutex_unlock(&pxp->tee_mutex); } static const struct component_ops i915_pxp_tee_component_ops = { @@ -82,3 +144,28 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp) component_del(i915->drm.dev, &i915_pxp_tee_component_ops); pxp->pxp_component_added = false; } + +int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, + int arb_session_id) +{ + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + struct pxp_tee_create_arb_in msg_in = {0}; + struct pxp_tee_create_arb_out msg_out = {0}; + int ret; + + msg_in.header.api_version = PXP_TEE_APIVER; + msg_in.header.command_id = PXP_TEE_ARB_CMDID; + msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header); + msg_in.protection_mode = PXP_TEE_ARB_PROTECTION_MODE; + msg_in.session_id = arb_session_id; + + ret = intel_pxp_tee_io_message(pxp, + &msg_in, sizeof(msg_in), + &msg_out, sizeof(msg_out), + NULL); + + if (ret) + drm_err(&i915->drm, "Failed to send tee msg ret=[%d]\n", ret); + + return ret; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h index 23d050a5d3e7..c136053ce340 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h @@ -11,4 +11,7 @@ int intel_pxp_tee_component_init(struct intel_pxp *pxp); void intel_pxp_tee_component_fini(struct intel_pxp *pxp); +int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, + int arb_session_id); + #endif /* __INTEL_PXP_TEE_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h new file mode 100644 index 000000000000..36e9b0868f5c --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_TEE_INTERFACE_H__ +#define __INTEL_PXP_TEE_INTERFACE_H__ + +#include + +#define PXP_TEE_APIVER 0x40002 +#define PXP_TEE_ARB_CMDID 0x1e +#define PXP_TEE_ARB_PROTECTION_MODE 0x2 + +/* PXP TEE message header */ +struct pxp_tee_cmd_header { + u32 api_version; + u32 command_id; + u32 status; + /* Length of the message (excluding the header) */ + u32 buffer_len; +} __packed; + +/* PXP TEE message input to create a arbitrary session */ +struct pxp_tee_create_arb_in { + struct pxp_tee_cmd_header header; + u32 protection_mode; + u32 session_id; +} __packed; + +/* PXP TEE message output to create a arbitrary session */ +struct pxp_tee_create_arb_out { + struct pxp_tee_cmd_header header; +} __packed; + +#endif /* __INTEL_PXP_TEE_INTERFACE_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 3a8e17e591bd..d393e46a7d98 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -6,6 +6,7 @@ #ifndef __INTEL_PXP_TYPES_H__ #define __INTEL_PXP_TYPES_H__ +#include #include struct intel_context; @@ -16,6 +17,15 @@ struct intel_pxp { bool pxp_component_added; struct intel_context *ce; + + /* + * After a teardown, the arb session can still be in play on the HW + * even if the keys are gone, so we can't rely on the HW state of the + * session to know if it's valid and need to track the status in SW. + */ + bool arb_is_valid; + + struct mutex tee_mutex; /* protects the tee channel binding */ }; #endif /* __INTEL_PXP_TYPES_H__ */ diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index bde5860b3686..920e9e852e5a 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -3038,6 +3038,9 @@ struct drm_i915_gem_create_ext_memory_regions { __u64 regions; }; +/* ID of the protected content session managed by i915 when PXP is active */ +#define I915_PROTECTED_CONTENT_DEFAULT_SESSION 0xf + #if defined(__cplusplus) } #endif From 95c9e1224da36711a1fc49e243c949a93108e72d Mon Sep 17 00:00:00 2001 From: "Huang, Sean Z" Date: Fri, 24 Sep 2021 12:14:43 -0700 Subject: [PATCH 253/554] drm/i915/pxp: Implement arb session teardown Teardown is triggered when the display topology changes and no long meets the secure playback requirement, and hardware trashes all the encryption keys for display. Additionally, we want to emit a teardown operation to make sure we're clean on boot and resume v2: emit in the ring, use high prio request (Chris) v3: better defines, stalling flush, cleaned up and renamed submission funcs (Chris) v12: fix uninitialized variable bug Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-9-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/gt/intel_gpu_commands.h | 22 ++- drivers/gpu/drm/i915/pxp/intel_pxp.c | 7 +- drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c | 141 +++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h | 15 ++ drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 29 ++++ drivers/gpu/drm/i915/pxp/intel_pxp_session.h | 1 + 7 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 1152348c04a9..e318153d1efa 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -281,6 +281,7 @@ i915-y += i915_perf.o # Protected execution platform (PXP) support i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp.o \ + pxp/intel_pxp_cmd.o \ pxp/intel_pxp_session.o \ pxp/intel_pxp_tee.o diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h index 1c3af0fc0456..f8253012d166 100644 --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h @@ -28,10 +28,13 @@ #define INSTR_26_TO_24_MASK 0x7000000 #define INSTR_26_TO_24_SHIFT 24 +#define __INSTR(client) ((client) << INSTR_CLIENT_SHIFT) + /* * Memory interface instructions used by the kernel */ -#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) +#define MI_INSTR(opcode, flags) \ + (__INSTR(INSTR_MI_CLIENT) | (opcode) << 23 | (flags)) /* Many MI commands use bit 22 of the header dword for GGTT vs PPGTT */ #define MI_GLOBAL_GTT (1<<22) @@ -57,6 +60,7 @@ #define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) #define MI_SUSPEND_FLUSH_EN (1<<0) #define MI_SET_APPID MI_INSTR(0x0e, 0) +#define MI_SET_APPID_SESSION_ID(x) ((x) << 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) #define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_ON (0x1<<21) @@ -146,6 +150,7 @@ #define MI_STORE_REGISTER_MEM_GEN8 MI_INSTR(0x24, 2) #define MI_SRM_LRM_GLOBAL_GTT (1<<22) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ +#define MI_FLUSH_DW_PROTECTED_MEM_EN (1 << 22) #define MI_FLUSH_DW_STORE_INDEX (1<<21) #define MI_INVALIDATE_TLB (1<<18) #define MI_FLUSH_DW_OP_STOREDW (1<<14) @@ -272,6 +277,19 @@ #define MI_MATH_REG_ZF 0x32 #define MI_MATH_REG_CF 0x33 +/* + * Media instructions used by the kernel + */ +#define MEDIA_INSTR(pipe, op, sub_op, flags) \ + (__INSTR(INSTR_RC_CLIENT) | (pipe) << INSTR_SUBCLIENT_SHIFT | \ + (op) << INSTR_26_TO_24_SHIFT | (sub_op) << 16 | (flags)) + +#define MFX_WAIT MEDIA_INSTR(1, 0, 0, 0) +#define MFX_WAIT_DW0_MFX_SYNC_CONTROL_FLAG REG_BIT(8) +#define MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG REG_BIT(9) + +#define CRYPTO_KEY_EXCHANGE MEDIA_INSTR(2, 6, 9, 0) + /* * Commands used only by the command parser */ @@ -328,8 +346,6 @@ #define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS \ ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x47<<16)) -#define MFX_WAIT ((0x3<<29)|(0x1<<27)|(0x0<<16)) - #define COLOR_BLT ((0x2<<29)|(0x40<<22)) #define SRC_COPY_BLT ((0x2<<29)|(0x43<<22)) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 65598487a7b2..6afa87f90eef 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -110,9 +110,14 @@ void intel_pxp_fini(struct intel_pxp *pxp) void intel_pxp_init_hw(struct intel_pxp *pxp) { + int ret; + kcr_pxp_enable(pxp_to_gt(pxp)); - intel_pxp_create_arb_session(pxp); + /* always emit a full termination to clean the state */ + ret = intel_pxp_terminate_arb_session_and_global(pxp); + if (!ret) + intel_pxp_create_arb_session(pxp); } void intel_pxp_fini_hw(struct intel_pxp *pxp) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c new file mode 100644 index 000000000000..f41e45763d0d --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#include "intel_pxp.h" +#include "intel_pxp_cmd.h" +#include "intel_pxp_session.h" +#include "gt/intel_context.h" +#include "gt/intel_engine_pm.h" +#include "gt/intel_gpu_commands.h" +#include "gt/intel_ring.h" + +#include "i915_trace.h" + +/* stall until prior PXP and MFX/HCP/HUC objects are cmopleted */ +#define MFX_WAIT_PXP (MFX_WAIT | \ + MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG | \ + MFX_WAIT_DW0_MFX_SYNC_CONTROL_FLAG) + +static u32 *pxp_emit_session_selection(u32 *cs, u32 idx) +{ + *cs++ = MFX_WAIT_PXP; + + /* pxp off */ + *cs++ = MI_FLUSH_DW; + *cs++ = 0; + *cs++ = 0; + + /* select session */ + *cs++ = MI_SET_APPID | MI_SET_APPID_SESSION_ID(idx); + + *cs++ = MFX_WAIT_PXP; + + /* pxp on */ + *cs++ = MI_FLUSH_DW | MI_FLUSH_DW_PROTECTED_MEM_EN | + MI_FLUSH_DW_OP_STOREDW | MI_FLUSH_DW_STORE_INDEX; + *cs++ = I915_GEM_HWS_PXP_ADDR | MI_FLUSH_DW_USE_GTT; + *cs++ = 0; + + *cs++ = MFX_WAIT_PXP; + + return cs; +} + +static u32 *pxp_emit_inline_termination(u32 *cs) +{ + /* session inline termination */ + *cs++ = CRYPTO_KEY_EXCHANGE; + *cs++ = 0; + + return cs; +} + +static u32 *pxp_emit_session_termination(u32 *cs, u32 idx) +{ + cs = pxp_emit_session_selection(cs, idx); + cs = pxp_emit_inline_termination(cs); + + return cs; +} + +static u32 *pxp_emit_wait(u32 *cs) +{ + /* wait for cmds to go through */ + *cs++ = MFX_WAIT_PXP; + *cs++ = 0; + + return cs; +} + +/* + * if we ever need to terminate more than one session, we can submit multiple + * selections and terminations back-to-back with a single wait at the end + */ +#define SELECTION_LEN 10 +#define TERMINATION_LEN 2 +#define SESSION_TERMINATION_LEN(x) ((SELECTION_LEN + TERMINATION_LEN) * (x)) +#define WAIT_LEN 2 + +static void pxp_request_commit(struct i915_request *rq) +{ + struct i915_sched_attr attr = { .priority = I915_PRIORITY_MAX }; + struct intel_timeline * const tl = i915_request_timeline(rq); + + lockdep_unpin_lock(&tl->mutex, rq->cookie); + + trace_i915_request_add(rq); + __i915_request_commit(rq); + __i915_request_queue(rq, &attr); + + mutex_unlock(&tl->mutex); +} + +int intel_pxp_terminate_session(struct intel_pxp *pxp, u32 id) +{ + struct i915_request *rq; + struct intel_context *ce = pxp->ce; + u32 *cs; + int err = 0; + + if (!intel_pxp_is_enabled(pxp)) + return 0; + + rq = i915_request_create(ce); + if (IS_ERR(rq)) + return PTR_ERR(rq); + + if (ce->engine->emit_init_breadcrumb) { + err = ce->engine->emit_init_breadcrumb(rq); + if (err) + goto out_rq; + } + + cs = intel_ring_begin(rq, SESSION_TERMINATION_LEN(1) + WAIT_LEN); + if (IS_ERR(cs)) { + err = PTR_ERR(cs); + goto out_rq; + } + + cs = pxp_emit_session_termination(cs, id); + cs = pxp_emit_wait(cs); + + intel_ring_advance(rq, cs); + +out_rq: + i915_request_get(rq); + + if (unlikely(err)) + i915_request_set_error_once(rq, err); + + pxp_request_commit(rq); + + if (!err && i915_request_wait(rq, 0, HZ / 5) < 0) + err = -ETIME; + + i915_request_put(rq); + + return err; +} + diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h new file mode 100644 index 000000000000..6d6299543578 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_CMD_H__ +#define __INTEL_PXP_CMD_H__ + +#include + +struct intel_pxp; + +int intel_pxp_terminate_session(struct intel_pxp *pxp, u32 idx); + +#endif /* __INTEL_PXP_CMD_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 3331868f354c..b8e24adeb1f3 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -7,6 +7,7 @@ #include "i915_drv.h" #include "intel_pxp.h" +#include "intel_pxp_cmd.h" #include "intel_pxp_session.h" #include "intel_pxp_tee.h" #include "intel_pxp_types.h" @@ -15,6 +16,9 @@ #define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */ +/* PXP global terminate register for session termination */ +#define PXP_GLOBAL_TERMINATE _MMIO(0x320f8) + static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id) { struct intel_gt *gt = pxp_to_gt(pxp); @@ -72,3 +76,28 @@ int intel_pxp_create_arb_session(struct intel_pxp *pxp) return 0; } + +int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) +{ + int ret; + struct intel_gt *gt = pxp_to_gt(pxp); + + pxp->arb_is_valid = false; + + /* terminate the hw sessions */ + ret = intel_pxp_terminate_session(pxp, ARB_SESSION); + if (ret) { + drm_err(>->i915->drm, "Failed to submit session termination\n"); + return ret; + } + + ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false); + if (ret) { + drm_err(>->i915->drm, "Session state did not clear\n"); + return ret; + } + + intel_uncore_write(gt->uncore, PXP_GLOBAL_TERMINATE, 1); + + return ret; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h index 316c3bebed9c..7354314b1cc4 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h @@ -11,5 +11,6 @@ struct intel_pxp; int intel_pxp_create_arb_session(struct intel_pxp *pxp); +int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp); #endif /* __INTEL_PXP_SESSION_H__ */ From 2ae096872a2c61da476fb072348ef8f07ea54c9b Mon Sep 17 00:00:00 2001 From: "Huang, Sean Z" Date: Fri, 24 Sep 2021 12:14:44 -0700 Subject: [PATCH 254/554] drm/i915/pxp: Implement PXP irq handler The HW will generate a teardown interrupt when session termination is required, which requires i915 to submit a terminating batch. Once the HW is done with the termination it will generate another interrupt, at which point it is safe to re-create the session. Since the termination and re-creation flow is something we want to trigger from the driver as well, use a common work function that can be called both from the irq handler and from the driver set-up flows, which has the addded benefit of allowing us to skip any extra locks because the work itself serializes the operations. v2: use struct completion instead of bool (Chris) v3: drop locks, clean up functions and improve comments (Chris), move to common work function. v4: improve comments, simplify wait logic (Rodrigo) v5: unconditionally set interrupts, rename state_attacked var (Rodrigo) v10: remove inclusion of intel_gt_types.h from intel_pxp.h (Jani) Signed-off-by: Alan Previn Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-10-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/gt/intel_gt_irq.c | 7 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/pxp/intel_pxp.c | 66 ++++++++++-- drivers/gpu/drm/i915/pxp/intel_pxp.h | 8 ++ drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 100 +++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_irq.h | 32 ++++++ drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 54 +++++++++- drivers/gpu/drm/i915/pxp/intel_pxp_session.h | 5 +- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 8 +- drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 18 ++++ 11 files changed, 284 insertions(+), 16 deletions(-) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_irq.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_irq.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e318153d1efa..5363d3b3fda7 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -282,6 +282,7 @@ i915-y += i915_perf.o i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp.o \ pxp/intel_pxp_cmd.o \ + pxp/intel_pxp_irq.o \ pxp/intel_pxp_session.o \ pxp/intel_pxp_tee.o diff --git a/drivers/gpu/drm/i915/gt/intel_gt_irq.c b/drivers/gpu/drm/i915/gt/intel_gt_irq.c index b2de83be4d97..699a74582d32 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_irq.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_irq.c @@ -13,6 +13,7 @@ #include "intel_lrc_reg.h" #include "intel_uncore.h" #include "intel_rps.h" +#include "pxp/intel_pxp_irq.h" static void guc_irq_handler(struct intel_guc *guc, u16 iir) { @@ -64,6 +65,9 @@ gen11_other_irq_handler(struct intel_gt *gt, const u8 instance, if (instance == OTHER_GTPM_INSTANCE) return gen11_rps_irq_handler(>->rps, iir); + if (instance == OTHER_KCR_INSTANCE) + return intel_pxp_irq_handler(>->pxp, iir); + WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n", instance, iir); } @@ -196,6 +200,9 @@ void gen11_gt_irq_reset(struct intel_gt *gt) intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK, ~0); intel_uncore_write(uncore, GEN11_GUC_SG_INTR_ENABLE, 0); intel_uncore_write(uncore, GEN11_GUC_SG_INTR_MASK, ~0); + + intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, 0); + intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~0); } void gen11_gt_irq_postinstall(struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 64d795461fc5..e2647c02a4d2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8124,6 +8124,7 @@ enum { /* irq instances for OTHER_CLASS */ #define OTHER_GUC_INSTANCE 0 #define OTHER_GTPM_INSTANCE 1 +#define OTHER_KCR_INSTANCE 4 #define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4)) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 6afa87f90eef..2e188217c3b7 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -2,7 +2,9 @@ /* * Copyright(c) 2020 Intel Corporation. */ +#include #include "intel_pxp.h" +#include "intel_pxp_irq.h" #include "intel_pxp_session.h" #include "intel_pxp_tee.h" #include "gt/intel_context.h" @@ -80,6 +82,16 @@ void intel_pxp_init(struct intel_pxp *pxp) mutex_init(&pxp->tee_mutex); + /* + * we'll use the completion to check if there is a termination pending, + * so we start it as completed and we reinit it when a termination + * is triggered. + */ + init_completion(&pxp->termination); + complete_all(&pxp->termination); + + INIT_WORK(&pxp->session_work, intel_pxp_session_work); + ret = create_vcs_context(pxp); if (ret) return; @@ -108,19 +120,61 @@ void intel_pxp_fini(struct intel_pxp *pxp) destroy_vcs_context(pxp); } +void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp) +{ + pxp->arb_is_valid = false; + reinit_completion(&pxp->termination); +} + +static void intel_pxp_queue_termination(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + + /* + * We want to get the same effect as if we received a termination + * interrupt, so just pretend that we did. + */ + spin_lock_irq(>->irq_lock); + intel_pxp_mark_termination_in_progress(pxp); + pxp->session_events |= PXP_TERMINATION_REQUEST; + queue_work(system_unbound_wq, &pxp->session_work); + spin_unlock_irq(>->irq_lock); +} + +/* + * the arb session is restarted from the irq work when we receive the + * termination completion interrupt + */ +int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) +{ + if (!intel_pxp_is_enabled(pxp)) + return 0; + + if (!wait_for_completion_timeout(&pxp->termination, + msecs_to_jiffies(100))) + return -ETIMEDOUT; + + if (!pxp->arb_is_valid) + return -EIO; + + return 0; +} + void intel_pxp_init_hw(struct intel_pxp *pxp) { - int ret; - kcr_pxp_enable(pxp_to_gt(pxp)); + intel_pxp_irq_enable(pxp); - /* always emit a full termination to clean the state */ - ret = intel_pxp_terminate_arb_session_and_global(pxp); - if (!ret) - intel_pxp_create_arb_session(pxp); + /* + * the session could've been attacked while we weren't loaded, so + * handle it as if it was and re-create it. + */ + intel_pxp_queue_termination(pxp); } void intel_pxp_fini_hw(struct intel_pxp *pxp) { kcr_pxp_disable(pxp_to_gt(pxp)); + + intel_pxp_irq_disable(pxp); } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 2960e8338c82..54b268280379 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -22,6 +22,9 @@ void intel_pxp_fini(struct intel_pxp *pxp); void intel_pxp_init_hw(struct intel_pxp *pxp); void intel_pxp_fini_hw(struct intel_pxp *pxp); + +void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp); +int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp); #else static inline void intel_pxp_init(struct intel_pxp *pxp) { @@ -30,6 +33,11 @@ static inline void intel_pxp_init(struct intel_pxp *pxp) static inline void intel_pxp_fini(struct intel_pxp *pxp) { } + +static inline int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) +{ + return -ENODEV; +} #endif #endif /* __INTEL_PXP_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c new file mode 100644 index 000000000000..300cf2b96fda --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020 Intel Corporation. + */ +#include +#include "intel_pxp.h" +#include "intel_pxp_irq.h" +#include "intel_pxp_session.h" +#include "gt/intel_gt_irq.h" +#include "gt/intel_gt_types.h" +#include "i915_irq.h" +#include "i915_reg.h" + +/** + * intel_pxp_irq_handler - Handles PXP interrupts. + * @pxp: pointer to pxp struct + * @iir: interrupt vector + */ +void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + + if (GEM_WARN_ON(!intel_pxp_is_enabled(pxp))) + return; + + lockdep_assert_held(>->irq_lock); + + if (unlikely(!iir)) + return; + + if (iir & (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT | + GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { + /* immediately mark PXP as inactive on termination */ + intel_pxp_mark_termination_in_progress(pxp); + pxp->session_events |= PXP_TERMINATION_REQUEST; + } + + if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) + pxp->session_events |= PXP_TERMINATION_COMPLETE; + + if (pxp->session_events) + queue_work(system_unbound_wq, &pxp->session_work); +} + +static inline void __pxp_set_interrupts(struct intel_gt *gt, u32 interrupts) +{ + struct intel_uncore *uncore = gt->uncore; + const u32 mask = interrupts << 16; + + intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_ENABLE, mask); + intel_uncore_write(uncore, GEN11_CRYPTO_RSVD_INTR_MASK, ~mask); +} + +static inline void pxp_irq_reset(struct intel_gt *gt) +{ + spin_lock_irq(>->irq_lock); + gen11_gt_reset_one_iir(gt, 0, GEN11_KCR); + spin_unlock_irq(>->irq_lock); +} + +void intel_pxp_irq_enable(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + + spin_lock_irq(>->irq_lock); + + if (!pxp->irq_enabled) + WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR)); + + __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS); + pxp->irq_enabled = true; + + spin_unlock_irq(>->irq_lock); +} + +void intel_pxp_irq_disable(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + + /* + * We always need to submit a global termination when we re-enable the + * interrupts, so there is no need to make sure that the session state + * makes sense at the end of this function. Just make sure this is not + * called in a path were the driver consider the session as valid and + * doesn't call a termination on restart. + */ + GEM_WARN_ON(intel_pxp_is_active(pxp)); + + spin_lock_irq(>->irq_lock); + + pxp->irq_enabled = false; + __pxp_set_interrupts(gt, 0); + + spin_unlock_irq(>->irq_lock); + intel_synchronize_irq(gt->i915); + + pxp_irq_reset(gt); + + flush_work(&pxp->session_work); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h new file mode 100644 index 000000000000..8b5793654844 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_IRQ_H__ +#define __INTEL_PXP_IRQ_H__ + +#include + +struct intel_pxp; + +#define GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT BIT(1) +#define GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT BIT(2) +#define GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT BIT(3) + +#define GEN12_PXP_INTERRUPTS \ + (GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT | \ + GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT | \ + GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) + +#ifdef CONFIG_DRM_I915_PXP +void intel_pxp_irq_enable(struct intel_pxp *pxp); +void intel_pxp_irq_disable(struct intel_pxp *pxp); +void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir); +#else +static inline void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) +{ +} +#endif + +#endif /* __INTEL_PXP_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index b8e24adeb1f3..67c30e534d50 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -48,7 +48,7 @@ static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_pla return ret; } -int intel_pxp_create_arb_session(struct intel_pxp *pxp) +static int pxp_create_arb_session(struct intel_pxp *pxp) { struct intel_gt *gt = pxp_to_gt(pxp); int ret; @@ -77,12 +77,13 @@ int intel_pxp_create_arb_session(struct intel_pxp *pxp) return 0; } -int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) +static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) { int ret; struct intel_gt *gt = pxp_to_gt(pxp); - pxp->arb_is_valid = false; + /* must mark termination in progress calling this function */ + GEM_WARN_ON(pxp->arb_is_valid); /* terminate the hw sessions */ ret = intel_pxp_terminate_session(pxp, ARB_SESSION); @@ -101,3 +102,50 @@ int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) return ret; } + +static void pxp_terminate(struct intel_pxp *pxp) +{ + int ret; + + pxp->hw_state_invalidated = true; + + /* + * if we fail to submit the termination there is no point in waiting for + * it to complete. PXP will be marked as non-active until the next + * termination is issued. + */ + ret = pxp_terminate_arb_session_and_global(pxp); + if (ret) + complete_all(&pxp->termination); +} + +static void pxp_terminate_complete(struct intel_pxp *pxp) +{ + /* Re-create the arb session after teardown handle complete */ + if (fetch_and_zero(&pxp->hw_state_invalidated)) + pxp_create_arb_session(pxp); + + complete_all(&pxp->termination); +} + +void intel_pxp_session_work(struct work_struct *work) +{ + struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work); + struct intel_gt *gt = pxp_to_gt(pxp); + u32 events = 0; + + spin_lock_irq(>->irq_lock); + events = fetch_and_zero(&pxp->session_events); + spin_unlock_irq(>->irq_lock); + + if (!events) + return; + + if (events & PXP_TERMINATION_REQUEST) { + events &= ~PXP_TERMINATION_COMPLETE; + pxp_terminate(pxp); + } + + if (events & PXP_TERMINATION_COMPLETE) + pxp_terminate_complete(pxp); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h index 7354314b1cc4..ba4c9d2b94b7 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h @@ -8,9 +8,8 @@ #include -struct intel_pxp; +struct work_struct; -int intel_pxp_create_arb_session(struct intel_pxp *pxp); -int intel_pxp_terminate_arb_session_and_global(struct intel_pxp *pxp); +void intel_pxp_session_work(struct work_struct *work); #endif /* __INTEL_PXP_SESSION_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index accbbf9aa6d1..494bd6b48514 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -80,6 +80,7 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, { struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + int ret; mutex_lock(&pxp->tee_mutex); pxp->pxp_component = data; @@ -88,15 +89,14 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, /* the component is required to fully start the PXP HW */ intel_pxp_init_hw(pxp); - - if (!pxp->arb_is_valid) { + ret = intel_pxp_wait_for_arb_start(pxp); + if (ret) { drm_err(&i915->drm, "Failed to create arb session during bind\n"); intel_pxp_fini_hw(pxp); pxp->pxp_component = NULL; - return -EIO; } - return 0; + return ret; } static void i915_pxp_tee_component_unbind(struct device *i915_kdev, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index d393e46a7d98..5a170e43c959 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -6,8 +6,10 @@ #ifndef __INTEL_PXP_TYPES_H__ #define __INTEL_PXP_TYPES_H__ +#include #include #include +#include struct intel_context; struct i915_pxp_component; @@ -26,6 +28,22 @@ struct intel_pxp { bool arb_is_valid; struct mutex tee_mutex; /* protects the tee channel binding */ + + /* + * If the HW perceives an attack on the integrity of the encryption it + * will invalidate the keys and expect SW to re-initialize the session. + * We keep track of this state to make sure we only re-start the arb + * session when required. + */ + bool hw_state_invalidated; + + bool irq_enabled; + struct completion termination; + + struct work_struct session_work; + u32 session_events; /* protected with gt->irq_lock */ +#define PXP_TERMINATION_REQUEST BIT(0) +#define PXP_TERMINATION_COMPLETE BIT(1) }; #endif /* __INTEL_PXP_TYPES_H__ */ From d3ac8d42168a9be7380be8035df8b6d3780ec2a1 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:45 -0700 Subject: [PATCH 255/554] drm/i915/pxp: interfaces for using protected objects This api allow user mode to create protected buffers and to mark contexts as making use of such objects. Only when using contexts marked in such a way is the execution guaranteed to work as expected. Contexts can only be marked as using protected content at creation time (i.e. the parameter is immutable) and they must be both bannable and not recoverable. Given that the protected session gets invalidated on suspend, contexts created this way hold a runtime pm wakeref until they're either destroyed or invalidated. All protected objects and contexts will be considered invalid when the PXP session is destroyed and all new submissions using them will be rejected. All intel contexts within the invalidated gem contexts will be marked banned. Userspace can detect that an invalidation has occurred via the RESET_STATS ioctl, where we report it the same way as a ban due to a hang. v5: squash patches, rebase on proto_ctx, update kerneldoc v6: rebase on obj create_ext changes v7: Use session counter to check if an object it valid, hold wakeref in context, don't add a new flag to RESET_STATS (Daniel) v8: don't increase guilty count for contexts banned during pxp invalidation (Rodrigo) v9: better comments, avoid wakeref put race between pxp_inval and context_close, add usage examples (Rodrigo) v10: modify internal set/get-protected-context functions to not return -ENODEV when setting PXP param to false or getting param when running on pxp-unsupported hw or getting param when i915 was built with CONFIG_PXP off Signed-off-by: Alan Previn Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Bommu Krishnaiah Cc: Rodrigo Vivi Cc: Chris Wilson Cc: Lionel Landwerlin Cc: Jason Ekstrand Cc: Daniel Vetter Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-11-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 95 ++++++++++++++++--- drivers/gpu/drm/i915/gem/i915_gem_context.h | 6 ++ .../gpu/drm/i915/gem/i915_gem_context_types.h | 28 ++++++ drivers/gpu/drm/i915/gem/i915_gem_create.c | 72 ++++++++++---- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 18 ++++ drivers/gpu/drm/i915/gem/i915_gem_object.c | 1 + drivers/gpu/drm/i915/gem/i915_gem_object.h | 6 ++ .../gpu/drm/i915/gem/i915_gem_object_types.h | 9 +- .../gpu/drm/i915/gem/selftests/mock_context.c | 4 +- drivers/gpu/drm/i915/pxp/intel_pxp.c | 77 +++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp.h | 12 +++ drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 6 ++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 9 ++ include/uapi/drm/i915_drm.h | 94 ++++++++++++++++++ 14 files changed, 402 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 8208fd5b72c3..08360d6bbd1e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -77,6 +77,8 @@ #include "gt/intel_gpu_commands.h" #include "gt/intel_ring.h" +#include "pxp/intel_pxp.h" + #include "i915_gem_context.h" #include "i915_trace.h" #include "i915_user_extensions.h" @@ -186,10 +188,13 @@ static int validate_priority(struct drm_i915_private *i915, return 0; } -static void proto_context_close(struct i915_gem_proto_context *pc) +static void proto_context_close(struct drm_i915_private *i915, + struct i915_gem_proto_context *pc) { int i; + if (pc->pxp_wakeref) + intel_runtime_pm_put(&i915->runtime_pm, pc->pxp_wakeref); if (pc->vm) i915_vm_put(pc->vm); if (pc->user_engines) { @@ -241,6 +246,33 @@ static int proto_context_set_persistence(struct drm_i915_private *i915, return 0; } +static int proto_context_set_protected(struct drm_i915_private *i915, + struct i915_gem_proto_context *pc, + bool protected) +{ + int ret = 0; + + if (!protected) { + pc->uses_protected_content = false; + } else if (!intel_pxp_is_enabled(&i915->gt.pxp)) { + ret = -ENODEV; + } else if ((pc->user_flags & BIT(UCONTEXT_RECOVERABLE)) || + !(pc->user_flags & BIT(UCONTEXT_BANNABLE))) { + ret = -EPERM; + } else { + pc->uses_protected_content = true; + + /* + * protected context usage requires the PXP session to be up, + * which in turn requires the device to be active. + */ + pc->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm); + ret = intel_pxp_wait_for_arb_start(&i915->gt.pxp); + } + + return ret; +} + static struct i915_gem_proto_context * proto_context_create(struct drm_i915_private *i915, unsigned int flags) { @@ -269,7 +301,7 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags) return pc; proto_close: - proto_context_close(pc); + proto_context_close(i915, pc); return err; } @@ -693,6 +725,8 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv, ret = -EPERM; else if (args->value) pc->user_flags |= BIT(UCONTEXT_BANNABLE); + else if (pc->uses_protected_content) + ret = -EPERM; else pc->user_flags &= ~BIT(UCONTEXT_BANNABLE); break; @@ -700,10 +734,12 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv, case I915_CONTEXT_PARAM_RECOVERABLE: if (args->size) ret = -EINVAL; - else if (args->value) - pc->user_flags |= BIT(UCONTEXT_RECOVERABLE); - else + else if (!args->value) pc->user_flags &= ~BIT(UCONTEXT_RECOVERABLE); + else if (pc->uses_protected_content) + ret = -EPERM; + else + pc->user_flags |= BIT(UCONTEXT_RECOVERABLE); break; case I915_CONTEXT_PARAM_PRIORITY: @@ -731,6 +767,11 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv, args->value); break; + case I915_CONTEXT_PARAM_PROTECTED_CONTENT: + ret = proto_context_set_protected(fpriv->dev_priv, pc, + args->value); + break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_RINGSIZE: @@ -956,6 +997,9 @@ static void i915_gem_context_release_work(struct work_struct *work) if (vm) i915_vm_put(vm); + if (ctx->pxp_wakeref) + intel_runtime_pm_put(&ctx->i915->runtime_pm, ctx->pxp_wakeref); + mutex_destroy(&ctx->engines_mutex); mutex_destroy(&ctx->lut_mutex); @@ -1338,6 +1382,11 @@ i915_gem_create_context(struct drm_i915_private *i915, goto err_engines; } + if (pc->uses_protected_content) { + ctx->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm); + ctx->uses_protected_content = true; + } + trace_i915_context_create(ctx); return ctx; @@ -1409,7 +1458,7 @@ int i915_gem_context_open(struct drm_i915_private *i915, } ctx = i915_gem_create_context(i915, pc); - proto_context_close(pc); + proto_context_close(i915, pc); if (IS_ERR(ctx)) { err = PTR_ERR(ctx); goto err; @@ -1436,7 +1485,7 @@ void i915_gem_context_close(struct drm_file *file) unsigned long idx; xa_for_each(&file_priv->proto_context_xa, idx, pc) - proto_context_close(pc); + proto_context_close(file_priv->dev_priv, pc); xa_destroy(&file_priv->proto_context_xa); mutex_destroy(&file_priv->proto_context_lock); @@ -1731,6 +1780,15 @@ static int set_priority(struct i915_gem_context *ctx, return 0; } +static int get_protected(struct i915_gem_context *ctx, + struct drm_i915_gem_context_param *args) +{ + args->size = 0; + args->value = i915_gem_context_uses_protected_content(ctx); + + return 0; +} + static int ctx_setparam(struct drm_i915_file_private *fpriv, struct i915_gem_context *ctx, struct drm_i915_gem_context_param *args) @@ -1754,6 +1812,8 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv, ret = -EPERM; else if (args->value) i915_gem_context_set_bannable(ctx); + else if (i915_gem_context_uses_protected_content(ctx)) + ret = -EPERM; /* can't clear this for protected contexts */ else i915_gem_context_clear_bannable(ctx); break; @@ -1761,10 +1821,12 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv, case I915_CONTEXT_PARAM_RECOVERABLE: if (args->size) ret = -EINVAL; - else if (args->value) - i915_gem_context_set_recoverable(ctx); - else + else if (!args->value) i915_gem_context_clear_recoverable(ctx); + else if (i915_gem_context_uses_protected_content(ctx)) + ret = -EPERM; /* can't set this for protected contexts */ + else + i915_gem_context_set_recoverable(ctx); break; case I915_CONTEXT_PARAM_PRIORITY: @@ -1779,6 +1841,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv, ret = set_persistence(ctx, args); break; + case I915_CONTEXT_PARAM_PROTECTED_CONTENT: case I915_CONTEXT_PARAM_NO_ZEROMAP: case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_RINGSIZE: @@ -1857,7 +1920,7 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv, old = xa_erase(&file_priv->proto_context_xa, id); GEM_BUG_ON(old != pc); - proto_context_close(pc); + proto_context_close(file_priv->dev_priv, pc); /* One for the xarray and one for the caller */ return i915_gem_context_get(ctx); @@ -1943,7 +2006,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, goto err_pc; } - proto_context_close(ext_data.pc); + proto_context_close(i915, ext_data.pc); gem_context_register(ctx, ext_data.fpriv, id); } else { ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id); @@ -1957,7 +2020,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, return 0; err_pc: - proto_context_close(ext_data.pc); + proto_context_close(i915, ext_data.pc); return ret; } @@ -1988,7 +2051,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, GEM_WARN_ON(ctx && pc); if (pc) - proto_context_close(pc); + proto_context_close(file_priv->dev_priv, pc); if (ctx) context_close(ctx); @@ -2106,6 +2169,10 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, args->value = i915_gem_context_is_persistent(ctx); break; + case I915_CONTEXT_PARAM_PROTECTED_CONTENT: + ret = get_protected(ctx, args); + break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_ENGINES: diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h index d3279086a5e7..babfecb17ad1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h @@ -108,6 +108,12 @@ i915_gem_context_clear_user_engines(struct i915_gem_context *ctx) clear_bit(CONTEXT_USER_ENGINES, &ctx->flags); } +static inline bool +i915_gem_context_uses_protected_content(const struct i915_gem_context *ctx) +{ + return ctx->uses_protected_content; +} + /* i915_gem_context.c */ void i915_gem_init__contexts(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h index c4617e4d9fa9..a627b09c4680 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h @@ -198,6 +198,12 @@ struct i915_gem_proto_context { /** @single_timeline: See See &i915_gem_context.syncobj */ bool single_timeline; + + /** @uses_protected_content: See &i915_gem_context.uses_protected_content */ + bool uses_protected_content; + + /** @pxp_wakeref: See &i915_gem_context.pxp_wakeref */ + intel_wakeref_t pxp_wakeref; }; /** @@ -321,6 +327,28 @@ struct i915_gem_context { #define CONTEXT_CLOSED 0 #define CONTEXT_USER_ENGINES 1 + /** + * @uses_protected_content: context uses PXP-encrypted objects. + * + * This flag can only be set at ctx creation time and it's immutable for + * the lifetime of the context. See I915_CONTEXT_PARAM_PROTECTED_CONTENT + * in uapi/drm/i915_drm.h for more info on setting restrictions and + * expected behaviour of marked contexts. + */ + bool uses_protected_content; + + /** + * @pxp_wakeref: wakeref to keep the device awake when PXP is in use + * + * PXP sessions are invalidated when the device is suspended, which in + * turns invalidates all contexts and objects using it. To keep the + * flow simple, we keep the device awake when contexts using PXP objects + * are in use. It is expected that the userspace application only uses + * PXP when the display is on, so taking a wakeref here shouldn't worsen + * our power metrics. + */ + intel_wakeref_t pxp_wakeref; + /** @mutex: guards everything that isn't engines or handles_vma */ struct mutex mutex; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c index 1d341b8c47c0..8955d6abcef1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c @@ -6,6 +6,7 @@ #include "gem/i915_gem_ioctls.h" #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" +#include "pxp/intel_pxp.h" #include "i915_drv.h" #include "i915_trace.h" @@ -82,21 +83,11 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj, return 0; } -/** - * Creates a new object using the same path as DRM_I915_GEM_CREATE_EXT - * @i915: i915 private - * @size: size of the buffer, in bytes - * @placements: possible placement regions, in priority order - * @n_placements: number of possible placement regions - * - * This function is exposed primarily for selftests and does very little - * error checking. It is assumed that the set of placement regions has - * already been verified to be valid. - */ -struct drm_i915_gem_object * -__i915_gem_object_create_user(struct drm_i915_private *i915, u64 size, - struct intel_memory_region **placements, - unsigned int n_placements) +static struct drm_i915_gem_object * +__i915_gem_object_create_user_ext(struct drm_i915_private *i915, u64 size, + struct intel_memory_region **placements, + unsigned int n_placements, + unsigned int ext_flags) { struct intel_memory_region *mr = placements[0]; struct drm_i915_gem_object *obj; @@ -135,6 +126,9 @@ __i915_gem_object_create_user(struct drm_i915_private *i915, u64 size, GEM_BUG_ON(size != obj->base.size); + /* Add any flag set by create_ext options */ + obj->flags |= ext_flags; + trace_i915_gem_object_create(obj); return obj; @@ -145,6 +139,26 @@ object_free: return ERR_PTR(ret); } +/** + * Creates a new object using the same path as DRM_I915_GEM_CREATE_EXT + * @i915: i915 private + * @size: size of the buffer, in bytes + * @placements: possible placement regions, in priority order + * @n_placements: number of possible placement regions + * + * This function is exposed primarily for selftests and does very little + * error checking. It is assumed that the set of placement regions has + * already been verified to be valid. + */ +struct drm_i915_gem_object * +__i915_gem_object_create_user(struct drm_i915_private *i915, u64 size, + struct intel_memory_region **placements, + unsigned int n_placements) +{ + return __i915_gem_object_create_user_ext(i915, size, placements, + n_placements, 0); +} + int i915_gem_dumb_create(struct drm_file *file, struct drm_device *dev, @@ -224,6 +238,7 @@ struct create_ext { struct drm_i915_private *i915; struct intel_memory_region *placements[INTEL_REGION_UNKNOWN]; unsigned int n_placements; + unsigned long flags; }; static void repr_placements(char *buf, size_t size, @@ -353,8 +368,28 @@ static int ext_set_placements(struct i915_user_extension __user *base, return set_placements(&ext, data); } +static int ext_set_protected(struct i915_user_extension __user *base, void *data) +{ + struct drm_i915_gem_create_ext_protected_content ext; + struct create_ext *ext_data = data; + + if (copy_from_user(&ext, base, sizeof(ext))) + return -EFAULT; + + if (ext.flags) + return -EINVAL; + + if (!intel_pxp_is_enabled(&ext_data->i915->gt.pxp)) + return -ENODEV; + + ext_data->flags |= I915_BO_PROTECTED; + + return 0; +} + static const i915_user_extension_fn create_extensions[] = { [I915_GEM_CREATE_EXT_MEMORY_REGIONS] = ext_set_placements, + [I915_GEM_CREATE_EXT_PROTECTED_CONTENT] = ext_set_protected, }; /** @@ -389,9 +424,10 @@ i915_gem_create_ext_ioctl(struct drm_device *dev, void *data, ext_data.n_placements = 1; } - obj = __i915_gem_object_create_user(i915, args->size, - ext_data.placements, - ext_data.n_placements); + obj = __i915_gem_object_create_user_ext(i915, args->size, + ext_data.placements, + ext_data.n_placements, + ext_data.flags); if (IS_ERR(obj)) return PTR_ERR(obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index c2f74dba0557..9447ce6ea500 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -21,6 +21,8 @@ #include "gt/intel_gt_pm.h" #include "gt/intel_ring.h" +#include "pxp/intel_pxp.h" + #include "i915_drv.h" #include "i915_gem_clflush.h" #include "i915_gem_context.h" @@ -810,6 +812,22 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle) if (unlikely(!obj)) return ERR_PTR(-ENOENT); + /* + * If the user has opted-in for protected-object tracking, make + * sure the object encryption can be used. + * We only need to do this when the object is first used with + * this context, because the context itself will be banned when + * the protected objects become invalid. + */ + if (i915_gem_context_uses_protected_content(eb->gem_context) && + i915_gem_object_is_protected(obj)) { + err = intel_pxp_key_check(&vm->gt->pxp, obj); + if (err) { + i915_gem_object_put(obj); + return ERR_PTR(err); + } + } + vma = i915_vma_instance(obj, vm, NULL); if (IS_ERR(vma)) { i915_gem_object_put(obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index b88b121e244a..76ce6a1500bc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -25,6 +25,7 @@ #include #include "display/intel_frontbuffer.h" +#include "pxp/intel_pxp.h" #include "i915_drv.h" #include "i915_gem_clflush.h" #include "i915_gem_context.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 7f9f2e5ba0ec..9df3ee60604e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -272,6 +272,12 @@ i915_gem_object_clear_tiling_quirk(struct drm_i915_gem_object *obj) clear_bit(I915_TILING_QUIRK_BIT, &obj->flags); } +static inline bool +i915_gem_object_is_protected(const struct drm_i915_gem_object *obj) +{ + return obj->flags & I915_BO_PROTECTED; +} + static inline bool i915_gem_object_type_has(const struct drm_i915_gem_object *obj, unsigned long flags) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index fa2ba9e2a4d0..7c3da4e3e737 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -304,7 +304,7 @@ struct drm_i915_gem_object { I915_BO_ALLOC_PM_EARLY) #define I915_BO_READONLY BIT(6) #define I915_TILING_QUIRK_BIT 7 /* unknown swizzling; do not release! */ - +#define I915_BO_PROTECTED BIT(8) /** * @mem_flags - Mutable placement-related flags * @@ -544,6 +544,13 @@ struct drm_i915_gem_object { bool created:1; } ttm; + /* + * Record which PXP key instance this object was created against (if + * any), so we can use it to determine if the encryption is valid by + * comparing against the current key instance. + */ + u32 pxp_key_instance; + /** Record of address bit 17 of each page at last unbind. */ unsigned long *bit_17; diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c index 067d68a6fe4c..c0a8ef368044 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c @@ -88,7 +88,7 @@ live_context(struct drm_i915_private *i915, struct file *file) return ERR_CAST(pc); ctx = i915_gem_create_context(i915, pc); - proto_context_close(pc); + proto_context_close(i915, pc); if (IS_ERR(ctx)) return ctx; @@ -163,7 +163,7 @@ kernel_context(struct drm_i915_private *i915, } ctx = i915_gem_create_context(i915, pc); - proto_context_close(pc); + proto_context_close(i915, pc); if (IS_ERR(ctx)) return ctx; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 2e188217c3b7..ee507fd8ae19 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -7,6 +7,7 @@ #include "intel_pxp_irq.h" #include "intel_pxp_session.h" #include "intel_pxp_tee.h" +#include "gem/i915_gem_context.h" #include "gt/intel_context.h" #include "i915_drv.h" @@ -178,3 +179,79 @@ void intel_pxp_fini_hw(struct intel_pxp *pxp) intel_pxp_irq_disable(pxp); } + +int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj) +{ + if (!intel_pxp_is_active(pxp)) + return -ENODEV; + + if (!i915_gem_object_is_protected(obj)) + return -EINVAL; + + GEM_BUG_ON(!pxp->key_instance); + + /* + * If this is the first time we're using this object, it's not + * encrypted yet; it will be encrypted with the current key, so mark it + * as such. If the object is already encrypted, check instead if the + * used key is still valid. + */ + if (!obj->pxp_key_instance) + obj->pxp_key_instance = pxp->key_instance; + else if (obj->pxp_key_instance != pxp->key_instance) + return -ENOEXEC; + + return 0; +} + +void intel_pxp_invalidate(struct intel_pxp *pxp) +{ + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + struct i915_gem_context *ctx, *cn; + + /* ban all contexts marked as protected */ + spin_lock_irq(&i915->gem.contexts.lock); + list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) { + struct i915_gem_engines_iter it; + struct intel_context *ce; + + if (!kref_get_unless_zero(&ctx->ref)) + continue; + + if (likely(!i915_gem_context_uses_protected_content(ctx))) { + i915_gem_context_put(ctx); + continue; + } + + spin_unlock_irq(&i915->gem.contexts.lock); + + /* + * By the time we get here we are either going to suspend with + * quiesced execution or the HW keys are already long gone and + * in this case it is worthless to attempt to close the context + * and wait for its execution. It will hang the GPU if it has + * not already. So, as a fast mitigation, we can ban the + * context as quick as we can. That might race with the + * execbuffer, but currently this is the best that can be done. + */ + for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) + intel_context_ban(ce, NULL); + i915_gem_context_unlock_engines(ctx); + + /* + * The context has been banned, no need to keep the wakeref. + * This is safe from races because the only other place this + * is touched is context_release and we're holding a ctx ref + */ + if (ctx->pxp_wakeref) { + intel_runtime_pm_put(&i915->runtime_pm, + ctx->pxp_wakeref); + ctx->pxp_wakeref = 0; + } + + spin_lock_irq(&i915->gem.contexts.lock); + list_safe_reset_next(ctx, cn, link); + i915_gem_context_put(ctx); + } + spin_unlock_irq(&i915->gem.contexts.lock); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 54b268280379..430f01ea9860 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -8,6 +8,8 @@ #include "intel_pxp_types.h" +struct drm_i915_gem_object; + static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp) { return pxp->ce; @@ -25,6 +27,10 @@ void intel_pxp_fini_hw(struct intel_pxp *pxp); void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp); int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp); + +int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj); + +void intel_pxp_invalidate(struct intel_pxp *pxp); #else static inline void intel_pxp_init(struct intel_pxp *pxp) { @@ -38,6 +44,12 @@ static inline int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) { return -ENODEV; } + +static inline int intel_pxp_key_check(struct intel_pxp *pxp, + struct drm_i915_gem_object *obj) +{ + return -ENODEV; +} #endif #endif /* __INTEL_PXP_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 67c30e534d50..c6a5e4197e40 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -72,6 +72,9 @@ static int pxp_create_arb_session(struct intel_pxp *pxp) return ret; } + if (!++pxp->key_instance) + ++pxp->key_instance; + pxp->arb_is_valid = true; return 0; @@ -85,6 +88,9 @@ static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) /* must mark termination in progress calling this function */ GEM_WARN_ON(pxp->arb_is_valid); + /* invalidate protected objects */ + intel_pxp_invalidate(pxp); + /* terminate the hw sessions */ ret = intel_pxp_terminate_session(pxp, ARB_SESSION); if (ret) { diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 5a170e43c959..c394ab2e452b 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -7,7 +7,9 @@ #define __INTEL_PXP_TYPES_H__ #include +#include #include +#include #include #include @@ -27,6 +29,13 @@ struct intel_pxp { */ bool arb_is_valid; + /* + * Keep track of which key instance we're on, so we can use it to + * determine if an object was created using the current key or a + * previous one. + */ + u32 key_instance; + struct mutex tee_mutex; /* protects the tee channel binding */ /* diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 920e9e852e5a..aa2a7eccfb94 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1846,6 +1846,55 @@ struct drm_i915_gem_context_param { * attempted to use it, never re-use this context param number. */ #define I915_CONTEXT_PARAM_RINGSIZE 0xc + +/* + * I915_CONTEXT_PARAM_PROTECTED_CONTENT: + * + * Mark that the context makes use of protected content, which will result + * in the context being invalidated when the protected content session is. + * Given that the protected content session is killed on suspend, the device + * is kept awake for the lifetime of a protected context, so the user should + * make sure to dispose of them once done. + * This flag can only be set at context creation time and, when set to true, + * must be preceded by an explicit setting of I915_CONTEXT_PARAM_RECOVERABLE + * to false. This flag can't be set to true in conjunction with setting the + * I915_CONTEXT_PARAM_BANNABLE flag to false. Creation example: + * + * .. code-block:: C + * + * struct drm_i915_gem_context_create_ext_setparam p_protected = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT, + * .value = 1, + * } + * }; + * struct drm_i915_gem_context_create_ext_setparam p_norecover = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * .next_extension = to_user_pointer(&p_protected), + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_RECOVERABLE, + * .value = 0, + * } + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_norecover); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * In addition to the normal failure cases, setting this flag during context + * creation can result in the following errors: + * + * -ENODEV: feature not available + * -EPERM: trying to mark a recoverable or not bannable context as protected + */ +#define I915_CONTEXT_PARAM_PROTECTED_CONTENT 0xd /* Must be kept compact -- no holes and well documented */ __u64 value; @@ -2979,8 +3028,12 @@ struct drm_i915_gem_create_ext { * * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see * struct drm_i915_gem_create_ext_memory_regions. + * + * For I915_GEM_CREATE_EXT_PROTECTED_CONTENT usage see + * struct drm_i915_gem_create_ext_protected_content. */ #define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0 +#define I915_GEM_CREATE_EXT_PROTECTED_CONTENT 1 __u64 extensions; }; @@ -3038,6 +3091,47 @@ struct drm_i915_gem_create_ext_memory_regions { __u64 regions; }; +/** + * struct drm_i915_gem_create_ext_protected_content - The + * I915_OBJECT_PARAM_PROTECTED_CONTENT extension. + * + * If this extension is provided, buffer contents are expected to be protected + * by PXP encryption and require decryption for scan out and processing. This + * is only possible on platforms that have PXP enabled, on all other scenarios + * using this extension will cause the ioctl to fail and return -ENODEV. The + * flags parameter is reserved for future expansion and must currently be set + * to zero. + * + * The buffer contents are considered invalid after a PXP session teardown. + * + * The encryption is guaranteed to be processed correctly only if the object + * is submitted with a context created using the + * I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. This will also enable extra checks + * at submission time on the validity of the objects involved. + * + * Below is an example on how to create a protected object: + * + * .. code-block:: C + * + * struct drm_i915_gem_create_ext_protected_content protected_ext = { + * .base = { .name = I915_GEM_CREATE_EXT_PROTECTED_CONTENT }, + * .flags = 0, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = PAGE_SIZE, + * .extensions = (uintptr_t)&protected_ext, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + */ +struct drm_i915_gem_create_ext_protected_content { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + /** @flags: reserved for future usage, currently MBZ */ + __u32 flags; +}; + /* ID of the protected content session managed by i915 when PXP is active */ #define I915_PROTECTED_CONTENT_DEFAULT_SESSION 0xf From 32271ecd6596e67458c75d2d61805bb1c60d7363 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:46 -0700 Subject: [PATCH 256/554] drm/i915/pxp: start the arb session on demand Now that we can handle destruction and re-creation of the arb session, we can postpone the start of the session to the first submission that requires it, to avoid keeping it running with no user. v10: increase timeout when waiting in intel_pxp_start as firmware session startup is slower right after boot. v13: increase the same timeout by 50 milisec because previous timeout was not enough to cover two lower level 100 milisec timeouts in the session termination + creation steps. Signed-off-by: Alan Previn Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-12-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 4 ++- drivers/gpu/drm/i915/pxp/intel_pxp.c | 37 +++++++++++++------- drivers/gpu/drm/i915/pxp/intel_pxp.h | 10 ++++-- drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 2 +- drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 6 ++-- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 10 +----- drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 2 ++ 7 files changed, 42 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 08360d6bbd1e..51861a66547c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -267,7 +267,9 @@ static int proto_context_set_protected(struct drm_i915_private *i915, * which in turn requires the device to be active. */ pc->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm); - ret = intel_pxp_wait_for_arb_start(&i915->gt.pxp); + + if (!intel_pxp_is_active(&i915->gt.pxp)) + ret = intel_pxp_start(&i915->gt.pxp); } return ret; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index ee507fd8ae19..7f241c0218c1 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -91,6 +91,7 @@ void intel_pxp_init(struct intel_pxp *pxp) init_completion(&pxp->termination); complete_all(&pxp->termination); + mutex_init(&pxp->arb_mutex); INIT_WORK(&pxp->session_work, intel_pxp_session_work); ret = create_vcs_context(pxp); @@ -127,7 +128,7 @@ void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp) reinit_completion(&pxp->termination); } -static void intel_pxp_queue_termination(struct intel_pxp *pxp) +static void pxp_queue_termination(struct intel_pxp *pxp) { struct intel_gt *gt = pxp_to_gt(pxp); @@ -146,31 +147,41 @@ static void intel_pxp_queue_termination(struct intel_pxp *pxp) * the arb session is restarted from the irq work when we receive the * termination completion interrupt */ -int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) +int intel_pxp_start(struct intel_pxp *pxp) { + int ret = 0; + if (!intel_pxp_is_enabled(pxp)) - return 0; + return -ENODEV; + + mutex_lock(&pxp->arb_mutex); + + if (pxp->arb_is_valid) + goto unlock; + + pxp_queue_termination(pxp); if (!wait_for_completion_timeout(&pxp->termination, - msecs_to_jiffies(100))) - return -ETIMEDOUT; + msecs_to_jiffies(250))) { + ret = -ETIMEDOUT; + goto unlock; + } + + /* make sure the compiler doesn't optimize the double access */ + barrier(); if (!pxp->arb_is_valid) - return -EIO; + ret = -EIO; - return 0; +unlock: + mutex_unlock(&pxp->arb_mutex); + return ret; } void intel_pxp_init_hw(struct intel_pxp *pxp) { kcr_pxp_enable(pxp_to_gt(pxp)); intel_pxp_irq_enable(pxp); - - /* - * the session could've been attacked while we weren't loaded, so - * handle it as if it was and re-create it. - */ - intel_pxp_queue_termination(pxp); } void intel_pxp_fini_hw(struct intel_pxp *pxp) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 430f01ea9860..bce0014d9ff9 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -26,7 +26,8 @@ void intel_pxp_init_hw(struct intel_pxp *pxp); void intel_pxp_fini_hw(struct intel_pxp *pxp); void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp); -int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp); + +int intel_pxp_start(struct intel_pxp *pxp); int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj); @@ -40,11 +41,16 @@ static inline void intel_pxp_fini(struct intel_pxp *pxp) { } -static inline int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) +static inline int intel_pxp_start(struct intel_pxp *pxp) { return -ENODEV; } +static inline bool intel_pxp_is_active(const struct intel_pxp *pxp) +{ + return false; +} + static inline int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c index 300cf2b96fda..7b25efa82b76 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c @@ -32,7 +32,7 @@ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { /* immediately mark PXP as inactive on termination */ intel_pxp_mark_termination_in_progress(pxp); - pxp->session_events |= PXP_TERMINATION_REQUEST; + pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED; } if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index c6a5e4197e40..a95cc443a48d 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -88,9 +88,6 @@ static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp) /* must mark termination in progress calling this function */ GEM_WARN_ON(pxp->arb_is_valid); - /* invalidate protected objects */ - intel_pxp_invalidate(pxp); - /* terminate the hw sessions */ ret = intel_pxp_terminate_session(pxp, ARB_SESSION); if (ret) { @@ -147,6 +144,9 @@ void intel_pxp_session_work(struct work_struct *work) if (!events) return; + if (events & PXP_INVAL_REQUIRED) + intel_pxp_invalidate(pxp); + if (events & PXP_TERMINATION_REQUEST) { events &= ~PXP_TERMINATION_COMPLETE; pxp_terminate(pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 494bd6b48514..3fc3ddfd02b3 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -78,9 +78,7 @@ unlock: static int i915_pxp_tee_component_bind(struct device *i915_kdev, struct device *tee_kdev, void *data) { - struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); - int ret; mutex_lock(&pxp->tee_mutex); pxp->pxp_component = data; @@ -89,14 +87,8 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, /* the component is required to fully start the PXP HW */ intel_pxp_init_hw(pxp); - ret = intel_pxp_wait_for_arb_start(pxp); - if (ret) { - drm_err(&i915->drm, "Failed to create arb session during bind\n"); - intel_pxp_fini_hw(pxp); - pxp->pxp_component = NULL; - } - return ret; + return 0; } static void i915_pxp_tee_component_unbind(struct device *i915_kdev, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index c394ab2e452b..ae24064bb57e 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -27,6 +27,7 @@ struct intel_pxp { * even if the keys are gone, so we can't rely on the HW state of the * session to know if it's valid and need to track the status in SW. */ + struct mutex arb_mutex; /* protects arb session start */ bool arb_is_valid; /* @@ -53,6 +54,7 @@ struct intel_pxp { u32 session_events; /* protected with gt->irq_lock */ #define PXP_TERMINATION_REQUEST BIT(0) #define PXP_TERMINATION_COMPLETE BIT(1) +#define PXP_INVAL_REQUIRED BIT(2) }; #endif /* __INTEL_PXP_TYPES_H__ */ From 0cfab4cb3c4e90c1c2f4b18c0b8ac4cb946808c8 Mon Sep 17 00:00:00 2001 From: "Huang, Sean Z" Date: Fri, 24 Sep 2021 12:14:47 -0700 Subject: [PATCH 257/554] drm/i915/pxp: Enable PXP power management During the power event S3+ sleep/resume, hardware will lose all the encryption keys for every hardware session, even though the session state might still be marked as alive after resume. Therefore, we should consider the session as dead on suspend and invalidate all the objects. The session will be automatically restarted on the first protected submission on resume. v2: runtime suspend also invalidates the keys v3: fix return codes, simplify rpm ops (Chris), use the new worker func v4: invalidate the objects on suspend, don't re-create the arb sesson on resume (delayed to first submission). v5: move irq changes back to irq patch (Rodrigo) v6: drop invalidation in runtime suspend (Rodrigo) Signed-off-by: Huang, Sean Z Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-13-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/gt/intel_gt_pm.c | 16 ++++++- drivers/gpu/drm/i915/i915_drv.c | 2 + drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 1 + drivers/gpu/drm/i915/pxp/intel_pxp_pm.c | 46 ++++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_pm.h | 24 ++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 38 +++++++++++----- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 9 ++++ 8 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_pm.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_pm.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 5363d3b3fda7..dadf879b228c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -283,6 +283,7 @@ i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp.o \ pxp/intel_pxp_cmd.o \ pxp/intel_pxp_irq.o \ + pxp/intel_pxp_pm.o \ pxp/intel_pxp_session.o \ pxp/intel_pxp_tee.o diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index e9da36530b45..524eaf678790 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -18,6 +18,7 @@ #include "intel_rc6.h" #include "intel_rps.h" #include "intel_wakeref.h" +#include "pxp/intel_pxp_pm.h" #define I915_GT_SUSPEND_IDLE_TIMEOUT (HZ / 2) @@ -264,6 +265,8 @@ int intel_gt_resume(struct intel_gt *gt) intel_uc_resume(>->uc); + intel_pxp_resume(>->pxp); + user_forcewake(gt, false); out_fw: @@ -297,6 +300,8 @@ void intel_gt_suspend_prepare(struct intel_gt *gt) { user_forcewake(gt, true); wait_for_suspend(gt); + + intel_pxp_suspend(>->pxp, false); } static suspend_state_t pm_suspend_target(void) @@ -348,6 +353,7 @@ void intel_gt_suspend_late(struct intel_gt *gt) void intel_gt_runtime_suspend(struct intel_gt *gt) { + intel_pxp_suspend(>->pxp, true); intel_uc_runtime_suspend(>->uc); GT_TRACE(gt, "\n"); @@ -355,11 +361,19 @@ void intel_gt_runtime_suspend(struct intel_gt *gt) int intel_gt_runtime_resume(struct intel_gt *gt) { + int ret; + GT_TRACE(gt, "\n"); intel_gt_init_swizzling(gt); intel_ggtt_restore_fences(gt->ggtt); - return intel_uc_runtime_resume(>->uc); + ret = intel_uc_runtime_resume(>->uc); + if (ret) + return ret; + + intel_pxp_resume(>->pxp); + + return 0; } static ktime_t __intel_gt_get_awake_time(const struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ed7b421cad44..d24209f5f37b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -67,6 +67,8 @@ #include "gt/intel_gt_pm.h" #include "gt/intel_rc6.h" +#include "pxp/intel_pxp_pm.h" + #include "i915_debugfs.h" #include "i915_drv.h" #include "i915_ioc32.h" diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c index 7b25efa82b76..8d5553772ded 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c @@ -10,6 +10,7 @@ #include "gt/intel_gt_types.h" #include "i915_irq.h" #include "i915_reg.h" +#include "intel_runtime_pm.h" /** * intel_pxp_irq_handler - Handles PXP interrupts. diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c new file mode 100644 index 000000000000..23fd86de5a24 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2020 Intel Corporation. + */ + +#include "intel_pxp.h" +#include "intel_pxp_irq.h" +#include "intel_pxp_pm.h" +#include "intel_pxp_session.h" + +void intel_pxp_suspend(struct intel_pxp *pxp, bool runtime) +{ + if (!intel_pxp_is_enabled(pxp)) + return; + + pxp->arb_is_valid = false; + + /* + * Contexts using protected objects keep a runtime PM reference, so we + * can only runtime suspend when all of them have been either closed + * or banned. Therefore, there is no need to invalidate in that + * scenario. + */ + if (!runtime) + intel_pxp_invalidate(pxp); + + intel_pxp_fini_hw(pxp); + + pxp->hw_state_invalidated = false; +} + +void intel_pxp_resume(struct intel_pxp *pxp) +{ + if (!intel_pxp_is_enabled(pxp)) + return; + + /* + * The PXP component gets automatically unbound when we go into S3 and + * re-bound after we come out, so in that scenario we can defer the + * hw init to the bind call. + */ + if (!pxp->pxp_component) + return; + + intel_pxp_init_hw(pxp); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h new file mode 100644 index 000000000000..c89e97a0c3d0 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2020, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_PM_H__ +#define __INTEL_PXP_PM_H__ + +#include "intel_pxp_types.h" + +#ifdef CONFIG_DRM_I915_PXP +void intel_pxp_suspend(struct intel_pxp *pxp, bool runtime); +void intel_pxp_resume(struct intel_pxp *pxp); +#else +static inline void intel_pxp_suspend(struct intel_pxp *pxp, bool runtime) +{ +} + +static inline void intel_pxp_resume(struct intel_pxp *pxp) +{ +} +#endif + +#endif /* __INTEL_PXP_PM_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index a95cc443a48d..d02732f04757 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -21,29 +21,36 @@ static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id) { - struct intel_gt *gt = pxp_to_gt(pxp); + struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore; intel_wakeref_t wakeref; u32 sip = 0; - with_intel_runtime_pm(gt->uncore->rpm, wakeref) - sip = intel_uncore_read(gt->uncore, GEN12_KCR_SIP); + /* if we're suspended the session is considered off */ + with_intel_runtime_pm_if_in_use(uncore->rpm, wakeref) + sip = intel_uncore_read(uncore, GEN12_KCR_SIP); return sip & BIT(id); } static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play) { - struct intel_gt *gt = pxp_to_gt(pxp); + struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore; intel_wakeref_t wakeref; u32 mask = BIT(id); int ret; - with_intel_runtime_pm(gt->uncore->rpm, wakeref) - ret = intel_wait_for_register(gt->uncore, - GEN12_KCR_SIP, - mask, - in_play ? mask : 0, - 100); + /* if we're suspended the session is considered off */ + wakeref = intel_runtime_pm_get_if_in_use(uncore->rpm); + if (!wakeref) + return in_play ? -ENODEV : 0; + + ret = intel_wait_for_register(uncore, + GEN12_KCR_SIP, + mask, + in_play ? mask : 0, + 100); + + intel_runtime_pm_put(uncore->rpm, wakeref); return ret; } @@ -135,6 +142,7 @@ void intel_pxp_session_work(struct work_struct *work) { struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work); struct intel_gt *gt = pxp_to_gt(pxp); + intel_wakeref_t wakeref; u32 events = 0; spin_lock_irq(>->irq_lock); @@ -147,6 +155,14 @@ void intel_pxp_session_work(struct work_struct *work) if (events & PXP_INVAL_REQUIRED) intel_pxp_invalidate(pxp); + /* + * If we're processing an event while suspending then don't bother, + * we're going to re-init everything on resume anyway. + */ + wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm); + if (!wakeref) + return; + if (events & PXP_TERMINATION_REQUEST) { events &= ~PXP_TERMINATION_COMPLETE; pxp_terminate(pxp); @@ -154,4 +170,6 @@ void intel_pxp_session_work(struct work_struct *work) if (events & PXP_TERMINATION_COMPLETE) pxp_terminate_complete(pxp); + + intel_runtime_pm_put(gt->uncore->rpm, wakeref); } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 3fc3ddfd02b3..49508f31dcb7 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -78,16 +78,25 @@ unlock: static int i915_pxp_tee_component_bind(struct device *i915_kdev, struct device *tee_kdev, void *data) { + struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + intel_wakeref_t wakeref; mutex_lock(&pxp->tee_mutex); pxp->pxp_component = data; pxp->pxp_component->tee_dev = tee_kdev; mutex_unlock(&pxp->tee_mutex); + /* if we are suspended, the HW will be re-initialized on resume */ + wakeref = intel_runtime_pm_get_if_in_use(&i915->runtime_pm); + if (!wakeref) + return 0; + /* the component is required to fully start the PXP HW */ intel_pxp_init_hw(pxp); + intel_runtime_pm_put(&i915->runtime_pm, wakeref); + return 0; } From ef6ba31dd3840588418e70f4dd63ce6022e1a254 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Fri, 24 Sep 2021 12:14:48 -0700 Subject: [PATCH 258/554] drm/i915/pxp: Add plane decryption support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to enable/disable PLANE_SURF Decryption Request bit. It requires only to enable plane decryption support when following condition met. 1. PXP session is enabled. 2. Buffer object is protected. v2: - Used gen fb obj user_flags instead gem_object_metadata. [Krishna] v3: - intel_pxp_gem_object_status() API changes. v4: use intel_pxp_is_active (Daniele) v5: rebase and use the new protected object status checker (Daniele) v6: used plane state for plane_decryption to handle async flip as suggested by Ville. v7: check pxp session while plane decrypt state computation. [Ville] removed pointless code. [Ville] v8 (Daniele): update PXP check v9: move decrypt check after icl_check_nv12_planes() when overlays have fb set (Juston) v10 (Daniele): update PXP check again to match rework in earlier patches and don't consider protection valid if the object has not been used in an execbuf beforehand. Cc: Bommu Krishnaiah Cc: Huang Sean Z Cc: Gaurav Kumar Cc: Ville Syrjälä Signed-off-by: Anshuman Gupta Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Juston Li Reviewed-by: Rodrigo Vivi Reviewed-by: Uma Shankar #v9 Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-14-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 26 +++++++++++++++++++ .../drm/i915/display/intel_display_types.h | 3 +++ .../drm/i915/display/skl_universal_plane.c | 15 ++++++++--- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/pxp/intel_pxp.c | 9 ++++--- drivers/gpu/drm/i915/pxp/intel_pxp.h | 7 +++-- 7 files changed, 54 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 134a6acbd8fb..b9b4f1fbb8ac 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -70,6 +70,8 @@ #include "gt/intel_rps.h" #include "gt/gen8_ppgtt.h" +#include "pxp/intel_pxp.h" + #include "g4x_dp.h" #include "g4x_hdmi.h" #include "i915_drv.h" @@ -9627,13 +9629,23 @@ static int intel_bigjoiner_add_affected_planes(struct intel_atomic_state *state) return 0; } +static bool bo_has_valid_encryption(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + + return intel_pxp_key_check(&i915->gt.pxp, obj, false) == 0; +} + static int intel_atomic_check_planes(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_crtc_state *old_crtc_state, *new_crtc_state; struct intel_plane_state *plane_state; struct intel_plane *plane; + struct intel_plane_state *new_plane_state; + struct intel_plane_state *old_plane_state; struct intel_crtc *crtc; + const struct drm_framebuffer *fb; int i, ret; ret = icl_add_linked_planes(state); @@ -9681,6 +9693,16 @@ static int intel_atomic_check_planes(struct intel_atomic_state *state) return ret; } + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { + new_plane_state = intel_atomic_get_new_plane_state(state, plane); + old_plane_state = intel_atomic_get_old_plane_state(state, plane); + fb = new_plane_state->hw.fb; + if (fb) + new_plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); + else + new_plane_state->decrypt = old_plane_state->decrypt; + } + return 0; } @@ -9967,6 +9989,10 @@ static int intel_atomic_check_async(struct intel_atomic_state *state) drm_dbg_kms(&i915->drm, "Color range cannot be changed in async flip\n"); return -EINVAL; } + + /* plane decryption is allow to change only in synchronous flips */ + if (old_plane_state->decrypt != new_plane_state->decrypt) + return -EINVAL; } return 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 6beeeeba1bed..53b5db3c6228 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -629,6 +629,9 @@ struct intel_plane_state { struct intel_fb_view view; + /* Plane pxp decryption state */ + bool decrypt; + /* plane control register */ u32 ctl; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 724e7b04f3b6..55e3f093b951 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -18,6 +18,7 @@ #include "intel_sprite.h" #include "skl_scaler.h" #include "skl_universal_plane.h" +#include "pxp/intel_pxp.h" static const u32 skl_plane_formats[] = { DRM_FORMAT_C8, @@ -1024,7 +1025,7 @@ skl_program_plane(struct intel_plane *plane, u8 alpha = plane_state->hw.alpha >> 8; u32 plane_color_ctl = 0, aux_dist = 0; unsigned long irqflags; - u32 keymsk, keymax; + u32 keymsk, keymax, plane_surf; u32 plane_ctl = plane_state->ctl; plane_ctl |= skl_plane_ctl_crtc(crtc_state); @@ -1113,8 +1114,16 @@ skl_program_plane(struct intel_plane *plane, * the control register just before the surface register. */ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); + plane_surf = intel_plane_ggtt_offset(plane_state) + surf_addr; + + /* + * FIXME: pxp session invalidation can hit any time even at time of commit + * or after the commit, display content will be garbage. + */ + if (plane_state->decrypt) + plane_surf |= PLANE_SURF_DECRYPT; + + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), plane_surf); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 9447ce6ea500..8b3a25bd93e6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -821,7 +821,7 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle) */ if (i915_gem_context_uses_protected_content(eb->gem_context) && i915_gem_object_is_protected(obj)) { - err = intel_pxp_key_check(&vm->gt->pxp, obj); + err = intel_pxp_key_check(&vm->gt->pxp, obj, true); if (err) { i915_gem_object_put(obj); return ERR_PTR(err); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e2647c02a4d2..4be684b0fcd4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7383,6 +7383,7 @@ enum { #define _PLANE_SURF_3(pipe) _PIPE(pipe, _PLANE_SURF_3_A, _PLANE_SURF_3_B) #define PLANE_SURF(pipe, plane) \ _MMIO_PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe)) +#define PLANE_SURF_DECRYPT REG_BIT(2) #define _PLANE_OFFSET_1_B 0x711a4 #define _PLANE_OFFSET_2_B 0x712a4 diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 7f241c0218c1..b85b72f12726 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -191,7 +191,9 @@ void intel_pxp_fini_hw(struct intel_pxp *pxp) intel_pxp_irq_disable(pxp); } -int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj) +int intel_pxp_key_check(struct intel_pxp *pxp, + struct drm_i915_gem_object *obj, + bool assign) { if (!intel_pxp_is_active(pxp)) return -ENODEV; @@ -207,9 +209,10 @@ int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj) * as such. If the object is already encrypted, check instead if the * used key is still valid. */ - if (!obj->pxp_key_instance) + if (!obj->pxp_key_instance && assign) obj->pxp_key_instance = pxp->key_instance; - else if (obj->pxp_key_instance != pxp->key_instance) + + if (obj->pxp_key_instance != pxp->key_instance) return -ENOEXEC; return 0; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index bce0014d9ff9..aa262258d4d4 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -29,7 +29,9 @@ void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp); int intel_pxp_start(struct intel_pxp *pxp); -int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj); +int intel_pxp_key_check(struct intel_pxp *pxp, + struct drm_i915_gem_object *obj, + bool assign); void intel_pxp_invalidate(struct intel_pxp *pxp); #else @@ -52,7 +54,8 @@ static inline bool intel_pxp_is_active(const struct intel_pxp *pxp) } static inline int intel_pxp_key_check(struct intel_pxp *pxp, - struct drm_i915_gem_object *obj) + struct drm_i915_gem_object *obj, + bool assign) { return -ENODEV; } From 6eba56f64d5d5ea5f273557fe46e21799a60da99 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Fri, 24 Sep 2021 12:14:49 -0700 Subject: [PATCH 259/554] drm/i915/pxp: black pixels on pxp disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When protected sufaces has flipped and pxp session is disabled, display black pixels by using plane color CTM correction. v2: - Display black pixels in async flip too. v3: - Removed the black pixels logic for async flip. [Ville] - Used plane state to force black pixels. [Ville] v4 (Daniele): update pxp_is_borked check. v5: rebase on top of v9 plane decryption moving the decrypt check (Juston) Cc: Ville Syrjälä Cc: Gaurav Kumar Cc: Shankar Uma Signed-off-by: Anshuman Gupta Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Juston Li Reviewed-by: Rodrigo Vivi Reviewed-by: Uma Shankar Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-15-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 12 ++++- .../drm/i915/display/intel_display_types.h | 3 ++ .../drm/i915/display/skl_universal_plane.c | 36 ++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 46 +++++++++++++++++++ 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b9b4f1fbb8ac..85d0cce4d0c7 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9636,6 +9636,11 @@ static bool bo_has_valid_encryption(struct drm_i915_gem_object *obj) return intel_pxp_key_check(&i915->gt.pxp, obj, false) == 0; } +static bool pxp_is_borked(struct drm_i915_gem_object *obj) +{ + return i915_gem_object_is_protected(obj) && !bo_has_valid_encryption(obj); +} + static int intel_atomic_check_planes(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); @@ -9697,10 +9702,13 @@ static int intel_atomic_check_planes(struct intel_atomic_state *state) new_plane_state = intel_atomic_get_new_plane_state(state, plane); old_plane_state = intel_atomic_get_old_plane_state(state, plane); fb = new_plane_state->hw.fb; - if (fb) + if (fb) { new_plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); - else + new_plane_state->force_black = pxp_is_borked(intel_fb_obj(fb)); + } else { new_plane_state->decrypt = old_plane_state->decrypt; + new_plane_state->force_black = old_plane_state->force_black; + } } return 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 53b5db3c6228..0fe03ef57023 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -632,6 +632,9 @@ struct intel_plane_state { /* Plane pxp decryption state */ bool decrypt; + /* Plane state to display black pixels when pxp is borked */ + bool force_black; + /* plane control register */ u32 ctl; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 55e3f093b951..c4adcb3e12b3 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1002,6 +1002,33 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, } } +static void intel_load_plane_csc_black(struct intel_plane *intel_plane) +{ + struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); + enum pipe pipe = intel_plane->pipe; + enum plane_id plane = intel_plane->id; + u16 postoff = 0; + + drm_dbg_kms(&dev_priv->drm, "plane color CTM to black %s:%d\n", + intel_plane->base.name, plane); + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 0), 0); + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 1), 0); + + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 2), 0); + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 3), 0); + + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 4), 0); + intel_de_write_fw(dev_priv, PLANE_CSC_COEFF(pipe, plane, 5), 0); + + intel_de_write_fw(dev_priv, PLANE_CSC_PREOFF(pipe, plane, 0), 0); + intel_de_write_fw(dev_priv, PLANE_CSC_PREOFF(pipe, plane, 1), 0); + intel_de_write_fw(dev_priv, PLANE_CSC_PREOFF(pipe, plane, 2), 0); + + intel_de_write_fw(dev_priv, PLANE_CSC_POSTOFF(pipe, plane, 0), postoff); + intel_de_write_fw(dev_priv, PLANE_CSC_POSTOFF(pipe, plane, 1), postoff); + intel_de_write_fw(dev_priv, PLANE_CSC_POSTOFF(pipe, plane, 2), postoff); +} + static void skl_program_plane(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -1115,14 +1142,21 @@ skl_program_plane(struct intel_plane *plane, */ intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); plane_surf = intel_plane_ggtt_offset(plane_state) + surf_addr; + plane_color_ctl = intel_de_read_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id)); /* * FIXME: pxp session invalidation can hit any time even at time of commit * or after the commit, display content will be garbage. */ - if (plane_state->decrypt) + if (plane_state->decrypt) { plane_surf |= PLANE_SURF_DECRYPT; + } else if (plane_state->force_black) { + intel_load_plane_csc_black(plane); + plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE; + } + intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), + plane_color_ctl); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), plane_surf); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4be684b0fcd4..47bfffe0b4de 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7260,6 +7260,7 @@ enum { #define _PLANE_COLOR_CTL_3_A 0x703CC /* GLK+ */ #define PLANE_COLOR_PIPE_GAMMA_ENABLE (1 << 30) /* Pre-ICL */ #define PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE (1 << 28) +#define PLANE_COLOR_PLANE_CSC_ENABLE REG_BIT(21) /* ICL+ */ #define PLANE_COLOR_INPUT_CSC_ENABLE (1 << 20) /* ICL+ */ #define PLANE_COLOR_PIPE_CSC_ENABLE (1 << 23) /* Pre-ICL */ #define PLANE_COLOR_CSC_MODE_BYPASS (0 << 17) @@ -11377,6 +11378,51 @@ enum skl_power_gate { _PAL_PREC_MULTI_SEG_DATA_A, \ _PAL_PREC_MULTI_SEG_DATA_B) +#define _MMIO_PLANE_GAMC(plane, i, a, b) _MMIO(_PIPE(plane, a, b) + (i) * 4) + +/* Plane CSC Registers */ +#define _PLANE_CSC_RY_GY_1_A 0x70210 +#define _PLANE_CSC_RY_GY_2_A 0x70310 + +#define _PLANE_CSC_RY_GY_1_B 0x71210 +#define _PLANE_CSC_RY_GY_2_B 0x71310 + +#define _PLANE_CSC_RY_GY_1(pipe) _PIPE(pipe, _PLANE_CSC_RY_GY_1_A, \ + _PLANE_CSC_RY_GY_1_B) +#define _PLANE_CSC_RY_GY_2(pipe) _PIPE(pipe, _PLANE_INPUT_CSC_RY_GY_2_A, \ + _PLANE_INPUT_CSC_RY_GY_2_B) +#define PLANE_CSC_COEFF(pipe, plane, index) _MMIO_PLANE(plane, \ + _PLANE_CSC_RY_GY_1(pipe) + (index) * 4, \ + _PLANE_CSC_RY_GY_2(pipe) + (index) * 4) + +#define _PLANE_CSC_PREOFF_HI_1_A 0x70228 +#define _PLANE_CSC_PREOFF_HI_2_A 0x70328 + +#define _PLANE_CSC_PREOFF_HI_1_B 0x71228 +#define _PLANE_CSC_PREOFF_HI_2_B 0x71328 + +#define _PLANE_CSC_PREOFF_HI_1(pipe) _PIPE(pipe, _PLANE_CSC_PREOFF_HI_1_A, \ + _PLANE_CSC_PREOFF_HI_1_B) +#define _PLANE_CSC_PREOFF_HI_2(pipe) _PIPE(pipe, _PLANE_CSC_PREOFF_HI_2_A, \ + _PLANE_CSC_PREOFF_HI_2_B) +#define PLANE_CSC_PREOFF(pipe, plane, index) _MMIO_PLANE(plane, _PLANE_CSC_PREOFF_HI_1(pipe) + \ + (index) * 4, _PLANE_CSC_PREOFF_HI_2(pipe) + \ + (index) * 4) + +#define _PLANE_CSC_POSTOFF_HI_1_A 0x70234 +#define _PLANE_CSC_POSTOFF_HI_2_A 0x70334 + +#define _PLANE_CSC_POSTOFF_HI_1_B 0x71234 +#define _PLANE_CSC_POSTOFF_HI_2_B 0x71334 + +#define _PLANE_CSC_POSTOFF_HI_1(pipe) _PIPE(pipe, _PLANE_CSC_POSTOFF_HI_1_A, \ + _PLANE_CSC_POSTOFF_HI_1_B) +#define _PLANE_CSC_POSTOFF_HI_2(pipe) _PIPE(pipe, _PLANE_CSC_POSTOFF_HI_2_A, \ + _PLANE_CSC_POSTOFF_HI_2_B) +#define PLANE_CSC_POSTOFF(pipe, plane, index) _MMIO_PLANE(plane, _PLANE_CSC_POSTOFF_HI_1(pipe) + \ + (index) * 4, _PLANE_CSC_POSTOFF_HI_2(pipe) + \ + (index) * 4) + /* pipe CSC & degamma/gamma LUTs on CHV */ #define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900) #define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904) From 390cf1b28b11190121cb05d4cec1f86787b47668 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:50 -0700 Subject: [PATCH 260/554] drm/i915/pxp: add pxp debugfs 2 debugfs files, one to query the current status of the pxp session and one to trigger an invalidation for testing. v2: rename debugfs, fix date (Alan) v12: rebased to latest drm-tip (rename of files/structs from debugfs_gt to intel_debugfs_gt caused compiler errors). Signed-off-by: Daniele Ceraolo Spurio Reviewed-by : Alan Previn Reviewed-by: Alan Previn Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-16-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/gt/intel_gt_debugfs.c | 2 + drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c | 78 ++++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h | 21 ++++++ 4 files changed, 102 insertions(+) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index dadf879b228c..b2a8406b5398 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -282,6 +282,7 @@ i915-y += i915_perf.o i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp.o \ pxp/intel_pxp_cmd.o \ + pxp/intel_pxp_debugfs.o \ pxp/intel_pxp_irq.o \ pxp/intel_pxp_pm.o \ pxp/intel_pxp_session.o \ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index 03fb4aefbf90..1fe19ccd2794 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -10,6 +10,7 @@ #include "intel_gt_engines_debugfs.h" #include "intel_gt_pm_debugfs.h" #include "intel_sseu_debugfs.h" +#include "pxp/intel_pxp_debugfs.h" #include "uc/intel_uc_debugfs.h" void intel_gt_debugfs_register(struct intel_gt *gt) @@ -28,6 +29,7 @@ void intel_gt_debugfs_register(struct intel_gt *gt) intel_sseu_debugfs_register(gt, root); intel_uc_debugfs_register(>->uc, root); + intel_pxp_debugfs_register(>->pxp, root); } void intel_gt_debugfs_register_files(struct dentry *root, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c new file mode 100644 index 000000000000..10e1e45471f1 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include +#include + +#include "gt/intel_gt_debugfs.h" +#include "pxp/intel_pxp.h" +#include "pxp/intel_pxp_irq.h" +#include "i915_drv.h" + +static int pxp_info_show(struct seq_file *m, void *data) +{ + struct intel_pxp *pxp = m->private; + struct drm_printer p = drm_seq_file_printer(m); + bool enabled = intel_pxp_is_enabled(pxp); + + if (!enabled) { + drm_printf(&p, "pxp disabled\n"); + return 0; + } + + drm_printf(&p, "active: %s\n", yesno(intel_pxp_is_active(pxp))); + drm_printf(&p, "instance counter: %u\n", pxp->key_instance); + + return 0; +} +DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(pxp_info); + +static int pxp_terminate_get(void *data, u64 *val) +{ + /* nothing to read */ + return -EPERM; +} + +static int pxp_terminate_set(void *data, u64 val) +{ + struct intel_pxp *pxp = data; + struct intel_gt *gt = pxp_to_gt(pxp); + + if (!intel_pxp_is_active(pxp)) + return -ENODEV; + + /* simulate a termination interrupt */ + spin_lock_irq(>->irq_lock); + intel_pxp_irq_handler(pxp, GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT); + spin_unlock_irq(>->irq_lock); + + if (!wait_for_completion_timeout(&pxp->termination, + msecs_to_jiffies(100))) + return -ETIMEDOUT; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(pxp_terminate_fops, pxp_terminate_get, pxp_terminate_set, "%llx\n"); +void intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *gt_root) +{ + static const struct intel_gt_debugfs_file files[] = { + { "info", &pxp_info_fops, NULL }, + { "terminate_state", &pxp_terminate_fops, NULL }, + }; + struct dentry *root; + + if (!gt_root) + return; + + if (!HAS_PXP((pxp_to_gt(pxp)->i915))) + return; + + root = debugfs_create_dir("pxp", gt_root); + if (IS_ERR(root)) + return; + + intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), pxp); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h new file mode 100644 index 000000000000..7e0c3d2f5d7e --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_PXP_DEBUGFS_H__ +#define __INTEL_PXP_DEBUGFS_H__ + +struct intel_pxp; +struct dentry; + +#ifdef CONFIG_DRM_I915_PXP +void intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *root); +#else +static inline void +intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *root) +{ +} +#endif + +#endif /* __INTEL_PXP_DEBUGFS_H__ */ From 2d5517a5c8bfcdc3a401d18a9d0cdf67de4fdcc7 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:51 -0700 Subject: [PATCH 261/554] drm/i915/pxp: add PXP documentation Now that all the pieces are in place we can add a description of how the feature works. Also modify the comments in struct intel_pxp into kerneldoc. v2: improve doc (Rodrigo) Signed-off-by: Daniele Ceraolo Spurio Cc: Daniel Vetter Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-17-alan.previn.teres.alexis@intel.com --- Documentation/gpu/i915.rst | 8 ++++ drivers/gpu/drm/i915/pxp/intel_pxp.c | 28 +++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 47 ++++++++++++++++------ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index e9b11044075e..a671fb2c1878 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -474,6 +474,14 @@ Object Tiling IOCTLs .. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_tiling.c :doc: buffer object tiling +Protected Objects +----------------- + +.. kernel-doc:: drivers/gpu/drm/i915/pxp/intel_pxp.c + :doc: PXP + +.. kernel-doc:: drivers/gpu/drm/i915/pxp/intel_pxp_types.h + Microcontrollers ================ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index b85b72f12726..e2314ad9546d 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -11,6 +11,34 @@ #include "gt/intel_context.h" #include "i915_drv.h" +/** + * DOC: PXP + * + * PXP (Protected Xe Path) is a feature available in Gen12 and newer platforms. + * It allows execution and flip to display of protected (i.e. encrypted) + * objects. The SW support is enabled via the CONFIG_DRM_I915_PXP kconfig. + * + * Objects can opt-in to PXP encryption at creation time via the + * I915_GEM_CREATE_EXT_PROTECTED_CONTENT create_ext flag. For objects to be + * correctly protected they must be used in conjunction with a context created + * with the I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. See the documentation + * of those two uapi flags for details and restrictions. + * + * Protected objects are tied to a pxp session; currently we only support one + * session, which i915 manages and whose index is available in the uapi + * (I915_PROTECTED_CONTENT_DEFAULT_SESSION) for use in instructions targeting + * protected objects. + * The session is invalidated by the HW when certain events occur (e.g. + * suspend/resume). When this happens, all the objects that were used with the + * session are marked as invalid and all contexts marked as using protected + * content are banned. Any further attempt at using them in an execbuf call is + * rejected, while flips are converted to black frames. + * + * Some of the PXP setup operations are performed by the Management Engine, + * which is handled by the mei driver; communication between i915 and mei is + * performed via the mei_pxp component module. + */ + struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp) { return container_of(pxp, struct intel_gt, pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index ae24064bb57e..73ef7d1754e1 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -16,42 +16,65 @@ struct intel_context; struct i915_pxp_component; +/** + * struct intel_pxp - pxp state + */ struct intel_pxp { + /** + * @pxp_component: i915_pxp_component struct of the bound mei_pxp + * module. Only set and cleared inside component bind/unbind functions, + * which are protected by &tee_mutex. + */ struct i915_pxp_component *pxp_component; + /** + * @pxp_component_added: track if the pxp component has been added. + * Set and cleared in tee init and fini functions respectively. + */ bool pxp_component_added; + /** @ce: kernel-owned context used for PXP operations */ struct intel_context *ce; - /* + /** @arb_mutex: protects arb session start */ + struct mutex arb_mutex; + /** + * @arb_is_valid: tracks arb session status. * After a teardown, the arb session can still be in play on the HW * even if the keys are gone, so we can't rely on the HW state of the * session to know if it's valid and need to track the status in SW. */ - struct mutex arb_mutex; /* protects arb session start */ bool arb_is_valid; - /* - * Keep track of which key instance we're on, so we can use it to - * determine if an object was created using the current key or a + /** + * @key_instance: tracks which key instance we're on, so we can use it + * to determine if an object was created using the current key or a * previous one. */ u32 key_instance; - struct mutex tee_mutex; /* protects the tee channel binding */ + /** @tee_mutex: protects the tee channel binding and messaging. */ + struct mutex tee_mutex; - /* - * If the HW perceives an attack on the integrity of the encryption it - * will invalidate the keys and expect SW to re-initialize the session. - * We keep track of this state to make sure we only re-start the arb - * session when required. + /** + * @hw_state_invalidated: if the HW perceives an attack on the integrity + * of the encryption it will invalidate the keys and expect SW to + * re-initialize the session. We keep track of this state to make sure + * we only re-start the arb session when required. */ bool hw_state_invalidated; + /** @irq_enabled: tracks the status of the kcr irqs */ bool irq_enabled; + /** + * @termination: tracks the status of a pending termination. Only + * re-initialized under gt->irq_lock and completed in &session_work. + */ struct completion termination; + /** @session_work: worker that manages session events. */ struct work_struct session_work; - u32 session_events; /* protected with gt->irq_lock */ + /** @session_events: pending session events, protected with gt->irq_lock. */ + u32 session_events; #define PXP_TERMINATION_REQUEST BIT(0) #define PXP_TERMINATION_COMPLETE BIT(1) #define PXP_INVAL_REQUIRED BIT(2) From 6f8e203897144e59de00ed910982af3d7c3e4a7f Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 24 Sep 2021 12:14:52 -0700 Subject: [PATCH 262/554] drm/i915/pxp: enable PXP for integrated Gen12 Note that discrete cards can support PXP as well, but we haven't tested on those yet so keeping it disabled for now. Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210924191452.1539378-18-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index d1da31df276c..8adbd9ad7a46 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -865,6 +865,7 @@ static const struct intel_device_info jsl_info = { }, \ TGL_CURSOR_OFFSETS, \ .has_global_mocs = 1, \ + .has_pxp = 1, \ .display.has_dsb = 1 static const struct intel_device_info tgl_info = { @@ -891,6 +892,7 @@ static const struct intel_device_info rkl_info = { #define DGFX_FEATURES \ .memory_regions = REGION_SMEM | REGION_LMEM | REGION_STOLEN_LMEM, \ .has_llc = 0, \ + .has_pxp = 0, \ .has_snoop = 1, \ .is_dgfx = 1 From 4b2437f6f7b05ffcc7007f8e8d4f028ab86707dd Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 14 Sep 2021 12:49:45 -0700 Subject: [PATCH 263/554] drm/i915: Clean up disabled warnings i915 enables a wider set of warnings with '-Wall -Wextra' then disables several with cc-disable-warning. If an unknown flag gets added to KBUILD_CFLAGS when building with clang, all subsequent calls to cc-{disable-warning,option} will fail, meaning that all of these warnings do not get disabled [1]. A separate series will address the root cause of the issue by not adding these flags when building with clang [2]; however, the symptom of these extra warnings appearing can be addressed separately by just removing the calls to cc-disable-warning, which makes the build ever so slightly faster because the compiler does not need to be called as much before building. The following warnings are supported by GCC 4.9 and clang 10.0.1, which are the minimum supported versions of these compilers so the call to cc-disable-warning is not necessary. Masahiro cleaned this up for the reset of the kernel in commit 4c8dd95a723d ("kbuild: add some extra warning flags unconditionally"). * -Wmissing-field-initializers * -Wsign-compare * -Wtype-limits * -Wunused-parameter -Wunused-but-set-variable was implemented in clang 13.0.0 and -Wframe-address was implemented in clang 12.0.0 so the cc-disable-warning calls are kept for these two warnings. Lastly, -Winitializer-overrides is clang's version of -Woverride-init, which is disabled for the specific files that are problematic. clang added a compatibility alias in clang 8.0.0 so -Winitializer-overrides can be removed. [1]: https://lore.kernel.org/r/202108210311.CBtcgoUL-lkp@intel.com/ [2]: https://lore.kernel.org/r/20210824022640.2170859-1-nathan@kernel.org/ Reviewed-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210914194944.4004260-1-nathan@kernel.org --- drivers/gpu/drm/i915/Makefile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b2a8406b5398..e1d6f551ab53 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -13,13 +13,11 @@ # will most likely get a sudden build breakage... Hopefully we will fix # new warnings before CI updates! subdir-ccflags-y := -Wall -Wextra -subdir-ccflags-y += $(call cc-disable-warning, unused-parameter) -subdir-ccflags-y += $(call cc-disable-warning, type-limits) -subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers) +subdir-ccflags-y += -Wno-unused-parameter +subdir-ccflags-y += -Wno-type-limits +subdir-ccflags-y += -Wno-missing-field-initializers +subdir-ccflags-y += -Wno-sign-compare subdir-ccflags-y += $(call cc-disable-warning, unused-but-set-variable) -# clang warnings -subdir-ccflags-y += $(call cc-disable-warning, sign-compare) -subdir-ccflags-y += $(call cc-disable-warning, initializer-overrides) subdir-ccflags-y += $(call cc-disable-warning, frame-address) subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror From d08df3b0bdb25546e86dc9a6c4e3ec0c43832299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 22:09:42 +0300 Subject: [PATCH 264/554] drm/i915: Extend the async flip VT-d w/a to skl/bxt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like skl/bxt/derivatives also need the plane stride stretch w/a when using async flips and VT-d is enabled, or else we get corruption on screen. To my surprise this was even documented in bspec, but only as a note on the CHICHKEN_PIPESL register description rather than on the w/a list. So very much the same thing as on HSW/BDW, except the bits moved yet again. Cc: stable@vger.kernel.org Cc: Karthik B S Fixes: 55ea1cb178ef ("drm/i915: Enable async flips in i915") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930190943.17547-1-ville.syrjala@linux.intel.com Reviewed-by: Matt Roper --- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ drivers/gpu/drm/i915/intel_pm.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c6e883bd4850..cfc40877681c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8192,6 +8192,11 @@ enum { #define HSW_SPR_STRETCH_MAX_X1 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 3) #define HSW_FBCQ_DIS (1 << 22) #define BDW_DPRS_MASK_VBLANK_SRD (1 << 0) +#define SKL_PLANE1_STRETCH_MAX_MASK REG_GENMASK(1, 0) +#define SKL_PLANE1_STRETCH_MAX_X8 REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 0) +#define SKL_PLANE1_STRETCH_MAX_X4 REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 1) +#define SKL_PLANE1_STRETCH_MAX_X2 REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 2) +#define SKL_PLANE1_STRETCH_MAX_X1 REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 3) #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) #define _CHICKEN_TRANS_A 0x420c0 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ef5f73934dab..74d4620a4999 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -76,6 +76,8 @@ struct intel_wm_config { static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) { + enum pipe pipe; + if (HAS_LLC(dev_priv)) { /* * WaCompressedResourceDisplayNewHashMode:skl,kbl @@ -89,6 +91,16 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) SKL_DE_COMPRESSED_HASH_MODE); } + for_each_pipe(dev_priv, pipe) { + /* + * "Plane N strech max must be programmed to 11b (x1) + * when Async flips are enabled on that plane." + */ + if (!IS_GEMINILAKE(dev_priv) && intel_vtd_active()) + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), + SKL_PLANE1_STRETCH_MAX_MASK, SKL_PLANE1_STRETCH_MAX_X1); + } + /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */ intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); From 7d396cacaea63bafe68d3a84971845c043b7c579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 30 Sep 2021 22:09:43 +0300 Subject: [PATCH 265/554] drm/i195: Make the async flip VT-d workaround dynamic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the VT-d vs. async flip issues are plaguing a wider range of supported hw let's try to minimize the impact on normal operation by flipping the relevant chicken bits on and off as needed. I presume there is some power/perf impact on since this is reducing some prefetching I think. Cc: Karthik B S Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210930190943.17547-2-ville.syrjala@linux.intel.com Reviewed-by: Matt Roper --- drivers/gpu/drm/i915/display/intel_display.c | 35 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 26 --------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 873b6b0c0581..b2e2e039744d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2311,6 +2311,33 @@ static bool needs_cursorclk_wa(const struct intel_crtc_state *crtc_state) return false; } +static void intel_async_flip_vtd_wa(struct drm_i915_private *i915, + enum pipe pipe, bool enable) +{ + if (DISPLAY_VER(i915) == 9) { + /* + * "Plane N strech max must be programmed to 11b (x1) + * when Async flips are enabled on that plane." + */ + intel_de_rmw(i915, CHICKEN_PIPESL_1(pipe), + SKL_PLANE1_STRETCH_MAX_MASK, + enable ? SKL_PLANE1_STRETCH_MAX_X1 : SKL_PLANE1_STRETCH_MAX_X8); + } else { + /* Also needed on HSW/BDW albeit undocumented */ + intel_de_rmw(i915, CHICKEN_PIPESL_1(pipe), + HSW_PRI_STRETCH_MAX_MASK, + enable ? HSW_PRI_STRETCH_MAX_X1 : HSW_PRI_STRETCH_MAX_X8); + } +} + +static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + return crtc_state->uapi.async_flip && intel_vtd_active() && + (DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915)); +} + static bool planes_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { @@ -2346,6 +2373,10 @@ static void intel_post_plane_update(struct intel_atomic_state *state, intel_fbc_post_update(state, crtc); intel_drrs_page_flip(state, crtc); + if (needs_async_flip_vtd_wa(old_crtc_state) && + !needs_async_flip_vtd_wa(new_crtc_state)) + intel_async_flip_vtd_wa(dev_priv, pipe, false); + if (needs_nv12_wa(old_crtc_state) && !needs_nv12_wa(new_crtc_state)) skl_wa_827(dev_priv, pipe, false); @@ -2444,6 +2475,10 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, if (intel_fbc_pre_update(state, crtc)) intel_wait_for_vblank(dev_priv, pipe); + if (!needs_async_flip_vtd_wa(old_crtc_state) && + needs_async_flip_vtd_wa(new_crtc_state)) + intel_async_flip_vtd_wa(dev_priv, pipe, true); + /* Display WA 827 */ if (!needs_nv12_wa(old_crtc_state) && needs_nv12_wa(new_crtc_state)) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 74d4620a4999..73178d0cf0c9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -76,8 +76,6 @@ struct intel_wm_config { static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) { - enum pipe pipe; - if (HAS_LLC(dev_priv)) { /* * WaCompressedResourceDisplayNewHashMode:skl,kbl @@ -91,16 +89,6 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) SKL_DE_COMPRESSED_HASH_MODE); } - for_each_pipe(dev_priv, pipe) { - /* - * "Plane N strech max must be programmed to 11b (x1) - * when Async flips are enabled on that plane." - */ - if (!IS_GEMINILAKE(dev_priv) && intel_vtd_active()) - intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), - SKL_PLANE1_STRETCH_MAX_MASK, SKL_PLANE1_STRETCH_MAX_X1); - } - /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */ intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); @@ -7599,11 +7587,6 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) | BDW_DPRS_MASK_VBLANK_SRD); - - /* Undocumented but fixes async flip + VT-d corruption */ - if (intel_vtd_active()) - intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), - HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1); } /* WaVSRefCountFullforceMissDisable:bdw */ @@ -7639,20 +7622,11 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) static void hsw_init_clock_gating(struct drm_i915_private *dev_priv) { - enum pipe pipe; - /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) | HSW_FBCQ_DIS); - for_each_pipe(dev_priv, pipe) { - /* Undocumented but fixes async flip + VT-d corruption */ - if (intel_vtd_active()) - intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), - HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1); - } - /* This is required by WaCatErrorRejectionIssue:hsw */ intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | From 84edf53776343d6b5bf5fa59a6f600a22ca23c40 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 1 Oct 2021 08:58:25 -0700 Subject: [PATCH 266/554] drm/i915: Fix bug in user proto-context creation that leaked contexts Set number of engines before attempting to create contexts so the function free_engines can clean up properly. Also check return of alloc_engines for NULL. v2: (Tvrtko) - Send as stand alone patch (John Harrison) - Check for alloc_engines returning NULL v3: (Checkpatch / Tvrtko) - Remove braces around single line if statement Cc: Jason Ekstrand Fixes: d4433c7600f7 ("drm/i915/gem: Use the proto-context to handle create parameters (v5)") Reviewed-by: Tvrtko Ursulin Signed-off-by: Matthew Brost Cc: Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211001155825.6762-1-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 51861a66547c..74e33a4cdfe8 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -941,6 +941,10 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, unsigned int n; e = alloc_engines(num_engines); + if (!e) + return ERR_PTR(-ENOMEM); + e->num_engines = num_engines; + for (n = 0; n < num_engines; n++) { struct intel_context *ce; int ret; @@ -974,7 +978,6 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, goto free_engines; } } - e->num_engines = num_engines; return e; From 85bb2f6e1c4b4c63cf8541c8c0167781edb4198f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2021 13:37:37 +0300 Subject: [PATCH 267/554] drm/i915/tc: Delete bogus NULL check in intel_ddi_encoder_destroy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "digi_port" pointer can't be NULL and we have already dereferenced it so checking for NULL is not necessary. Delete the check. Signed-off-by: Dan Carpenter Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004103737.GC25015@kili --- drivers/gpu/drm/i915/display/intel_ddi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 0d4cf7fa8720..3f7bbeb3e3cd 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3937,8 +3937,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) intel_display_power_flush_work(i915); drm_encoder_cleanup(encoder); - if (dig_port) - kfree(dig_port->hdcp_port_data.streams); + kfree(dig_port->hdcp_port_data.streams); kfree(dig_port); } From e7bd95a7ed4e4c8aa82a33f89eb09f596cf37a4b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 4 Oct 2021 09:21:27 -0700 Subject: [PATCH 268/554] drm/edid: Fix crash with zero/invalid EDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the commit bac9c2948224 ("drm/edid: Break out reading block 0 of the EDID") I broke out reading the base block of the EDID to its own function. Unfortunately, when I did that I messed up the handling when drm_edid_is_zero() indicated that we had an EDID that was all 0x00 or when we went through 4 loops and didn't get a valid EDID. Specifically I needed to pass the broken EDID to connector_bad_edid() but now I was passing an error-pointer. Let's re-jigger things so we can pass the bad EDID in properly. Fixes: bac9c2948224 ("drm/edid: Break out reading block 0 of the EDID") Reported-by: kernel test robot Reported-by: Geert Uytterhoeven Signed-off-by: Douglas Anderson Reviewed-by: Ville Syrjälä Tested-by: Geert Uytterhoeven Link: https://patchwork.freedesktop.org/patch/msgid/20211004092100.1.Ic90a5ebd44c75db963112be167a03cc96f9fb249@changeid --- drivers/gpu/drm/drm_edid.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9b19eee0e1b4..9c9463ec5465 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1911,13 +1911,15 @@ int drm_add_override_edid_modes(struct drm_connector *connector) } EXPORT_SYMBOL(drm_add_override_edid_modes); -static struct edid *drm_do_get_edid_base_block( +static struct edid *drm_do_get_edid_base_block(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len), - void *data, bool *edid_corrupt, int *null_edid_counter) + void *data) { - int i; + int *null_edid_counter = connector ? &connector->null_edid_counter : NULL; + bool *edid_corrupt = connector ? &connector->edid_corrupt : NULL; void *edid; + int i; edid = kmalloc(EDID_LENGTH, GFP_KERNEL); if (edid == NULL) @@ -1941,9 +1943,8 @@ static struct edid *drm_do_get_edid_base_block( return edid; carp: - kfree(edid); - return ERR_PTR(-EINVAL); - + if (connector) + connector_bad_edid(connector, edid, 1); out: kfree(edid); return NULL; @@ -1982,14 +1983,9 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, if (override) return override; - edid = (u8 *)drm_do_get_edid_base_block(get_edid_block, data, - &connector->edid_corrupt, - &connector->null_edid_counter); - if (IS_ERR_OR_NULL(edid)) { - if (IS_ERR(edid)) - connector_bad_edid(connector, edid, 1); + edid = (u8 *)drm_do_get_edid_base_block(connector, get_edid_block, data); + if (!edid) return NULL; - } /* if there's no extensions or no connector, we're done */ valid_extensions = edid[0x7e]; @@ -2142,14 +2138,13 @@ u32 drm_edid_get_panel_id(struct i2c_adapter *adapter) struct edid *edid; u32 panel_id; - edid = drm_do_get_edid_base_block(drm_do_probe_ddc_edid, adapter, - NULL, NULL); + edid = drm_do_get_edid_base_block(NULL, drm_do_probe_ddc_edid, adapter); /* * There are no manufacturer IDs of 0, so if there is a problem reading * the EDID then we'll just return 0. */ - if (IS_ERR_OR_NULL(edid)) + if (!edid) return 0; panel_id = edid_extract_panel_id(edid); From 07f82a47e8a985ef939826ee8d75fe108c98126e Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 5 Oct 2021 12:31:35 +0100 Subject: [PATCH 269/554] drm/i915: Handle Intel igfx + Intel dgfx hybrid graphics setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In short this makes i915 work for hybrid setups (DRI_PRIME=1 with Mesa) when rendering is done on Intel dgfx and scanout/composition on Intel igfx. Before this patch the driver was not quite ready for that setup, mainly because it was able to emit a semaphore wait between the two GPUs, which results in deadlocks because semaphore target location in HWSP is neither shared between the two, nor mapped in both GGTT spaces. To fix it the patch adds an additional check to a couple of relevant code paths in order to prevent using semaphores for inter-engine synchronisation when relevant objects are not in the same GGTT space. v2: * Avoid adding rq->i915. (Chris) v3: * Use GGTT which describes the limit more precisely. Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211005113135.768295-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_request.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 79da5eca60af..4f189982f67e 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1145,6 +1145,12 @@ __emit_semaphore_wait(struct i915_request *to, return 0; } +static bool +can_use_semaphore_wait(struct i915_request *to, struct i915_request *from) +{ + return to->engine->gt->ggtt == from->engine->gt->ggtt; +} + static int emit_semaphore_wait(struct i915_request *to, struct i915_request *from, @@ -1153,6 +1159,9 @@ emit_semaphore_wait(struct i915_request *to, const intel_engine_mask_t mask = READ_ONCE(from->engine)->mask; struct i915_sw_fence *wait = &to->submit; + if (!can_use_semaphore_wait(to, from)) + goto await_fence; + if (!intel_context_use_semaphores(to->context)) goto await_fence; @@ -1256,7 +1265,8 @@ __i915_request_await_execution(struct i915_request *to, * immediate execution, and so we must wait until it reaches the * active slot. */ - if (intel_engine_has_semaphores(to->engine) && + if (can_use_semaphore_wait(to, from) && + intel_engine_has_semaphores(to->engine) && !i915_request_has_initial_breadcrumb(to)) { err = __emit_semaphore_wait(to, from, from->fence.seqno - 1); if (err < 0) From c921ff373b469ad7907cde219fa700909f59cac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 15:10:03 +0200 Subject: [PATCH 270/554] dma-buf: add dma_resv_for_each_fence_unlocked v8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract the complexity of iterating over all the fences in a dma_resv object. The new loop handles the whole RCU and retry dance and returns only fences where we can be sure we grabbed the right one. v2: fix accessing the shared fences while they might be freed, improve kerneldoc, rename _cursor to _iter, add dma_resv_iter_is_exclusive, add dma_resv_iter_begin/end v3: restructor the code, move rcu_read_lock()/unlock() into the iterator, add dma_resv_iter_is_restarted() v4: fix NULL deref when no explicit fence exists, drop superflous rcu_read_lock()/unlock() calls. v5: fix typos in the documentation v6: fix coding error when excl fence is NULL v7: one more logic fix v8: fix index check in dma_resv_iter_is_exclusive() Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin (v7) Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-2-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 100 +++++++++++++++++++++++++++++++++++++ include/linux/dma-resv.h | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 84fbe60629e3..3cbcf66a137e 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -323,6 +323,106 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence) } EXPORT_SYMBOL(dma_resv_add_excl_fence); +/** + * dma_resv_iter_restart_unlocked - restart the unlocked iterator + * @cursor: The dma_resv_iter object to restart + * + * Restart the unlocked iteration by initializing the cursor object. + */ +static void dma_resv_iter_restart_unlocked(struct dma_resv_iter *cursor) +{ + cursor->seq = read_seqcount_begin(&cursor->obj->seq); + cursor->index = -1; + if (cursor->all_fences) + cursor->fences = dma_resv_shared_list(cursor->obj); + else + cursor->fences = NULL; + cursor->is_restarted = true; +} + +/** + * dma_resv_iter_walk_unlocked - walk over fences in a dma_resv obj + * @cursor: cursor to record the current position + * + * Return all the fences in the dma_resv object which are not yet signaled. + * The returned fence has an extra local reference so will stay alive. + * If a concurrent modify is detected the whole iteration is started over again. + */ +static void dma_resv_iter_walk_unlocked(struct dma_resv_iter *cursor) +{ + struct dma_resv *obj = cursor->obj; + + do { + /* Drop the reference from the previous round */ + dma_fence_put(cursor->fence); + + if (cursor->index == -1) { + cursor->fence = dma_resv_excl_fence(obj); + cursor->index++; + if (!cursor->fence) + continue; + + } else if (!cursor->fences || + cursor->index >= cursor->fences->shared_count) { + cursor->fence = NULL; + break; + + } else { + struct dma_resv_list *fences = cursor->fences; + unsigned int idx = cursor->index++; + + cursor->fence = rcu_dereference(fences->shared[idx]); + } + cursor->fence = dma_fence_get_rcu(cursor->fence); + if (!cursor->fence || !dma_fence_is_signaled(cursor->fence)) + break; + } while (true); +} + +/** + * dma_resv_iter_first_unlocked - first fence in an unlocked dma_resv obj. + * @cursor: the cursor with the current position + * + * Returns the first fence from an unlocked dma_resv obj. + */ +struct dma_fence *dma_resv_iter_first_unlocked(struct dma_resv_iter *cursor) +{ + rcu_read_lock(); + do { + dma_resv_iter_restart_unlocked(cursor); + dma_resv_iter_walk_unlocked(cursor); + } while (read_seqcount_retry(&cursor->obj->seq, cursor->seq)); + rcu_read_unlock(); + + return cursor->fence; +} +EXPORT_SYMBOL(dma_resv_iter_first_unlocked); + +/** + * dma_resv_iter_next_unlocked - next fence in an unlocked dma_resv obj. + * @cursor: the cursor with the current position + * + * Returns the next fence from an unlocked dma_resv obj. + */ +struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor) +{ + bool restart; + + rcu_read_lock(); + cursor->is_restarted = false; + restart = read_seqcount_retry(&cursor->obj->seq, cursor->seq); + do { + if (restart) + dma_resv_iter_restart_unlocked(cursor); + dma_resv_iter_walk_unlocked(cursor); + restart = true; + } while (read_seqcount_retry(&cursor->obj->seq, cursor->seq)); + rcu_read_unlock(); + + return cursor->fence; +} +EXPORT_SYMBOL(dma_resv_iter_next_unlocked); + /** * dma_resv_copy_fences - Copy all fences from src to dst. * @dst: the destination reservation object diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index 9100dd3dc21f..764138ad8583 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -149,6 +149,101 @@ struct dma_resv { struct dma_resv_list __rcu *fence; }; +/** + * struct dma_resv_iter - current position into the dma_resv fences + * + * Don't touch this directly in the driver, use the accessor function instead. + */ +struct dma_resv_iter { + /** @obj: The dma_resv object we iterate over */ + struct dma_resv *obj; + + /** @all_fences: If all fences should be returned */ + bool all_fences; + + /** @fence: the currently handled fence */ + struct dma_fence *fence; + + /** @seq: sequence number to check for modifications */ + unsigned int seq; + + /** @index: index into the shared fences */ + unsigned int index; + + /** @fences: the shared fences */ + struct dma_resv_list *fences; + + /** @is_restarted: true if this is the first returned fence */ + bool is_restarted; +}; + +struct dma_fence *dma_resv_iter_first_unlocked(struct dma_resv_iter *cursor); +struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor); + +/** + * dma_resv_iter_begin - initialize a dma_resv_iter object + * @cursor: The dma_resv_iter object to initialize + * @obj: The dma_resv object which we want to iterate over + * @all_fences: If all fences should be returned or just the exclusive one + */ +static inline void dma_resv_iter_begin(struct dma_resv_iter *cursor, + struct dma_resv *obj, + bool all_fences) +{ + cursor->obj = obj; + cursor->all_fences = all_fences; + cursor->fence = NULL; +} + +/** + * dma_resv_iter_end - cleanup a dma_resv_iter object + * @cursor: the dma_resv_iter object which should be cleaned up + * + * Make sure that the reference to the fence in the cursor is properly + * dropped. + */ +static inline void dma_resv_iter_end(struct dma_resv_iter *cursor) +{ + dma_fence_put(cursor->fence); +} + +/** + * dma_resv_iter_is_exclusive - test if the current fence is the exclusive one + * @cursor: the cursor of the current position + * + * Returns true if the currently returned fence is the exclusive one. + */ +static inline bool dma_resv_iter_is_exclusive(struct dma_resv_iter *cursor) +{ + return cursor->index == 0; +} + +/** + * dma_resv_iter_is_restarted - test if this is the first fence after a restart + * @cursor: the cursor with the current position + * + * Return true if this is the first fence in an iteration after a restart. + */ +static inline bool dma_resv_iter_is_restarted(struct dma_resv_iter *cursor) +{ + return cursor->is_restarted; +} + +/** + * dma_resv_for_each_fence_unlocked - unlocked fence iterator + * @cursor: a struct dma_resv_iter pointer + * @fence: the current fence + * + * Iterate over the fences in a struct dma_resv object without holding the + * &dma_resv.lock and using RCU instead. The cursor needs to be initialized + * with dma_resv_iter_begin() and cleaned up with dma_resv_iter_end(). Inside + * the iterator a reference to the dma_fence is held and the RCU lock dropped. + * When the dma_resv is modified the iteration starts over again. + */ +#define dma_resv_for_each_fence_unlocked(cursor, fence) \ + for (fence = dma_resv_iter_first_unlocked(cursor); \ + fence; fence = dma_resv_iter_next_unlocked(cursor)) + #define dma_resv_held(obj) lockdep_is_held(&(obj)->lock.base) #define dma_resv_assert_held(obj) lockdep_assert_held(&(obj)->lock.base) From 96601e8a4755d333a8d2e826134d5220ae2e8c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 15:15:01 +0200 Subject: [PATCH 271/554] dma-buf: use new iterator in dma_resv_copy_fences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the function much simpler since the complex retry logic is now handled else where. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-5-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 88 +++++++++++++++----------------------- 1 file changed, 34 insertions(+), 54 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 3cbcf66a137e..08e5b8c381f4 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -432,74 +432,54 @@ EXPORT_SYMBOL(dma_resv_iter_next_unlocked); */ int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src) { - struct dma_resv_list *src_list, *dst_list; - struct dma_fence *old, *new; - unsigned int i; + struct dma_resv_iter cursor; + struct dma_resv_list *list; + struct dma_fence *f, *excl; dma_resv_assert_held(dst); - rcu_read_lock(); - src_list = dma_resv_shared_list(src); + list = NULL; + excl = NULL; -retry: - if (src_list) { - unsigned int shared_count = src_list->shared_count; + dma_resv_iter_begin(&cursor, src, true); + dma_resv_for_each_fence_unlocked(&cursor, f) { - rcu_read_unlock(); + if (dma_resv_iter_is_restarted(&cursor)) { + dma_resv_list_free(list); + dma_fence_put(excl); - dst_list = dma_resv_list_alloc(shared_count); - if (!dst_list) - return -ENOMEM; + if (cursor.fences) { + unsigned int cnt = cursor.fences->shared_count; - rcu_read_lock(); - src_list = dma_resv_shared_list(src); - if (!src_list || src_list->shared_count > shared_count) { - kfree(dst_list); - goto retry; + list = dma_resv_list_alloc(cnt); + if (!list) { + dma_resv_iter_end(&cursor); + return -ENOMEM; + } + + list->shared_count = 0; + + } else { + list = NULL; + } + excl = NULL; } - dst_list->shared_count = 0; - for (i = 0; i < src_list->shared_count; ++i) { - struct dma_fence __rcu **dst; - struct dma_fence *fence; - - fence = rcu_dereference(src_list->shared[i]); - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, - &fence->flags)) - continue; - - if (!dma_fence_get_rcu(fence)) { - dma_resv_list_free(dst_list); - src_list = dma_resv_shared_list(src); - goto retry; - } - - if (dma_fence_is_signaled(fence)) { - dma_fence_put(fence); - continue; - } - - dst = &dst_list->shared[dst_list->shared_count++]; - rcu_assign_pointer(*dst, fence); - } - } else { - dst_list = NULL; + dma_fence_get(f); + if (dma_resv_iter_is_exclusive(&cursor)) + excl = f; + else + RCU_INIT_POINTER(list->shared[list->shared_count++], f); } - - new = dma_fence_get_rcu_safe(&src->fence_excl); - rcu_read_unlock(); - - src_list = dma_resv_shared_list(dst); - old = dma_resv_excl_fence(dst); + dma_resv_iter_end(&cursor); write_seqcount_begin(&dst->seq); - /* write_seqcount_begin provides the necessary memory barrier */ - RCU_INIT_POINTER(dst->fence_excl, new); - RCU_INIT_POINTER(dst->fence, dst_list); + excl = rcu_replace_pointer(dst->fence_excl, excl, dma_resv_held(dst)); + list = rcu_replace_pointer(dst->fence, list, dma_resv_held(dst)); write_seqcount_end(&dst->seq); - dma_resv_list_free(src_list); - dma_fence_put(old); + dma_resv_list_free(list); + dma_fence_put(excl); return 0; } From d3c80698c9f58a0683badf78793eebaa0c71afbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 15:25:22 +0200 Subject: [PATCH 272/554] dma-buf: use new iterator in dma_resv_get_fences v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the function much simpler since the complex retry logic is now handled elsewhere. v2: use sizeof(void*) instead v3: fix rebase bug Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-6-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 108 ++++++++++++------------------------- 1 file changed, 35 insertions(+), 73 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 08e5b8c381f4..5d4fe62cc132 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -489,99 +489,61 @@ EXPORT_SYMBOL(dma_resv_copy_fences); * dma_resv_get_fences - Get an object's shared and exclusive * fences without update side lock held * @obj: the reservation object - * @pfence_excl: the returned exclusive fence (or NULL) - * @pshared_count: the number of shared fences returned - * @pshared: the array of shared fence ptrs returned (array is krealloc'd to + * @fence_excl: the returned exclusive fence (or NULL) + * @shared_count: the number of shared fences returned + * @shared: the array of shared fence ptrs returned (array is krealloc'd to * the required size, and must be freed by caller) * * Retrieve all fences from the reservation object. If the pointer for the * exclusive fence is not specified the fence is put into the array of the * shared fences as well. Returns either zero or -ENOMEM. */ -int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, - unsigned int *pshared_count, - struct dma_fence ***pshared) +int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl, + unsigned int *shared_count, struct dma_fence ***shared) { - struct dma_fence **shared = NULL; - struct dma_fence *fence_excl; - unsigned int shared_count; - int ret = 1; + struct dma_resv_iter cursor; + struct dma_fence *fence; - do { - struct dma_resv_list *fobj; - unsigned int i, seq; - size_t sz = 0; + *shared_count = 0; + *shared = NULL; - shared_count = i = 0; + if (fence_excl) + *fence_excl = NULL; - rcu_read_lock(); - seq = read_seqcount_begin(&obj->seq); + dma_resv_iter_begin(&cursor, obj, true); + dma_resv_for_each_fence_unlocked(&cursor, fence) { - fence_excl = dma_resv_excl_fence(obj); - if (fence_excl && !dma_fence_get_rcu(fence_excl)) - goto unlock; + if (dma_resv_iter_is_restarted(&cursor)) { + unsigned int count; - fobj = dma_resv_shared_list(obj); - if (fobj) - sz += sizeof(*shared) * fobj->shared_max; + while (*shared_count) + dma_fence_put((*shared)[--(*shared_count)]); - if (!pfence_excl && fence_excl) - sz += sizeof(*shared); + if (fence_excl) + dma_fence_put(*fence_excl); - if (sz) { - struct dma_fence **nshared; + count = cursor.fences ? cursor.fences->shared_count : 0; + count += fence_excl ? 0 : 1; - nshared = krealloc(shared, sz, - GFP_NOWAIT | __GFP_NOWARN); - if (!nshared) { - rcu_read_unlock(); - - dma_fence_put(fence_excl); - fence_excl = NULL; - - nshared = krealloc(shared, sz, GFP_KERNEL); - if (nshared) { - shared = nshared; - continue; - } - - ret = -ENOMEM; - break; - } - shared = nshared; - shared_count = fobj ? fobj->shared_count : 0; - for (i = 0; i < shared_count; ++i) { - shared[i] = rcu_dereference(fobj->shared[i]); - if (!dma_fence_get_rcu(shared[i])) - break; + /* Eventually re-allocate the array */ + *shared = krealloc_array(*shared, count, + sizeof(void *), + GFP_KERNEL); + if (count && !*shared) { + dma_resv_iter_end(&cursor); + return -ENOMEM; } } - if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { - while (i--) - dma_fence_put(shared[i]); - dma_fence_put(fence_excl); - goto unlock; - } - - ret = 0; -unlock: - rcu_read_unlock(); - } while (ret); - - if (pfence_excl) - *pfence_excl = fence_excl; - else if (fence_excl) - shared[shared_count++] = fence_excl; - - if (!shared_count) { - kfree(shared); - shared = NULL; + dma_fence_get(fence); + if (dma_resv_iter_is_exclusive(&cursor) && fence_excl) + *fence_excl = fence; + else + (*shared)[(*shared_count)++] = fence; } + dma_resv_iter_end(&cursor); - *pshared_count = shared_count; - *pshared = shared; - return ret; + return 0; } EXPORT_SYMBOL_GPL(dma_resv_get_fences); From ada5c48b11a3df814701daa9cd11305a75a5f1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 15:28:03 +0200 Subject: [PATCH 273/554] dma-buf: use new iterator in dma_resv_wait_timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the function much simpler since the complex retry logic is now handled elsewhere. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-7-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 71 +++++--------------------------------- 1 file changed, 9 insertions(+), 62 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 5d4fe62cc132..61efa557dcf3 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -565,74 +565,21 @@ long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, unsigned long timeout) { long ret = timeout ? timeout : 1; - unsigned int seq, shared_count; + struct dma_resv_iter cursor; struct dma_fence *fence; - int i; -retry: - shared_count = 0; - seq = read_seqcount_begin(&obj->seq); - rcu_read_lock(); - i = -1; - - fence = dma_resv_excl_fence(obj); - if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { - if (!dma_fence_get_rcu(fence)) - goto unlock_retry; - - if (dma_fence_is_signaled(fence)) { - dma_fence_put(fence); - fence = NULL; - } - - } else { - fence = NULL; - } - - if (wait_all) { - struct dma_resv_list *fobj = dma_resv_shared_list(obj); - - if (fobj) - shared_count = fobj->shared_count; - - for (i = 0; !fence && i < shared_count; ++i) { - struct dma_fence *lfence; - - lfence = rcu_dereference(fobj->shared[i]); - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, - &lfence->flags)) - continue; - - if (!dma_fence_get_rcu(lfence)) - goto unlock_retry; - - if (dma_fence_is_signaled(lfence)) { - dma_fence_put(lfence); - continue; - } - - fence = lfence; - break; - } - } - - rcu_read_unlock(); - if (fence) { - if (read_seqcount_retry(&obj->seq, seq)) { - dma_fence_put(fence); - goto retry; - } + dma_resv_iter_begin(&cursor, obj, wait_all); + dma_resv_for_each_fence_unlocked(&cursor, fence) { ret = dma_fence_wait_timeout(fence, intr, ret); - dma_fence_put(fence); - if (ret > 0 && wait_all && (i + 1 < shared_count)) - goto retry; + if (ret <= 0) { + dma_resv_iter_end(&cursor); + return ret; + } } - return ret; + dma_resv_iter_end(&cursor); -unlock_retry: - rcu_read_unlock(); - goto retry; + return ret; } EXPORT_SYMBOL_GPL(dma_resv_wait_timeout); From 7fa828cb926532a90de23763bc143523d2ff209c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 15 Jun 2021 15:34:11 +0200 Subject: [PATCH 274/554] dma-buf: use new iterator in dma_resv_test_signaled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the function much simpler since the complex retry logic is now handled elsewhere. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-8-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 57 +++++--------------------------------- 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 61efa557dcf3..a480af9581bd 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -584,22 +584,6 @@ long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, EXPORT_SYMBOL_GPL(dma_resv_wait_timeout); -static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) -{ - struct dma_fence *fence, *lfence = passed_fence; - int ret = 1; - - if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) { - fence = dma_fence_get_rcu(lfence); - if (!fence) - return -1; - - ret = !!dma_fence_is_signaled(fence); - dma_fence_put(fence); - } - return ret; -} - /** * dma_resv_test_signaled - Test if a reservation object's fences have been * signaled. @@ -616,43 +600,16 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) */ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) { + struct dma_resv_iter cursor; struct dma_fence *fence; - unsigned int seq; - int ret; - rcu_read_lock(); -retry: - ret = true; - seq = read_seqcount_begin(&obj->seq); - - if (test_all) { - struct dma_resv_list *fobj = dma_resv_shared_list(obj); - unsigned int i, shared_count; - - shared_count = fobj ? fobj->shared_count : 0; - for (i = 0; i < shared_count; ++i) { - fence = rcu_dereference(fobj->shared[i]); - ret = dma_resv_test_signaled_single(fence); - if (ret < 0) - goto retry; - else if (!ret) - break; - } + dma_resv_iter_begin(&cursor, obj, test_all); + dma_resv_for_each_fence_unlocked(&cursor, fence) { + dma_resv_iter_end(&cursor); + return false; } - - fence = dma_resv_excl_fence(obj); - if (ret && fence) { - ret = dma_resv_test_signaled_single(fence); - if (ret < 0) - goto retry; - - } - - if (read_seqcount_retry(&obj->seq, seq)) - goto retry; - - rcu_read_unlock(); - return ret; + dma_resv_iter_end(&cursor); + return true; } EXPORT_SYMBOL_GPL(dma_resv_test_signaled); From 9962601ca5719050906915c3c33a63744ac7b15c Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 22 Sep 2021 20:59:08 +0800 Subject: [PATCH 275/554] drm/bridge: dw-hdmi-cec: Make use of the helper function devm_add_action_or_reset() The helper function devm_add_action_or_reset() will internally call devm_add_action(), and if devm_add_action() fails then it will execute the action mentioned and return the error code. So use devm_add_action_or_reset() instead of devm_add_action() to simplify the error handling, reduce the code. Signed-off-by: Cai Huoqing Reviewed-by: Laurent Pinchart Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20210922125909.215-1-caihuoqing@baidu.com --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c index 70ab4fbdc23e..c8f44bcb298a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c @@ -265,11 +265,9 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev) /* override the module pointer */ cec->adap->owner = THIS_MODULE; - ret = devm_add_action(&pdev->dev, dw_hdmi_cec_del, cec); - if (ret) { - cec_delete_adapter(cec->adap); + ret = devm_add_action_or_reset(&pdev->dev, dw_hdmi_cec_del, cec); + if (ret) return ret; - } ret = devm_request_threaded_irq(&pdev->dev, cec->irq, dw_hdmi_cec_hardirq, From 8bc2f5c3c50eb45e7d9229e57efcf4b34b45aba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Oct 2021 20:05:31 +0300 Subject: [PATCH 276/554] drm/i915: Tweak the DP "max vswing reached?" condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we consider the max vswing reached when we transmit a the max voltage level, but we don't consider pre-emphasis at all. This kinda matches older DP specs that only had some vague text about transmitting the maximum voltage swing. Latest versions now say something vague about consider the sum of the vswing and pre-emphasis fields in the ADJUST_REQUEST_LANE registers. Very vague, and super confusing especially the fact that it talks about transmitted voltgage swing in the same sentence as it say to look at the requested values. Also glanced at the link CTS spec, and that one seems to have tests that assume contradicting behaviour. Some say to consider just the vswing level we transmit, others say to check for sum of transmitted vswing+preemph being 3. So let's try to take some kind of sane middle ground here. I think what could make sense is only consider max vswing reached if MAX_SWING_REACHED==1 _and_ vswing+preemph==3. That will allow things to go all the way up to vswing 3 + pre-emph 0 or vswing 2 + pre-emph 1, depending on what the maximum supported vswing is. Only considering the sum of vswing+pre-emph doesn't make much sense to me since we could terminate too early if the sink requests eg. vswing 0 + pre-emph 3. And if we'd stick to the current code we could terminate too early of the sink asks for vswing 2 + pre-emph 0 when vswing level 3 is not supported. Side note: I don't really understand why any of this stuff is "specified" at all. There is already a limit of 5 attempts at the same vswing+pre-emph level, and a total limit of 10 attempts. So might as well stick to the same max 5 attempts across the board IMO. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004170535.4173-2-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- .../drm/i915/display/intel_dp_link_training.c | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index c052ce14894d..a45569b8c959 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -492,11 +492,27 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp, { int lane; - for (lane = 0; lane < crtc_state->lane_count; lane++) - if ((intel_dp->train_set[lane] & - DP_TRAIN_MAX_SWING_REACHED) == 0) + /* + * FIXME: The DP spec is very confusing here, also the Link CTS + * spec seems to have self contradicting tests around this area. + * + * In lieu of better ideas let's just stop when we've reached the + * max supported vswing with its max pre-emphasis, which is either + * 2+1 or 3+0 depending on whether vswing level 3 is supported or not. + */ + for (lane = 0; lane < crtc_state->lane_count; lane++) { + u8 v = (intel_dp->train_set[lane] & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + u8 p = (intel_dp->train_set[lane] & DP_TRAIN_PRE_EMPHASIS_MASK) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + + if ((intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0) return false; + if (v + p != 3) + return false; + } + return true; } From be1525048c587efbe8e647a3980d75244b55abc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Oct 2021 20:05:32 +0300 Subject: [PATCH 277/554] drm/i915: Show LTTPR in the TPS debug print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Indicate which LTTPR we're currently attempting to train when we print which training pattern we're using. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004170535.4173-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/g4x_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 11 +++++++---- drivers/gpu/drm/i915/display/intel_dp_link_training.h | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 60ae2ba52006..85a09c3e09e8 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -637,7 +637,7 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp, /* enable with pattern 1 (as per spec) */ intel_dp_program_link_training_pattern(intel_dp, crtc_state, - DP_TRAINING_PATTERN_1); + DP_PHY_DPRX, DP_TRAINING_PATTERN_1); /* * Magic for VLV/CHV. We _must_ first set up the register diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index a45569b8c959..6bab097cafd2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -376,7 +376,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, int len; intel_dp_program_link_training_pattern(intel_dp, crtc_state, - dp_train_pat); + dp_phy, dp_train_pat); buf[0] = dp_train_pat; /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ @@ -404,17 +404,20 @@ static char dp_training_pattern_name(u8 train_pat) void intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, u8 dp_train_pat) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u8 train_pat = intel_dp_training_pattern_symbol(dp_train_pat); + char phy_name[10]; if (train_pat != DP_TRAINING_PATTERN_DISABLE) drm_dbg_kms(&dev_priv->drm, - "[ENCODER:%d:%s] Using DP training pattern TPS%c\n", + "[ENCODER:%d:%s] Using DP training pattern TPS%c, at %s\n", encoder->base.base.id, encoder->base.name, - dp_training_pattern_name(train_pat)); + dp_training_pattern_name(train_pat), + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat); } @@ -855,7 +858,7 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp, intel_dp->link_trained = true; intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX); - intel_dp_program_link_training_pattern(intel_dp, crtc_state, + intel_dp_program_link_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX, DP_TRAINING_PATTERN_DISABLE); } diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index 9d24d594368c..6a3a7b37349a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -19,6 +19,7 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp, const u8 link_status[DP_LINK_STATUS_SIZE]); void intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, u8 dp_train_pat); void intel_dp_set_signal_levels(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, From 1f662675335b884fe76a7899901b0761fa2e472e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Oct 2021 20:05:33 +0300 Subject: [PATCH 278/554] drm/i915: Print the DP vswing adjustment request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print out each DP vswing adjustment request we got from the RX. Could help in diagnosing what's going on during link training. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004170535.4173-4-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- .../drm/i915/display/intel_dp_link_training.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 6bab097cafd2..5657be1461ec 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -343,14 +343,41 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, return v | p; } +#define TRAIN_REQ_FMT "%d/%d/%d/%d" +#define _TRAIN_REQ_VSWING_ARGS(link_status, lane) \ + (drm_dp_get_adjust_request_voltage((link_status), (lane)) >> DP_TRAIN_VOLTAGE_SWING_SHIFT) +#define TRAIN_REQ_VSWING_ARGS(link_status) \ + _TRAIN_REQ_VSWING_ARGS(link_status, 0), \ + _TRAIN_REQ_VSWING_ARGS(link_status, 1), \ + _TRAIN_REQ_VSWING_ARGS(link_status, 2), \ + _TRAIN_REQ_VSWING_ARGS(link_status, 3) +#define _TRAIN_REQ_PREEMPH_ARGS(link_status, lane) \ + (drm_dp_get_adjust_request_pre_emphasis((link_status), (lane)) >> DP_TRAIN_PRE_EMPHASIS_SHIFT) +#define TRAIN_REQ_PREEMPH_ARGS(link_status) \ + _TRAIN_REQ_PREEMPH_ARGS(link_status, 0), \ + _TRAIN_REQ_PREEMPH_ARGS(link_status, 1), \ + _TRAIN_REQ_PREEMPH_ARGS(link_status, 2), \ + _TRAIN_REQ_PREEMPH_ARGS(link_status, 3) + void intel_dp_get_adjust_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy, const u8 link_status[DP_LINK_STATUS_SIZE]) { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + char phy_name[10]; int lane; + drm_dbg_kms(encoder->base.dev, "[ENCODER:%d:%s] lanes: %d, " + "vswing request: " TRAIN_REQ_FMT ", " + "pre-emphasis request: " TRAIN_REQ_FMT ", at %s\n", + encoder->base.base.id, encoder->base.name, + crtc_state->lane_count, + TRAIN_REQ_VSWING_ARGS(link_status), + TRAIN_REQ_PREEMPH_ARGS(link_status), + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); + for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = intel_dp_get_lane_adjust_train(intel_dp, crtc_state, From 6c4d46523bf30772d8f68a9233853c3357bbb8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Oct 2021 20:05:34 +0300 Subject: [PATCH 279/554] drm/i915: Pimp link training debug prints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify all debug prints during link training to include information on both the encoder and the LTTPR. We unify the format to something like "[ENCODER:1:FOO][LTTPR 1] Something something". Though not sure if those brackets around the dp_phy just make it look like line noise? I'll accept suggestions on better formatting. I'm slightly on the fence about also including the connector, but technically only the DPRX is the SST connector (ie. intel_dp->attached_connector). I suppose you could think of it as the branch device/whatever in the topology, and we're training the link leading to it. So that could argue for its inclusion. But it's all getting a bit long alrady, so not going to do it I think. v2: Keep the connector name in the final passed/failed debug print Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004170535.4173-5-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- .../drm/i915/display/intel_dp_link_training.c | 169 +++++++++++------- 1 file changed, 108 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 5657be1461ec..681c8bc53dd4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -25,15 +25,6 @@ #include "intel_dp.h" #include "intel_dp_link_training.h" -static void -intel_dp_dump_link_status(struct drm_device *drm, - const u8 link_status[DP_LINK_STATUS_SIZE]) -{ - drm_dbg_kms(drm, - "ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n", - link_status[0], link_status[1], link_status[2], - link_status[3], link_status[4], link_status[5]); -} static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp) { @@ -66,6 +57,7 @@ static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp, static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy); char phy_name[10]; @@ -73,21 +65,22 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) { drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "failed to read the PHY caps for %s\n", - phy_name); + "[ENCODER:%d:%s][%s] failed to read the PHY caps\n", + encoder->base.base.id, encoder->base.name, phy_name); return; } drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "%s PHY capabilities: %*ph\n", - phy_name, + "[ENCODER:%d:%s][%s] PHY capabilities: %*ph\n", + encoder->base.base.id, encoder->base.name, phy_name, (int)sizeof(intel_dp->lttpr_phy_caps[0]), phy_caps); } static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); if (intel_dp_is_edp(intel_dp)) return false; @@ -104,7 +97,8 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) goto reset_caps; drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "LTTPR common capabilities: %*ph\n", + "[ENCODER:%d:%s] LTTPR common capabilities: %*ph\n", + encoder->base.base.id, encoder->base.name, (int)sizeof(intel_dp->lttpr_common_caps), intel_dp->lttpr_common_caps); @@ -130,6 +124,8 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) static int intel_dp_init_lttpr(struct intel_dp *intel_dp) { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); int lttpr_count; int i; @@ -161,8 +157,9 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp) return 0; if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false)) { - drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n"); + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s] Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n", + encoder->base.base.id, encoder->base.name); intel_dp_set_lttpr_transparent_mode(intel_dp, true); intel_dp_reset_lttpr_count(intel_dp); @@ -366,17 +363,18 @@ intel_dp_get_adjust_train(struct intel_dp *intel_dp, const u8 link_status[DP_LINK_STATUS_SIZE]) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); char phy_name[10]; int lane; - drm_dbg_kms(encoder->base.dev, "[ENCODER:%d:%s] lanes: %d, " + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " "vswing request: " TRAIN_REQ_FMT ", " - "pre-emphasis request: " TRAIN_REQ_FMT ", at %s\n", + "pre-emphasis request: " TRAIN_REQ_FMT "\n", encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), crtc_state->lane_count, TRAIN_REQ_VSWING_ARGS(link_status), - TRAIN_REQ_PREEMPH_ARGS(link_status), - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); + TRAIN_REQ_PREEMPH_ARGS(link_status)); for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = @@ -435,16 +433,16 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, u8 dp_train_pat) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 train_pat = intel_dp_training_pattern_symbol(dp_train_pat); char phy_name[10]; if (train_pat != DP_TRAINING_PATTERN_DISABLE) - drm_dbg_kms(&dev_priv->drm, - "[ENCODER:%d:%s] Using DP training pattern TPS%c, at %s\n", + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][%s] Using DP training pattern TPS%c\n", encoder->base.base.id, encoder->base.name, - dp_training_pattern_name(train_pat), - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + dp_training_pattern_name(train_pat)); intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat); } @@ -472,17 +470,17 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); char phy_name[10]; - drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] lanes: %d, " + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " "vswing levels: " TRAIN_SET_FMT ", " - "pre-emphasis levels: " TRAIN_SET_FMT ", at %s\n", + "pre-emphasis levels: " TRAIN_SET_FMT "\n", encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), crtc_state->lane_count, TRAIN_SET_VSWING_ARGS(intel_dp->train_set), - TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set), - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); + TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set)); if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy)) encoder->set_signal_levels(encoder, crtc_state); @@ -554,7 +552,8 @@ static bool intel_dp_prepare_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 link_config[2]; u8 link_bw, rate_select; @@ -566,10 +565,12 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp, if (link_bw) drm_dbg_kms(&i915->drm, - "Using LINK_BW_SET value %02x\n", link_bw); + "[ENCODER:%d:%s] Using LINK_BW_SET value %02x\n", + encoder->base.base.id, encoder->base.name, link_bw); else drm_dbg_kms(&i915->drm, - "Using LINK_RATE_SET value %02x\n", rate_select); + "[ENCODER:%d:%s] Using LINK_RATE_SET value %02x\n", + encoder->base.base.id, encoder->base.name, rate_select); /* Write the link configuration data */ link_config[0] = link_bw; @@ -619,6 +620,22 @@ static bool intel_dp_adjust_request_changed(int lane_count, return false; } +static void +intel_dp_dump_link_status(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE]) +{ + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + char phy_name[10]; + + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][%s] ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n", + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + link_status[0], link_status[1], link_status[2], + link_status[3], link_status[4], link_status[5]); +} + /* * Perform the link training clock recovery phase on the given DP PHY using * training pattern 1. @@ -628,16 +645,21 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 old_link_status[DP_LINK_STATUS_SIZE] = {}; int voltage_tries, cr_tries, max_cr_tries; bool max_vswing_reached = false; + char phy_name[10]; + + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)); /* clock recovery */ if (!intel_dp_reset_link_train(intel_dp, crtc_state, dp_phy, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE)) { - drm_err(&i915->drm, "failed to enable link training\n"); + drm_err(&i915->drm, "[ENCODER:%d:%s][%s] Failed to enable link training\n", + encoder->base.base.id, encoder->base.name, phy_name); return false; } @@ -662,23 +684,29 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy, link_status) < 0) { - drm_err(&i915->drm, "failed to get link status\n"); + drm_err(&i915->drm, "[ENCODER:%d:%s][%s] Failed to get link status\n", + encoder->base.base.id, encoder->base.name, phy_name); return false; } if (drm_dp_clock_recovery_ok(link_status, crtc_state->lane_count)) { - drm_dbg_kms(&i915->drm, "clock recovery OK\n"); + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][%s] Clock recovery OK\n", + encoder->base.base.id, encoder->base.name, phy_name); return true; } if (voltage_tries == 5) { drm_dbg_kms(&i915->drm, - "Same voltage tried 5 times\n"); + "[ENCODER:%d:%s][%s] Same voltage tried 5 times\n", + encoder->base.base.id, encoder->base.name, phy_name); return false; } if (max_vswing_reached) { - drm_dbg_kms(&i915->drm, "Max Voltage Swing reached\n"); + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][%s] Max Voltage Swing reached\n", + encoder->base.base.id, encoder->base.name, phy_name); return false; } @@ -687,7 +715,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) { drm_err(&i915->drm, - "failed to update link training\n"); + "[ENCODER:%d:%s][%s] Failed to update link training\n", + encoder->base.base.id, encoder->base.name, phy_name); return false; } @@ -701,10 +730,12 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, if (intel_dp_link_max_vswing_reached(intel_dp, crtc_state)) max_vswing_reached = true; - } + drm_err(&i915->drm, - "Failed clock recovery %d times, giving up!\n", max_cr_tries); + "[ENCODER:%d:%s][%s] Failed clock recovery %d times, giving up!\n", + encoder->base.base.id, encoder->base.name, phy_name, max_cr_tries); + return false; } @@ -788,11 +819,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); int tries; u32 training_pattern; u8 link_status[DP_LINK_STATUS_SIZE]; bool channel_eq = false; + char phy_name[10]; + + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)); training_pattern = intel_dp_training_pattern(intel_dp, crtc_state, dp_phy); /* Scrambling is disabled for TPS2/3 and enabled for TPS4 */ @@ -802,7 +837,10 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, /* channel equalization */ if (!intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, training_pattern)) { - drm_err(&i915->drm, "failed to start channel equalization\n"); + drm_err(&i915->drm, + "[ENCODER:%d:%s][%s] Failed to start channel equalization\n", + encoder->base.base.id, encoder->base.name, + phy_name); return false; } @@ -812,25 +850,28 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy, link_status) < 0) { drm_err(&i915->drm, - "failed to get link status\n"); + "[ENCODER:%d:%s][%s] Failed to get link status\n", + encoder->base.base.id, encoder->base.name, phy_name); break; } /* Make sure clock is still ok */ if (!drm_dp_clock_recovery_ok(link_status, crtc_state->lane_count)) { - intel_dp_dump_link_status(&i915->drm, link_status); + intel_dp_dump_link_status(intel_dp, dp_phy, link_status); drm_dbg_kms(&i915->drm, - "Clock recovery check failed, cannot " - "continue channel equalization\n"); + "[ENCODER:%d:%s][%s] Clock recovery check failed, cannot " + "continue channel equalization\n", + encoder->base.base.id, encoder->base.name, phy_name); break; } if (drm_dp_channel_eq_ok(link_status, crtc_state->lane_count)) { channel_eq = true; - drm_dbg_kms(&i915->drm, "Channel EQ done. DP Training " - "successful\n"); + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][%s] Channel EQ done. DP Training successful\n", + encoder->base.base.id, encoder->base.name, phy_name); break; } @@ -839,16 +880,18 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp, crtc_state, dp_phy)) { drm_err(&i915->drm, - "failed to update link training\n"); + "[ENCODER:%d:%s][%s] Failed to update link training\n", + encoder->base.base.id, encoder->base.name, phy_name); break; } } /* Try 5 times, else fail and try at lower BW */ if (tries == 5) { - intel_dp_dump_link_status(&i915->drm, link_status); + intel_dp_dump_link_status(intel_dp, dp_phy, link_status); drm_dbg_kms(&i915->drm, - "Channel equalization failed 5 times\n"); + "[ENCODER:%d:%s][%s] Channel equalization failed 5 times\n", + encoder->base.base.id, encoder->base.name, phy_name); } return channel_eq; @@ -894,7 +937,8 @@ intel_dp_link_train_phy(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, enum drm_dp_phy dp_phy) { - struct intel_connector *intel_connector = intel_dp->attached_connector; + struct intel_connector *connector = intel_dp->attached_connector; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; char phy_name[10]; bool ret = false; @@ -908,12 +952,12 @@ intel_dp_link_train_phy(struct intel_dp *intel_dp, out: drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s\n", - intel_connector->base.base.id, - intel_connector->base.name, + "[CONNECTOR:%d:%s][ENCODER:%d:%s][%s] Link Training %s at link rate = %d, lane count = %d\n", + connector->base.base.id, connector->base.name, + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), ret ? "passed" : "failed", - crtc_state->port_clock, crtc_state->lane_count, - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name))); + crtc_state->port_clock, crtc_state->lane_count); return ret; } @@ -922,10 +966,13 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { struct intel_connector *intel_connector = intel_dp->attached_connector; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; if (intel_dp->hobl_active) { drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "Link Training failed with HOBL active, not enabling it from now on"); + "[ENCODER:%d:%s] Link Training failed with HOBL active, " + "not enabling it from now on", + encoder->base.base.id, encoder->base.name); intel_dp->hobl_failed = true; } else if (intel_dp_get_link_train_fallback_values(intel_dp, crtc_state->port_clock, From 210de399659abe7a1aa43fbb6a1afce66887a001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 4 Oct 2021 20:05:35 +0300 Subject: [PATCH 280/554] drm/i915: Call intel_dp_dump_link_status() for CR failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I suppose intel_dp_dump_link_status() might be useful for diagnosing link training failures. Hoever we only call from the channel EQ phase currently. Let's call it from the CR phase as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211004170535.4173-6-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 681c8bc53dd4..1a943ae38a6b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -649,6 +649,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 old_link_status[DP_LINK_STATUS_SIZE] = {}; int voltage_tries, cr_tries, max_cr_tries; + u8 link_status[DP_LINK_STATUS_SIZE]; bool max_vswing_reached = false; char phy_name[10]; @@ -678,8 +679,6 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, voltage_tries = 1; for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) { - u8 link_status[DP_LINK_STATUS_SIZE]; - intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy); if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, dp_phy, @@ -697,6 +696,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, } if (voltage_tries == 5) { + intel_dp_dump_link_status(intel_dp, dp_phy, link_status); drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] Same voltage tried 5 times\n", encoder->base.base.id, encoder->base.name, phy_name); @@ -704,6 +704,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, } if (max_vswing_reached) { + intel_dp_dump_link_status(intel_dp, dp_phy, link_status); drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] Max Voltage Swing reached\n", encoder->base.base.id, encoder->base.name, phy_name); @@ -732,6 +733,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, max_vswing_reached = true; } + intel_dp_dump_link_status(intel_dp, dp_phy, link_status); drm_err(&i915->drm, "[ENCODER:%d:%s][%s] Failed clock recovery %d times, giving up!\n", encoder->base.base.id, encoder->base.name, phy_name, max_cr_tries); From 149ac2e7ae1845191bd18b66a725392ac83a0c47 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Mon, 6 Sep 2021 11:35:41 +0800 Subject: [PATCH 281/554] drm/i915: Free the returned object of acpi_evaluate_dsm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per the comment on top of acpi_evaluate_dsm(): | * Evaluate device's _DSM method with specified GUID, revision id and | * function number. Caller needs to free the returned object. We should free the returned object of acpi_evaluate_dsm() to avoid memory leakage. Otherwise the kmemleak splat will be triggered at boot time (if we compile kernel with CONFIG_DEBUG_TEST_DRIVER_REMOVE=y). Fixes: 8e55f99c510f ("drm/i915: Invoke another _DSM to enable MUX on HP Workstation laptops") Cc: Kai-Heng Feng Signed-off-by: Zenghui Yu Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210906033541.862-1-yuzenghui@huawei.com --- drivers/gpu/drm/i915/display/intel_acpi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index 72cac55c0f0f..e78430001f07 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -186,13 +186,16 @@ void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915) { struct pci_dev *pdev = to_pci_dev(i915->drm.dev); acpi_handle dhandle; + union acpi_object *obj; dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) return; - acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, - INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); + obj = acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, + INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); + if (obj) + ACPI_FREE(obj); } /* From 71af6bae771a6ac60e634b6afe00e8ffc5514ad4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 7 Oct 2021 15:42:01 +0300 Subject: [PATCH 282/554] drm/i915/dg2: fix snps buf trans for uhbr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UHBR check was using > instead of >=. Use the helper instead to avoid mistakes. Also always use the non-UHBR values for HDMI. v2: Use intel_crtc_has_dp_encoder() && intel_dp_is_uhbr() (Ville) Fixes: 2817efaeb608 ("drm/i915/dg2: add SNPS PHY translations for UHBR link rates") Reported-by: Ville Syrjälä Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211007124201.18686-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index a2d39131ea53..78cd8f77b49d 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -8,6 +8,7 @@ #include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dp.h" /* HDMI/DVI modes ignore everything but the last 2 items. So we share * them for both DP and FDI transports, allowing those ports to @@ -1611,7 +1612,8 @@ dg2_get_snps_buf_trans(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, int *n_entries) { - if (crtc_state->port_clock > 1000000) + if (intel_crtc_has_dp_encoder(crtc_state) && + intel_dp_is_uhbr(crtc_state)) return intel_get_buf_trans(&dg2_snps_trans_uhbr, n_entries); else return intel_get_buf_trans(&dg2_snps_trans, n_entries); From 1a839e016e4964b5c8384e5d82e5e5ac02a23f52 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 5 Oct 2021 10:17:28 -0700 Subject: [PATCH 283/554] drm/i915: remove IS_ACTIVE When trying to bring IS_ACTIVE to linux/kconfig.h I thought it wouldn't provide much value just encapsulating it in a boolean context. So I also added the support for handling undefined macros as the IS_ENABLED() counterpart. However the feedback received from Masahiro Yamada was that it is too ugly, not providing much value. And just wrapping in a boolean context is too dumb - we could simply open code it. As detailed in commit babaab2f4738 ("drm/i915: Encapsulate kconfig constant values inside boolean predicates"), the IS_ACTIVE macro was added to workaround a compilation warning. However after checking again our current uses of IS_ACTIVE it turned out there is only 1 case in which it triggers a warning in clang (due -Wconstant-logical-operand) and 2 in smatch. All the others can simply use the shorter version, without wrapping it in any macro. So here I'm dialing all the way back to simply removing the macro. That single case hit by clang can be changed to make the constant come first, so it doesn't think it's mask: - if (context && CONFIG_DRM_I915_FENCE_TIMEOUT) + if (CONFIG_DRM_I915_FENCE_TIMEOUT && context) As talked with Dan Carpenter, that logic will be added in smatch as well, so it will also stop warning about it. Signed-off-by: Lucas De Marchi Reviewed-by: Jani Nikula Reviewed-by: Masahiro Yamada Link: https://patchwork.freedesktop.org/patch/msgid/20211005171728.3147094-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 2 +- drivers/gpu/drm/i915/gt/intel_engine.h | 4 ++-- drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c | 2 +- drivers/gpu/drm/i915/gt/intel_engine_types.h | 2 +- .../gpu/drm/i915/gt/intel_execlists_submission.c | 2 +- .../gpu/drm/i915/gt/selftest_engine_heartbeat.c | 4 ++-- drivers/gpu/drm/i915/gt/selftest_execlists.c | 14 +++++++------- drivers/gpu/drm/i915/i915_config.c | 2 +- drivers/gpu/drm/i915/i915_request.c | 2 +- drivers/gpu/drm/i915/i915_utils.h | 13 ------------- 11 files changed, 18 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 74e33a4cdfe8..d225d3dd0b40 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -804,7 +804,7 @@ static int intel_context_set_gem(struct intel_context *ce, intel_engine_has_semaphores(ce->engine)) __set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags); - if (IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) && + if (CONFIG_DRM_I915_REQUEST_TIMEOUT && ctx->i915->params.request_timeout_ms) { unsigned int timeout_ms = ctx->i915->params.request_timeout_ms; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 5130e8ed9564..65fc6ff5f59d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -395,7 +395,7 @@ retry: /* Track the mmo associated with the fenced vma */ vma->mmo = mmo; - if (IS_ACTIVE(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)) + if (CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND) intel_wakeref_auto(&i915->ggtt.userfault_wakeref, msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)); diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index eed4634c08cd..452248884ef1 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -275,7 +275,7 @@ static inline bool intel_engine_uses_guc(const struct intel_engine_cs *engine) static inline bool intel_engine_has_preempt_reset(const struct intel_engine_cs *engine) { - if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT)) + if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT) return false; return intel_engine_has_preemption(engine); @@ -302,7 +302,7 @@ intel_virtual_engine_has_heartbeat(const struct intel_engine_cs *engine) static inline bool intel_engine_has_heartbeat(const struct intel_engine_cs *engine) { - if (!IS_ACTIVE(CONFIG_DRM_I915_HEARTBEAT_INTERVAL)) + if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL) return false; if (intel_engine_is_virtual(engine)) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index 74775ae961b2..a3698f611f45 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -207,7 +207,7 @@ out: void intel_engine_unpark_heartbeat(struct intel_engine_cs *engine) { - if (!IS_ACTIVE(CONFIG_DRM_I915_HEARTBEAT_INTERVAL)) + if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL) return; next_heartbeat(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index 5ae1207c363b..9167ce52487c 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -556,7 +556,7 @@ intel_engine_has_semaphores(const struct intel_engine_cs *engine) static inline bool intel_engine_has_timeslices(const struct intel_engine_cs *engine) { - if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (!CONFIG_DRM_I915_TIMESLICE_DURATION) return false; return engine->flags & I915_ENGINE_HAS_TIMESLICES; diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 7147fe80919e..73a79c2acd3a 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -3339,7 +3339,7 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) engine->flags |= I915_ENGINE_HAS_SEMAPHORES; if (can_preempt(engine)) { engine->flags |= I915_ENGINE_HAS_PREEMPTION; - if (IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (CONFIG_DRM_I915_TIMESLICE_DURATION) engine->flags |= I915_ENGINE_HAS_TIMESLICES; } } diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index 317eebf086c3..6e6e4d747cca 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -290,7 +290,7 @@ static int live_heartbeat_fast(void *arg) int err = 0; /* Check that the heartbeat ticks at the desired rate. */ - if (!IS_ACTIVE(CONFIG_DRM_I915_HEARTBEAT_INTERVAL)) + if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL) return 0; for_each_engine(engine, gt, id) { @@ -352,7 +352,7 @@ static int live_heartbeat_off(void *arg) int err = 0; /* Check that we can turn off heartbeat and not interrupt VIP */ - if (!IS_ACTIVE(CONFIG_DRM_I915_HEARTBEAT_INTERVAL)) + if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL) return 0; for_each_engine(engine, gt, id) { diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c index b3863abc51f5..25a8c4f62b0d 100644 --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c @@ -992,7 +992,7 @@ static int live_timeslice_preempt(void *arg) * need to preempt the current task and replace it with another * ready task. */ - if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (!CONFIG_DRM_I915_TIMESLICE_DURATION) return 0; obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE); @@ -1122,7 +1122,7 @@ static int live_timeslice_rewind(void *arg) * but only a few of those requests, forcing us to rewind the * RING_TAIL of the original request. */ - if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (!CONFIG_DRM_I915_TIMESLICE_DURATION) return 0; for_each_engine(engine, gt, id) { @@ -1299,7 +1299,7 @@ static int live_timeslice_queue(void *arg) * ELSP[1] is already occupied, so must rely on timeslicing to * eject ELSP[0] in favour of the queue.) */ - if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (!CONFIG_DRM_I915_TIMESLICE_DURATION) return 0; obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE); @@ -1420,7 +1420,7 @@ static int live_timeslice_nopreempt(void *arg) * We should not timeslice into a request that is marked with * I915_REQUEST_NOPREEMPT. */ - if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION)) + if (!CONFIG_DRM_I915_TIMESLICE_DURATION) return 0; if (igt_spinner_init(&spin, gt)) @@ -2260,7 +2260,7 @@ static int __cancel_hostile(struct live_preempt_cancel *arg) int err; /* Preempt cancel non-preemptible spinner in ELSP0 */ - if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT)) + if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT) return 0; if (!intel_has_reset_engine(arg->engine->gt)) @@ -2316,7 +2316,7 @@ static int __cancel_fail(struct live_preempt_cancel *arg) struct i915_request *rq; int err; - if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT)) + if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT) return 0; if (!intel_has_reset_engine(engine->gt)) @@ -3375,7 +3375,7 @@ static int live_preempt_timeout(void *arg) * Check that we force preemption to occur by cancelling the previous * context if it refuses to yield the GPU. */ - if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT)) + if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT) return 0; if (!intel_has_reset_engine(gt)) diff --git a/drivers/gpu/drm/i915/i915_config.c b/drivers/gpu/drm/i915/i915_config.c index b79b5f6d2cfa..afb828dab53b 100644 --- a/drivers/gpu/drm/i915/i915_config.c +++ b/drivers/gpu/drm/i915/i915_config.c @@ -8,7 +8,7 @@ unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915, u64 context) { - if (context && IS_ACTIVE(CONFIG_DRM_I915_FENCE_TIMEOUT)) + if (CONFIG_DRM_I915_FENCE_TIMEOUT && context) return msecs_to_jiffies_timeout(CONFIG_DRM_I915_FENCE_TIMEOUT); return 0; diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 4f189982f67e..ed64fa9defdf 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1862,7 +1862,7 @@ long i915_request_wait(struct i915_request *rq, * completion. That requires having a good predictor for the request * duration, which we currently lack. */ - if (IS_ACTIVE(CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT) && + if (CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT && __i915_spin_request(rq, state)) goto out; diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 5259edacde38..62f189e064a9 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -458,17 +458,4 @@ static inline bool timer_expired(const struct timer_list *t) return timer_active(t) && !timer_pending(t); } -/* - * This is a lookalike for IS_ENABLED() that takes a kconfig value, - * e.g. CONFIG_DRM_I915_SPIN_REQUEST, and evaluates whether it is non-zero - * i.e. whether the configuration is active. Wrapping up the config inside - * a boolean context prevents clang and smatch from complaining about potential - * issues in confusing logical-&& with bitwise-& for constants. - * - * Sadly IS_ENABLED() itself does not work with kconfig values. - * - * Returns 0 if @config is 0, 1 if set to any value. - */ -#define IS_ACTIVE(config) ((config) != 0) - #endif /* !__I915_UTILS_H */ From c474420ba412280bc49888c3ce224f0c650c0dcb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 7 Oct 2021 13:57:27 +0300 Subject: [PATCH 284/554] drm/i915/dp: take LTTPR into account in 128b/132b rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Limit the supported UHBR rates based on the repeater support, if there are repeaters. This should be done in DP helper level, but that requires an overhaul of the LTTPR handling, as the max rate is not enough to represent how 128b/132b rates may be masked along the way. Curiously, the spec says: * Shall be cleared to 00h when operating in 8b/10b Link Layer. * Each LTTPR on the way back to the DPTX shall clear the bits that do not correspond to the LTTPR's current bit rate. It's rather vague if we can reliably use the field at this time due to the wording "operating" and "current". But it would seem bizarre to have to wait until trying to operate a 128b/132b link layer at a certain bit rate to figure this out. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211007105727.18439-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 74a657ae131a..f6b26ce71ad0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -140,6 +140,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) return; } + /* + * Sink rates for 8b/10b. + */ max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps); if (max_lttpr_rate) @@ -163,6 +166,21 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) drm_dp_dpcd_readb(&intel_dp->aux, DP_128B132B_SUPPORTED_LINK_RATES, &uhbr_rates); + if (drm_dp_lttpr_count(intel_dp->lttpr_common_caps)) { + /* We have a repeater */ + if (intel_dp->lttpr_common_caps[0] >= 0x20 && + intel_dp->lttpr_common_caps[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] & + DP_PHY_REPEATER_128B132B_SUPPORTED) { + /* Repeater supports 128b/132b, valid UHBR rates */ + uhbr_rates &= intel_dp->lttpr_common_caps[DP_PHY_REPEATER_128B132B_RATES - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + } else { + /* Does not support 128b/132b */ + uhbr_rates = 0; + } + } + if (uhbr_rates & DP_UHBR10) intel_dp->sink_rates[i++] = 1000000; if (uhbr_rates & DP_UHBR13_5) From a94a6d76c9843c3577078ec297caf0d76b6fa12e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 6 Oct 2021 13:16:18 +0300 Subject: [PATCH 285/554] drm/i915/mst: abstract intel_dp_mst_source_support() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a function for checking source MST support. Drop intel_dp->can_mst and use intel_dp->mst_mgr.cbs to indicate the same. It's the single point of truth without additional state variables. In code, "source support" is also self-documenting as opposed to the vague "can mst". Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211006101618.22066-1-jani.nikula@intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 5 +++-- .../gpu/drm/i915/display/intel_display_types.h | 1 - drivers/gpu/drm/i915/display/intel_dp.c | 10 +++++----- drivers/gpu/drm/i915/display/intel_dp_mst.c | 15 +++++++++++---- drivers/gpu/drm/i915/display/intel_dp_mst.h | 4 +++- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 309d74fd86ce..bc5113589f0a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -7,12 +7,13 @@ #include #include "i915_debugfs.h" +#include "intel_de.h" #include "intel_display_debugfs.h" #include "intel_display_power.h" -#include "intel_de.h" #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dp.h" +#include "intel_dp_mst.h" #include "intel_drrs.h" #include "intel_fbc.h" #include "intel_hdcp.h" @@ -1379,7 +1380,7 @@ static int i915_dp_mst_info(struct seq_file *m, void *unused) continue; dig_port = enc_to_dig_port(intel_encoder); - if (!dig_port->dp.can_mst) + if (!intel_dp_mst_source_support(&dig_port->dp)) continue; seq_printf(m, "MST Source Port [ENCODER:%d:%s]\n", diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index a811e13720bf..004fc0a12dfe 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1574,7 +1574,6 @@ struct intel_dp { struct intel_pps pps; - bool can_mst; /* this port supports mst */ bool is_mst; int active_mst_links; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f6b26ce71ad0..10fda20a5bd8 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2667,7 +2667,7 @@ intel_dp_can_mst(struct intel_dp *intel_dp) struct drm_i915_private *i915 = dp_to_i915(intel_dp); return i915->params.enable_dp_mst && - intel_dp->can_mst && + intel_dp_mst_source_support(intel_dp) && drm_dp_read_mst_cap(&intel_dp->aux, intel_dp->dpcd); } @@ -2682,10 +2682,10 @@ intel_dp_configure_mst(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] MST support: port: %s, sink: %s, modparam: %s\n", encoder->base.base.id, encoder->base.name, - yesno(intel_dp->can_mst), yesno(sink_can_mst), + yesno(intel_dp_mst_source_support(intel_dp)), yesno(sink_can_mst), yesno(i915->params.enable_dp_mst)); - if (!intel_dp->can_mst) + if (!intel_dp_mst_source_support(intel_dp)) return; intel_dp->is_mst = sink_can_mst && @@ -5085,7 +5085,7 @@ void intel_dp_mst_suspend(struct drm_i915_private *dev_priv) intel_dp = enc_to_intel_dp(encoder); - if (!intel_dp->can_mst) + if (!intel_dp_mst_source_support(intel_dp)) continue; if (intel_dp->is_mst) @@ -5109,7 +5109,7 @@ void intel_dp_mst_resume(struct drm_i915_private *dev_priv) intel_dp = enc_to_intel_dp(encoder); - if (!intel_dp->can_mst) + if (!intel_dp_mst_source_support(intel_dp)) continue; ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index fd0a31bc3dcd..0de0b4ff4d73 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -977,24 +977,31 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) dig_port->max_lanes, max_source_rate, conn_base_id); - if (ret) + if (ret) { + intel_dp->mst_mgr.cbs = NULL; return ret; - - intel_dp->can_mst = true; + } return 0; } +bool intel_dp_mst_source_support(struct intel_dp *intel_dp) +{ + return intel_dp->mst_mgr.cbs; +} + void intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port) { struct intel_dp *intel_dp = &dig_port->dp; - if (!intel_dp->can_mst) + if (!intel_dp_mst_source_support(intel_dp)) return; drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr); /* encoders will get killed by normal cleanup */ + + intel_dp->mst_mgr.cbs = NULL; } bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index 6afda4e86b3c..f7301de6cdfb 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -8,13 +8,15 @@ #include -struct intel_digital_port; struct intel_crtc_state; +struct intel_digital_port; +struct intel_dp; int intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port); int intel_dp_mst_encoder_active_links(struct intel_digital_port *dig_port); bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state); bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state); +bool intel_dp_mst_source_support(struct intel_dp *intel_dp); #endif /* __INTEL_DP_MST_H__ */ From 1605b5be7a79df90150d4ce8c640a0f0911ba9e6 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Mon, 11 Oct 2021 16:27:04 +0800 Subject: [PATCH 286/554] drm/amdgpu: query default sclk from smu for cyan_skillfish Query default sclk instead of hard code. Signed-off-by: Lang Yu Acked-by: Huang Rui Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 3d4c65bc29dc..cbc3f99e8573 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -47,7 +47,6 @@ /* unit: MHz */ #define CYAN_SKILLFISH_SCLK_MIN 1000 #define CYAN_SKILLFISH_SCLK_MAX 2000 -#define CYAN_SKILLFISH_SCLK_DEFAULT 1800 /* unit: mV */ #define CYAN_SKILLFISH_VDDC_MIN 700 @@ -59,6 +58,8 @@ static struct gfx_user_settings { uint32_t vddc; } cyan_skillfish_user_settings; +static uint32_t cyan_skillfish_sclk_default; + #define FEATURE_MASK(feature) (1ULL << feature) #define SMC_DPM_FEATURE ( \ FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ @@ -365,13 +366,19 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) return false; ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2); - if (ret) return false; feature_enabled = (uint64_t)feature_mask[0] | ((uint64_t)feature_mask[1] << 32); + /* + * cyan_skillfish specific, query default sclk inseted of hard code. + */ + if (!cyan_skillfish_sclk_default) + cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, + &cyan_skillfish_sclk_default); + return !!(feature_enabled & SMC_DPM_FEATURE); } @@ -444,14 +451,14 @@ static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu, return -EINVAL; } - if (input[1] <= CYAN_SKILLFISH_SCLK_MIN || + if (input[1] < CYAN_SKILLFISH_SCLK_MIN || input[1] > CYAN_SKILLFISH_SCLK_MAX) { dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n", CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX); return -EINVAL; } - if (input[2] <= CYAN_SKILLFISH_VDDC_MIN || + if (input[2] < CYAN_SKILLFISH_VDDC_MIN || input[2] > CYAN_SKILLFISH_VDDC_MAX) { dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n", CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX); @@ -468,7 +475,7 @@ static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu, return -EINVAL; } - cyan_skillfish_user_settings.sclk = CYAN_SKILLFISH_SCLK_DEFAULT; + cyan_skillfish_user_settings.sclk = cyan_skillfish_sclk_default; cyan_skillfish_user_settings.vddc = CYAN_SKILLFISH_VDDC_MAGIC; break; From a0f9f85466683436da4be1f02aa14a8549157651 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 8 Oct 2021 10:21:42 -0400 Subject: [PATCH 287/554] drm/amdgpu/nbio7.4: don't use GPU_HDP_FLUSH bit 12 It's used internally by firmware. Using it in the driver could conflict with firmware. Reviewed-by: James Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 91b3afa946f5..3b7775d74bb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -56,12 +56,15 @@ * These are nbio v7_4_1 registers mask. Temporarily define these here since * nbio v7_4_1 header is incomplete. */ -#define GPU_HDP_FLUSH_DONE__RSVD_ENG0_MASK 0x00001000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG0_MASK 0x00001000L /* Don't use. Firmware uses this bit internally */ #define GPU_HDP_FLUSH_DONE__RSVD_ENG1_MASK 0x00002000L #define GPU_HDP_FLUSH_DONE__RSVD_ENG2_MASK 0x00004000L #define GPU_HDP_FLUSH_DONE__RSVD_ENG3_MASK 0x00008000L #define GPU_HDP_FLUSH_DONE__RSVD_ENG4_MASK 0x00010000L #define GPU_HDP_FLUSH_DONE__RSVD_ENG5_MASK 0x00020000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG6_MASK 0x00040000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG7_MASK 0x00080000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG8_MASK 0x00100000L #define mmBIF_MMSCH1_DOORBELL_RANGE 0x01dc #define mmBIF_MMSCH1_DOORBELL_RANGE_BASE_IDX 2 @@ -332,14 +335,14 @@ const struct nbio_hdp_flush_reg nbio_v7_4_hdp_flush_reg = { .ref_and_mask_cp7 = GPU_HDP_FLUSH_DONE__CP7_MASK, .ref_and_mask_cp8 = GPU_HDP_FLUSH_DONE__CP8_MASK, .ref_and_mask_cp9 = GPU_HDP_FLUSH_DONE__CP9_MASK, - .ref_and_mask_sdma0 = GPU_HDP_FLUSH_DONE__SDMA0_MASK, - .ref_and_mask_sdma1 = GPU_HDP_FLUSH_DONE__SDMA1_MASK, - .ref_and_mask_sdma2 = GPU_HDP_FLUSH_DONE__RSVD_ENG0_MASK, - .ref_and_mask_sdma3 = GPU_HDP_FLUSH_DONE__RSVD_ENG1_MASK, - .ref_and_mask_sdma4 = GPU_HDP_FLUSH_DONE__RSVD_ENG2_MASK, - .ref_and_mask_sdma5 = GPU_HDP_FLUSH_DONE__RSVD_ENG3_MASK, - .ref_and_mask_sdma6 = GPU_HDP_FLUSH_DONE__RSVD_ENG4_MASK, - .ref_and_mask_sdma7 = GPU_HDP_FLUSH_DONE__RSVD_ENG5_MASK, + .ref_and_mask_sdma0 = GPU_HDP_FLUSH_DONE__RSVD_ENG1_MASK, + .ref_and_mask_sdma1 = GPU_HDP_FLUSH_DONE__RSVD_ENG2_MASK, + .ref_and_mask_sdma2 = GPU_HDP_FLUSH_DONE__RSVD_ENG3_MASK, + .ref_and_mask_sdma3 = GPU_HDP_FLUSH_DONE__RSVD_ENG4_MASK, + .ref_and_mask_sdma4 = GPU_HDP_FLUSH_DONE__RSVD_ENG5_MASK, + .ref_and_mask_sdma5 = GPU_HDP_FLUSH_DONE__RSVD_ENG6_MASK, + .ref_and_mask_sdma6 = GPU_HDP_FLUSH_DONE__RSVD_ENG7_MASK, + .ref_and_mask_sdma7 = GPU_HDP_FLUSH_DONE__RSVD_ENG8_MASK, }; static void nbio_v7_4_init_registers(struct amdgpu_device *adev) From 319f4def310cc0851208410e05db325e6c884046 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 11 Oct 2021 21:21:43 +0300 Subject: [PATCH 288/554] drm/i915/dp: abstract intel_dp_lane_max_vswing_reached() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add per-lane abstraction for max vswing reached to make follow-up cleaner, as this one reverses the conditions. v2: both conditions need to be true, reverse (Ville) Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211011182144.22074-1-jani.nikula@intel.com --- .../drm/i915/display/intel_dp_link_training.c | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 1a943ae38a6b..1d4bcb91cd3b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -515,29 +515,37 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, return ret == crtc_state->lane_count; } +/* + * FIXME: The DP spec is very confusing here, also the Link CTS spec seems to + * have self contradicting tests around this area. + * + * In lieu of better ideas let's just stop when we've reached the max supported + * vswing with its max pre-emphasis, which is either 2+1 or 3+0 depending on + * whether vswing level 3 is supported or not. + */ +static bool intel_dp_lane_max_vswing_reached(u8 train_set_lane) +{ + u8 v = (train_set_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + u8 p = (train_set_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + + if ((train_set_lane & DP_TRAIN_MAX_SWING_REACHED) == 0) + return false; + + if (v + p != 3) + return false; + + return true; +} + static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { int lane; - /* - * FIXME: The DP spec is very confusing here, also the Link CTS - * spec seems to have self contradicting tests around this area. - * - * In lieu of better ideas let's just stop when we've reached the - * max supported vswing with its max pre-emphasis, which is either - * 2+1 or 3+0 depending on whether vswing level 3 is supported or not. - */ for (lane = 0; lane < crtc_state->lane_count; lane++) { - u8 v = (intel_dp->train_set[lane] & DP_TRAIN_VOLTAGE_SWING_MASK) >> - DP_TRAIN_VOLTAGE_SWING_SHIFT; - u8 p = (intel_dp->train_set[lane] & DP_TRAIN_PRE_EMPHASIS_MASK) >> - DP_TRAIN_PRE_EMPHASIS_SHIFT; - - if ((intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0) - return false; - - if (v + p != 3) + if (!intel_dp_lane_max_vswing_reached(intel_dp->train_set[lane])) return false; } From 5c31e9d013b52cc8420ca97e5ae004c9d4b8cf7f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 11 Oct 2021 21:21:44 +0300 Subject: [PATCH 289/554] drm/i915/dg2: update link training for 128b/132b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 128b/132b channel coding link training uses more straightforward TX FFE preset values. Reuse voltage tries and max vswing for retry logic. The delays for 128b/132b are still all wrong, but this is regardless a step forward. v2: Fix UHBR rate checks, use intel_dp_is_uhbr() helper v3: - Rebase - Modify intel_dp_adjust_request_changed() and intel_dp_link_max_vswing_reached() to take 128b/132b into account. (Ville) v4: - Train request printing for TX FFE (Ville) - Log 8b/10b vs. 128b/132b (Ville) - Add helper for per-lane max vswing / tx ffe (Ville) - Name functions with tx_ffe/vswing instead of 128b132b/8b10b Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211011182144.22074-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 18 ++- .../drm/i915/display/intel_dp_link_training.c | 151 ++++++++++++++---- 2 files changed, 133 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3f7bbeb3e3cd..59428ce4f8c1 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1338,13 +1338,20 @@ static int translate_signal_level(struct intel_dp *intel_dp, return 0; } -static int intel_ddi_dp_level(struct intel_dp *intel_dp, int lane) +static int intel_ddi_dp_level(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + int lane) { u8 train_set = intel_dp->train_set[lane]; - u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | - DP_TRAIN_PRE_EMPHASIS_MASK); - return translate_signal_level(intel_dp, signal_levels); + if (intel_dp_is_uhbr(crtc_state)) { + return train_set & DP_TX_FFE_PRESET_VALUE_MASK; + } else { + u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + + return translate_signal_level(intel_dp, signal_levels); + } } int intel_ddi_level(struct intel_encoder *encoder, @@ -1362,7 +1369,8 @@ int intel_ddi_level(struct intel_encoder *encoder, if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) level = intel_ddi_hdmi_level(encoder, trans); else - level = intel_ddi_dp_level(enc_to_intel_dp(encoder), lane); + level = intel_ddi_dp_level(enc_to_intel_dp(encoder), crtc_state, + lane); if (drm_WARN_ON_ONCE(&i915->drm, level >= n_entries)) level = n_entries - 1; diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 1d4bcb91cd3b..85676c953e0a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -304,11 +304,32 @@ static bool has_per_lane_signal_levels(struct intel_dp *intel_dp, return !intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy); } -static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - enum drm_dp_phy dp_phy, - const u8 link_status[DP_LINK_STATUS_SIZE], - int lane) +/* 128b/132b */ +static u8 intel_dp_get_lane_adjust_tx_ffe_preset(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + u8 tx_ffe = 0; + + if (has_per_lane_signal_levels(intel_dp, dp_phy)) { + lane = min(lane, crtc_state->lane_count - 1); + tx_ffe = drm_dp_get_adjust_tx_ffe_preset(link_status, lane); + } else { + for (lane = 0; lane < crtc_state->lane_count; lane++) + tx_ffe = max(tx_ffe, drm_dp_get_adjust_tx_ffe_preset(link_status, lane)); + } + + return tx_ffe; +} + +/* 8b/10b */ +static u8 intel_dp_get_lane_adjust_vswing_preemph(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) { u8 v = 0; u8 p = 0; @@ -340,6 +361,20 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, return v | p; } +static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + enum drm_dp_phy dp_phy, + const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + if (intel_dp_is_uhbr(crtc_state)) + return intel_dp_get_lane_adjust_tx_ffe_preset(intel_dp, crtc_state, + dp_phy, link_status, lane); + else + return intel_dp_get_lane_adjust_vswing_preemph(intel_dp, crtc_state, + dp_phy, link_status, lane); +} + #define TRAIN_REQ_FMT "%d/%d/%d/%d" #define _TRAIN_REQ_VSWING_ARGS(link_status, lane) \ (drm_dp_get_adjust_request_voltage((link_status), (lane)) >> DP_TRAIN_VOLTAGE_SWING_SHIFT) @@ -355,6 +390,13 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, _TRAIN_REQ_PREEMPH_ARGS(link_status, 1), \ _TRAIN_REQ_PREEMPH_ARGS(link_status, 2), \ _TRAIN_REQ_PREEMPH_ARGS(link_status, 3) +#define _TRAIN_REQ_TX_FFE_ARGS(link_status, lane) \ + drm_dp_get_adjust_tx_ffe_preset((link_status), (lane)) +#define TRAIN_REQ_TX_FFE_ARGS(link_status) \ + _TRAIN_REQ_TX_FFE_ARGS(link_status, 0), \ + _TRAIN_REQ_TX_FFE_ARGS(link_status, 1), \ + _TRAIN_REQ_TX_FFE_ARGS(link_status, 2), \ + _TRAIN_REQ_TX_FFE_ARGS(link_status, 3) void intel_dp_get_adjust_train(struct intel_dp *intel_dp, @@ -367,14 +409,23 @@ intel_dp_get_adjust_train(struct intel_dp *intel_dp, char phy_name[10]; int lane; - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " - "vswing request: " TRAIN_REQ_FMT ", " - "pre-emphasis request: " TRAIN_REQ_FMT "\n", - encoder->base.base.id, encoder->base.name, - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), - crtc_state->lane_count, - TRAIN_REQ_VSWING_ARGS(link_status), - TRAIN_REQ_PREEMPH_ARGS(link_status)); + if (intel_dp_is_uhbr(crtc_state)) { + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, " + "TX FFE request: " TRAIN_REQ_FMT "\n", + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + crtc_state->lane_count, + TRAIN_REQ_TX_FFE_ARGS(link_status)); + } else { + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, " + "vswing request: " TRAIN_REQ_FMT ", " + "pre-emphasis request: " TRAIN_REQ_FMT "\n", + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + crtc_state->lane_count, + TRAIN_REQ_VSWING_ARGS(link_status), + TRAIN_REQ_PREEMPH_ARGS(link_status)); + } for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = @@ -464,6 +515,13 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, _TRAIN_SET_PREEMPH_ARGS((train_set)[1]), \ _TRAIN_SET_PREEMPH_ARGS((train_set)[2]), \ _TRAIN_SET_PREEMPH_ARGS((train_set)[3]) +#define _TRAIN_SET_TX_FFE_ARGS(train_set) \ + ((train_set) & DP_TX_FFE_PRESET_VALUE_MASK), "" +#define TRAIN_SET_TX_FFE_ARGS(train_set) \ + _TRAIN_SET_TX_FFE_ARGS((train_set)[0]), \ + _TRAIN_SET_TX_FFE_ARGS((train_set)[1]), \ + _TRAIN_SET_TX_FFE_ARGS((train_set)[2]), \ + _TRAIN_SET_TX_FFE_ARGS((train_set)[3]) void intel_dp_set_signal_levels(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -473,14 +531,23 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp, struct drm_i915_private *i915 = to_i915(encoder->base.dev); char phy_name[10]; - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " - "vswing levels: " TRAIN_SET_FMT ", " - "pre-emphasis levels: " TRAIN_SET_FMT "\n", - encoder->base.base.id, encoder->base.name, - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), - crtc_state->lane_count, - TRAIN_SET_VSWING_ARGS(intel_dp->train_set), - TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set)); + if (intel_dp_is_uhbr(crtc_state)) { + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, " + "TX FFE presets: " TRAIN_SET_FMT "\n", + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + crtc_state->lane_count, + TRAIN_SET_TX_FFE_ARGS(intel_dp->train_set)); + } else { + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, " + "vswing levels: " TRAIN_SET_FMT ", " + "pre-emphasis levels: " TRAIN_SET_FMT "\n", + encoder->base.base.id, encoder->base.name, + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), + crtc_state->lane_count, + TRAIN_SET_VSWING_ARGS(intel_dp->train_set), + TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set)); + } if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy)) encoder->set_signal_levels(encoder, crtc_state); @@ -515,7 +582,16 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, return ret == crtc_state->lane_count; } +/* 128b/132b */ +static bool intel_dp_lane_max_tx_ffe_reached(u8 train_set_lane) +{ + return (train_set_lane & DP_TX_FFE_PRESET_VALUE_MASK) == + DP_TX_FFE_PRESET_VALUE_MASK; +} + /* + * 8b/10b + * * FIXME: The DP spec is very confusing here, also the Link CTS spec seems to * have self contradicting tests around this area. * @@ -545,8 +621,15 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp, int lane; for (lane = 0; lane < crtc_state->lane_count; lane++) { - if (!intel_dp_lane_max_vswing_reached(intel_dp->train_set[lane])) - return false; + u8 train_set_lane = intel_dp->train_set[lane]; + + if (intel_dp_is_uhbr(crtc_state)) { + if (!intel_dp_lane_max_tx_ffe_reached(train_set_lane)) + return false; + } else { + if (!intel_dp_lane_max_vswing_reached(train_set_lane)) + return false; + } } return true; @@ -609,17 +692,24 @@ static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_d drm_dp_lttpr_link_train_clock_recovery_delay(); } -static bool intel_dp_adjust_request_changed(int lane_count, +static bool intel_dp_adjust_request_changed(const struct intel_crtc_state *crtc_state, const u8 old_link_status[DP_LINK_STATUS_SIZE], const u8 new_link_status[DP_LINK_STATUS_SIZE]) { int lane; - for (lane = 0; lane < lane_count; lane++) { - u8 old = drm_dp_get_adjust_request_voltage(old_link_status, lane) | - drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane); - u8 new = drm_dp_get_adjust_request_voltage(new_link_status, lane) | - drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane); + for (lane = 0; lane < crtc_state->lane_count; lane++) { + u8 old, new; + + if (intel_dp_is_uhbr(crtc_state)) { + old = drm_dp_get_adjust_tx_ffe_preset(old_link_status, lane); + new = drm_dp_get_adjust_tx_ffe_preset(new_link_status, lane); + } else { + old = drm_dp_get_adjust_request_voltage(old_link_status, lane) | + drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane); + new = drm_dp_get_adjust_request_voltage(new_link_status, lane) | + drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane); + } if (old != new) return true; @@ -729,8 +819,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, return false; } - if (!intel_dp_adjust_request_changed(crtc_state->lane_count, - old_link_status, link_status)) + if (!intel_dp_adjust_request_changed(crtc_state, old_link_status, link_status)) ++voltage_tries; else voltage_tries = 1; From 74a75dc908692dd0548209004e53832c02433c0c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Oct 2021 14:34:55 +1000 Subject: [PATCH 290/554] drm/i915/display: move plane prepare/cleanup to intel_atomic_plane.c Start to refactor more stuff out of intel_display.c. These fit better in this file. This moves the rps boosting code as well as this is the only user of it. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211012043502.1377715-2-airlied@gmail.com --- .../gpu/drm/i915/display/intel_atomic_plane.c | 208 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_display.c | 208 ------------------ drivers/gpu/drm/i915/display/intel_display.h | 4 - 3 files changed, 208 insertions(+), 212 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 47234d898549..53ee56453270 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -41,6 +41,7 @@ #include "intel_display_types.h" #include "intel_pm.h" #include "intel_sprite.h" +#include "gt/intel_rps.h" static void intel_plane_state_reset(struct intel_plane_state *plane_state, struct intel_plane *plane) @@ -601,6 +602,213 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state, return 0; } +struct wait_rps_boost { + struct wait_queue_entry wait; + + struct drm_crtc *crtc; + struct i915_request *request; +}; + +static int do_rps_boost(struct wait_queue_entry *_wait, + unsigned mode, int sync, void *key) +{ + struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait); + struct i915_request *rq = wait->request; + + /* + * If we missed the vblank, but the request is already running it + * is reasonable to assume that it will complete before the next + * vblank without our intervention, so leave RPS alone. + */ + if (!i915_request_started(rq)) + intel_rps_boost(rq); + i915_request_put(rq); + + drm_crtc_vblank_put(wait->crtc); + + list_del(&wait->wait.entry); + kfree(wait); + return 1; +} + +static void add_rps_boost_after_vblank(struct drm_crtc *crtc, + struct dma_fence *fence) +{ + struct wait_rps_boost *wait; + + if (!dma_fence_is_i915(fence)) + return; + + if (DISPLAY_VER(to_i915(crtc->dev)) < 6) + return; + + if (drm_crtc_vblank_get(crtc)) + return; + + wait = kmalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) { + drm_crtc_vblank_put(crtc); + return; + } + + wait->request = to_request(dma_fence_get(fence)); + wait->crtc = crtc; + + wait->wait.func = do_rps_boost; + wait->wait.flags = 0; + + add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait); +} + +/** + * intel_prepare_plane_fb - Prepare fb for usage on plane + * @_plane: drm plane to prepare for + * @_new_plane_state: the plane state being prepared + * + * Prepares a framebuffer for usage on a display plane. Generally this + * involves pinning the underlying object and updating the frontbuffer tracking + * bits. Some older platforms need special physical address handling for + * cursor planes. + * + * Returns 0 on success, negative error code on failure. + */ +static int +intel_prepare_plane_fb(struct drm_plane *_plane, + struct drm_plane_state *_new_plane_state) +{ + struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; + struct intel_plane *plane = to_intel_plane(_plane); + struct intel_plane_state *new_plane_state = + to_intel_plane_state(_new_plane_state); + struct intel_atomic_state *state = + to_intel_atomic_state(new_plane_state->uapi.state); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct intel_plane_state *old_plane_state = + intel_atomic_get_old_plane_state(state, plane); + struct drm_i915_gem_object *obj = intel_fb_obj(new_plane_state->hw.fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(old_plane_state->hw.fb); + int ret; + + if (old_obj) { + const struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, + to_intel_crtc(old_plane_state->hw.crtc)); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. Note that we rely on userspace rendering + * into the buffer attached to the pipe they are waiting + * on. If not, userspace generates a GPU hang with IPEHR + * point to the MI_WAIT_FOR_EVENT. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. + */ + if (intel_crtc_needs_modeset(crtc_state)) { + ret = i915_sw_fence_await_reservation(&state->commit_ready, + old_obj->base.resv, NULL, + false, 0, + GFP_KERNEL); + if (ret < 0) + return ret; + } + } + + if (new_plane_state->uapi.fence) { /* explicit fencing */ + i915_gem_fence_wait_priority(new_plane_state->uapi.fence, + &attr); + ret = i915_sw_fence_await_dma_fence(&state->commit_ready, + new_plane_state->uapi.fence, + i915_fence_timeout(dev_priv), + GFP_KERNEL); + if (ret < 0) + return ret; + } + + if (!obj) + return 0; + + + ret = intel_plane_pin_fb(new_plane_state); + if (ret) + return ret; + + i915_gem_object_wait_priority(obj, 0, &attr); + + if (!new_plane_state->uapi.fence) { /* implicit fencing */ + struct dma_fence *fence; + + ret = i915_sw_fence_await_reservation(&state->commit_ready, + obj->base.resv, NULL, + false, + i915_fence_timeout(dev_priv), + GFP_KERNEL); + if (ret < 0) + goto unpin_fb; + + fence = dma_resv_get_excl_unlocked(obj->base.resv); + if (fence) { + add_rps_boost_after_vblank(new_plane_state->hw.crtc, + fence); + dma_fence_put(fence); + } + } else { + add_rps_boost_after_vblank(new_plane_state->hw.crtc, + new_plane_state->uapi.fence); + } + + /* + * We declare pageflips to be interactive and so merit a small bias + * towards upclocking to deliver the frame on time. By only changing + * the RPS thresholds to sample more regularly and aim for higher + * clocks we can hopefully deliver low power workloads (like kodi) + * that are not quite steady state without resorting to forcing + * maximum clocks following a vblank miss (see do_rps_boost()). + */ + if (!state->rps_interactive) { + intel_rps_mark_interactive(&dev_priv->gt.rps, true); + state->rps_interactive = true; + } + + return 0; + +unpin_fb: + intel_plane_unpin_fb(new_plane_state); + + return ret; +} + +/** + * intel_cleanup_plane_fb - Cleans up an fb after plane use + * @plane: drm plane to clean up for + * @_old_plane_state: the state from the previous modeset + * + * Cleans up a framebuffer that has just been removed from a plane. + */ +static void +intel_cleanup_plane_fb(struct drm_plane *plane, + struct drm_plane_state *_old_plane_state) +{ + struct intel_plane_state *old_plane_state = + to_intel_plane_state(_old_plane_state); + struct intel_atomic_state *state = + to_intel_atomic_state(old_plane_state->uapi.state); + struct drm_i915_private *dev_priv = to_i915(plane->dev); + struct drm_i915_gem_object *obj = intel_fb_obj(old_plane_state->hw.fb); + + if (!obj) + return; + + if (state->rps_interactive) { + intel_rps_mark_interactive(&dev_priv->gt.rps, false); + state->rps_interactive = false; + } + + /* Should only be called after a successful intel_prepare_plane_fb()! */ + intel_plane_unpin_fb(old_plane_state); +} + static const struct drm_plane_helper_funcs intel_plane_helper_funcs = { .prepare_fb = intel_prepare_plane_fb, .cleanup_fb = intel_cleanup_plane_fb, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b2e2e039744d..d1fa17929b1f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -68,7 +68,6 @@ #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_object.h" -#include "gt/intel_rps.h" #include "gt/gen8_ppgtt.h" #include "g4x_dp.h" @@ -10479,64 +10478,6 @@ static int intel_atomic_commit(struct drm_device *dev, return 0; } -struct wait_rps_boost { - struct wait_queue_entry wait; - - struct drm_crtc *crtc; - struct i915_request *request; -}; - -static int do_rps_boost(struct wait_queue_entry *_wait, - unsigned mode, int sync, void *key) -{ - struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait); - struct i915_request *rq = wait->request; - - /* - * If we missed the vblank, but the request is already running it - * is reasonable to assume that it will complete before the next - * vblank without our intervention, so leave RPS alone. - */ - if (!i915_request_started(rq)) - intel_rps_boost(rq); - i915_request_put(rq); - - drm_crtc_vblank_put(wait->crtc); - - list_del(&wait->wait.entry); - kfree(wait); - return 1; -} - -static void add_rps_boost_after_vblank(struct drm_crtc *crtc, - struct dma_fence *fence) -{ - struct wait_rps_boost *wait; - - if (!dma_fence_is_i915(fence)) - return; - - if (DISPLAY_VER(to_i915(crtc->dev)) < 6) - return; - - if (drm_crtc_vblank_get(crtc)) - return; - - wait = kmalloc(sizeof(*wait), GFP_KERNEL); - if (!wait) { - drm_crtc_vblank_put(crtc); - return; - } - - wait->request = to_request(dma_fence_get(fence)); - wait->crtc = crtc; - - wait->wait.func = do_rps_boost; - wait->wait.flags = 0; - - add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait); -} - int intel_plane_pin_fb(struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); @@ -10603,155 +10544,6 @@ void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) } } -/** - * intel_prepare_plane_fb - Prepare fb for usage on plane - * @_plane: drm plane to prepare for - * @_new_plane_state: the plane state being prepared - * - * Prepares a framebuffer for usage on a display plane. Generally this - * involves pinning the underlying object and updating the frontbuffer tracking - * bits. Some older platforms need special physical address handling for - * cursor planes. - * - * Returns 0 on success, negative error code on failure. - */ -int -intel_prepare_plane_fb(struct drm_plane *_plane, - struct drm_plane_state *_new_plane_state) -{ - struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; - struct intel_plane *plane = to_intel_plane(_plane); - struct intel_plane_state *new_plane_state = - to_intel_plane_state(_new_plane_state); - struct intel_atomic_state *state = - to_intel_atomic_state(new_plane_state->uapi.state); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct intel_plane_state *old_plane_state = - intel_atomic_get_old_plane_state(state, plane); - struct drm_i915_gem_object *obj = intel_fb_obj(new_plane_state->hw.fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(old_plane_state->hw.fb); - int ret; - - if (old_obj) { - const struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, - to_intel_crtc(old_plane_state->hw.crtc)); - - /* Big Hammer, we also need to ensure that any pending - * MI_WAIT_FOR_EVENT inside a user batch buffer on the - * current scanout is retired before unpinning the old - * framebuffer. Note that we rely on userspace rendering - * into the buffer attached to the pipe they are waiting - * on. If not, userspace generates a GPU hang with IPEHR - * point to the MI_WAIT_FOR_EVENT. - * - * This should only fail upon a hung GPU, in which case we - * can safely continue. - */ - if (intel_crtc_needs_modeset(crtc_state)) { - ret = i915_sw_fence_await_reservation(&state->commit_ready, - old_obj->base.resv, NULL, - false, 0, - GFP_KERNEL); - if (ret < 0) - return ret; - } - } - - if (new_plane_state->uapi.fence) { /* explicit fencing */ - i915_gem_fence_wait_priority(new_plane_state->uapi.fence, - &attr); - ret = i915_sw_fence_await_dma_fence(&state->commit_ready, - new_plane_state->uapi.fence, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - return ret; - } - - if (!obj) - return 0; - - - ret = intel_plane_pin_fb(new_plane_state); - if (ret) - return ret; - - i915_gem_object_wait_priority(obj, 0, &attr); - - if (!new_plane_state->uapi.fence) { /* implicit fencing */ - struct dma_fence *fence; - - ret = i915_sw_fence_await_reservation(&state->commit_ready, - obj->base.resv, NULL, - false, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - goto unpin_fb; - - fence = dma_resv_get_excl_unlocked(obj->base.resv); - if (fence) { - add_rps_boost_after_vblank(new_plane_state->hw.crtc, - fence); - dma_fence_put(fence); - } - } else { - add_rps_boost_after_vblank(new_plane_state->hw.crtc, - new_plane_state->uapi.fence); - } - - /* - * We declare pageflips to be interactive and so merit a small bias - * towards upclocking to deliver the frame on time. By only changing - * the RPS thresholds to sample more regularly and aim for higher - * clocks we can hopefully deliver low power workloads (like kodi) - * that are not quite steady state without resorting to forcing - * maximum clocks following a vblank miss (see do_rps_boost()). - */ - if (!state->rps_interactive) { - intel_rps_mark_interactive(&dev_priv->gt.rps, true); - state->rps_interactive = true; - } - - return 0; - -unpin_fb: - intel_plane_unpin_fb(new_plane_state); - - return ret; -} - -/** - * intel_cleanup_plane_fb - Cleans up an fb after plane use - * @plane: drm plane to clean up for - * @_old_plane_state: the state from the previous modeset - * - * Cleans up a framebuffer that has just been removed from a plane. - */ -void -intel_cleanup_plane_fb(struct drm_plane *plane, - struct drm_plane_state *_old_plane_state) -{ - struct intel_plane_state *old_plane_state = - to_intel_plane_state(_old_plane_state); - struct intel_atomic_state *state = - to_intel_atomic_state(old_plane_state->uapi.state); - struct drm_i915_private *dev_priv = to_i915(plane->dev); - struct drm_i915_gem_object *obj = intel_fb_obj(old_plane_state->hw.fb); - - if (!obj) - return; - - if (state->rps_interactive) { - intel_rps_mark_interactive(&dev_priv->gt.rps, false); - state->rps_interactive = false; - } - - /* Should only be called after a successful intel_prepare_plane_fb()! */ - intel_plane_unpin_fb(old_plane_state); -} - /** * intel_plane_destroy - destroy a plane * @plane: plane to destroy diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 3028072c2cf3..a08903bb7647 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -585,10 +585,6 @@ void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags); struct drm_framebuffer * intel_framebuffer_create(struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd); -int intel_prepare_plane_fb(struct drm_plane *plane, - struct drm_plane_state *new_state); -void intel_cleanup_plane_fb(struct drm_plane *plane, - struct drm_plane_state *old_state); void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, enum pipe pipe); From 2f9a995a38d89f499850b48bf6b769f95239eaf9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Oct 2021 14:34:56 +1000 Subject: [PATCH 291/554] drm/i915/display: let intel_plane_uses_fence be used from other places. I want to refactor some stuff using this so make it shared. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211012043502.1377715-3-airlied@gmail.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_display.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d1fa17929b1f..5254180934bb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -851,7 +851,7 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info return size; } -static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) +bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index a08903bb7647..d655d996d465 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -615,6 +615,7 @@ void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state); +bool intel_plane_uses_fence(const struct intel_plane_state *plane_state); bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, u64 modifier); From 0d594ea0cff28c44cb9314023c4064676d929f8d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Oct 2021 14:34:57 +1000 Subject: [PATCH 292/554] drm/i915/display: refactor out initial plane config for crtcs This just pulls this out into a function so it can be moved to another file easier. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211012043502.1377715-4-airlied@gmail.com --- drivers/gpu/drm/i915/display/intel_display.c | 44 +++++++++++--------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5254180934bb..39a7b24135c9 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -11460,6 +11460,30 @@ cleanup_bios: return ret; } +static void +intel_crtc_initial_plane_config(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_initial_plane_config plane_config = {}; + + /* + * Note that reserving the BIOS fb up front prevents us + * from stuffing other stolen allocations like the ring + * on top. This prevents some ugliness at boot time, and + * can even allow for smooth boot transitions if the BIOS + * fb is large enough for the active pipe configuration. + */ + dev_priv->display->get_initial_plane_config(crtc, &plane_config); + + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_find_initial_plane_obj(crtc, &plane_config); + + plane_config_fini(&plane_config); +} + /* part #2: call after irq install, but before gem init */ int intel_modeset_init_nogem(struct drm_i915_private *i915) { @@ -11521,27 +11545,9 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { - struct intel_initial_plane_config plane_config = {}; - if (!to_intel_crtc_state(crtc->base.state)->uapi.active) continue; - - /* - * Note that reserving the BIOS fb up front prevents us - * from stuffing other stolen allocations like the ring - * on top. This prevents some ugliness at boot time, and - * can even allow for smooth boot transitions if the BIOS - * fb is large enough for the active pipe configuration. - */ - i915->display->get_initial_plane_config(crtc, &plane_config); - - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &plane_config); - - plane_config_fini(&plane_config); + intel_crtc_initial_plane_config(crtc); } /* From 1cd967c69410115912066a7340b14d87d39f0af9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Oct 2021 14:34:58 +1000 Subject: [PATCH 293/554] drm/i915/display: refactor initial plane config to a separate file This moves this functionality out of intel_display.c to separate self-contained file. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211012043502.1377715-5-airlied@gmail.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_display.c | 279 +---------------- drivers/gpu/drm/i915/display/intel_display.h | 2 + .../drm/i915/display/intel_plane_initial.c | 283 ++++++++++++++++++ .../drm/i915/display/intel_plane_initial.h | 13 + 5 files changed, 302 insertions(+), 276 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_plane_initial.c create mode 100644 drivers/gpu/drm/i915/display/intel_plane_initial.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index c36c8a4f0716..5d9794d80bc2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -225,6 +225,7 @@ i915-y += \ display/intel_hotplug.o \ display/intel_lpe_audio.o \ display/intel_overlay.o \ + display/intel_plane_initial.o \ display/intel_psr.o \ display/intel_quirks.o \ display/intel_sprite.o \ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 39a7b24135c9..b0684537f987 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -95,6 +95,7 @@ #include "intel_overlay.h" #include "intel_panel.h" #include "intel_pipe_crc.h" +#include "intel_plane_initial.h" #include "intel_pm.h" #include "intel_pps.h" #include "intel_psr.h" @@ -1238,123 +1239,6 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, DRM_MODE_ROTATE_0); } -static struct i915_vma * -initial_plane_vma(struct drm_i915_private *i915, - struct intel_initial_plane_config *plane_config) -{ - struct drm_i915_gem_object *obj; - struct i915_vma *vma; - u32 base, size; - - if (plane_config->size == 0) - return NULL; - - base = round_down(plane_config->base, - I915_GTT_MIN_ALIGNMENT); - size = round_up(plane_config->base + plane_config->size, - I915_GTT_MIN_ALIGNMENT); - size -= base; - - /* - * If the FB is too big, just don't use it since fbdev is not very - * important and we should probably use that space with FBC or other - * features. - */ - if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && - size * 2 > i915->stolen_usable_size) - return NULL; - - obj = i915_gem_object_create_stolen_for_preallocated(i915, base, size); - if (IS_ERR(obj)) - return NULL; - - /* - * Mark it WT ahead of time to avoid changing the - * cache_level during fbdev initialization. The - * unbind there would get stuck waiting for rcu. - */ - i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ? - I915_CACHE_WT : I915_CACHE_NONE); - - switch (plane_config->tiling) { - case I915_TILING_NONE: - break; - case I915_TILING_X: - case I915_TILING_Y: - obj->tiling_and_stride = - plane_config->fb->base.pitches[0] | - plane_config->tiling; - break; - default: - MISSING_CASE(plane_config->tiling); - goto err_obj; - } - - vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); - if (IS_ERR(vma)) - goto err_obj; - - if (i915_ggtt_pin(vma, NULL, 0, PIN_MAPPABLE | PIN_OFFSET_FIXED | base)) - goto err_obj; - - if (i915_gem_object_is_tiled(obj) && - !i915_vma_is_map_and_fenceable(vma)) - goto err_obj; - - return vma; - -err_obj: - i915_gem_object_put(obj); - return NULL; -} - -static bool -intel_alloc_initial_plane_obj(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; - struct drm_framebuffer *fb = &plane_config->fb->base; - struct i915_vma *vma; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - case I915_FORMAT_MOD_Y_TILED: - break; - default: - drm_dbg(&dev_priv->drm, - "Unsupported modifier for initial FB: 0x%llx\n", - fb->modifier); - return false; - } - - vma = initial_plane_vma(dev_priv, plane_config); - if (!vma) - return false; - - mode_cmd.pixel_format = fb->format->format; - mode_cmd.width = fb->width; - mode_cmd.height = fb->height; - mode_cmd.pitches[0] = fb->pitches[0]; - mode_cmd.modifier[0] = fb->modifier; - mode_cmd.flags = DRM_MODE_FB_MODIFIERS; - - if (intel_framebuffer_init(to_intel_framebuffer(fb), - vma->obj, &mode_cmd)) { - drm_dbg_kms(&dev_priv->drm, "intel fb init failed\n"); - goto err_vma; - } - - plane_config->vma = vma; - return true; - -err_vma: - i915_vma_put(vma); - return false; -} - static void intel_set_plane_visible(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state, @@ -1390,8 +1274,8 @@ static void fixup_plane_bitmasks(struct intel_crtc_state *crtc_state) } } -static void intel_plane_disable_noatomic(struct intel_crtc *crtc, - struct intel_plane *plane) +void intel_plane_disable_noatomic(struct intel_crtc *crtc, + struct intel_plane *plane) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = @@ -1436,123 +1320,6 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, intel_wait_for_vblank(dev_priv, crtc->pipe); } -static bool -intel_reuse_initial_plane_obj(struct drm_i915_private *i915, - const struct intel_initial_plane_config *plane_config, - struct drm_framebuffer **fb, - struct i915_vma **vma) -{ - struct intel_crtc *crtc; - - for_each_intel_crtc(&i915->drm, crtc) { - struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); - struct intel_plane *plane = - to_intel_plane(crtc->base.primary); - struct intel_plane_state *plane_state = - to_intel_plane_state(plane->base.state); - - if (!crtc_state->uapi.active) - continue; - - if (!plane_state->ggtt_vma) - continue; - - if (intel_plane_ggtt_offset(plane_state) == plane_config->base) { - *fb = plane_state->hw.fb; - *vma = plane_state->ggtt_vma; - return true; - } - } - - return false; -} - -static void -intel_find_initial_plane_obj(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); - struct intel_plane *plane = - to_intel_plane(crtc->base.primary); - struct intel_plane_state *plane_state = - to_intel_plane_state(plane->base.state); - struct drm_framebuffer *fb; - struct i915_vma *vma; - - /* - * TODO: - * Disable planes if get_initial_plane_config() failed. - * Make sure things work if the surface base is not page aligned. - */ - if (!plane_config->fb) - return; - - if (intel_alloc_initial_plane_obj(crtc, plane_config)) { - fb = &plane_config->fb->base; - vma = plane_config->vma; - goto valid_fb; - } - - /* - * Failed to alloc the obj, check to see if we should share - * an fb with another CRTC instead - */ - if (intel_reuse_initial_plane_obj(dev_priv, plane_config, &fb, &vma)) - goto valid_fb; - - /* - * We've failed to reconstruct the BIOS FB. Current display state - * indicates that the primary plane is visible, but has a NULL FB, - * which will lead to problems later if we don't fix it up. The - * simplest solution is to just disable the primary plane now and - * pretend the BIOS never had it enabled. - */ - intel_plane_disable_noatomic(crtc, plane); - if (crtc_state->bigjoiner) { - struct intel_crtc *slave = - crtc_state->bigjoiner_linked_crtc; - intel_plane_disable_noatomic(slave, to_intel_plane(slave->base.primary)); - } - - return; - -valid_fb: - plane_state->uapi.rotation = plane_config->rotation; - intel_fb_fill_view(to_intel_framebuffer(fb), - plane_state->uapi.rotation, &plane_state->view); - - __i915_vma_pin(vma); - plane_state->ggtt_vma = i915_vma_get(vma); - if (intel_plane_uses_fence(plane_state) && - i915_vma_pin_fence(vma) == 0 && vma->fence) - plane_state->flags |= PLANE_HAS_FENCE; - - plane_state->uapi.src_x = 0; - plane_state->uapi.src_y = 0; - plane_state->uapi.src_w = fb->width << 16; - plane_state->uapi.src_h = fb->height << 16; - - plane_state->uapi.crtc_x = 0; - plane_state->uapi.crtc_y = 0; - plane_state->uapi.crtc_w = fb->width; - plane_state->uapi.crtc_h = fb->height; - - if (plane_config->tiling) - dev_priv->preserve_bios_swizzle = true; - - plane_state->uapi.fb = fb; - drm_framebuffer_get(fb); - - plane_state->uapi.crtc = &crtc->base; - intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); - - atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); -} - unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) { @@ -11373,22 +11140,6 @@ static void intel_mode_config_cleanup(struct drm_i915_private *i915) drm_mode_config_cleanup(&i915->drm); } -static void plane_config_fini(struct intel_initial_plane_config *plane_config) -{ - if (plane_config->fb) { - struct drm_framebuffer *fb = &plane_config->fb->base; - - /* We may only have the stub and not a full framebuffer */ - if (drm_framebuffer_read_refcount(fb)) - drm_framebuffer_put(fb); - else - kfree(fb); - } - - if (plane_config->vma) - i915_vma_put(plane_config->vma); -} - /* part #1: call before irq install */ int intel_modeset_init_noirq(struct drm_i915_private *i915) { @@ -11460,30 +11211,6 @@ cleanup_bios: return ret; } -static void -intel_crtc_initial_plane_config(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_initial_plane_config plane_config = {}; - - /* - * Note that reserving the BIOS fb up front prevents us - * from stuffing other stolen allocations like the ring - * on top. This prevents some ugliness at boot time, and - * can even allow for smooth boot transitions if the BIOS - * fb is large enough for the active pipe configuration. - */ - dev_priv->display->get_initial_plane_config(crtc, &plane_config); - - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &plane_config); - - plane_config_fini(&plane_config); -} - /* part #2: call after irq install, but before gem init */ int intel_modeset_init_nogem(struct drm_i915_private *i915) { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index d655d996d465..38afc758d7d4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -625,6 +625,8 @@ void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state); struct intel_encoder * intel_get_crtc_new_encoder(const struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state); +void intel_plane_disable_noatomic(struct intel_crtc *crtc, + struct intel_plane *plane); void intel_display_driver_register(struct drm_i915_private *i915); void intel_display_driver_unregister(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c new file mode 100644 index 000000000000..dcd698a02da2 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include "intel_display_types.h" +#include "intel_plane_initial.h" +#include "intel_atomic_plane.h" +#include "intel_display.h" +#include "intel_fb.h" + +static bool +intel_reuse_initial_plane_obj(struct drm_i915_private *i915, + const struct intel_initial_plane_config *plane_config, + struct drm_framebuffer **fb, + struct i915_vma **vma) +{ + struct intel_crtc *crtc; + + for_each_intel_crtc(&i915->drm, crtc) { + struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + struct intel_plane *plane = + to_intel_plane(crtc->base.primary); + struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.state); + + if (!crtc_state->uapi.active) + continue; + + if (!plane_state->ggtt_vma) + continue; + + if (intel_plane_ggtt_offset(plane_state) == plane_config->base) { + *fb = plane_state->hw.fb; + *vma = plane_state->ggtt_vma; + return true; + } + } + + return false; +} + +static struct i915_vma * +initial_plane_vma(struct drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + u32 base, size; + + if (plane_config->size == 0) + return NULL; + + base = round_down(plane_config->base, + I915_GTT_MIN_ALIGNMENT); + size = round_up(plane_config->base + plane_config->size, + I915_GTT_MIN_ALIGNMENT); + size -= base; + + /* + * If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. + */ + if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && + size * 2 > i915->stolen_usable_size) + return NULL; + + obj = i915_gem_object_create_stolen_for_preallocated(i915, base, size); + if (IS_ERR(obj)) + return NULL; + + /* + * Mark it WT ahead of time to avoid changing the + * cache_level during fbdev initialization. The + * unbind there would get stuck waiting for rcu. + */ + i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ? + I915_CACHE_WT : I915_CACHE_NONE); + + switch (plane_config->tiling) { + case I915_TILING_NONE: + break; + case I915_TILING_X: + case I915_TILING_Y: + obj->tiling_and_stride = + plane_config->fb->base.pitches[0] | + plane_config->tiling; + break; + default: + MISSING_CASE(plane_config->tiling); + goto err_obj; + } + + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); + if (IS_ERR(vma)) + goto err_obj; + + if (i915_ggtt_pin(vma, NULL, 0, PIN_MAPPABLE | PIN_OFFSET_FIXED | base)) + goto err_obj; + + if (i915_gem_object_is_tiled(obj) && + !i915_vma_is_map_and_fenceable(vma)) + goto err_obj; + + return vma; + +err_obj: + i915_gem_object_put(obj); + return NULL; +} + +static bool +intel_alloc_initial_plane_obj(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + struct drm_framebuffer *fb = &plane_config->fb->base; + struct i915_vma *vma; + + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + break; + default: + drm_dbg(&dev_priv->drm, + "Unsupported modifier for initial FB: 0x%llx\n", + fb->modifier); + return false; + } + + vma = initial_plane_vma(dev_priv, plane_config); + if (!vma) + return false; + + mode_cmd.pixel_format = fb->format->format; + mode_cmd.width = fb->width; + mode_cmd.height = fb->height; + mode_cmd.pitches[0] = fb->pitches[0]; + mode_cmd.modifier[0] = fb->modifier; + mode_cmd.flags = DRM_MODE_FB_MODIFIERS; + + if (intel_framebuffer_init(to_intel_framebuffer(fb), + vma->obj, &mode_cmd)) { + drm_dbg_kms(&dev_priv->drm, "intel fb init failed\n"); + goto err_vma; + } + + plane_config->vma = vma; + return true; + +err_vma: + i915_vma_put(vma); + return false; +} + +static void +intel_find_initial_plane_obj(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + struct intel_plane *plane = + to_intel_plane(crtc->base.primary); + struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.state); + struct drm_framebuffer *fb; + struct i915_vma *vma; + + /* + * TODO: + * Disable planes if get_initial_plane_config() failed. + * Make sure things work if the surface base is not page aligned. + */ + if (!plane_config->fb) + return; + + if (intel_alloc_initial_plane_obj(crtc, plane_config)) { + fb = &plane_config->fb->base; + vma = plane_config->vma; + goto valid_fb; + } + + /* + * Failed to alloc the obj, check to see if we should share + * an fb with another CRTC instead + */ + if (intel_reuse_initial_plane_obj(dev_priv, plane_config, &fb, &vma)) + goto valid_fb; + + /* + * We've failed to reconstruct the BIOS FB. Current display state + * indicates that the primary plane is visible, but has a NULL FB, + * which will lead to problems later if we don't fix it up. The + * simplest solution is to just disable the primary plane now and + * pretend the BIOS never had it enabled. + */ + intel_plane_disable_noatomic(crtc, plane); + if (crtc_state->bigjoiner) { + struct intel_crtc *slave = + crtc_state->bigjoiner_linked_crtc; + intel_plane_disable_noatomic(slave, to_intel_plane(slave->base.primary)); + } + + return; + +valid_fb: + plane_state->uapi.rotation = plane_config->rotation; + intel_fb_fill_view(to_intel_framebuffer(fb), + plane_state->uapi.rotation, &plane_state->view); + + __i915_vma_pin(vma); + plane_state->ggtt_vma = i915_vma_get(vma); + if (intel_plane_uses_fence(plane_state) && + i915_vma_pin_fence(vma) == 0 && vma->fence) + plane_state->flags |= PLANE_HAS_FENCE; + + plane_state->uapi.src_x = 0; + plane_state->uapi.src_y = 0; + plane_state->uapi.src_w = fb->width << 16; + plane_state->uapi.src_h = fb->height << 16; + + plane_state->uapi.crtc_x = 0; + plane_state->uapi.crtc_y = 0; + plane_state->uapi.crtc_w = fb->width; + plane_state->uapi.crtc_h = fb->height; + + if (plane_config->tiling) + dev_priv->preserve_bios_swizzle = true; + + plane_state->uapi.fb = fb; + drm_framebuffer_get(fb); + + plane_state->uapi.crtc = &crtc->base; + intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); + + atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); +} + +static void plane_config_fini(struct intel_initial_plane_config *plane_config) +{ + if (plane_config->fb) { + struct drm_framebuffer *fb = &plane_config->fb->base; + + /* We may only have the stub and not a full framebuffer */ + if (drm_framebuffer_read_refcount(fb)) + drm_framebuffer_put(fb); + else + kfree(fb); + } + + if (plane_config->vma) + i915_vma_put(plane_config->vma); +} + +void intel_crtc_initial_plane_config(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_initial_plane_config plane_config = {}; + + /* + * Note that reserving the BIOS fb up front prevents us + * from stuffing other stolen allocations like the ring + * on top. This prevents some ugliness at boot time, and + * can even allow for smooth boot transitions if the BIOS + * fb is large enough for the active pipe configuration. + */ + dev_priv->display->get_initial_plane_config(crtc, &plane_config); + + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_find_initial_plane_obj(crtc, &plane_config); + + plane_config_fini(&plane_config); +} diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.h b/drivers/gpu/drm/i915/display/intel_plane_initial.h new file mode 100644 index 000000000000..c7e35ab3182b --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_PLANE_INITIAL_H__ +#define __INTEL_PLANE_INITIAL_H__ + +struct intel_crtc; + +void intel_crtc_initial_plane_config(struct intel_crtc *crtc); + +#endif From 814c8757115f9d7135126ac43d3a178b31e796dd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Oct 2021 14:34:59 +1000 Subject: [PATCH 294/554] drm/i915/display: move pin/unpin fb/plane code to a new file. This just moves this code out of the i915_display.c into a new standalone file. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211012043502.1377715-6-airlied@gmail.com --- drivers/gpu/drm/i915/Makefile | 1 + .../gpu/drm/i915/display/intel_atomic_plane.c | 1 + drivers/gpu/drm/i915/display/intel_cursor.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 258 ----------------- drivers/gpu/drm/i915/display/intel_display.h | 8 - drivers/gpu/drm/i915/display/intel_fb_pin.c | 274 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fb_pin.h | 28 ++ drivers/gpu/drm/i915/display/intel_fbdev.c | 1 + 8 files changed, 306 insertions(+), 267 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_fb_pin.c create mode 100644 drivers/gpu/drm/i915/display/intel_fb_pin.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 5d9794d80bc2..f35485806ec5 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -216,6 +216,7 @@ i915-y += \ display/intel_drrs.o \ display/intel_dsb.o \ display/intel_fb.o \ + display/intel_fb_pin.o \ display/intel_fbc.o \ display/intel_fdi.o \ display/intel_fifo_underrun.o \ diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 53ee56453270..0be8c00e3db9 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -39,6 +39,7 @@ #include "intel_atomic_plane.h" #include "intel_cdclk.h" #include "intel_display_types.h" +#include "intel_fb_pin.h" #include "intel_pm.h" #include "intel_sprite.h" #include "gt/intel_rps.h" diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index f6dcb5aa63f6..11842f212613 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -17,7 +17,7 @@ #include "intel_display_types.h" #include "intel_display.h" #include "intel_fb.h" - +#include "intel_fb_pin.h" #include "intel_frontbuffer.h" #include "intel_pm.h" #include "intel_psr.h" diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b0684537f987..0fe3c2f50971 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -862,198 +862,6 @@ bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) plane_state->view.gtt.type == I915_GGTT_VIEW_NORMAL); } -static struct i915_vma * -intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, - const struct i915_ggtt_view *view, - bool uses_fence, - unsigned long *out_flags, - struct i915_address_space *vm) -{ - struct drm_device *dev = fb->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct i915_vma *vma; - u32 alignment; - int ret; - - if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) - return ERR_PTR(-EINVAL); - - alignment = 4096 * 512; - - atomic_inc(&dev_priv->gpu_error.pending_fb_pin); - - ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); - if (ret) { - vma = ERR_PTR(ret); - goto err; - } - - vma = i915_vma_instance(obj, vm, view); - if (IS_ERR(vma)) - goto err; - - if (i915_vma_misplaced(vma, 0, alignment, 0)) { - ret = i915_vma_unbind(vma); - if (ret) { - vma = ERR_PTR(ret); - goto err; - } - } - - ret = i915_vma_pin(vma, 0, alignment, PIN_GLOBAL); - if (ret) { - vma = ERR_PTR(ret); - goto err; - } - - vma->display_alignment = max_t(u64, vma->display_alignment, alignment); - - i915_gem_object_flush_if_display(obj); - - i915_vma_get(vma); -err: - atomic_dec(&dev_priv->gpu_error.pending_fb_pin); - - return vma; -} - -struct i915_vma * -intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, - bool phys_cursor, - const struct i915_ggtt_view *view, - bool uses_fence, - unsigned long *out_flags) -{ - struct drm_device *dev = fb->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - intel_wakeref_t wakeref; - struct i915_gem_ww_ctx ww; - struct i915_vma *vma; - unsigned int pinctl; - u32 alignment; - int ret; - - if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) - return ERR_PTR(-EINVAL); - - if (phys_cursor) - alignment = intel_cursor_alignment(dev_priv); - else - alignment = intel_surf_alignment(fb, 0); - if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) - return ERR_PTR(-EINVAL); - - /* Note that the w/a also requires 64 PTE of padding following the - * bo. We currently fill all unused PTE with the shadow page and so - * we should always have valid PTE following the scanout preventing - * the VT-d warning. - */ - if (intel_scanout_needs_vtd_wa(dev_priv) && alignment < 256 * 1024) - alignment = 256 * 1024; - - /* - * Global gtt pte registers are special registers which actually forward - * writes to a chunk of system memory. Which means that there is no risk - * that the register values disappear as soon as we call - * intel_runtime_pm_put(), so it is correct to wrap only the - * pin/unpin/fence and not more. - */ - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - - atomic_inc(&dev_priv->gpu_error.pending_fb_pin); - - /* - * Valleyview is definitely limited to scanning out the first - * 512MiB. Lets presume this behaviour was inherited from the - * g4x display engine and that all earlier gen are similarly - * limited. Testing suggests that it is a little more - * complicated than this. For example, Cherryview appears quite - * happy to scanout from anywhere within its global aperture. - */ - pinctl = 0; - if (HAS_GMCH(dev_priv)) - pinctl |= PIN_MAPPABLE; - - i915_gem_ww_ctx_init(&ww, true); -retry: - ret = i915_gem_object_lock(obj, &ww); - if (!ret && phys_cursor) - ret = i915_gem_object_attach_phys(obj, alignment); - else if (!ret && HAS_LMEM(dev_priv)) - ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM); - /* TODO: Do we need to sync when migration becomes async? */ - if (!ret) - ret = i915_gem_object_pin_pages(obj); - if (ret) - goto err; - - if (!ret) { - vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment, - view, pinctl); - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto err_unpin; - } - } - - if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { - /* - * Install a fence for tiled scan-out. Pre-i965 always needs a - * fence, whereas 965+ only requires a fence if using - * framebuffer compression. For simplicity, we always, when - * possible, install a fence as the cost is not that onerous. - * - * If we fail to fence the tiled scanout, then either the - * modeset will reject the change (which is highly unlikely as - * the affected systems, all but one, do not have unmappable - * space) or we will not be able to enable full powersaving - * techniques (also likely not to apply due to various limits - * FBC and the like impose on the size of the buffer, which - * presumably we violated anyway with this unmappable buffer). - * Anyway, it is presumably better to stumble onwards with - * something and try to run the system in a "less than optimal" - * mode that matches the user configuration. - */ - ret = i915_vma_pin_fence(vma); - if (ret != 0 && DISPLAY_VER(dev_priv) < 4) { - i915_vma_unpin(vma); - goto err_unpin; - } - ret = 0; - - if (vma->fence) - *out_flags |= PLANE_HAS_FENCE; - } - - i915_vma_get(vma); - -err_unpin: - i915_gem_object_unpin_pages(obj); -err: - if (ret == -EDEADLK) { - ret = i915_gem_ww_ctx_backoff(&ww); - if (!ret) - goto retry; - } - i915_gem_ww_ctx_fini(&ww); - if (ret) - vma = ERR_PTR(ret); - - atomic_dec(&dev_priv->gpu_error.pending_fb_pin); - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - return vma; -} - -void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags) -{ - if (flags & PLANE_HAS_FENCE) - i915_vma_unpin_fence(vma); - i915_vma_unpin(vma); - i915_vma_put(vma); -} - /* * Convert the x/y offsets into a linear offset. * Only valid with 0/180 degree rotation, which is fine since linear @@ -10245,72 +10053,6 @@ static int intel_atomic_commit(struct drm_device *dev, return 0; } -int intel_plane_pin_fb(struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct drm_framebuffer *fb = plane_state->hw.fb; - struct i915_vma *vma; - bool phys_cursor = - plane->id == PLANE_CURSOR && - INTEL_INFO(dev_priv)->display.cursor_needs_physical; - - if (!intel_fb_uses_dpt(fb)) { - vma = intel_pin_and_fence_fb_obj(fb, phys_cursor, - &plane_state->view.gtt, - intel_plane_uses_fence(plane_state), - &plane_state->flags); - if (IS_ERR(vma)) - return PTR_ERR(vma); - - plane_state->ggtt_vma = vma; - } else { - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - - vma = intel_dpt_pin(intel_fb->dpt_vm); - if (IS_ERR(vma)) - return PTR_ERR(vma); - - plane_state->ggtt_vma = vma; - - vma = intel_pin_fb_obj_dpt(fb, &plane_state->view.gtt, false, - &plane_state->flags, intel_fb->dpt_vm); - if (IS_ERR(vma)) { - intel_dpt_unpin(intel_fb->dpt_vm); - plane_state->ggtt_vma = NULL; - return PTR_ERR(vma); - } - - plane_state->dpt_vma = vma; - - WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); - } - - return 0; -} - -void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) -{ - struct drm_framebuffer *fb = old_plane_state->hw.fb; - struct i915_vma *vma; - - if (!intel_fb_uses_dpt(fb)) { - vma = fetch_and_zero(&old_plane_state->ggtt_vma); - if (vma) - intel_unpin_fb_vma(vma, old_plane_state->flags); - } else { - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - - vma = fetch_and_zero(&old_plane_state->dpt_vma); - if (vma) - intel_unpin_fb_vma(vma, old_plane_state->flags); - - vma = fetch_and_zero(&old_plane_state->ggtt_vma); - if (vma) - intel_dpt_unpin(intel_fb->dpt_vm); - } -} - /** * intel_plane_destroy - destroy a plane * @plane: plane to destroy diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 38afc758d7d4..0c76bf57f86b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -576,12 +576,6 @@ int intel_get_load_detect_pipe(struct drm_connector *connector, void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old, struct drm_modeset_acquire_ctx *ctx); -struct i915_vma * -intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, bool phys_cursor, - const struct i915_ggtt_view *view, - bool uses_fence, - unsigned long *out_flags); -void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags); struct drm_framebuffer * intel_framebuffer_create(struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd); @@ -620,8 +614,6 @@ bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, u64 modifier); -int intel_plane_pin_fb(struct intel_plane_state *plane_state); -void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state); struct intel_encoder * intel_get_crtc_new_encoder(const struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c new file mode 100644 index 000000000000..3f77f3013584 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +/** + * DOC: display pinning helpers + */ + +#include "intel_display_types.h" +#include "intel_fb_pin.h" +#include "intel_fb.h" + +#include "intel_dpt.h" + +#include "gem/i915_gem_object.h" + +static struct i915_vma * +intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, + const struct i915_ggtt_view *view, + bool uses_fence, + unsigned long *out_flags, + struct i915_address_space *vm) +{ + struct drm_device *dev = fb->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct i915_vma *vma; + u32 alignment; + int ret; + + if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) + return ERR_PTR(-EINVAL); + + alignment = 4096 * 512; + + atomic_inc(&dev_priv->gpu_error.pending_fb_pin); + + ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + + vma = i915_vma_instance(obj, vm, view); + if (IS_ERR(vma)) + goto err; + + if (i915_vma_misplaced(vma, 0, alignment, 0)) { + ret = i915_vma_unbind(vma); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + } + + ret = i915_vma_pin(vma, 0, alignment, PIN_GLOBAL); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + + vma->display_alignment = max_t(u64, vma->display_alignment, alignment); + + i915_gem_object_flush_if_display(obj); + + i915_vma_get(vma); +err: + atomic_dec(&dev_priv->gpu_error.pending_fb_pin); + + return vma; +} + +struct i915_vma * +intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, + bool phys_cursor, + const struct i915_ggtt_view *view, + bool uses_fence, + unsigned long *out_flags) +{ + struct drm_device *dev = fb->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + intel_wakeref_t wakeref; + struct i915_gem_ww_ctx ww; + struct i915_vma *vma; + unsigned int pinctl; + u32 alignment; + int ret; + + if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) + return ERR_PTR(-EINVAL); + + if (phys_cursor) + alignment = intel_cursor_alignment(dev_priv); + else + alignment = intel_surf_alignment(fb, 0); + if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) + return ERR_PTR(-EINVAL); + + /* Note that the w/a also requires 64 PTE of padding following the + * bo. We currently fill all unused PTE with the shadow page and so + * we should always have valid PTE following the scanout preventing + * the VT-d warning. + */ + if (intel_scanout_needs_vtd_wa(dev_priv) && alignment < 256 * 1024) + alignment = 256 * 1024; + + /* + * Global gtt pte registers are special registers which actually forward + * writes to a chunk of system memory. Which means that there is no risk + * that the register values disappear as soon as we call + * intel_runtime_pm_put(), so it is correct to wrap only the + * pin/unpin/fence and not more. + */ + wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + + atomic_inc(&dev_priv->gpu_error.pending_fb_pin); + + /* + * Valleyview is definitely limited to scanning out the first + * 512MiB. Lets presume this behaviour was inherited from the + * g4x display engine and that all earlier gen are similarly + * limited. Testing suggests that it is a little more + * complicated than this. For example, Cherryview appears quite + * happy to scanout from anywhere within its global aperture. + */ + pinctl = 0; + if (HAS_GMCH(dev_priv)) + pinctl |= PIN_MAPPABLE; + + i915_gem_ww_ctx_init(&ww, true); +retry: + ret = i915_gem_object_lock(obj, &ww); + if (!ret && phys_cursor) + ret = i915_gem_object_attach_phys(obj, alignment); + else if (!ret && HAS_LMEM(dev_priv)) + ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM); + /* TODO: Do we need to sync when migration becomes async? */ + if (!ret) + ret = i915_gem_object_pin_pages(obj); + if (ret) + goto err; + + if (!ret) { + vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment, + view, pinctl); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err_unpin; + } + } + + if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { + /* + * Install a fence for tiled scan-out. Pre-i965 always needs a + * fence, whereas 965+ only requires a fence if using + * framebuffer compression. For simplicity, we always, when + * possible, install a fence as the cost is not that onerous. + * + * If we fail to fence the tiled scanout, then either the + * modeset will reject the change (which is highly unlikely as + * the affected systems, all but one, do not have unmappable + * space) or we will not be able to enable full powersaving + * techniques (also likely not to apply due to various limits + * FBC and the like impose on the size of the buffer, which + * presumably we violated anyway with this unmappable buffer). + * Anyway, it is presumably better to stumble onwards with + * something and try to run the system in a "less than optimal" + * mode that matches the user configuration. + */ + ret = i915_vma_pin_fence(vma); + if (ret != 0 && DISPLAY_VER(dev_priv) < 4) { + i915_vma_unpin(vma); + goto err_unpin; + } + ret = 0; + + if (vma->fence) + *out_flags |= PLANE_HAS_FENCE; + } + + i915_vma_get(vma); + +err_unpin: + i915_gem_object_unpin_pages(obj); +err: + if (ret == -EDEADLK) { + ret = i915_gem_ww_ctx_backoff(&ww); + if (!ret) + goto retry; + } + i915_gem_ww_ctx_fini(&ww); + if (ret) + vma = ERR_PTR(ret); + + atomic_dec(&dev_priv->gpu_error.pending_fb_pin); + intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); + return vma; +} + +void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags) +{ + if (flags & PLANE_HAS_FENCE) + i915_vma_unpin_fence(vma); + i915_vma_unpin(vma); + i915_vma_put(vma); +} + +int intel_plane_pin_fb(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct drm_framebuffer *fb = plane_state->hw.fb; + struct i915_vma *vma; + bool phys_cursor = + plane->id == PLANE_CURSOR && + INTEL_INFO(dev_priv)->display.cursor_needs_physical; + + if (!intel_fb_uses_dpt(fb)) { + vma = intel_pin_and_fence_fb_obj(fb, phys_cursor, + &plane_state->view.gtt, + intel_plane_uses_fence(plane_state), + &plane_state->flags); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + } else { + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + vma = intel_dpt_pin(intel_fb->dpt_vm); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + + vma = intel_pin_fb_obj_dpt(fb, &plane_state->view.gtt, false, + &plane_state->flags, intel_fb->dpt_vm); + if (IS_ERR(vma)) { + intel_dpt_unpin(intel_fb->dpt_vm); + plane_state->ggtt_vma = NULL; + return PTR_ERR(vma); + } + + plane_state->dpt_vma = vma; + + WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); + } + + return 0; +} + +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) +{ + struct drm_framebuffer *fb = old_plane_state->hw.fb; + struct i915_vma *vma; + + if (!intel_fb_uses_dpt(fb)) { + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + intel_unpin_fb_vma(vma, old_plane_state->flags); + } else { + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + vma = fetch_and_zero(&old_plane_state->dpt_vma); + if (vma) + intel_unpin_fb_vma(vma, old_plane_state->flags); + + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + intel_dpt_unpin(intel_fb->dpt_vm); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.h b/drivers/gpu/drm/i915/display/intel_fb_pin.h new file mode 100644 index 000000000000..e4fcd0218d9d --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_FB_PIN_H__ +#define __INTEL_FB_PIN_H__ + +#include + +struct drm_framebuffer; +struct i915_vma; +struct intel_plane_state; +struct i915_ggtt_view; + +struct i915_vma * +intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, + bool phys_cursor, + const struct i915_ggtt_view *view, + bool uses_fence, + unsigned long *out_flags); + +void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags); + +int intel_plane_pin_fb(struct intel_plane_state *plane_state); +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 53484267b2a4..adc3a81be9f7 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -46,6 +46,7 @@ #include "i915_drv.h" #include "intel_display_types.h" #include "intel_fb.h" +#include "intel_fb_pin.h" #include "intel_fbdev.h" #include "intel_frontbuffer.h" From aa5e9f98113bf3808beb65c8b0ad452fd94cf797 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 7 Oct 2021 16:32:10 -0700 Subject: [PATCH 295/554] drm/i915/gt: include tsc.h where used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are currently using tsc_khz as a fallback so add the right include. For other architectures we may need to add a different fallback, but this is not being used by dgfx so we may as well just paper it over. Signed-off-by: Lucas De Marchi Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20211007233212.3896460-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_llc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gt/intel_llc.c b/drivers/gpu/drm/i915/gt/intel_llc.c index eb1a15deed22..d6c6b8b0a1e6 100644 --- a/drivers/gpu/drm/i915/gt/intel_llc.c +++ b/drivers/gpu/drm/i915/gt/intel_llc.c @@ -3,6 +3,7 @@ * Copyright © 2019 Intel Corporation */ +#include #include #include "i915_drv.h" From a5b51a9f8523a0b88ce7e8e8059f75a43c34c57f Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 7 Oct 2021 16:32:11 -0700 Subject: [PATCH 296/554] drm/i915/gt: add asm/cacheflush.h for use of clflush() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's include what we use instead of relying on other indirect includes. Signed-off-by: Lucas De Marchi Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20211007233212.3896460-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_engine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 452248884ef1..d5ac49c0691e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -2,6 +2,7 @@ #ifndef _INTEL_RINGBUFFER_H_ #define _INTEL_RINGBUFFER_H_ +#include #include #include From c5f44559e919fadff5c03864d92c09a5a90bdbe4 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 7 Oct 2021 16:32:12 -0700 Subject: [PATCH 297/554] drm/i915/display: remove unused intel-mid.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing from intel-mid.h and this is only available on x86, so remove it as we prepare support for other architectures. Signed-off-by: Lucas De Marchi Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20211007233212.3896460-4-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index c2a2cd1f84dc..61c2ef6a4b8c 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -31,7 +31,6 @@ #include #include -#include #include #include From c46f4405486d953dd749613f67d3a0eec69e1b87 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 30 Sep 2021 17:58:16 -0700 Subject: [PATCH 298/554] drm/i915: Stop using I915_TILING_* in client blit selftest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The I915_TILING_* definitions in the uapi header are intended solely for tiling modes that are visible to the old de-tiling fence ioctls. Since modern hardware does not support de-tiling fences, we should not add new definitions for new tiling types going forward. However we do want the client blit selftest to eventually cover other new tiling modes (such as Tile4), so switch it to using its own enum of tiling modes. Cc: Ville Syrjälä Cc: Stanislav Lisovskiy Signed-off-by: Matt Roper Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211001005816.73330-1-matthew.d.roper@intel.com --- .../i915/gem/selftests/i915_gem_client_blt.c | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c index ecbcbb86ae1e..8402ed925a69 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c @@ -17,13 +17,20 @@ #include "huge_gem_object.h" #include "mock_context.h" +enum client_tiling { + CLIENT_TILING_LINEAR, + CLIENT_TILING_X, + CLIENT_TILING_Y, + CLIENT_NUM_TILING_TYPES +}; + #define WIDTH 512 #define HEIGHT 32 struct blit_buffer { struct i915_vma *vma; u32 start_val; - u32 tiling; + enum client_tiling tiling; }; struct tiled_blits { @@ -53,9 +60,9 @@ static int prepare_blit(const struct tiled_blits *t, *cs++ = MI_LOAD_REGISTER_IMM(1); *cs++ = i915_mmio_reg_offset(BCS_SWCTRL); cmd = (BCS_SRC_Y | BCS_DST_Y) << 16; - if (src->tiling == I915_TILING_Y) + if (src->tiling == CLIENT_TILING_Y) cmd |= BCS_SRC_Y; - if (dst->tiling == I915_TILING_Y) + if (dst->tiling == CLIENT_TILING_Y) cmd |= BCS_DST_Y; *cs++ = cmd; @@ -172,7 +179,7 @@ static int tiled_blits_create_buffers(struct tiled_blits *t, t->buffers[i].vma = vma; t->buffers[i].tiling = - i915_prandom_u32_max_state(I915_TILING_Y + 1, prng); + i915_prandom_u32_max_state(CLIENT_TILING_Y + 1, prng); } return 0; @@ -197,17 +204,17 @@ static u64 swizzle_bit(unsigned int bit, u64 offset) static u64 tiled_offset(const struct intel_gt *gt, u64 v, unsigned int stride, - unsigned int tiling) + enum client_tiling tiling) { unsigned int swizzle; u64 x, y; - if (tiling == I915_TILING_NONE) + if (tiling == CLIENT_TILING_LINEAR) return v; y = div64_u64_rem(v, stride, &x); - if (tiling == I915_TILING_X) { + if (tiling == CLIENT_TILING_X) { v = div64_u64_rem(y, 8, &y) * stride * 8; v += y * 512; v += div64_u64_rem(x, 512, &x) << 12; @@ -244,12 +251,12 @@ static u64 tiled_offset(const struct intel_gt *gt, return v; } -static const char *repr_tiling(int tiling) +static const char *repr_tiling(enum client_tiling tiling) { switch (tiling) { - case I915_TILING_NONE: return "linear"; - case I915_TILING_X: return "X"; - case I915_TILING_Y: return "Y"; + case CLIENT_TILING_LINEAR: return "linear"; + case CLIENT_TILING_X: return "X"; + case CLIENT_TILING_Y: return "Y"; default: return "unknown"; } } From 369b7d04baf3334d3473b2bb0b210a4e51d7bb67 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 8 Oct 2021 10:23:38 -0400 Subject: [PATCH 299/554] drm/amdgpu/nbio2.3: don't use GPU_HDP_FLUSH bit 12 It's used internally by firmware. Using it in the driver could conflict with firmware. v2: squash in fix for navi1x (Alex) Reviewed-by: James Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 5 ++- drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c | 31 +++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 2bebd2ce6474..0249911d744e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1134,12 +1134,15 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(2, 3, 0): case IP_VERSION(2, 3, 1): case IP_VERSION(2, 3, 2): + adev->nbio.funcs = &nbio_v2_3_funcs; + adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg; + break; case IP_VERSION(3, 3, 0): case IP_VERSION(3, 3, 1): case IP_VERSION(3, 3, 2): case IP_VERSION(3, 3, 3): adev->nbio.funcs = &nbio_v2_3_funcs; - adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg; + adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg_sc; break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c index b184b656b9b6..4ecd2b5808ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c @@ -53,6 +53,16 @@ #define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 +#define GPU_HDP_FLUSH_DONE__RSVD_ENG0_MASK 0x00001000L /* Don't use. Firmware uses this bit internally */ +#define GPU_HDP_FLUSH_DONE__RSVD_ENG1_MASK 0x00002000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG2_MASK 0x00004000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG3_MASK 0x00008000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG4_MASK 0x00010000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG5_MASK 0x00020000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG6_MASK 0x00040000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG7_MASK 0x00080000L +#define GPU_HDP_FLUSH_DONE__RSVD_ENG8_MASK 0x00100000L + static void nbio_v2_3_remap_hdp_registers(struct amdgpu_device *adev) { WREG32_SOC15(NBIO, 0, mmREMAP_HDP_MEM_FLUSH_CNTL, @@ -318,6 +328,27 @@ const struct nbio_hdp_flush_reg nbio_v2_3_hdp_flush_reg = { .ref_and_mask_sdma1 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__SDMA1_MASK, }; +const struct nbio_hdp_flush_reg nbio_v2_3_hdp_flush_reg_sc = { + .ref_and_mask_cp0 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP0_MASK, + .ref_and_mask_cp1 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP1_MASK, + .ref_and_mask_cp2 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP2_MASK, + .ref_and_mask_cp3 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP3_MASK, + .ref_and_mask_cp4 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP4_MASK, + .ref_and_mask_cp5 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP5_MASK, + .ref_and_mask_cp6 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP6_MASK, + .ref_and_mask_cp7 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP7_MASK, + .ref_and_mask_cp8 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP8_MASK, + .ref_and_mask_cp9 = BIF_BX_PF_GPU_HDP_FLUSH_DONE__CP9_MASK, + .ref_and_mask_sdma0 = GPU_HDP_FLUSH_DONE__RSVD_ENG1_MASK, + .ref_and_mask_sdma1 = GPU_HDP_FLUSH_DONE__RSVD_ENG2_MASK, + .ref_and_mask_sdma2 = GPU_HDP_FLUSH_DONE__RSVD_ENG3_MASK, + .ref_and_mask_sdma3 = GPU_HDP_FLUSH_DONE__RSVD_ENG4_MASK, + .ref_and_mask_sdma4 = GPU_HDP_FLUSH_DONE__RSVD_ENG5_MASK, + .ref_and_mask_sdma5 = GPU_HDP_FLUSH_DONE__RSVD_ENG6_MASK, + .ref_and_mask_sdma6 = GPU_HDP_FLUSH_DONE__RSVD_ENG7_MASK, + .ref_and_mask_sdma7 = GPU_HDP_FLUSH_DONE__RSVD_ENG8_MASK, +}; + static void nbio_v2_3_init_registers(struct amdgpu_device *adev) { uint32_t def, data; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h index a43b60acf7f6..6074dd3a1ed8 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.h @@ -27,6 +27,7 @@ #include "soc15_common.h" extern const struct nbio_hdp_flush_reg nbio_v2_3_hdp_flush_reg; +extern const struct nbio_hdp_flush_reg nbio_v2_3_hdp_flush_reg_sc; extern const struct amdgpu_nbio_funcs nbio_v2_3_funcs; #endif From 71cbfeb38141928f65dd84db61df01e36119cceb Mon Sep 17 00:00:00 2001 From: Alex Sierra Date: Mon, 7 Jun 2021 13:14:50 -0500 Subject: [PATCH 300/554] drm/amdkfd: avoid conflicting address mappings [Why] Avoid conflict with address ranges mapped by SVM mechanism that try to be allocated again through ioctl_alloc in the same process. And viceversa. [How] For ioctl_alloc_memory_of_gpu allocations Check if the address range passed into ioctl memory alloc does not exist already in the kfd_process svms->objects interval tree. For SVM allocations Look for the address range into the interval tree VA from the VM inside of each pdds used in a kfd_process. Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 13 ++++ drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 79 +++++++++++++++++++----- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 86afd37b098d..3177c4a0e753 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1251,6 +1251,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, struct kfd_process_device *pdd; void *mem; struct kfd_dev *dev; + struct svm_range_list *svms = &p->svms; int idr_handle; long err; uint64_t offset = args->mmap_offset; @@ -1259,6 +1260,18 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, if (args->size == 0) return -EINVAL; +#if IS_ENABLED(CONFIG_HSA_AMD_SVM) + mutex_lock(&svms->lock); + if (interval_tree_iter_first(&svms->objects, + args->va_addr >> PAGE_SHIFT, + (args->va_addr + args->size - 1) >> PAGE_SHIFT)) { + pr_err("Address: 0x%llx already allocated by SVM\n", + args->va_addr); + mutex_unlock(&svms->lock); + return -EADDRINUSE; + } + mutex_unlock(&svms->lock); +#endif dev = kfd_device_by_id(args->gpu_id); if (!dev) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 179080329af8..298669b7b2d8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2662,9 +2662,54 @@ int svm_range_list_init(struct kfd_process *p) return 0; } +/** + * svm_range_check_vm - check if virtual address range mapped already + * @p: current kfd_process + * @start: range start address, in pages + * @last: range last address, in pages + * + * The purpose is to avoid virtual address ranges already allocated by + * kfd_ioctl_alloc_memory_of_gpu ioctl. + * It looks for each pdd in the kfd_process. + * + * Context: Process context + * + * Return 0 - OK, if the range is not mapped. + * Otherwise error code: + * -EADDRINUSE - if address is mapped already by kfd_ioctl_alloc_memory_of_gpu + * -ERESTARTSYS - A wait for the buffer to become unreserved was interrupted by + * a signal. Release all buffer reservations and return to user-space. + */ +static int +svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last) +{ + uint32_t i; + int r; + + for (i = 0; i < p->n_pdds; i++) { + struct amdgpu_vm *vm; + + if (!p->pdds[i]->drm_priv) + continue; + + vm = drm_priv_to_vm(p->pdds[i]->drm_priv); + r = amdgpu_bo_reserve(vm->root.bo, false); + if (r) + return r; + if (interval_tree_iter_first(&vm->va, start, last)) { + pr_debug("Range [0x%llx 0x%llx] already mapped\n", start, last); + amdgpu_bo_unreserve(vm->root.bo); + return -EADDRINUSE; + } + amdgpu_bo_unreserve(vm->root.bo); + } + + return 0; +} + /** * svm_range_is_valid - check if virtual address range is valid - * @mm: current process mm_struct + * @p: current kfd_process * @start: range start address, in pages * @size: range size, in pages * @@ -2673,28 +2718,27 @@ int svm_range_list_init(struct kfd_process *p) * Context: Process context * * Return: - * true - valid svm range - * false - invalid svm range + * 0 - OK, otherwise error code */ -static bool -svm_range_is_valid(struct mm_struct *mm, uint64_t start, uint64_t size) +static int +svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size) { const unsigned long device_vma = VM_IO | VM_PFNMAP | VM_MIXEDMAP; struct vm_area_struct *vma; unsigned long end; + unsigned long start_unchg = start; start <<= PAGE_SHIFT; end = start + (size << PAGE_SHIFT); - do { - vma = find_vma(mm, start); + vma = find_vma(p->mm, start); if (!vma || start < vma->vm_start || (vma->vm_flags & device_vma)) - return false; + return -EFAULT; start = min(end, vma->vm_end); } while (start < end); - return true; + return svm_range_check_vm(p, start_unchg, (end - 1) >> PAGE_SHIFT); } /** @@ -2997,9 +3041,9 @@ svm_range_set_attr(struct kfd_process *p, uint64_t start, uint64_t size, svm_range_list_lock_and_flush_work(svms, mm); - if (!svm_range_is_valid(mm, start, size)) { - pr_debug("invalid range\n"); - r = -EFAULT; + r = svm_range_is_valid(p, start, size); + if (r) { + pr_debug("invalid range r=%d\n", r); mmap_write_unlock(mm); goto out; } @@ -3101,6 +3145,7 @@ svm_range_get_attr(struct kfd_process *p, uint64_t start, uint64_t size, uint32_t flags_or = 0; int gpuidx; uint32_t i; + int r = 0; pr_debug("svms 0x%p [0x%llx 0x%llx] nattr 0x%x\n", &p->svms, start, start + size - 1, nattr); @@ -3114,12 +3159,12 @@ svm_range_get_attr(struct kfd_process *p, uint64_t start, uint64_t size, flush_work(&p->svms.deferred_list_work); mmap_read_lock(mm); - if (!svm_range_is_valid(mm, start, size)) { - pr_debug("invalid range\n"); - mmap_read_unlock(mm); - return -EINVAL; - } + r = svm_range_is_valid(p, start, size); mmap_read_unlock(mm); + if (r) { + pr_debug("invalid range r=%d\n", r); + return r; + } for (i = 0; i < nattr; i++) { switch (attrs[i].type) { From 6bdfc37b5cccc12e54e7019907d7eb4ff9e741fb Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Tue, 17 Aug 2021 16:47:26 +0800 Subject: [PATCH 301/554] drm/amdkfd: export svm_range_list_lock_and_flush_work export svm_range_list_lock_and_flush_work to make other kfd parts be able to sync svm_range_list. Signed-off-by: Yifan Zhang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 298669b7b2d8..425d55deca10 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1547,7 +1547,7 @@ unreserve_out: * Context: Returns with mmap write lock held, pending deferred work flushed * */ -static void +void svm_range_list_lock_and_flush_work(struct svm_range_list *svms, struct mm_struct *mm) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index c6ec55354c7b..6dc91c33e80f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -188,6 +188,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, void *owner); struct kfd_process_device * svm_range_get_pdd_by_adev(struct svm_range *prange, struct amdgpu_device *adev); +void svm_range_list_lock_and_flush_work(struct svm_range_list *svms, struct mm_struct *mm); /* SVM API and HMM page migration work together, device memory type * is initialized to not 0 when page migration register device memory. From 9c152f54d9f6abdc9dd0817d8634c3ea0842c1c4 Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Sat, 14 Aug 2021 17:53:14 +0800 Subject: [PATCH 302/554] drm/amdkfd: fix KFDSVMRangeTest.PartialUnmapSysMemTest fails [ RUN ] KFDSVMRangeTest.PartialUnmapSysMemTest /home/yifan/brahma/libhsakmt/tests/kfdtest/src/KFDTestUtil.cpp:245: Failure Value of: (hsaKmtAllocMemory(m_Node, m_Size, m_Flags, &m_pBuf)) Actual: 1 Expected: HSAKMT_STATUS_SUCCESS Which is: 0 /home/yifan/brahma/libhsakmt/tests/kfdtest/src/KFDTestUtil.cpp:248: Failure Value of: (hsaKmtMapMemoryToGPUNodes(m_pBuf, m_Size, __null, mapFlags, 1, &m_Node)) Actual: 1 Expected: HSAKMT_STATUS_SUCCESS Which is: 0 /home/yifan/brahma/libhsakmt/tests/kfdtest/src/KFDTestUtil.cpp:306: Failure Expected: ((void *)__null) != (ptr), actual: NULL vs NULL Segmentation fault (core dumped) [ ] Profile: Full Test [ ] HW capabilities: 0x9 kernel log: [ 102.029150] ret_from_fork+0x22/0x30 [ 102.029158] ---[ end trace 15c34e782714f9a3 ]--- [ 3613.603598] amdgpu: Address: 0x7f7149ccc000 already allocated by SVM [ 3613.610620] show_signal_msg: 27 callbacks suppressed These is race with deferred actions from previous memory map changes (e.g. munmap).Flush pending deffered work to avoid such case. Signed-off-by: Yifan Zhang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 3177c4a0e753..4de907f3e66a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1261,7 +1261,12 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, return -EINVAL; #if IS_ENABLED(CONFIG_HSA_AMD_SVM) + /* Flush pending deferred work to avoid racing with deferred actions + * from previous memory map changes (e.g. munmap). + */ + svm_range_list_lock_and_flush_work(svms, current->mm); mutex_lock(&svms->lock); + mmap_write_unlock(current->mm); if (interval_tree_iter_first(&svms->objects, args->va_addr >> PAGE_SHIFT, (args->va_addr + args->size - 1) >> PAGE_SHIFT)) { From 7e3fb209d518112628f3f5abd6e66053ac4b0767 Mon Sep 17 00:00:00 2001 From: Alex Sierra Date: Thu, 30 Sep 2021 10:38:08 -0500 Subject: [PATCH 303/554] amd/amdkfd: remove svms declaration to avoid werror svm_range_list svms declaration removed to avoid werror when CONFIG_HSA_AMD_SVM is not enabled. Signed-off-by: Alex Sierra Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 4de907f3e66a..f1e7edeb4e6b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1251,7 +1251,6 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, struct kfd_process_device *pdd; void *mem; struct kfd_dev *dev; - struct svm_range_list *svms = &p->svms; int idr_handle; long err; uint64_t offset = args->mmap_offset; @@ -1264,18 +1263,18 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, /* Flush pending deferred work to avoid racing with deferred actions * from previous memory map changes (e.g. munmap). */ - svm_range_list_lock_and_flush_work(svms, current->mm); - mutex_lock(&svms->lock); + svm_range_list_lock_and_flush_work(&p->svms, current->mm); + mutex_lock(&p->svms.lock); mmap_write_unlock(current->mm); - if (interval_tree_iter_first(&svms->objects, + if (interval_tree_iter_first(&p->svms.objects, args->va_addr >> PAGE_SHIFT, (args->va_addr + args->size - 1) >> PAGE_SHIFT)) { pr_err("Address: 0x%llx already allocated by SVM\n", args->va_addr); - mutex_unlock(&svms->lock); + mutex_unlock(&p->svms.lock); return -EADDRINUSE; } - mutex_unlock(&svms->lock); + mutex_unlock(&p->svms.lock); #endif dev = kfd_device_by_id(args->gpu_id); if (!dev) From d1bfbe8a3202640c28a5769faff49b732af2438b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 6 Oct 2021 14:06:05 +0000 Subject: [PATCH 304/554] amd/display: check cursor plane matches underlying plane The current logic checks whether the cursor plane blending properties match the primary plane's. However that's wrong, because the cursor is painted on all planes underneath. If the cursor is over the primary plane and the overlay plane, it's painted on both pipes. Iterate over the CRTC planes and check their scaling match the cursor's. v4: fix typo in commit message (Harry) Signed-off-by: Simon Ser Cc: Alex Deucher Cc: Harry Wentland Cc: Nicholas Kazlauskas Cc: Bas Nieuwenhuizen Cc: Rodrigo Siqueira Cc: Sean Paul Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f35561b5a465..ec914823ec6f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10535,18 +10535,18 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, struct drm_crtc *crtc, struct drm_crtc_state *new_crtc_state) { - struct drm_plane_state *new_cursor_state, *new_primary_state; - int cursor_scale_w, cursor_scale_h, primary_scale_w, primary_scale_h; + struct drm_plane *cursor = crtc->cursor, *underlying; + struct drm_plane_state *new_cursor_state, *new_underlying_state; + int i; + int cursor_scale_w, cursor_scale_h, underlying_scale_w, underlying_scale_h; /* On DCE and DCN there is no dedicated hardware cursor plane. We get a * cursor per pipe but it's going to inherit the scaling and * positioning from the underlying pipe. Check the cursor plane's - * blending properties match the primary plane's. */ + * blending properties match the underlying planes'. */ - new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor); - new_primary_state = drm_atomic_get_new_plane_state(state, crtc->primary); - if (!new_cursor_state || !new_primary_state || - !new_cursor_state->fb || !new_primary_state->fb) { + new_cursor_state = drm_atomic_get_new_plane_state(state, cursor); + if (!new_cursor_state || !new_cursor_state->fb) { return 0; } @@ -10555,15 +10555,34 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, cursor_scale_h = new_cursor_state->crtc_h * 1000 / (new_cursor_state->src_h >> 16); - primary_scale_w = new_primary_state->crtc_w * 1000 / - (new_primary_state->src_w >> 16); - primary_scale_h = new_primary_state->crtc_h * 1000 / - (new_primary_state->src_h >> 16); + for_each_new_plane_in_state_reverse(state, underlying, new_underlying_state, i) { + /* Narrow down to non-cursor planes on the same CRTC as the cursor */ + if (new_underlying_state->crtc != crtc || underlying == crtc->cursor) + continue; - if (cursor_scale_w != primary_scale_w || - cursor_scale_h != primary_scale_h) { - drm_dbg_atomic(crtc->dev, "Cursor plane scaling doesn't match primary plane\n"); - return -EINVAL; + /* Ignore disabled planes */ + if (!new_underlying_state->fb) + continue; + + underlying_scale_w = new_underlying_state->crtc_w * 1000 / + (new_underlying_state->src_w >> 16); + underlying_scale_h = new_underlying_state->crtc_h * 1000 / + (new_underlying_state->src_h >> 16); + + if (cursor_scale_w != underlying_scale_w || + cursor_scale_h != underlying_scale_h) { + drm_dbg_atomic(crtc->dev, + "Cursor [PLANE:%d:%s] scaling doesn't match underlying [PLANE:%d:%s]\n", + cursor->base.id, cursor->name, underlying->base.id, underlying->name); + return -EINVAL; + } + + /* If this plane covers the whole CRTC, no need to check planes underneath */ + if (new_underlying_state->crtc_x <= 0 && + new_underlying_state->crtc_y <= 0 && + new_underlying_state->crtc_x + new_underlying_state->crtc_w >= new_crtc_state->mode.hdisplay && + new_underlying_state->crtc_y + new_underlying_state->crtc_h >= new_crtc_state->mode.vdisplay) + break; } return 0; From fe04957e26e7a633e0b4052590c5c6a1d5cb3e89 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Tue, 12 Oct 2021 14:10:46 +0800 Subject: [PATCH 305/554] drm/amdgpu: enable display for cyan skillfish Display support for cyan skillfish is ready now. Enable it! Signed-off-by: Lang Yu Reviewed-by: Huang Rui Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 0249911d744e..9645b95b9c42 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -736,6 +736,7 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(1, 0, 1): case IP_VERSION(2, 0, 2): case IP_VERSION(2, 0, 0): + case IP_VERSION(2, 0, 3): case IP_VERSION(2, 1, 0): case IP_VERSION(3, 0, 0): case IP_VERSION(3, 0, 2): @@ -745,8 +746,6 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(3, 1, 3): amdgpu_device_ip_block_add(adev, &dm_ip_block); break; - case IP_VERSION(2, 0, 3): - break; default: return -EINVAL; } From 9470620e99e90999dc367bdcccc7e1274dcbb796 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 5 Oct 2021 10:55:57 -0400 Subject: [PATCH 306/554] drm/amd/display: Enable PSR by default on newer DCN [Why] For optimal power savings on panels that can support it. This was previously left disabled by default because of issues with compositors that do not pageflip and scan out directly to the frontbuffer. For these compositors we now have detection methods that wait for x number of pageflips after a full update - triggered by a buffer or format change typically. This may introduce bugs or new cases not tested by users so this is only currently targeting newer DCN. [How] Add code in DM to set PSR state by default for newer DCN while falling back to the feature mask for older. Add a global debug flag that can be set to disable it for either. Signed-off-by: Nicholas Kazlauskas Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 ++++++++++++++++- drivers/gpu/drm/amd/include/amd_shared.h | 5 +++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ec914823ec6f..20065a145851 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4031,6 +4031,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) int32_t primary_planes; enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; + bool psr_feature_enabled = false; dm->display_indexes_num = dm->dc->caps.max_streams; /* Update the actual used number of crtc */ @@ -4113,6 +4114,19 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", adev->ip_versions[DCE_HWIP][0]); } + + /* Determine whether to enable PSR support by default. */ + if (!(amdgpu_dc_debug_mask & DC_DISABLE_PSR)) { + switch (adev->ip_versions[DCE_HWIP][0]) { + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + psr_feature_enabled = true; + break; + default: + psr_feature_enabled = amdgpu_dc_feature_mask & DC_PSR_MASK; + break; + } + } #endif /* loops over all connectors on the board */ @@ -4156,7 +4170,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } else if (dc_link_detect(link, DETECT_REASON_BOOT)) { amdgpu_dm_update_connector_after_detect(aconnector); register_backlight_device(dm, link); - if (amdgpu_dc_feature_mask & DC_PSR_MASK) + + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); } diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 257f280d3d53..f1a46d16f7ea 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -228,7 +228,7 @@ enum DC_FEATURE_MASK { DC_FBC_MASK = (1 << 0), //0x1, disabled by default DC_MULTI_MON_PP_MCLK_SWITCH_MASK = (1 << 1), //0x2, enabled by default DC_DISABLE_FRACTIONAL_PWM_MASK = (1 << 2), //0x4, disabled by default - DC_PSR_MASK = (1 << 3), //0x8, disabled by default + DC_PSR_MASK = (1 << 3), //0x8, disabled by default for dcn < 3.1 DC_EDP_NO_POWER_SEQUENCING = (1 << 4), //0x10, disabled by default }; @@ -236,7 +236,8 @@ enum DC_DEBUG_MASK { DC_DISABLE_PIPE_SPLIT = 0x1, DC_DISABLE_STUTTER = 0x2, DC_DISABLE_DSC = 0x4, - DC_DISABLE_CLOCK_GATING = 0x8 + DC_DISABLE_CLOCK_GATING = 0x8, + DC_DISABLE_PSR = 0x10, }; enum amd_dpm_forced_level; From 62e5a7e2333a9f5395f6a9db766b7b06c949fe7a Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 12 Oct 2021 10:04:03 -0400 Subject: [PATCH 307/554] drm/amd/display: Fix surface optimization regression on Carrizo [Why] DCE legacy optimization path isn't well tested under new DC optimization flow which can result in underflow occuring when initializing X11 on Carrizo. [How] Retain the legacy optimization flow for DCE and keep the new one for DCN to satisfy optimizations being correctly applied for ASIC that can support it. Fixes: 34316c1e561db0 ("drm/amd/display: Optimize bandwidth on following fast update") Reported-by: Tom St Denis Tested-by: Tom St Denis Reviewed-by: Harry Wentland Signed-off-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index da942e9f5142..f9876e429f26 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3118,8 +3118,13 @@ void dc_commit_updates_for_stream(struct dc *dc, if (new_pipe->plane_state && new_pipe->plane_state != old_pipe->plane_state) new_pipe->plane_state->force_full_update = true; } - } else if (update_type == UPDATE_TYPE_FAST) { - /* Previous frame finished and HW is ready for optimization. */ + } else if (update_type == UPDATE_TYPE_FAST && dc_ctx->dce_version >= DCE_VERSION_MAX) { + /* + * Previous frame finished and HW is ready for optimization. + * + * Only relevant for DCN behavior where we can guarantee the optimization + * is safe to apply - retain the legacy behavior for DCE. + */ dc_post_update_surfaces_to_stream(dc); } @@ -3178,6 +3183,12 @@ void dc_commit_updates_for_stream(struct dc *dc, } } + /* Legacy optimization path for DCE. */ + if (update_type >= UPDATE_TYPE_FULL && dc_ctx->dce_version < DCE_VERSION_MAX) { + dc_post_update_surfaces_to_stream(dc); + TRACE_DCE_CLOCK_STATE(&context->bw_ctx.bw.dce); + } + return; } From 1f3b22e4eb162e0b1d423106a47484943a22a309 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Fri, 8 Oct 2021 16:07:45 -0400 Subject: [PATCH 308/554] drm/amd/display: fix null pointer deref when plugging in display [Why&How] When system boots in headless mode, connecting a 4k display creates a null pointer dereference due to hubp for a certain plane being null. Add a condition to check for null hubp before dereferencing it. Signed-off-by: Aurabindo Pillai Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 01a90badd173..2936a334cd64 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -969,7 +969,8 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc, /* turning off DPG */ pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, false); for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe) - mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false); + if (mpcc_pipe->plane_res.hubp) + mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false); stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space, color_depth, solid_color, width, height, offset); From a4967a1ebf1b9e68cc99ab666ece65733fffcac6 Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Mon, 20 Sep 2021 15:29:23 -0400 Subject: [PATCH 309/554] drm/amdgpu: Enable RAS error injection after mode2 reset on Aldebaran Add the missing call to re-enable RAS error injections on the Aldebaran mode2 reset code path. Signed-off-by: Mukul Joshi Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 148f6c3343ab..bcfdb63b1d42 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -307,6 +307,8 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev) adev->ip_blocks[i].status.late_initialized = true; } + amdgpu_ras_set_error_query_ready(adev, true); + amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE); amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE); From 91a1a52d03aa0f1f2b51c7df8a7bf437e906e29f Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Mon, 20 Sep 2021 20:48:23 -0400 Subject: [PATCH 310/554] drm/amdgpu: Fix RAS page retirement with mode2 reset on Aldebaran During mode2 reset, the GPU is temporarily removed from the mgpu_info list. As a result, page retirement fails because it cannot find the GPU in the GPU list. To fix this, create our own list of GPUs that support MCE notifier based page retirement and use that list to check if the UMC error occurred on a GPU that supports MCE notifier based page retirement. Signed-off-by: Mukul Joshi Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index e8875351967e..08133de21fdd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -112,7 +112,12 @@ static bool amdgpu_ras_check_bad_page_unlock(struct amdgpu_ras *con, static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev, uint64_t addr); #ifdef CONFIG_X86_MCE_AMD -static void amdgpu_register_bad_pages_mca_notifier(void); +static void amdgpu_register_bad_pages_mca_notifier(struct amdgpu_device *adev); +struct mce_notifier_adev_list { + struct amdgpu_device *devs[MAX_GPU_INSTANCE]; + int num_gpu; +}; +static struct mce_notifier_adev_list mce_adev_list; #endif void amdgpu_ras_set_error_query_ready(struct amdgpu_device *adev, bool ready) @@ -2108,7 +2113,7 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) #ifdef CONFIG_X86_MCE_AMD if ((adev->asic_type == CHIP_ALDEBARAN) && (adev->gmc.xgmi.connected_to_cpu)) - amdgpu_register_bad_pages_mca_notifier(); + amdgpu_register_bad_pages_mca_notifier(adev); #endif return 0; @@ -2605,24 +2610,18 @@ void amdgpu_release_ras_context(struct amdgpu_device *adev) #ifdef CONFIG_X86_MCE_AMD static struct amdgpu_device *find_adev(uint32_t node_id) { - struct amdgpu_gpu_instance *gpu_instance; int i; struct amdgpu_device *adev = NULL; - mutex_lock(&mgpu_info.mutex); + for (i = 0; i < mce_adev_list.num_gpu; i++) { + adev = mce_adev_list.devs[i]; - for (i = 0; i < mgpu_info.num_gpu; i++) { - gpu_instance = &(mgpu_info.gpu_ins[i]); - adev = gpu_instance->adev; - - if (adev->gmc.xgmi.connected_to_cpu && + if (adev && adev->gmc.xgmi.connected_to_cpu && adev->gmc.xgmi.physical_node_id == node_id) break; adev = NULL; } - mutex_unlock(&mgpu_info.mutex); - return adev; } @@ -2718,8 +2717,18 @@ static struct notifier_block amdgpu_bad_page_nb = { .priority = MCE_PRIO_UC, }; -static void amdgpu_register_bad_pages_mca_notifier(void) +static void amdgpu_register_bad_pages_mca_notifier(struct amdgpu_device *adev) { + /* + * Add the adev to the mce_adev_list. + * During mode2 reset, amdgpu device is temporarily + * removed from the mgpu_info list which can cause + * page retirement to fail. + * Use this list instead of mgpu_info to find the amdgpu + * device on which the UMC error was reported. + */ + mce_adev_list.devs[mce_adev_list.num_gpu++] = adev; + /* * Register the x86 notifier only once * with MCE subsystem. From 2d1ac1cbe57b306b244c43aa11610b89ea5a3178 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Wed, 18 Aug 2021 23:31:36 -0400 Subject: [PATCH 311/554] amdgpu/pm: (v2) add limit_type to (pptable_funcs)->set_power_limit signature v2 add check for SMU_DEFAULT_PPT_LIMIT v1 modify (pptable_funcs)->set_power_limit signature modify smu11 set_power_limit signature (arcturus, navi10, sienna_cichlid) modify smu13 set_power_limit signature (aldabaran) modify vangogh_set_power_limit signature (vangogh) === Test === sudo bash AMDGPU_PCI_ADDR=`lspci -nn | grep "VGA\|Display" | cut -d " " -f 1` AMDGPU_HWMON=`ls -la /sys/class/hwmon | grep $AMDGPU_PCI_ADDR | awk '{print $9}'` HWMON_DIR=/sys/class/hwmon/${AMDGPU_HWMON} LOGFILE=pp_show_power_cap.log cp $LOGFILE{,.old} lspci -nn | grep "VGA\|Display" > $LOGFILE FILES=" power1_cap power2_cap" for f in $FILES do if test -f "$HWMON_DIR/$f"; then echo === $f === >> $LOGFILE cat $HWMON_DIR/$f >> $LOGFILE RESTORE_VALUE=`cat $HWMON_DIR/$f` 2>&1 >> $LOGFILE echo RESTORE_VALUE $RESTORE_VALUE >> $LOGFILE echo 120000000 > $HWMON_DIR/$f sleep 3 cat $HWMON_DIR/$f >> $LOGFILE echo $RESTORE_VALUE > $HWMON_DIR/$f sleep 3 cat $HWMON_DIR/$f >> $LOGFILE else echo === $f === >> $LOGFILE echo File Not Found >> $LOGFILE fi done cat $LOGFILE Signed-off-by: Darren Powell Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h | 4 +++- drivers/gpu/drm/amd/pm/inc/smu_v11_0.h | 4 +++- drivers/gpu/drm/amd/pm/inc/smu_v13_0.h | 4 +++- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 5 +++-- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 17 +++++++++++------ .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 7 ++++--- .../gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 6 ++++-- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 11 ++++++++--- 8 files changed, 39 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h index 8156729c370b..3557f4e7fc30 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h @@ -1008,7 +1008,9 @@ struct pptable_funcs { /** * @set_power_limit: Set power limit in watts. */ - int (*set_power_limit)(struct smu_context *smu, uint32_t n); + int (*set_power_limit)(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit); /** * @init_max_sustainable_clocks: Populate max sustainable clock speed diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h index cbdae8a2c698..2d422e6a9feb 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h @@ -197,7 +197,9 @@ int smu_v11_0_notify_display_change(struct smu_context *smu); int smu_v11_0_get_current_power_limit(struct smu_context *smu, uint32_t *power_limit); -int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n); +int smu_v11_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit); int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h index dc91eb608791..e5d3b0d1a032 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h @@ -163,7 +163,9 @@ int smu_v13_0_notify_display_change(struct smu_context *smu); int smu_v13_0_get_current_power_limit(struct smu_context *smu, uint32_t *power_limit); -int smu_v13_0_set_power_limit(struct smu_context *smu, uint32_t n); +int smu_v13_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit); int smu_v13_0_init_max_sustainable_clocks(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 4ea7e90ef60d..160efc0a3893 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2344,9 +2344,10 @@ static int smu_set_power_limit(void *handle, uint32_t limit) mutex_lock(&smu->mutex); + limit &= (1<<24)-1; if (limit_type != SMU_DEFAULT_PPT_LIMIT) if (smu->ppt_funcs->set_power_limit) { - ret = smu->ppt_funcs->set_power_limit(smu, limit); + ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit); goto out; } @@ -2362,7 +2363,7 @@ static int smu_set_power_limit(void *handle, uint32_t limit) limit = smu->current_power_limit; if (smu->ppt_funcs->set_power_limit) { - ret = smu->ppt_funcs->set_power_limit(smu, limit); + ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit); if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.power_limit = limit; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 3470c33ee09d..b9386c55bd85 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -978,11 +978,16 @@ int smu_v11_0_get_current_power_limit(struct smu_context *smu, return ret; } -int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n) +int smu_v11_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) { int power_src; int ret = 0; + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { dev_err(smu->adev->dev, "Setting new power limit is not supported!\n"); return -EOPNOTSUPP; @@ -1001,16 +1006,16 @@ int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n) * BIT 16-23: PowerSource * BIT 0-15: PowerLimit */ - n &= 0xFFFF; - n |= 0 << 24; - n |= (power_src) << 16; - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n, NULL); + limit &= 0xFFFF; + limit |= 0 << 24; + limit |= (power_src) << 16; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL); if (ret) { dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); return ret; } - smu->current_power_limit = n; + smu->current_power_limit = limit; return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index f6ef0ce6e9e2..eba516428f1b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2144,11 +2144,12 @@ static int vangogh_get_ppt_limit(struct smu_context *smu, return 0; } -static int vangogh_set_power_limit(struct smu_context *smu, uint32_t ppt_limit) +static int vangogh_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t ppt_limit) { struct smu_11_5_power_context *power_context = - smu->smu_power.power_context; - uint32_t limit_type = ppt_limit >> 24; + smu->smu_power.power_context; int ret = 0; if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 5019903db492..59a7d276541d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1241,11 +1241,13 @@ static int aldebaran_get_power_limit(struct smu_context *smu, return 0; } -static int aldebaran_set_power_limit(struct smu_context *smu, uint32_t n) +static int aldebaran_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) { /* Power limit can be set only through primary die */ if (aldebaran_is_primary(smu)) - return smu_v13_0_set_power_limit(smu, n); + return smu_v13_0_set_power_limit(smu, limit_type, limit); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 05c5e61f3506..35145db6eedf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -945,22 +945,27 @@ int smu_v13_0_get_current_power_limit(struct smu_context *smu, return ret; } -int smu_v13_0_set_power_limit(struct smu_context *smu, uint32_t n) +int smu_v13_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) { int ret = 0; + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { dev_err(smu->adev->dev, "Setting new power limit is not supported!\n"); return -EOPNOTSUPP; } - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL); if (ret) { dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); return ret; } - smu->current_power_limit = n; + smu->current_power_limit = limit; return 0; } From 02f8aa9f2a3249d32316d745d1e4a3afef4180e5 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Fri, 20 Aug 2021 22:08:07 -0400 Subject: [PATCH 312/554] drm/amd/pm: Fix incorrect power limit readback in smu11 if POWER_SOURCE_DC when smu->adev->pm.ac_power == 0, message parameter with bit 16 set is saved to smu->current_power_limit. Fixes: 0cb4c62125a9 ("drm/amd/pm: correct power limit setting for SMU V11)" Signed-off-by: Darren Powell Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index b9386c55bd85..aa4d34f35c33 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -984,6 +984,7 @@ int smu_v11_0_set_power_limit(struct smu_context *smu, { int power_src; int ret = 0; + uint32_t limit_param; if (limit_type != SMU_DEFAULT_PPT_LIMIT) return -EINVAL; @@ -1006,10 +1007,10 @@ int smu_v11_0_set_power_limit(struct smu_context *smu, * BIT 16-23: PowerSource * BIT 0-15: PowerLimit */ - limit &= 0xFFFF; - limit |= 0 << 24; - limit |= (power_src) << 16; - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL); + limit_param = (limit & 0xFFFF); + limit_param |= 0 << 24; + limit_param |= (power_src) << 16; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit_param, NULL); if (ret) { dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); return ret; From a273bc9937e64ddb3798ba0fd5c92b5f3fce84c4 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Tue, 5 Oct 2021 11:12:18 -0400 Subject: [PATCH 313/554] drm/amdkfd: ratelimited svm debug messages No function change, use pr_debug_ratelimited to avoid per page debug message overflowing dmesg buf and console log. use dev_err to show error message from unexpected situation, to provide clue to help debug without enabling dynamic debug log. Define dev_fmt to output function name in error message. Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 34 +++++++++++++----------- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 17 +++++++----- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index f53e17a94ad8..b05c0579d0b9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -20,7 +20,6 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ - #include #include #include @@ -34,6 +33,11 @@ #include "kfd_svm.h" #include "kfd_migrate.h" +#ifdef dev_fmt +#undef dev_fmt +#endif +#define dev_fmt(fmt) "kfd_migrate: %s: " fmt, __func__ + static uint64_t svm_migrate_direct_mapping_addr(struct amdgpu_device *adev, uint64_t addr) { @@ -151,14 +155,14 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys, gart_d = svm_migrate_direct_mapping_addr(adev, *vram); } if (r) { - pr_debug("failed %d to create gart mapping\n", r); + dev_err(adev->dev, "fail %d create gart mapping\n", r); goto out_unlock; } r = amdgpu_copy_buffer(ring, gart_s, gart_d, size * PAGE_SIZE, NULL, &next, false, true, false); if (r) { - pr_debug("failed %d to copy memory\n", r); + dev_err(adev->dev, "fail %d to copy memory\n", r); goto out_unlock; } @@ -285,7 +289,7 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, r = svm_range_vram_node_new(adev, prange, true); if (r) { - pr_debug("failed %d get 0x%llx pages from vram\n", r, npages); + dev_err(adev->dev, "fail %d to alloc vram\n", r); goto out; } @@ -305,7 +309,7 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, DMA_TO_DEVICE); r = dma_mapping_error(dev, src[i]); if (r) { - pr_debug("failed %d dma_map_page\n", r); + dev_err(adev->dev, "fail %d dma_map_page\n", r); goto out_free_vram_pages; } } else { @@ -325,8 +329,8 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, continue; } - pr_debug("dma mapping src to 0x%llx, page_to_pfn 0x%lx\n", - src[i] >> PAGE_SHIFT, page_to_pfn(spage)); + pr_debug_ratelimited("dma mapping src to 0x%llx, pfn 0x%lx\n", + src[i] >> PAGE_SHIFT, page_to_pfn(spage)); if (j >= (cursor.size >> PAGE_SHIFT) - 1 && i < npages - 1) { r = svm_migrate_copy_memory_gart(adev, src + i - j, @@ -405,8 +409,8 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, r = migrate_vma_setup(&migrate); if (r) { - pr_debug("failed %d prepare migrate svms 0x%p [0x%lx 0x%lx]\n", - r, prange->svms, prange->start, prange->last); + dev_err(adev->dev, "vma setup fail %d range [0x%lx 0x%lx]\n", r, + prange->start, prange->last); goto out_free; } if (migrate.cpages != npages) { @@ -506,7 +510,7 @@ static void svm_migrate_page_free(struct page *page) struct svm_range_bo *svm_bo = page->zone_device_data; if (svm_bo) { - pr_debug("svm_bo ref left: %d\n", kref_read(&svm_bo->kref)); + pr_debug_ratelimited("ref: %d\n", kref_read(&svm_bo->kref)); svm_range_bo_unref(svm_bo); } } @@ -572,12 +576,12 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_FROM_DEVICE); r = dma_mapping_error(dev, dst[i]); if (r) { - pr_debug("failed %d dma_map_page\n", r); + dev_err(adev->dev, "fail %d dma_map_page\n", r); goto out_oom; } - pr_debug("dma mapping dst to 0x%llx, page_to_pfn 0x%lx\n", - dst[i] >> PAGE_SHIFT, page_to_pfn(dpage)); + pr_debug_ratelimited("dma mapping dst to 0x%llx, pfn 0x%lx\n", + dst[i] >> PAGE_SHIFT, page_to_pfn(dpage)); migrate->dst[i] = migrate_pfn(page_to_pfn(dpage)); migrate->dst[i] |= MIGRATE_PFN_LOCKED; @@ -631,8 +635,8 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, r = migrate_vma_setup(&migrate); if (r) { - pr_debug("failed %d prepare migrate svms 0x%p [0x%lx 0x%lx]\n", - r, prange->svms, prange->start, prange->last); + dev_err(adev->dev, "vma setup fail %d range [0x%lx 0x%lx]\n", r, + prange->start, prange->last); goto out_free; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 425d55deca10..49c92713c2ad 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -33,6 +33,11 @@ #include "kfd_svm.h" #include "kfd_migrate.h" +#ifdef dev_fmt +#undef dev_fmt +#endif +#define dev_fmt(fmt) "kfd_svm: %s: " fmt, __func__ + #define AMDGPU_SVM_RANGE_RESTORE_DELAY_MS 1 /* Long enough to ensure no retry fault comes after svm range is restored and @@ -158,17 +163,17 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, bo_adev->vm_manager.vram_base_offset - bo_adev->kfd.dev->pgmap.range.start; addr[i] |= SVM_RANGE_VRAM_DOMAIN; - pr_debug("vram address detected: 0x%llx\n", addr[i]); + pr_debug_ratelimited("vram address: 0x%llx\n", addr[i]); continue; } addr[i] = dma_map_page(dev, page, 0, PAGE_SIZE, dir); r = dma_mapping_error(dev, addr[i]); if (r) { - pr_debug("failed %d dma_map_page\n", r); + dev_err(dev, "failed %d dma_map_page\n", r); return r; } - pr_debug("dma mapping 0x%llx for page addr 0x%lx\n", - addr[i] >> PAGE_SHIFT, page_to_pfn(page)); + pr_debug_ratelimited("dma mapping 0x%llx for page addr 0x%lx\n", + addr[i] >> PAGE_SHIFT, page_to_pfn(page)); } return 0; } @@ -217,7 +222,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, for (i = offset; i < offset + npages; i++) { if (!svm_is_valid_dma_mapping_addr(dev, dma_addr[i])) continue; - pr_debug("dma unmapping 0x%llx\n", dma_addr[i] >> PAGE_SHIFT); + pr_debug_ratelimited("unmap 0x%llx\n", dma_addr[i] >> PAGE_SHIFT); dma_unmap_page(dev, dma_addr[i], PAGE_SIZE, dir); dma_addr[i] = 0; } @@ -1454,7 +1459,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, /* This should never happen. actual_loc gets set by * svm_migrate_ram_to_vram after allocating a BO. */ - WARN(1, "VRAM BO missing during validation\n"); + WARN_ONCE(1, "VRAM BO missing during validation\n"); return -EINVAL; } From ca432dcc27a1bca71a5e7b35399617d5efb3af45 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Tue, 5 Oct 2021 11:13:21 -0400 Subject: [PATCH 314/554] drm/amdkfd: handle svm partial migration cpages 0 migrate_vma_setup may return cpages 0, means 0 page can be migrated, treat this as error case to skip the rest of vma migration steps. Change svm_migrate_vma_to_vram and svm_migrate_vma_to_ram to return the number of pages migrated successfully or error code. The caller add up all the successful migration pages and update prange->actual_loc only if the total migrated pages is not 0. This also removes the warning message "VRAM BO missing during validation" if migration cpages is 0. Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 86 ++++++++++++++---------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index b05c0579d0b9..147300a161d0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -376,7 +376,7 @@ out: return r; } -static int +static long svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, struct vm_area_struct *vma, uint64_t start, uint64_t end) @@ -413,19 +413,23 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, prange->start, prange->last); goto out_free; } - if (migrate.cpages != npages) { - pr_debug("Partial migration. 0x%lx/0x%llx pages can be migrated\n", - migrate.cpages, - npages); + + if (migrate.cpages != npages) + pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + migrate.cpages, npages); + else + pr_debug("0x%lx pages migrated\n", migrate.cpages); + + if (!migrate.cpages) { + pr_debug("failed collect migrate sys pages [0x%lx 0x%lx]\n", + prange->start, prange->last); + goto out_free; } - if (migrate.cpages) { - r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, - scratch); - migrate_vma_pages(&migrate); - svm_migrate_copy_done(adev, mfence); - migrate_vma_finalize(&migrate); - } + r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, scratch); + migrate_vma_pages(&migrate); + svm_migrate_copy_done(adev, mfence); + migrate_vma_finalize(&migrate); svm_range_dma_unmap(adev->dev, scratch, 0, npages); svm_range_free_dma_mappings(prange); @@ -433,12 +437,13 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, out_free: kvfree(buf); out: - if (!r) { + if (!r && migrate.cpages) { pdd = svm_range_get_pdd_by_adev(prange, adev); if (pdd) WRITE_ONCE(pdd->page_in, pdd->page_in + migrate.cpages); - } + return migrate.cpages; + } return r; } @@ -460,7 +465,8 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, unsigned long addr, start, end; struct vm_area_struct *vma; struct amdgpu_device *adev; - int r = 0; + unsigned long cpages = 0; + long r = 0; if (prange->actual_loc == best_loc) { pr_debug("svms 0x%p [0x%lx 0x%lx] already on best_loc 0x%x\n", @@ -492,17 +498,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, next = min(vma->vm_end, end); r = svm_migrate_vma_to_vram(adev, prange, vma, addr, next); - if (r) { - pr_debug("failed to migrate\n"); + if (r < 0) { + pr_debug("failed %ld to migrate\n", r); break; + } else { + cpages += r; } addr = next; } - if (!r) + if (cpages) prange->actual_loc = best_loc; - return r; + return r < 0 ? r : 0; } static void svm_migrate_page_free(struct page *page) @@ -603,7 +611,7 @@ out_oom: return r; } -static int +static long svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, struct vm_area_struct *vma, uint64_t start, uint64_t end) { @@ -640,29 +648,35 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, goto out_free; } - pr_debug("cpages %ld\n", migrate.cpages); + if (migrate.cpages != npages) + pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + migrate.cpages, npages); + else + pr_debug("0x%lx pages migrated\n", migrate.cpages); - if (migrate.cpages) { - r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, - scratch, npages); - migrate_vma_pages(&migrate); - svm_migrate_copy_done(adev, mfence); - migrate_vma_finalize(&migrate); - } else { + if (!migrate.cpages) { pr_debug("failed collect migrate device pages [0x%lx 0x%lx]\n", prange->start, prange->last); + goto out_free; } + r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, + scratch, npages); + migrate_vma_pages(&migrate); + svm_migrate_copy_done(adev, mfence); + migrate_vma_finalize(&migrate); svm_range_dma_unmap(adev->dev, scratch, 0, npages); out_free: kvfree(buf); out: - if (!r) { + if (!r && migrate.cpages) { pdd = svm_range_get_pdd_by_adev(prange, adev); if (pdd) WRITE_ONCE(pdd->page_out, pdd->page_out + migrate.cpages); + + return migrate.cpages; } return r; } @@ -684,7 +698,8 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm) unsigned long addr; unsigned long start; unsigned long end; - int r = 0; + unsigned long cpages = 0; + long r = 0; if (!prange->actual_loc) { pr_debug("[0x%lx 0x%lx] already migrated to ram\n", @@ -715,18 +730,21 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm) next = min(vma->vm_end, end); r = svm_migrate_vma_to_ram(adev, prange, vma, addr, next); - if (r) { - pr_debug("failed %d to migrate\n", r); + if (r < 0) { + pr_debug("failed %ld to migrate\n", r); break; + } else { + cpages += r; } addr = next; } - if (!r) { + if (cpages) { svm_range_vram_node_free(prange); prange->actual_loc = 0; } - return r; + + return r < 0 ? r : 0; } /** From afd18180c07026f94a80ff024acef5f4159084a4 Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 11 Oct 2021 20:37:01 +0800 Subject: [PATCH 315/554] drm/amdkfd: fix boot failure when iommu is disabled in Picasso. When IOMMU disabled in sbios and kfd in iommuv2 path, iommuv2 init will fail. But this failure should not block amdgpu driver init. Reported-by: youling Tested-by: youling Signed-off-by: Yifan Zhang Reviewed-by: James Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ---- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 239e71174855..7798276c8c49 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2398,10 +2398,6 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) if (!adev->gmc.xgmi.pending_reset) amdgpu_amdkfd_device_init(adev); - r = amdgpu_amdkfd_resume_iommu(adev); - if (r) - goto init_failed; - amdgpu_fru_get_product_info(adev); init_failed: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 064d42acd54e..08eedbc6699d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -1029,6 +1029,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, svm_migrate_init((struct amdgpu_device *)kfd->kgd); + if(kgd2kfd_resume_iommu(kfd)) + goto device_iommu_error; + if (kfd_resume(kfd)) goto kfd_resume_error; From 6f4b590aae217da16cfa44039a2abcfb209137ab Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 11 Oct 2021 20:42:31 +0800 Subject: [PATCH 316/554] drm/amdkfd: fix resume error when iommu disabled in Picasso When IOMMU disabled in sbios and kfd in iommuv2 path, IOMMU resume failure blocks system resume. Don't allow kfd to use iommu v2 when iommu is disabled. Reported-by: youling Tested-by: youling Signed-off-by: Yifan Zhang Reviewed-by: James Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 08eedbc6699d..99d2b9c875ea 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -1021,6 +1021,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd_double_confirm_iommu_support(kfd); if (kfd_iommu_device_init(kfd)) { + kfd->use_iommu_v2 = false; dev_err(kfd_device, "Error initializing iommuv2\n"); goto device_iommu_error; } From 972d321e871dbaf6cd0c851881b83d82a12354c9 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 8 Oct 2021 17:21:22 -0400 Subject: [PATCH 317/554] MAINTAINERS: Add Siqueira for AMD DC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit He's been helping maintain it for quite a while now. Make it official. Signed-off-by: Harry Wentland Acked-by: Christian König Acked-by: Alex Deucher Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fbfeca76f2af..a6c10e50605e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -902,6 +902,7 @@ F: include/uapi/linux/psp-sev.h AMD DISPLAY CORE M: Harry Wentland M: Leo Li +M: Rodrigo Siqueira L: amd-gfx@lists.freedesktop.org S: Supported T: git https://gitlab.freedesktop.org/agd5f/linux.git From 76c023fac32a191c51b16d811b1a311a827691f6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Oct 2021 11:21:24 -0400 Subject: [PATCH 318/554] drm/amdgpu/smu11: fix firmware version check for vangogh Was missed in the conversion to IP version checking. Fixes: af3b89d3a639d5 ("drm/amdgpu/smu11.0: convert to IP version checking") Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index aa4d34f35c33..5c1703cc25fd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -255,7 +255,7 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) case IP_VERSION(11, 0, 11): smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; break; - case CHIP_VANGOGH: + case IP_VERSION(11, 5, 0): smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_VANGOGH; break; case IP_VERSION(11, 0, 12): From f23750b5b3d98653b31d4469592935ef6364ad67 Mon Sep 17 00:00:00 2001 From: Thelford Williams Date: Wed, 13 Oct 2021 16:04:13 -0400 Subject: [PATCH 319/554] drm/amdgpu: fix out of bounds write Size can be any value and is user controlled resulting in overwriting the 40 byte array wr_buf with an arbitrary length of data from buf. Signed-off-by: Thelford Williams Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 814f67d86a3c..9b3ad56607bb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -264,7 +264,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { From 43fc10c1875fe6a5035fd4e0379f863c381347c9 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Mon, 11 Oct 2021 23:12:25 -0400 Subject: [PATCH 320/554] drm/amdkfd: unregistered svm range not overlap with TTM range When creating unregistered new svm range to recover retry fault, avoid new svm range to overlap with ranges or userptr ranges managed by TTM, otherwise svm migration will trigger TTM or userptr eviction, to evict user queues unexpectedly. Change helper amdgpu_ttm_tt_affect_userptr to return userptr which is inside the range. Add helper svm_range_check_vm_userptr to scan all userptr of the vm, and return overlap userptr bo start, last. Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 4 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 97 +++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 19d4d8b54490..590537b62a0a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1235,7 +1235,7 @@ struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm) * */ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, - unsigned long end) + unsigned long end, unsigned long *userptr) { struct amdgpu_ttm_tt *gtt = (void *)ttm; unsigned long size; @@ -1250,6 +1250,8 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, if (gtt->userptr > end || gtt->userptr + size <= start) return false; + if (userptr) + *userptr = gtt->userptr; return true; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 639c7b41e30b..7346ecff4438 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -182,7 +182,7 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm); bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, - unsigned long end); + unsigned long end, unsigned long *userptr); bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm, int *last_invalidated); bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 49c92713c2ad..b691c8495d66 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -50,7 +50,9 @@ static bool svm_range_cpu_invalidate_pagetables(struct mmu_interval_notifier *mni, const struct mmu_notifier_range *range, unsigned long cur_seq); - +static int +svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last, + uint64_t *bo_s, uint64_t *bo_l); static const struct mmu_interval_notifier_ops svm_range_mn_ops = { .invalidate = svm_range_cpu_invalidate_pagetables, }; @@ -2308,6 +2310,7 @@ svm_range_best_restore_location(struct svm_range *prange, return -1; } + static int svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, unsigned long *start, unsigned long *last) @@ -2355,8 +2358,59 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, vma->vm_end >> PAGE_SHIFT, *last); return 0; - } + +static int +svm_range_check_vm_userptr(struct kfd_process *p, uint64_t start, uint64_t last, + uint64_t *bo_s, uint64_t *bo_l) +{ + struct amdgpu_bo_va_mapping *mapping; + struct interval_tree_node *node; + struct amdgpu_bo *bo = NULL; + unsigned long userptr; + uint32_t i; + int r; + + for (i = 0; i < p->n_pdds; i++) { + struct amdgpu_vm *vm; + + if (!p->pdds[i]->drm_priv) + continue; + + vm = drm_priv_to_vm(p->pdds[i]->drm_priv); + r = amdgpu_bo_reserve(vm->root.bo, false); + if (r) + return r; + + /* Check userptr by searching entire vm->va interval tree */ + node = interval_tree_iter_first(&vm->va, 0, ~0ULL); + while (node) { + mapping = container_of((struct rb_node *)node, + struct amdgpu_bo_va_mapping, rb); + bo = mapping->bo_va->base.bo; + + if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, + start << PAGE_SHIFT, + last << PAGE_SHIFT, + &userptr)) { + node = interval_tree_iter_next(node, 0, ~0ULL); + continue; + } + + pr_debug("[0x%llx 0x%llx] already userptr mapped\n", + start, last); + if (bo_s && bo_l) { + *bo_s = userptr >> PAGE_SHIFT; + *bo_l = *bo_s + bo->tbo.ttm->num_pages - 1; + } + amdgpu_bo_unreserve(vm->root.bo); + return -EADDRINUSE; + } + amdgpu_bo_unreserve(vm->root.bo); + } + return 0; +} + static struct svm_range *svm_range_create_unregistered_range(struct amdgpu_device *adev, struct kfd_process *p, @@ -2366,10 +2420,26 @@ svm_range *svm_range_create_unregistered_range(struct amdgpu_device *adev, struct svm_range *prange = NULL; unsigned long start, last; uint32_t gpuid, gpuidx; + uint64_t bo_s = 0; + uint64_t bo_l = 0; + int r; if (svm_range_get_range_boundaries(p, addr, &start, &last)) return NULL; + r = svm_range_check_vm(p, start, last, &bo_s, &bo_l); + if (r != -EADDRINUSE) + r = svm_range_check_vm_userptr(p, start, last, &bo_s, &bo_l); + + if (r == -EADDRINUSE) { + if (addr >= bo_s && addr <= bo_l) + return NULL; + + /* Create one page svm range if 2MB range overlapping */ + start = addr; + last = addr; + } + prange = svm_range_new(&p->svms, start, last); if (!prange) { pr_debug("Failed to create prange in address [0x%llx]\n", addr); @@ -2672,6 +2742,8 @@ int svm_range_list_init(struct kfd_process *p) * @p: current kfd_process * @start: range start address, in pages * @last: range last address, in pages + * @bo_s: mapping start address in pages if address range already mapped + * @bo_l: mapping last address in pages if address range already mapped * * The purpose is to avoid virtual address ranges already allocated by * kfd_ioctl_alloc_memory_of_gpu ioctl. @@ -2686,8 +2758,11 @@ int svm_range_list_init(struct kfd_process *p) * a signal. Release all buffer reservations and return to user-space. */ static int -svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last) +svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last, + uint64_t *bo_s, uint64_t *bo_l) { + struct amdgpu_bo_va_mapping *mapping; + struct interval_tree_node *node; uint32_t i; int r; @@ -2701,8 +2776,17 @@ svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last) r = amdgpu_bo_reserve(vm->root.bo, false); if (r) return r; - if (interval_tree_iter_first(&vm->va, start, last)) { - pr_debug("Range [0x%llx 0x%llx] already mapped\n", start, last); + + node = interval_tree_iter_first(&vm->va, start, last); + if (node) { + pr_debug("range [0x%llx 0x%llx] already TTM mapped\n", + start, last); + mapping = container_of((struct rb_node *)node, + struct amdgpu_bo_va_mapping, rb); + if (bo_s && bo_l) { + *bo_s = mapping->start; + *bo_l = mapping->last; + } amdgpu_bo_unreserve(vm->root.bo); return -EADDRINUSE; } @@ -2743,7 +2827,8 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size) start = min(end, vma->vm_end); } while (start < end); - return svm_range_check_vm(p, start_unchg, (end - 1) >> PAGE_SHIFT); + return svm_range_check_vm(p, start_unchg, (end - 1) >> PAGE_SHIFT, NULL, + NULL); } /** From 29e41c919760954d92a5561aadc697848bb090ce Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Oct 2021 11:32:49 -0400 Subject: [PATCH 321/554] drm/amdgpu/swsmu: fix is_support_sw_smu() for VEGA20 VEGA20 is 11.0.2, but it's handled by powerplay, not swsmu. Fixes: a8967967f6a554 ("drm/amdgpu/amdgpu_smu: convert to IP version checking") Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 160efc0a3893..b06c59dcc1b4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -455,6 +455,10 @@ static int smu_get_power_num_states(void *handle, bool is_support_sw_smu(struct amdgpu_device *adev) { + /* vega20 is 11.0.2, but it's supported via the powerplay code */ + if (adev->asic_type == CHIP_VEGA20) + return false; + if (adev->ip_versions[MP1_HWIP][0] >= IP_VERSION(11, 0, 0)) return true; From 48737ac4d70faffeb516e2a9847e24f9a7eee05f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Oct 2021 11:47:56 -0400 Subject: [PATCH 322/554] drm/amdgpu/psp: add some missing cases to psp_check_pmfw_centralized_cstate_management Missed a few asics. v2: update comment Fixes: 82d05736c47b19 ("drm/amdgpu/amdgpu_psp: convert to IP version checking") Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 6b39e6c02dd8..2bfe0682e0e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -65,7 +65,6 @@ static int psp_securedisplay_terminate(struct psp_context *psp); * * This new sequence is required for * - Arcturus and onwards - * - Navi12 and onwards */ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp) { @@ -77,7 +76,9 @@ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp } switch (adev->ip_versions[MP0_HWIP][0]) { + case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 4): + case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 9): case IP_VERSION(11, 0, 11): From 1eecf31e3c962aabc1e9c5a469cfa2d161e5254d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 13 Oct 2021 13:11:59 +0300 Subject: [PATCH 323/554] drm/i915: split out vlv sideband to a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VLV/CHV sideband code is pretty distinct from the rest of the sideband code. Split it out to new vlv_sideband.[ch]. Pure code movement with relevant #include changes, and a tiny checkpatch fix on top. Cc: Lucas De Marchi Cc: Ville Syrjälä Reviewed-by: Hans de Goede Acked-by: Lucas De Marchi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/755ebbbaf01fc6d306b763b6ef60f45e671ba290.1634119597.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/g4x_dp.c | 2 +- drivers/gpu/drm/i915/display/g4x_hdmi.c | 2 +- drivers/gpu/drm/i915/display/intel_cdclk.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 1 + .../drm/i915/display/intel_display_debugfs.c | 1 - .../drm/i915/display/intel_display_power.c | 4 +- drivers/gpu/drm/i915/display/intel_dp.c | 1 - drivers/gpu/drm/i915/display/intel_dpio_phy.c | 5 +- drivers/gpu/drm/i915/display/intel_dpll.c | 2 +- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 2 +- drivers/gpu/drm/i915/display/vlv_dsi.c | 2 +- drivers/gpu/drm/i915/display/vlv_dsi_pll.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 1 + drivers/gpu/drm/i915/gt/intel_rps.c | 1 + drivers/gpu/drm/i915/i915_debugfs.c | 1 - drivers/gpu/drm/i915/i915_sysfs.c | 1 - drivers/gpu/drm/i915/intel_pm.c | 1 + drivers/gpu/drm/i915/intel_sideband.c | 257 ----------------- drivers/gpu/drm/i915/intel_sideband.h | 110 -------- drivers/gpu/drm/i915/vlv_sideband.c | 266 ++++++++++++++++++ drivers/gpu/drm/i915/vlv_sideband.h | 123 ++++++++ 22 files changed, 405 insertions(+), 382 deletions(-) create mode 100644 drivers/gpu/drm/i915/vlv_sideband.c create mode 100644 drivers/gpu/drm/i915/vlv_sideband.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 21b05ed0e4e8..d50d2b144fc6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -54,6 +54,7 @@ i915-y += i915_drv.o \ intel_step.o \ intel_uncore.o \ intel_wakeref.o \ + vlv_sideband.o \ vlv_suspend.o # core library code diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 85a09c3e09e8..dc41868d01ef 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -18,7 +18,7 @@ #include "intel_hdmi.h" #include "intel_hotplug.h" #include "intel_pps.h" -#include "intel_sideband.h" +#include "vlv_sideband.h" struct dp_link_dpll { int clock; diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index be352e9f0afc..88c427f3c346 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -14,8 +14,8 @@ #include "intel_fifo_underrun.h" #include "intel_hdmi.h" #include "intel_hotplug.h" -#include "intel_sideband.h" #include "intel_sdvo.h" +#include "vlv_sideband.h" static void intel_hdmi_prepare(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index ecb28e8f1eb6..44bb18773509 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -30,6 +30,7 @@ #include "intel_display_types.h" #include "intel_psr.h" #include "intel_sideband.h" +#include "vlv_sideband.h" /** * DOC: CDCLK / RAWCLK diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9cf987ee143d..3602fdb2a549 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -109,6 +109,7 @@ #include "i9xx_plane.h" #include "skl_scaler.h" #include "skl_universal_plane.h" +#include "vlv_sideband.h" static void i9xx_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index bc5113589f0a..e04767695530 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -20,7 +20,6 @@ #include "intel_hdmi.h" #include "intel_pm.h" #include "intel_psr.h" -#include "intel_sideband.h" #include "intel_sprite.h" static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 06e9879aedd7..709569211c85 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -3,12 +3,11 @@ * Copyright © 2019 Intel Corporation */ -#include "display/intel_crt.h" - #include "i915_drv.h" #include "i915_irq.h" #include "intel_cdclk.h" #include "intel_combo_phy.h" +#include "intel_crt.h" #include "intel_de.h" #include "intel_display_power.h" #include "intel_display_types.h" @@ -22,6 +21,7 @@ #include "intel_snps_phy.h" #include "intel_tc.h" #include "intel_vga.h" +#include "vlv_sideband.h" bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, enum i915_power_well_id power_well_id); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 10fda20a5bd8..9d8132dd4cc5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -66,7 +66,6 @@ #include "intel_panel.h" #include "intel_pps.h" #include "intel_psr.h" -#include "intel_sideband.h" #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vrr.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 5a2eccb12fe4..44edeb2e55c0 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -21,14 +21,13 @@ * DEALINGS IN THE SOFTWARE. */ -#include "display/intel_dp.h" - #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_dpio_phy.h" -#include "intel_sideband.h" +#include "vlv_sideband.h" /** * DOC: DPIO diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index b84ed4a1bd95..04a7af8340ca 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -13,8 +13,8 @@ #include "intel_lvds.h" #include "intel_panel.h" #include "intel_pps.h" -#include "intel_sideband.h" #include "intel_snps_phy.h" +#include "vlv_sideband.h" struct intel_limit { struct { diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 61c2ef6a4b8c..f241bedb8597 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -41,7 +41,7 @@ #include "i915_drv.h" #include "intel_display_types.h" #include "intel_dsi.h" -#include "intel_sideband.h" +#include "vlv_sideband.h" #define MIPI_TRANSFER_MODE_SHIFT 0 #define MIPI_VIRTUAL_CHANNEL_SHIFT 1 diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 081b772bfe10..07584695514b 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -40,8 +40,8 @@ #include "intel_dsi.h" #include "intel_fifo_underrun.h" #include "intel_panel.h" -#include "intel_sideband.h" #include "skl_scaler.h" +#include "vlv_sideband.h" /* return pixels in terms of txbyteclkhs */ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index 0078973cd219..5413b52ab6ba 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -31,7 +31,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" -#include "intel_sideband.h" +#include "vlv_sideband.h" static const u16 lfsr_converts[] = { 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 62 - 70 */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 5f84ad602642..1e00fa6fbf27 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -18,6 +18,7 @@ #include "intel_runtime_pm.h" #include "intel_sideband.h" #include "intel_uncore.h" +#include "vlv_sideband.h" static int fw_domains_show(struct seq_file *m, void *data) { diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 172de6c9f949..c47024dbe246 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -13,6 +13,7 @@ #include "intel_gt_pm_irq.h" #include "intel_rps.h" #include "intel_sideband.h" +#include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" #define BUSY_MAX_EI 20u /* ms */ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index fdbd46ff59e0..54ae75db121f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -49,7 +49,6 @@ #include "i915_scheduler.h" #include "i915_trace.h" #include "intel_pm.h" -#include "intel_sideband.h" static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node) { diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index cdf0e9c6fd73..1804f4142740 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -37,7 +37,6 @@ #include "i915_drv.h" #include "i915_sysfs.h" #include "intel_pm.h" -#include "intel_sideband.h" static inline struct drm_i915_private *kdev_minor_to_i915(struct device *kdev) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 73178d0cf0c9..c7831bb76862 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -49,6 +49,7 @@ #include "i915_trace.h" #include "intel_pm.h" #include "intel_sideband.h" +#include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" /* Stores plane specific WM parameters */ diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index e304bf44e1ff..59ef67216c15 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -27,263 +27,6 @@ #include "i915_drv.h" #include "intel_sideband.h" -/* - * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and - * VLV_VLV2_PUNIT_HAS_0.8.docx - */ - -/* Standard MMIO read, non-posted */ -#define SB_MRD_NP 0x00 -/* Standard MMIO write, non-posted */ -#define SB_MWR_NP 0x01 -/* Private register read, double-word addressing, non-posted */ -#define SB_CRRDDA_NP 0x06 -/* Private register write, double-word addressing, non-posted */ -#define SB_CRWRDA_NP 0x07 - -static void ping(void *info) -{ -} - -static void __vlv_punit_get(struct drm_i915_private *i915) -{ - iosf_mbi_punit_acquire(); - - /* - * Prevent the cpu from sleeping while we use this sideband, otherwise - * the punit may cause a machine hang. The issue appears to be isolated - * with changing the power state of the CPU package while changing - * the power state via the punit, and we have only observed it - * reliably on 4-core Baytail systems suggesting the issue is in the - * power delivery mechanism and likely to be be board/function - * specific. Hence we presume the workaround needs only be applied - * to the Valleyview P-unit and not all sideband communications. - */ - if (IS_VALLEYVIEW(i915)) { - cpu_latency_qos_update_request(&i915->sb_qos, 0); - on_each_cpu(ping, NULL, 1); - } -} - -static void __vlv_punit_put(struct drm_i915_private *i915) -{ - if (IS_VALLEYVIEW(i915)) - cpu_latency_qos_update_request(&i915->sb_qos, - PM_QOS_DEFAULT_VALUE); - - iosf_mbi_punit_release(); -} - -void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports) -{ - if (ports & BIT(VLV_IOSF_SB_PUNIT)) - __vlv_punit_get(i915); - - mutex_lock(&i915->sb_lock); -} - -void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports) -{ - mutex_unlock(&i915->sb_lock); - - if (ports & BIT(VLV_IOSF_SB_PUNIT)) - __vlv_punit_put(i915); -} - -static int vlv_sideband_rw(struct drm_i915_private *i915, - u32 devfn, u32 port, u32 opcode, - u32 addr, u32 *val) -{ - struct intel_uncore *uncore = &i915->uncore; - const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP); - int err; - - lockdep_assert_held(&i915->sb_lock); - if (port == IOSF_PORT_PUNIT) - iosf_mbi_assert_punit_acquired(); - - /* Flush the previous comms, just in case it failed last time. */ - if (intel_wait_for_register(uncore, - VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, - 5)) { - drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n", - is_read ? "read" : "write"); - return -EAGAIN; - } - - preempt_disable(); - - intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr); - intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val); - intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ, - (devfn << IOSF_DEVFN_SHIFT) | - (opcode << IOSF_OPCODE_SHIFT) | - (port << IOSF_PORT_SHIFT) | - (0xf << IOSF_BYTE_ENABLES_SHIFT) | - (0 << IOSF_BAR_SHIFT) | - IOSF_SB_BUSY); - - if (__intel_wait_for_register_fw(uncore, - VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, - 10000, 0, NULL) == 0) { - if (is_read) - *val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA); - err = 0; - } else { - drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n", - is_read ? "read" : "write"); - err = -ETIMEDOUT; - } - - preempt_enable(); - - return err; -} - -u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, - SB_CRRDDA_NP, addr, &val); - - return val; -} - -int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val) -{ - return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, - SB_CRWRDA_NP, addr, &val); -} - -u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, - SB_CRWRDA_NP, reg, &val); -} - -u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC, - SB_CRRDDA_NP, addr, &val); - - return val; -} - -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRWRDA_NP, reg, &val); -} - -u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, - SB_CRWRDA_NP, reg, &val); -} - -u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, - SB_CRWRDA_NP, reg, &val); -} - -static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy) -{ - /* - * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D) - * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C) - */ - if (IS_CHERRYVIEW(i915)) - return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO; - else - return IOSF_PORT_DPIO; -} - -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) -{ - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); - u32 val = 0; - - vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); - - /* - * FIXME: There might be some registers where all 1's is a valid value, - * so ideally we should check the register offset instead... - */ - drm_WARN(&i915->drm, val == 0xffffffff, - "DPIO read pipe %c reg 0x%x == 0x%x\n", - pipe_name(pipe), reg, val); - - return val; -} - -void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val) -{ - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); - - vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); -} - -u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP, - reg, &val); - return val; -} - -void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP, - reg, &val); -} - /* SBI access */ static int intel_sbi_rw(struct drm_i915_private *i915, u16 reg, enum intel_sbi_destination destination, diff --git a/drivers/gpu/drm/i915/intel_sideband.h b/drivers/gpu/drm/i915/intel_sideband.h index d1d14bcb8f56..914ffd98b38f 100644 --- a/drivers/gpu/drm/i915/intel_sideband.h +++ b/drivers/gpu/drm/i915/intel_sideband.h @@ -3,125 +3,15 @@ #ifndef _INTEL_SIDEBAND_H_ #define _INTEL_SIDEBAND_H_ -#include #include struct drm_i915_private; -enum pipe; enum intel_sbi_destination { SBI_ICLK, SBI_MPHY, }; -enum { - VLV_IOSF_SB_BUNIT, - VLV_IOSF_SB_CCK, - VLV_IOSF_SB_CCU, - VLV_IOSF_SB_DPIO, - VLV_IOSF_SB_FLISDSI, - VLV_IOSF_SB_GPIO, - VLV_IOSF_SB_NC, - VLV_IOSF_SB_PUNIT, -}; - -void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports); -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg); -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val); -void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports); - -static inline void vlv_bunit_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_BUNIT)); -} - -u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg); -void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val); - -static inline void vlv_bunit_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_BUNIT)); -} - -static inline void vlv_cck_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_CCK)); -} - -u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg); -void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val); - -static inline void vlv_cck_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_CCK)); -} - -static inline void vlv_ccu_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_CCU)); -} - -u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg); -void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val); - -static inline void vlv_ccu_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_CCU)); -} - -static inline void vlv_dpio_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_DPIO)); -} - -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg); -void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val); - -static inline void vlv_dpio_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_DPIO)); -} - -static inline void vlv_flisdsi_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_FLISDSI)); -} - -u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg); -void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val); - -static inline void vlv_flisdsi_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_FLISDSI)); -} - -static inline void vlv_nc_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_NC)); -} - -u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr); - -static inline void vlv_nc_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_NC)); -} - -static inline void vlv_punit_get(struct drm_i915_private *i915) -{ - vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_PUNIT)); -} - -u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr); -int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val); - -static inline void vlv_punit_put(struct drm_i915_private *i915) -{ - vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_PUNIT)); -} - u32 intel_sbi_read(struct drm_i915_private *i915, u16 reg, enum intel_sbi_destination destination); void intel_sbi_write(struct drm_i915_private *i915, u16 reg, u32 value, diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c new file mode 100644 index 000000000000..35380738a951 --- /dev/null +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013-2021 Intel Corporation + */ + +#include + +#include "i915_drv.h" +#include "vlv_sideband.h" + +/* + * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and + * VLV_VLV2_PUNIT_HAS_0.8.docx + */ + +/* Standard MMIO read, non-posted */ +#define SB_MRD_NP 0x00 +/* Standard MMIO write, non-posted */ +#define SB_MWR_NP 0x01 +/* Private register read, double-word addressing, non-posted */ +#define SB_CRRDDA_NP 0x06 +/* Private register write, double-word addressing, non-posted */ +#define SB_CRWRDA_NP 0x07 + +static void ping(void *info) +{ +} + +static void __vlv_punit_get(struct drm_i915_private *i915) +{ + iosf_mbi_punit_acquire(); + + /* + * Prevent the cpu from sleeping while we use this sideband, otherwise + * the punit may cause a machine hang. The issue appears to be isolated + * with changing the power state of the CPU package while changing + * the power state via the punit, and we have only observed it + * reliably on 4-core Baytail systems suggesting the issue is in the + * power delivery mechanism and likely to be board/function + * specific. Hence we presume the workaround needs only be applied + * to the Valleyview P-unit and not all sideband communications. + */ + if (IS_VALLEYVIEW(i915)) { + cpu_latency_qos_update_request(&i915->sb_qos, 0); + on_each_cpu(ping, NULL, 1); + } +} + +static void __vlv_punit_put(struct drm_i915_private *i915) +{ + if (IS_VALLEYVIEW(i915)) + cpu_latency_qos_update_request(&i915->sb_qos, + PM_QOS_DEFAULT_VALUE); + + iosf_mbi_punit_release(); +} + +void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports) +{ + if (ports & BIT(VLV_IOSF_SB_PUNIT)) + __vlv_punit_get(i915); + + mutex_lock(&i915->sb_lock); +} + +void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports) +{ + mutex_unlock(&i915->sb_lock); + + if (ports & BIT(VLV_IOSF_SB_PUNIT)) + __vlv_punit_put(i915); +} + +static int vlv_sideband_rw(struct drm_i915_private *i915, + u32 devfn, u32 port, u32 opcode, + u32 addr, u32 *val) +{ + struct intel_uncore *uncore = &i915->uncore; + const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP); + int err; + + lockdep_assert_held(&i915->sb_lock); + if (port == IOSF_PORT_PUNIT) + iosf_mbi_assert_punit_acquired(); + + /* Flush the previous comms, just in case it failed last time. */ + if (intel_wait_for_register(uncore, + VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, + 5)) { + drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n", + is_read ? "read" : "write"); + return -EAGAIN; + } + + preempt_disable(); + + intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr); + intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val); + intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ, + (devfn << IOSF_DEVFN_SHIFT) | + (opcode << IOSF_OPCODE_SHIFT) | + (port << IOSF_PORT_SHIFT) | + (0xf << IOSF_BYTE_ENABLES_SHIFT) | + (0 << IOSF_BAR_SHIFT) | + IOSF_SB_BUSY); + + if (__intel_wait_for_register_fw(uncore, + VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, + 10000, 0, NULL) == 0) { + if (is_read) + *val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA); + err = 0; + } else { + drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n", + is_read ? "read" : "write"); + err = -ETIMEDOUT; + } + + preempt_enable(); + + return err; +} + +u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, + SB_CRRDDA_NP, addr, &val); + + return val; +} + +int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val) +{ + return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, + SB_CRWRDA_NP, addr, &val); +} + +u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, + SB_CRRDDA_NP, reg, &val); + + return val; +} + +void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val) +{ + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, + SB_CRWRDA_NP, reg, &val); +} + +u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC, + SB_CRRDDA_NP, addr, &val); + + return val; +} + +u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, + SB_CRRDDA_NP, reg, &val); + + return val; +} + +void vlv_iosf_sb_write(struct drm_i915_private *i915, + u8 port, u32 reg, u32 val) +{ + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, + SB_CRWRDA_NP, reg, &val); +} + +u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, + SB_CRRDDA_NP, reg, &val); + + return val; +} + +void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val) +{ + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, + SB_CRWRDA_NP, reg, &val); +} + +u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, + SB_CRRDDA_NP, reg, &val); + + return val; +} + +void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val) +{ + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, + SB_CRWRDA_NP, reg, &val); +} + +static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy) +{ + /* + * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D) + * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C) + */ + if (IS_CHERRYVIEW(i915)) + return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO; + else + return IOSF_PORT_DPIO; +} + +u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) +{ + u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + u32 val = 0; + + vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); + + /* + * FIXME: There might be some registers where all 1's is a valid value, + * so ideally we should check the register offset instead... + */ + drm_WARN(&i915->drm, val == 0xffffffff, + "DPIO read pipe %c reg 0x%x == 0x%x\n", + pipe_name(pipe), reg, val); + + return val; +} + +void vlv_dpio_write(struct drm_i915_private *i915, + enum pipe pipe, int reg, u32 val) +{ + u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + + vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); +} + +u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP, + reg, &val); + return val; +} + +void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val) +{ + vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP, + reg, &val); +} diff --git a/drivers/gpu/drm/i915/vlv_sideband.h b/drivers/gpu/drm/i915/vlv_sideband.h new file mode 100644 index 000000000000..d7732f612e7f --- /dev/null +++ b/drivers/gpu/drm/i915/vlv_sideband.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2013-2021 Intel Corporation + */ + +#ifndef _VLV_SIDEBAND_H_ +#define _VLV_SIDEBAND_H_ + +#include +#include + +enum pipe; +struct drm_i915_private; + +enum { + VLV_IOSF_SB_BUNIT, + VLV_IOSF_SB_CCK, + VLV_IOSF_SB_CCU, + VLV_IOSF_SB_DPIO, + VLV_IOSF_SB_FLISDSI, + VLV_IOSF_SB_GPIO, + VLV_IOSF_SB_NC, + VLV_IOSF_SB_PUNIT, +}; + +void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports); +u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg); +void vlv_iosf_sb_write(struct drm_i915_private *i915, + u8 port, u32 reg, u32 val); +void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports); + +static inline void vlv_bunit_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_BUNIT)); +} + +u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg); +void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val); + +static inline void vlv_bunit_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_BUNIT)); +} + +static inline void vlv_cck_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_CCK)); +} + +u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg); +void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val); + +static inline void vlv_cck_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_CCK)); +} + +static inline void vlv_ccu_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_CCU)); +} + +u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg); +void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val); + +static inline void vlv_ccu_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_CCU)); +} + +static inline void vlv_dpio_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_DPIO)); +} + +u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg); +void vlv_dpio_write(struct drm_i915_private *i915, + enum pipe pipe, int reg, u32 val); + +static inline void vlv_dpio_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_DPIO)); +} + +static inline void vlv_flisdsi_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_FLISDSI)); +} + +u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg); +void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val); + +static inline void vlv_flisdsi_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_FLISDSI)); +} + +static inline void vlv_nc_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_NC)); +} + +u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr); + +static inline void vlv_nc_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_NC)); +} + +static inline void vlv_punit_get(struct drm_i915_private *i915) +{ + vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_PUNIT)); +} + +u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr); +int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val); + +static inline void vlv_punit_put(struct drm_i915_private *i915) +{ + vlv_iosf_sb_put(i915, BIT(VLV_IOSF_SB_PUNIT)); +} + +#endif /* _VLV_SIDEBAND_H_ */ From 05734ca2a8f76c9eb3890b3c9dfc3467f03105c1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Oct 2021 20:56:36 +0300 Subject: [PATCH 324/554] drm/i915/bios: gracefully disable dual eDP for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the time being, neither the power sequencer nor the backlight code properly support two eDP panels simultaneously. While the software states will be independent, the same sets of registers will be used for both eDP panels, clobbering the hardware state and leading to errors. Gracefully disable dual eDP until proper support has been added. Cc: José Roberto de Souza Cc: Uma Shankar Cc: Ville Syrjälä Cc: Swati Sharma Reviewed-by: José Roberto de Souza Acked-by: Ville Syrjälä Tested-by: Swati Sharma Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20211005175636.24669-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index f9776ca85de3..b99907c656bb 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1930,6 +1930,50 @@ static int _intel_bios_max_tmds_clock(const struct intel_bios_encoder_data *devd } } +static enum port get_edp_port(struct drm_i915_private *i915) +{ + const struct intel_bios_encoder_data *devdata; + enum port port; + + for_each_port(port) { + devdata = i915->vbt.ports[port]; + + if (devdata && intel_bios_encoder_supports_edp(devdata)) + return port; + } + + return PORT_NONE; +} + +/* + * FIXME: The power sequencer and backlight code currently do not support more + * than one set registers, at least not on anything other than VLV/CHV. It will + * clobber the registers. As a temporary workaround, gracefully prevent more + * than one eDP from being registered. + */ +static void sanitize_dual_edp(struct intel_bios_encoder_data *devdata, + enum port port) +{ + struct drm_i915_private *i915 = devdata->i915; + struct child_device_config *child = &devdata->child; + enum port p; + + /* CHV might not clobber PPS registers. */ + if (IS_CHERRYVIEW(i915)) + return; + + p = get_edp_port(i915); + if (p == PORT_NONE) + return; + + drm_dbg_kms(&i915->drm, "both ports %c and %c configured as eDP, " + "disabling port %c eDP\n", port_name(p), port_name(port), + port_name(port)); + + child->device_type &= ~DEVICE_TYPE_DISPLAYPORT_OUTPUT; + child->device_type &= ~DEVICE_TYPE_INTERNAL_CONNECTOR; +} + static bool is_port_valid(struct drm_i915_private *i915, enum port port) { /* @@ -1987,6 +2031,9 @@ static void parse_ddi_port(struct drm_i915_private *i915, supports_typec_usb, supports_tbt, devdata->dsc != NULL); + if (is_edp) + sanitize_dual_edp(devdata, port); + if (is_dvi) sanitize_ddc_pin(devdata, port); From 4dd4375bc4ff217f0a4a931772400c987720fb65 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Oct 2021 13:28:57 +0300 Subject: [PATCH 325/554] drm/i915: split out intel_pcode.[ch] to separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snb+ pcode mailbox code is not sideband, so split it out to a separate file. As can be seen from the #include changes, very few places use both sideband and pcode. Code movement only. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Reviewed-by: Lucas De Marchi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/185deb18eb739e5ae019e27834b9997dcc1347bc.1634207064.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_bw.c | 2 +- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 3 +- .../drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/display/intel_hdcp.c | 6 +- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 2 +- drivers/gpu/drm/i915/gt/intel_llc.c | 2 +- drivers/gpu/drm/i915/gt/intel_rc6.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 2 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/intel_dram.c | 2 +- drivers/gpu/drm/i915/intel_pcode.c | 235 ++++++++++++++++++ drivers/gpu/drm/i915/intel_pcode.h | 26 ++ drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_sideband.c | 228 ----------------- drivers/gpu/drm/i915/intel_sideband.h | 13 - 17 files changed, 277 insertions(+), 255 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_pcode.c create mode 100644 drivers/gpu/drm/i915/intel_pcode.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d50d2b144fc6..e44c72533a8c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -47,6 +47,7 @@ i915-y += i915_drv.o \ intel_dram.o \ intel_memory_region.o \ intel_pch.o \ + intel_pcode.o \ intel_pm.o \ intel_region_ttm.o \ intel_runtime_pm.o \ diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 4b94256d7319..8d9d888e9316 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -9,8 +9,8 @@ #include "intel_bw.h" #include "intel_cdclk.h" #include "intel_display_types.h" +#include "intel_pcode.h" #include "intel_pm.h" -#include "intel_sideband.h" /* Parameters for Qclk Geyserville (QGV) */ struct intel_qgv_point { diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 44bb18773509..9e466d829019 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -28,8 +28,8 @@ #include "intel_cdclk.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_pcode.h" #include "intel_psr.h" -#include "intel_sideband.h" #include "vlv_sideband.h" /** diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3602fdb2a549..b070cdcb3674 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -88,14 +88,15 @@ #include "intel_dp_link_training.h" #include "intel_dpt.h" #include "intel_fbc.h" -#include "intel_fdi.h" #include "intel_fbdev.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_frontbuffer.h" #include "intel_hdcp.h" #include "intel_hotplug.h" #include "intel_overlay.h" #include "intel_panel.h" +#include "intel_pcode.h" #include "intel_pipe_crc.h" #include "intel_plane_initial.h" #include "intel_pm.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 709569211c85..1672604f9ef7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -15,9 +15,9 @@ #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_hotplug.h" +#include "intel_pcode.h" #include "intel_pm.h" #include "intel_pps.h" -#include "intel_sideband.h" #include "intel_snps_phy.h" #include "intel_tc.h" #include "intel_vga.h" diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 9b9fd9d13043..4509fe7438e8 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -17,12 +17,12 @@ #include "i915_drv.h" #include "i915_reg.h" -#include "intel_display_power.h" +#include "intel_connector.h" #include "intel_de.h" +#include "intel_display_power.h" #include "intel_display_types.h" #include "intel_hdcp.h" -#include "intel_sideband.h" -#include "intel_connector.h" +#include "intel_pcode.h" #define KEY_LOAD_TRIES 5 #define HDCP2_LC_RETRY_CNT 3 diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 1e00fa6fbf27..b3ddb9106125 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -13,10 +13,10 @@ #include "intel_gt_pm.h" #include "intel_gt_pm_debugfs.h" #include "intel_llc.h" +#include "intel_pcode.h" #include "intel_rc6.h" #include "intel_rps.h" #include "intel_runtime_pm.h" -#include "intel_sideband.h" #include "intel_uncore.h" #include "vlv_sideband.h" diff --git a/drivers/gpu/drm/i915/gt/intel_llc.c b/drivers/gpu/drm/i915/gt/intel_llc.c index eb1a15deed22..9ca88f8ac5dd 100644 --- a/drivers/gpu/drm/i915/gt/intel_llc.c +++ b/drivers/gpu/drm/i915/gt/intel_llc.c @@ -8,7 +8,7 @@ #include "i915_drv.h" #include "intel_gt.h" #include "intel_llc.h" -#include "intel_sideband.h" +#include "intel_pcode.h" struct ia_constants { unsigned int min_gpu_freq; diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 799d382eea79..43093dd2d0c9 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -9,8 +9,8 @@ #include "i915_vgpu.h" #include "intel_gt.h" #include "intel_gt_pm.h" +#include "intel_pcode.h" #include "intel_rc6.h" -#include "intel_sideband.h" /** * DOC: RC6 diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index c47024dbe246..5e275f8dda8c 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -11,8 +11,8 @@ #include "intel_gt_clock_utils.h" #include "intel_gt_irq.h" #include "intel_gt_pm_irq.h" +#include "intel_pcode.h" #include "intel_rps.h" -#include "intel_sideband.h" #include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c65c3742887a..b18a250e5d2e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -84,9 +84,9 @@ #include "intel_dram.h" #include "intel_gvt.h" #include "intel_memory_region.h" +#include "intel_pcode.h" #include "intel_pm.h" #include "intel_region_ttm.h" -#include "intel_sideband.h" #include "vlv_suspend.h" static const struct drm_driver driver; diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 30a0cab5eff4..da3ad59d2b88 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -5,7 +5,7 @@ #include "i915_drv.h" #include "intel_dram.h" -#include "intel_sideband.h" +#include "intel_pcode.h" struct dram_dimm_info { u16 size; diff --git a/drivers/gpu/drm/i915/intel_pcode.c b/drivers/gpu/drm/i915/intel_pcode.c new file mode 100644 index 000000000000..e8c886e4e78d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_pcode.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2013-2021 Intel Corporation + */ + +#include "i915_drv.h" +#include "intel_pcode.h" + +static int gen6_check_mailbox_status(u32 mbox) +{ + switch (mbox & GEN6_PCODE_ERROR_MASK) { + case GEN6_PCODE_SUCCESS: + return 0; + case GEN6_PCODE_UNIMPLEMENTED_CMD: + return -ENODEV; + case GEN6_PCODE_ILLEGAL_CMD: + return -ENXIO; + case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: + case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: + return -EOVERFLOW; + case GEN6_PCODE_TIMEOUT: + return -ETIMEDOUT; + default: + MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); + return 0; + } +} + +static int gen7_check_mailbox_status(u32 mbox) +{ + switch (mbox & GEN6_PCODE_ERROR_MASK) { + case GEN6_PCODE_SUCCESS: + return 0; + case GEN6_PCODE_ILLEGAL_CMD: + return -ENXIO; + case GEN7_PCODE_TIMEOUT: + return -ETIMEDOUT; + case GEN7_PCODE_ILLEGAL_DATA: + return -EINVAL; + case GEN11_PCODE_ILLEGAL_SUBCOMMAND: + return -ENXIO; + case GEN11_PCODE_LOCKED: + return -EBUSY; + case GEN11_PCODE_REJECTED: + return -EACCES; + case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: + return -EOVERFLOW; + default: + MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); + return 0; + } +} + +static int __sandybridge_pcode_rw(struct drm_i915_private *i915, + u32 mbox, u32 *val, u32 *val1, + int fast_timeout_us, + int slow_timeout_ms, + bool is_read) +{ + struct intel_uncore *uncore = &i915->uncore; + + lockdep_assert_held(&i915->sb_lock); + + /* + * GEN6_PCODE_* are outside of the forcewake domain, we can use + * intel_uncore_read/write_fw variants to reduce the amount of work + * required when reading/writing. + */ + + if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) + return -EAGAIN; + + intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val); + intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0); + intel_uncore_write_fw(uncore, + GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); + + if (__intel_wait_for_register_fw(uncore, + GEN6_PCODE_MAILBOX, + GEN6_PCODE_READY, 0, + fast_timeout_us, + slow_timeout_ms, + &mbox)) + return -ETIMEDOUT; + + if (is_read) + *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA); + if (is_read && val1) + *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1); + + if (GRAPHICS_VER(i915) > 6) + return gen7_check_mailbox_status(mbox); + else + return gen6_check_mailbox_status(mbox); +} + +int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox, + u32 *val, u32 *val1) +{ + int err; + + mutex_lock(&i915->sb_lock); + err = __sandybridge_pcode_rw(i915, mbox, val, val1, + 500, 20, + true); + mutex_unlock(&i915->sb_lock); + + if (err) { + drm_dbg(&i915->drm, + "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n", + mbox, __builtin_return_address(0), err); + } + + return err; +} + +int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, + u32 mbox, u32 val, + int fast_timeout_us, + int slow_timeout_ms) +{ + int err; + + mutex_lock(&i915->sb_lock); + err = __sandybridge_pcode_rw(i915, mbox, &val, NULL, + fast_timeout_us, slow_timeout_ms, + false); + mutex_unlock(&i915->sb_lock); + + if (err) { + drm_dbg(&i915->drm, + "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n", + val, mbox, __builtin_return_address(0), err); + } + + return err; +} + +static bool skl_pcode_try_request(struct drm_i915_private *i915, u32 mbox, + u32 request, u32 reply_mask, u32 reply, + u32 *status) +{ + *status = __sandybridge_pcode_rw(i915, mbox, &request, NULL, + 500, 0, + true); + + return *status || ((request & reply_mask) == reply); +} + +/** + * skl_pcode_request - send PCODE request until acknowledgment + * @i915: device private + * @mbox: PCODE mailbox ID the request is targeted for + * @request: request ID + * @reply_mask: mask used to check for request acknowledgment + * @reply: value used to check for request acknowledgment + * @timeout_base_ms: timeout for polling with preemption enabled + * + * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE + * reports an error or an overall timeout of @timeout_base_ms+50 ms expires. + * The request is acknowledged once the PCODE reply dword equals @reply after + * applying @reply_mask. Polling is first attempted with preemption enabled + * for @timeout_base_ms and if this times out for another 50 ms with + * preemption disabled. + * + * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some + * other error as reported by PCODE. + */ +int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms) +{ + u32 status; + int ret; + + mutex_lock(&i915->sb_lock); + +#define COND \ + skl_pcode_try_request(i915, mbox, request, reply_mask, reply, &status) + + /* + * Prime the PCODE by doing a request first. Normally it guarantees + * that a subsequent request, at most @timeout_base_ms later, succeeds. + * _wait_for() doesn't guarantee when its passed condition is evaluated + * first, so send the first request explicitly. + */ + if (COND) { + ret = 0; + goto out; + } + ret = _wait_for(COND, timeout_base_ms * 1000, 10, 10); + if (!ret) + goto out; + + /* + * The above can time out if the number of requests was low (2 in the + * worst case) _and_ PCODE was busy for some reason even after a + * (queued) request and @timeout_base_ms delay. As a workaround retry + * the poll with preemption disabled to maximize the number of + * requests. Increase the timeout from @timeout_base_ms to 50ms to + * account for interrupts that could reduce the number of these + * requests, and for any quirks of the PCODE firmware that delays + * the request completion. + */ + drm_dbg_kms(&i915->drm, + "PCODE timeout, retrying with preemption disabled\n"); + drm_WARN_ON_ONCE(&i915->drm, timeout_base_ms > 3); + preempt_disable(); + ret = wait_for_atomic(COND, 50); + preempt_enable(); + +out: + mutex_unlock(&i915->sb_lock); + return ret ? ret : status; +#undef COND +} + +int intel_pcode_init(struct drm_i915_private *i915) +{ + int ret = 0; + + if (!IS_DGFX(i915)) + return ret; + + ret = skl_pcode_request(i915, DG1_PCODE_STATUS, + DG1_UNCORE_GET_INIT_STATUS, + DG1_UNCORE_INIT_STATUS_COMPLETE, + DG1_UNCORE_INIT_STATUS_COMPLETE, 180000); + + drm_dbg(&i915->drm, "PCODE init status %d\n", ret); + + if (ret) + drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n"); + + return ret; +} diff --git a/drivers/gpu/drm/i915/intel_pcode.h b/drivers/gpu/drm/i915/intel_pcode.h new file mode 100644 index 000000000000..50806649d4b6 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_pcode.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2013-2021 Intel Corporation + */ + +#ifndef _INTEL_PCODE_H_ +#define _INTEL_PCODE_H_ + +#include + +struct drm_i915_private; + +int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox, + u32 *val, u32 *val1); +int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, u32 mbox, + u32 val, int fast_timeout_us, + int slow_timeout_ms); +#define sandybridge_pcode_write(i915, mbox, val) \ + sandybridge_pcode_write_timeout(i915, mbox, val, 500, 0) + +int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms); + +int intel_pcode_init(struct drm_i915_private *i915); + +#endif /* _INTEL_PCODE_H */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c7831bb76862..f90fe39cf8ca 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -47,8 +47,8 @@ #include "i915_fixed.h" #include "i915_irq.h" #include "i915_trace.h" +#include "intel_pcode.h" #include "intel_pm.h" -#include "intel_sideband.h" #include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 59ef67216c15..1d30273b35c1 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -90,231 +90,3 @@ void intel_sbi_write(struct drm_i915_private *i915, u16 reg, u32 value, { intel_sbi_rw(i915, reg, destination, &value, false); } - -static int gen6_check_mailbox_status(u32 mbox) -{ - switch (mbox & GEN6_PCODE_ERROR_MASK) { - case GEN6_PCODE_SUCCESS: - return 0; - case GEN6_PCODE_UNIMPLEMENTED_CMD: - return -ENODEV; - case GEN6_PCODE_ILLEGAL_CMD: - return -ENXIO; - case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: - case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: - return -EOVERFLOW; - case GEN6_PCODE_TIMEOUT: - return -ETIMEDOUT; - default: - MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); - return 0; - } -} - -static int gen7_check_mailbox_status(u32 mbox) -{ - switch (mbox & GEN6_PCODE_ERROR_MASK) { - case GEN6_PCODE_SUCCESS: - return 0; - case GEN6_PCODE_ILLEGAL_CMD: - return -ENXIO; - case GEN7_PCODE_TIMEOUT: - return -ETIMEDOUT; - case GEN7_PCODE_ILLEGAL_DATA: - return -EINVAL; - case GEN11_PCODE_ILLEGAL_SUBCOMMAND: - return -ENXIO; - case GEN11_PCODE_LOCKED: - return -EBUSY; - case GEN11_PCODE_REJECTED: - return -EACCES; - case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: - return -EOVERFLOW; - default: - MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); - return 0; - } -} - -static int __sandybridge_pcode_rw(struct drm_i915_private *i915, - u32 mbox, u32 *val, u32 *val1, - int fast_timeout_us, - int slow_timeout_ms, - bool is_read) -{ - struct intel_uncore *uncore = &i915->uncore; - - lockdep_assert_held(&i915->sb_lock); - - /* - * GEN6_PCODE_* are outside of the forcewake domain, we can use - * intel_uncore_read/write_fw variants to reduce the amount of work - * required when reading/writing. - */ - - if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) - return -EAGAIN; - - intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val); - intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0); - intel_uncore_write_fw(uncore, - GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); - - if (__intel_wait_for_register_fw(uncore, - GEN6_PCODE_MAILBOX, - GEN6_PCODE_READY, 0, - fast_timeout_us, - slow_timeout_ms, - &mbox)) - return -ETIMEDOUT; - - if (is_read) - *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA); - if (is_read && val1) - *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1); - - if (GRAPHICS_VER(i915) > 6) - return gen7_check_mailbox_status(mbox); - else - return gen6_check_mailbox_status(mbox); -} - -int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox, - u32 *val, u32 *val1) -{ - int err; - - mutex_lock(&i915->sb_lock); - err = __sandybridge_pcode_rw(i915, mbox, val, val1, - 500, 20, - true); - mutex_unlock(&i915->sb_lock); - - if (err) { - drm_dbg(&i915->drm, - "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n", - mbox, __builtin_return_address(0), err); - } - - return err; -} - -int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, - u32 mbox, u32 val, - int fast_timeout_us, - int slow_timeout_ms) -{ - int err; - - mutex_lock(&i915->sb_lock); - err = __sandybridge_pcode_rw(i915, mbox, &val, NULL, - fast_timeout_us, slow_timeout_ms, - false); - mutex_unlock(&i915->sb_lock); - - if (err) { - drm_dbg(&i915->drm, - "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n", - val, mbox, __builtin_return_address(0), err); - } - - return err; -} - -static bool skl_pcode_try_request(struct drm_i915_private *i915, u32 mbox, - u32 request, u32 reply_mask, u32 reply, - u32 *status) -{ - *status = __sandybridge_pcode_rw(i915, mbox, &request, NULL, - 500, 0, - true); - - return *status || ((request & reply_mask) == reply); -} - -/** - * skl_pcode_request - send PCODE request until acknowledgment - * @i915: device private - * @mbox: PCODE mailbox ID the request is targeted for - * @request: request ID - * @reply_mask: mask used to check for request acknowledgment - * @reply: value used to check for request acknowledgment - * @timeout_base_ms: timeout for polling with preemption enabled - * - * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE - * reports an error or an overall timeout of @timeout_base_ms+50 ms expires. - * The request is acknowledged once the PCODE reply dword equals @reply after - * applying @reply_mask. Polling is first attempted with preemption enabled - * for @timeout_base_ms and if this times out for another 50 ms with - * preemption disabled. - * - * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some - * other error as reported by PCODE. - */ -int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, - u32 reply_mask, u32 reply, int timeout_base_ms) -{ - u32 status; - int ret; - - mutex_lock(&i915->sb_lock); - -#define COND \ - skl_pcode_try_request(i915, mbox, request, reply_mask, reply, &status) - - /* - * Prime the PCODE by doing a request first. Normally it guarantees - * that a subsequent request, at most @timeout_base_ms later, succeeds. - * _wait_for() doesn't guarantee when its passed condition is evaluated - * first, so send the first request explicitly. - */ - if (COND) { - ret = 0; - goto out; - } - ret = _wait_for(COND, timeout_base_ms * 1000, 10, 10); - if (!ret) - goto out; - - /* - * The above can time out if the number of requests was low (2 in the - * worst case) _and_ PCODE was busy for some reason even after a - * (queued) request and @timeout_base_ms delay. As a workaround retry - * the poll with preemption disabled to maximize the number of - * requests. Increase the timeout from @timeout_base_ms to 50ms to - * account for interrupts that could reduce the number of these - * requests, and for any quirks of the PCODE firmware that delays - * the request completion. - */ - drm_dbg_kms(&i915->drm, - "PCODE timeout, retrying with preemption disabled\n"); - drm_WARN_ON_ONCE(&i915->drm, timeout_base_ms > 3); - preempt_disable(); - ret = wait_for_atomic(COND, 50); - preempt_enable(); - -out: - mutex_unlock(&i915->sb_lock); - return ret ? ret : status; -#undef COND -} - -int intel_pcode_init(struct drm_i915_private *i915) -{ - int ret = 0; - - if (!IS_DGFX(i915)) - return ret; - - ret = skl_pcode_request(i915, DG1_PCODE_STATUS, - DG1_UNCORE_GET_INIT_STATUS, - DG1_UNCORE_INIT_STATUS_COMPLETE, - DG1_UNCORE_INIT_STATUS_COMPLETE, 180000); - - drm_dbg(&i915->drm, "PCODE init status %d\n", ret); - - if (ret) - drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n"); - - return ret; -} diff --git a/drivers/gpu/drm/i915/intel_sideband.h b/drivers/gpu/drm/i915/intel_sideband.h index 914ffd98b38f..9d937576f507 100644 --- a/drivers/gpu/drm/i915/intel_sideband.h +++ b/drivers/gpu/drm/i915/intel_sideband.h @@ -17,17 +17,4 @@ u32 intel_sbi_read(struct drm_i915_private *i915, u16 reg, void intel_sbi_write(struct drm_i915_private *i915, u16 reg, u32 value, enum intel_sbi_destination destination); -int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox, - u32 *val, u32 *val1); -int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, u32 mbox, - u32 val, int fast_timeout_us, - int slow_timeout_ms); -#define sandybridge_pcode_write(i915, mbox, val) \ - sandybridge_pcode_write_timeout(i915, mbox, val, 500, 0) - -int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, - u32 reply_mask, u32 reply, int timeout_base_ms); - -int intel_pcode_init(struct drm_i915_private *i915); - #endif /* _INTEL_SIDEBAND_H */ From abffa715dab85ce2864e2c3b17cede78af1ef652 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Oct 2021 13:28:58 +0300 Subject: [PATCH 326/554] drm/i915: rename intel_sideband.[ch] to intel_sbi.[ch] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that intel_sideband.[ch] has been decluttered, it's pure lpt/wpt iosf sideband. Let's call it intel_sbi, following the function naming. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Reviewed-by: Lucas De Marchi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/183423ff23b2d259e4a197e74daf6bcd750bfe14.1634207064.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_fdi.c | 2 +- .../i915/{intel_sideband.c => intel_sbi.c} | 27 +++---------------- .../i915/{intel_sideband.h => intel_sbi.h} | 9 ++++--- 5 files changed, 13 insertions(+), 29 deletions(-) rename drivers/gpu/drm/i915/{intel_sideband.c => intel_sbi.c} (56%) rename drivers/gpu/drm/i915/{intel_sideband.h => intel_sbi.h} (75%) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e44c72533a8c..660bb03de6fc 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -51,7 +51,7 @@ i915-y += i915_drv.o \ intel_pm.o \ intel_region_ttm.o \ intel_runtime_pm.o \ - intel_sideband.o \ + intel_sbi.o \ intel_step.o \ intel_uncore.o \ intel_wakeref.o \ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b070cdcb3674..ff598b6cd953 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -103,7 +103,7 @@ #include "intel_pps.h" #include "intel_psr.h" #include "intel_quirks.h" -#include "intel_sideband.h" +#include "intel_sbi.h" #include "intel_sprite.h" #include "intel_tc.h" #include "intel_vga.h" diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 51d6f810e69b..dd2cf0c59921 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -8,7 +8,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_fdi.h" -#include "intel_sideband.h" +#include "intel_sbi.h" static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum pipe pipe, bool state) diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sbi.c similarity index 56% rename from drivers/gpu/drm/i915/intel_sideband.c rename to drivers/gpu/drm/i915/intel_sbi.c index 1d30273b35c1..5ba8490a31e6 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sbi.c @@ -1,31 +1,12 @@ +// SPDX-License-Identifier: MIT /* - * Copyright © 2013 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. + * Copyright © 2013-2021 Intel Corporation * + * LPT/WPT IOSF sideband. */ -#include - #include "i915_drv.h" -#include "intel_sideband.h" +#include "intel_sbi.h" /* SBI access */ static int intel_sbi_rw(struct drm_i915_private *i915, u16 reg, diff --git a/drivers/gpu/drm/i915/intel_sideband.h b/drivers/gpu/drm/i915/intel_sbi.h similarity index 75% rename from drivers/gpu/drm/i915/intel_sideband.h rename to drivers/gpu/drm/i915/intel_sbi.h index 9d937576f507..f5a862210454 100644 --- a/drivers/gpu/drm/i915/intel_sideband.h +++ b/drivers/gpu/drm/i915/intel_sbi.h @@ -1,7 +1,10 @@ /* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2013-2021 Intel Corporation + */ -#ifndef _INTEL_SIDEBAND_H_ -#define _INTEL_SIDEBAND_H_ +#ifndef _INTEL_SBI_H_ +#define _INTEL_SBI_H_ #include @@ -17,4 +20,4 @@ u32 intel_sbi_read(struct drm_i915_private *i915, u16 reg, void intel_sbi_write(struct drm_i915_private *i915, u16 reg, u32 value, enum intel_sbi_destination destination); -#endif /* _INTEL_SIDEBAND_H */ +#endif /* _INTEL_SBI_H_ */ From 247c8a73793bb825ef7d621d2c9a4f2296b1b731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:22 +0300 Subject: [PATCH 327/554] drm/i915: Remove pointless extra namespace from dkl/snps buf trans structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct itself already has sufficient namespace. No need to duplicate it in the members. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +++--- drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h | 12 ++++++------ drivers/gpu/drm/i915/display/intel_snps_phy.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 59428ce4f8c1..fb5bd1f970c6 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1285,9 +1285,9 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, dpcnt_mask = (DKL_TX_PRESHOOT_COEFF_MASK | DKL_TX_DE_EMPAHSIS_COEFF_MASK | DKL_TX_VSWING_CONTROL_MASK); - dpcnt_val = DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.dkl_vswing_control); - dpcnt_val |= DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.dkl_de_emphasis_control); - dpcnt_val |= DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.dkl_preshoot_control); + dpcnt_val = DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing); + dpcnt_val |= DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis); + dpcnt_val |= DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.preshoot); for (ln = 0; ln < 2; ln++) { intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h index 6cdb8e9073c7..82fdc5ecd9de 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -40,15 +40,15 @@ struct icl_mg_phy_ddi_buf_trans { }; struct tgl_dkl_phy_ddi_buf_trans { - u32 dkl_vswing_control; - u32 dkl_preshoot_control; - u32 dkl_de_emphasis_control; + u32 vswing; + u32 preshoot; + u32 de_emphasis; }; struct dg2_snps_phy_buf_trans { - u8 snps_vswing; - u8 snps_pre_cursor; - u8 snps_post_cursor; + u8 vswing; + u8 pre_cursor; + u8 post_cursor; }; union intel_ddi_buf_trans_entry { diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index b18f08c851dc..5e20f340730f 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -68,9 +68,9 @@ void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < 4; ln++) { u32 val = 0; - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, trans->entries[level].snps.snps_vswing); - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, trans->entries[level].snps.snps_pre_cursor); - val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, trans->entries[level].snps.snps_post_cursor); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, trans->entries[level].snps.vswing); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_PRE, trans->entries[level].snps.pre_cursor); + val |= REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, trans->entries[level].snps.post_cursor); intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy), val); } From c2fdf53e1670a81c3fb9769d63745328fc33c656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:23 +0300 Subject: [PATCH 328/554] drm/i915: Shrink {icl_mg,tgl_dkl}_phy_ddi_buf_trans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the values we have in {icl_mg,tgl_dkl}_phy_ddi_buf_trans fit into u8. Shrink the types accordingly. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h index 82fdc5ecd9de..2133984a572b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -34,15 +34,15 @@ struct icl_ddi_buf_trans { }; struct icl_mg_phy_ddi_buf_trans { - u32 cri_txdeemph_override_11_6; - u32 cri_txdeemph_override_5_0; - u32 cri_txdeemph_override_17_12; + u8 cri_txdeemph_override_11_6; + u8 cri_txdeemph_override_5_0; + u8 cri_txdeemph_override_17_12; }; struct tgl_dkl_phy_ddi_buf_trans { - u32 vswing; - u32 preshoot; - u32 de_emphasis; + u8 vswing; + u8 preshoot; + u8 de_emphasis; }; struct dg2_snps_phy_buf_trans { From a1f01768f60afbdd275107a59859330c22859452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:24 +0300 Subject: [PATCH 329/554] drm/i915: Use standard form terminating condition for lane for loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use <4 instead of <=3 as the terminating condition for the loops over the 4 lanes. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index fb5bd1f970c6..4b8cae12a382 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1067,7 +1067,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, /* Program PORT_TX_DW4 */ /* We cannot write to GRP. It would overwrite individual loadgen. */ - for (ln = 0; ln <= 3; ln++) { + for (ln = 0; ln < 4; ln++) { val = intel_de_read(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy)); val &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | CURSOR_COEFF_MASK); @@ -1114,7 +1114,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0) * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0) */ - for (ln = 0; ln <= 3; ln++) { + for (ln = 0; ln < 4; ln++) { val = intel_de_read(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy)); val &= ~LOADGEN_SELECT; From f0298326d6fb10eaba514e04b5d341a54d340c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:26 +0300 Subject: [PATCH 330/554] drm/i915: Remove dead DKL_TX_LOADGEN_SHARING_PMD_DISABLE stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DKL_TX_LOADGEN_SHARING_PMD_DISABLE doesn't even seem to exist, also the spec says to skip all loadgen stuff. The code was dead anyway since it wasn't actually writing the value anywhere. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 8 -------- drivers/gpu/drm/i915/i915_reg.h | 1 - 2 files changed, 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 4b8cae12a382..b78857aed044 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1309,14 +1309,6 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, val = intel_de_read(dev_priv, DKL_TX_DPCNTL2(tc_port)); val &= ~DKL_TX_DP20BITMODE; intel_de_write(dev_priv, DKL_TX_DPCNTL2(tc_port), val); - - if ((intel_crtc_has_dp_encoder(crtc_state) && - crtc_state->port_clock == 162000) || - (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) && - crtc_state->port_clock == 594000)) - val |= DKL_TX_LOADGEN_SHARING_PMD_DISABLE; - else - val &= ~DKL_TX_LOADGEN_SHARING_PMD_DISABLE; } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a897f4abea0c..4ce29c226f09 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -11024,7 +11024,6 @@ enum skl_power_gate { _DKL_TX_DPCNTL1) #define _DKL_TX_DPCNTL2 0x2C8 -#define DKL_TX_LOADGEN_SHARING_PMD_DISABLE REG_BIT(12) #define DKL_TX_DP20BITMODE (1 << 2) #define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \ _DKL_PHY1_BASE, \ From 5e7fe4d9dcefc942c669b626411bbfbd8727e874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:27 +0300 Subject: [PATCH 331/554] drm/i915: Extract icl_combo_phy_loadgen_select() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the convoluted loadgen calculation into a small helper. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index b78857aed044..4464ecc602b0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1023,6 +1023,18 @@ static u8 intel_ddi_dp_preemph_max(struct intel_dp *intel_dp) return DP_TRAIN_PRE_EMPH_LEVEL_3; } +static u32 icl_combo_phy_loadgen_select(const struct intel_crtc_state *crtc_state, + int lane) +{ + if (crtc_state->port_clock > 600000) + return 0; + + if (crtc_state->lane_count == 4) + return lane >= 1 ? LOADGEN_SELECT : 0; + else + return lane == 1 || lane == 2 ? LOADGEN_SELECT : 0; +} + static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1089,11 +1101,8 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - int width, rate, ln; u32 val; - - width = crtc_state->lane_count; - rate = crtc_state->port_clock; + int ln; /* * 1. If port type is eDP or DP, @@ -1117,11 +1126,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < 4; ln++) { val = intel_de_read(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy)); val &= ~LOADGEN_SELECT; - - if ((rate <= 600000 && width == 4 && ln >= 1) || - (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) { - val |= LOADGEN_SELECT; - } + val |= icl_combo_phy_loadgen_select(crtc_state, ln); intel_de_write(dev_priv, ICL_PORT_TX_DW4_LN(ln, phy), val); } From e6908588008f96f7cb6f9cd6dc63236f819d3a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Oct 2021 23:49:25 +0300 Subject: [PATCH 332/554] drm/i915: Add all per-lane register definitions for icl combo phy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the FOO_LN() register macros for all the icl combo phy registers. Also get rid of the semi-pointless FOO_LN0() variants and just use the parametrized version. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211006204937.30774-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/icl_dsi.c | 14 +++++++------- drivers/gpu/drm/i915/display/intel_combo_phy.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_ddi.c | 14 +++++++------- drivers/gpu/drm/i915/i915_reg.h | 10 ++++------ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9ee62707ec72..168c84a74d30 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -233,7 +233,7 @@ static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) * Program voltage swing and pre-emphasis level values as per * table in BSPEC under DDI buffer programing */ - tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); tmp |= SCALING_MODE_SEL(0x2); tmp |= TAP2_DISABLE | TAP3_DISABLE; @@ -247,7 +247,7 @@ static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) tmp |= RTERM_SELECT(0x6); intel_de_write(dev_priv, ICL_PORT_TX_DW5_AUX(phy), tmp); - tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN(0, phy)); tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | RCOMP_SCALAR_MASK); tmp |= SWING_SEL_UPPER(0x2); @@ -455,7 +455,7 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) tmp &= ~FRC_LATENCY_OPTIM_MASK; tmp |= FRC_LATENCY_OPTIM_VAL(0x5); intel_de_write(dev_priv, ICL_PORT_TX_DW2_AUX(phy), tmp); - tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN(0, phy)); tmp &= ~FRC_LATENCY_OPTIM_MASK; tmp |= FRC_LATENCY_OPTIM_VAL(0x5); intel_de_write(dev_priv, ICL_PORT_TX_DW2_GRP(phy), tmp); @@ -470,7 +470,7 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) tmp); tmp = intel_de_read(dev_priv, - ICL_PORT_PCS_DW1_LN0(phy)); + ICL_PORT_PCS_DW1_LN(0, phy)); tmp &= ~LATENCY_OPTIM_MASK; tmp |= LATENCY_OPTIM_VAL(0x1); intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy), @@ -489,7 +489,7 @@ static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) /* clear common keeper enable bit */ for_each_dsi_phy(phy, intel_dsi->phys) { - tmp = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy)); tmp &= ~COMMON_KEEPER_EN; intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy), tmp); tmp = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_AUX(phy)); @@ -510,7 +510,7 @@ static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) /* Clear training enable to change swing values */ for_each_dsi_phy(phy, intel_dsi->phys) { - tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); tmp &= ~TX_TRAINING_EN; intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), tmp); tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_AUX(phy)); @@ -523,7 +523,7 @@ static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) /* Set training enable to trigger update */ for_each_dsi_phy(phy, intel_dsi->phys) { - tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); tmp |= TX_TRAINING_EN; intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), tmp); tmp = intel_de_read(dev_priv, ICL_PORT_TX_DW5_AUX(phy)); diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index bacdf8a16bcb..634e8d449457 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -220,13 +220,13 @@ static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv, return false; if (DISPLAY_VER(dev_priv) >= 12) { - ret &= check_phy_reg(dev_priv, phy, ICL_PORT_TX_DW8_LN0(phy), + ret &= check_phy_reg(dev_priv, phy, ICL_PORT_TX_DW8_LN(0, phy), ICL_PORT_TX_DW8_ODCC_CLK_SEL | ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK, ICL_PORT_TX_DW8_ODCC_CLK_SEL | ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2); - ret &= check_phy_reg(dev_priv, phy, ICL_PORT_PCS_DW1_LN0(phy), + ret &= check_phy_reg(dev_priv, phy, ICL_PORT_PCS_DW1_LN(0, phy), DCC_MODE_SELECT_MASK, DCC_MODE_SELECT_CONTINUOSLY); } @@ -343,13 +343,13 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv) skip_phy_misc: if (DISPLAY_VER(dev_priv) >= 12) { - val = intel_de_read(dev_priv, ICL_PORT_TX_DW8_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW8_LN(0, phy)); val &= ~ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK; val |= ICL_PORT_TX_DW8_ODCC_CLK_SEL; val |= ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2; intel_de_write(dev_priv, ICL_PORT_TX_DW8_GRP(phy), val); - val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy)); val &= ~DCC_MODE_SELECT_MASK; val |= DCC_MODE_SELECT_CONTINUOSLY; intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy), val); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 4464ecc602b0..1dcfe31e6c6f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1059,7 +1059,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, } /* Set PORT_TX_DW5 */ - val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK | TAP2_DISABLE | TAP3_DISABLE); val |= SCALING_MODE_SEL(0x2); @@ -1068,7 +1068,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val); /* Program PORT_TX_DW2 */ - val = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW2_LN(0, phy)); val &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | RCOMP_SCALAR_MASK); val |= SWING_SEL_UPPER(trans->entries[level].icl.dw2_swing_sel); @@ -1090,7 +1090,7 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, } /* Program PORT_TX_DW7 */ - val = intel_de_read(dev_priv, ICL_PORT_TX_DW7_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW7_LN(0, phy)); val &= ~N_SCALAR_MASK; val |= N_SCALAR(trans->entries[level].icl.dw7_n_scalar); intel_de_write(dev_priv, ICL_PORT_TX_DW7_GRP(phy), val); @@ -1109,7 +1109,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, * set PORT_PCS_DW1 cmnkeeper_enable to 1b, * else clear to 0b. */ - val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy)); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) val &= ~COMMON_KEEPER_EN; else @@ -1118,7 +1118,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, /* 2. Program loadgen select */ /* - * Program PORT_TX_DW4_LN depending on Bit rate and used lanes + * Program PORT_TX_DW4 depending on Bit rate and used lanes * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1) * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0) * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0) @@ -1136,7 +1136,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, intel_de_write(dev_priv, ICL_PORT_CL_DW5(phy), val); /* 4. Clear training enable to change swing values */ - val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); val &= ~TX_TRAINING_EN; intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val); @@ -1144,7 +1144,7 @@ static void icl_combo_phy_set_signal_levels(struct intel_encoder *encoder, icl_ddi_combo_vswing_program(encoder, crtc_state); /* 6. Set training enable to trigger update */ - val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); + val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN(0, phy)); val |= TX_TRAINING_EN; intel_de_write(dev_priv, ICL_PORT_TX_DW5_GRP(phy), val); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4ce29c226f09..8c8152de643f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1968,7 +1968,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) _ICL_PORT_PCS_LN(ln) + 4 * (dw)) #define ICL_PORT_PCS_DW1_AUX(phy) _MMIO(_ICL_PORT_PCS_DW_AUX(1, phy)) #define ICL_PORT_PCS_DW1_GRP(phy) _MMIO(_ICL_PORT_PCS_DW_GRP(1, phy)) -#define ICL_PORT_PCS_DW1_LN0(phy) _MMIO(_ICL_PORT_PCS_DW_LN(1, 0, phy)) +#define ICL_PORT_PCS_DW1_LN(ln, phy) _MMIO(_ICL_PORT_PCS_DW_LN(1, ln, phy)) #define DCC_MODE_SELECT_MASK (0x3 << 20) #define DCC_MODE_SELECT_CONTINUOSLY (0x3 << 20) #define COMMON_KEEPER_EN (1 << 26) @@ -1989,7 +1989,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ICL_PORT_TX_DW2_AUX(phy) _MMIO(_ICL_PORT_TX_DW_AUX(2, phy)) #define ICL_PORT_TX_DW2_GRP(phy) _MMIO(_ICL_PORT_TX_DW_GRP(2, phy)) -#define ICL_PORT_TX_DW2_LN0(phy) _MMIO(_ICL_PORT_TX_DW_LN(2, 0, phy)) +#define ICL_PORT_TX_DW2_LN(ln, phy) _MMIO(_ICL_PORT_TX_DW_LN(2, ln, phy)) #define SWING_SEL_UPPER(x) (((x) >> 3) << 15) #define SWING_SEL_UPPER_MASK (1 << 15) #define SWING_SEL_LOWER(x) (((x) & 0x7) << 11) @@ -2001,7 +2001,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ICL_PORT_TX_DW4_AUX(phy) _MMIO(_ICL_PORT_TX_DW_AUX(4, phy)) #define ICL_PORT_TX_DW4_GRP(phy) _MMIO(_ICL_PORT_TX_DW_GRP(4, phy)) -#define ICL_PORT_TX_DW4_LN0(phy) _MMIO(_ICL_PORT_TX_DW_LN(4, 0, phy)) #define ICL_PORT_TX_DW4_LN(ln, phy) _MMIO(_ICL_PORT_TX_DW_LN(4, ln, phy)) #define LOADGEN_SELECT (1 << 31) #define POST_CURSOR_1(x) ((x) << 12) @@ -2013,7 +2012,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ICL_PORT_TX_DW5_AUX(phy) _MMIO(_ICL_PORT_TX_DW_AUX(5, phy)) #define ICL_PORT_TX_DW5_GRP(phy) _MMIO(_ICL_PORT_TX_DW_GRP(5, phy)) -#define ICL_PORT_TX_DW5_LN0(phy) _MMIO(_ICL_PORT_TX_DW_LN(5, 0, phy)) +#define ICL_PORT_TX_DW5_LN(ln, phy) _MMIO(_ICL_PORT_TX_DW_LN(5, ln, phy)) #define TX_TRAINING_EN (1 << 31) #define TAP2_DISABLE (1 << 30) #define TAP3_DISABLE (1 << 29) @@ -2024,14 +2023,13 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ICL_PORT_TX_DW7_AUX(phy) _MMIO(_ICL_PORT_TX_DW_AUX(7, phy)) #define ICL_PORT_TX_DW7_GRP(phy) _MMIO(_ICL_PORT_TX_DW_GRP(7, phy)) -#define ICL_PORT_TX_DW7_LN0(phy) _MMIO(_ICL_PORT_TX_DW_LN(7, 0, phy)) #define ICL_PORT_TX_DW7_LN(ln, phy) _MMIO(_ICL_PORT_TX_DW_LN(7, ln, phy)) #define N_SCALAR(x) ((x) << 24) #define N_SCALAR_MASK (0x7F << 24) #define ICL_PORT_TX_DW8_AUX(phy) _MMIO(_ICL_PORT_TX_DW_AUX(8, phy)) #define ICL_PORT_TX_DW8_GRP(phy) _MMIO(_ICL_PORT_TX_DW_GRP(8, phy)) -#define ICL_PORT_TX_DW8_LN0(phy) _MMIO(_ICL_PORT_TX_DW_LN(8, 0, phy)) +#define ICL_PORT_TX_DW8_LN(ln, phy) _MMIO(_ICL_PORT_TX_DW_LN(8, ln, phy)) #define ICL_PORT_TX_DW8_ODCC_CLK_SEL REG_BIT(31) #define ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK REG_GENMASK(30, 29) #define ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2 REG_FIELD_PREP(ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK, 0x1) From 83f52364b15265aec47d07e02b0fbf4093ab8554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 12 Oct 2021 18:00:46 -0700 Subject: [PATCH 333/554] drm/i915: Remove memory frequency calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This memory frequency calculated is only used to check if it is zero, what is not useful as it will never actually be zero. Also the calculation is wrong, we should be checking other bit to select the appropriate frequency multiplier while this code is stuck with a fixed multiplier. So here dropping it as whole. v2: - Also remove memory frequency calculation for gen9 LP platforms Cc: Yakui Zhao Cc: Matt Roper Fixes: 5d0c938ec9cc ("drm/i915/gen11+: Only load DRAM information from pcode") Signed-off-by: José Roberto de Souza Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20211013010046.91858-1-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 8 -------- drivers/gpu/drm/i915/intel_dram.c | 30 ++---------------------------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8c8152de643f..da9055c3ebf0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -11106,12 +11106,6 @@ enum skl_power_gate { #define DC_STATE_DEBUG_MASK_CORES (1 << 0) #define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1) -#define BXT_P_CR_MC_BIOS_REQ_0_0_0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114) -#define BXT_REQ_DATA_MASK 0x3F -#define BXT_DRAM_CHANNEL_ACTIVE_SHIFT 12 -#define BXT_DRAM_CHANNEL_ACTIVE_MASK (0xF << 12) -#define BXT_MEMORY_FREQ_MULTIPLIER_HZ 133333333 - #define BXT_D_CR_DRP0_DUNIT8 0x1000 #define BXT_D_CR_DRP0_DUNIT9 0x1200 #define BXT_D_CR_DRP0_DUNIT_START 8 @@ -11142,9 +11136,7 @@ enum skl_power_gate { #define BXT_DRAM_TYPE_LPDDR4 (0x2 << 22) #define BXT_DRAM_TYPE_DDR4 (0x4 << 22) -#define SKL_MEMORY_FREQ_MULTIPLIER_HZ 266666666 #define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5E04) -#define SKL_REQ_DATA_MASK (0xF << 0) #define DG1_GEAR_TYPE REG_BIT(16) #define SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5000) diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index da3ad59d2b88..84bb212bae4b 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -244,7 +244,6 @@ static int skl_get_dram_info(struct drm_i915_private *i915) { struct dram_info *dram_info = &i915->dram_info; - u32 mem_freq_khz, val; int ret; dram_info->type = skl_get_dram_type(i915); @@ -255,17 +254,6 @@ skl_get_dram_info(struct drm_i915_private *i915) if (ret) return ret; - val = intel_uncore_read(&i915->uncore, - SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); - mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) * - SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000); - - if (dram_info->num_channels * mem_freq_khz == 0) { - drm_info(&i915->drm, - "Couldn't get system memory bandwidth\n"); - return -EINVAL; - } - return 0; } @@ -350,24 +338,10 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val) static int bxt_get_dram_info(struct drm_i915_private *i915) { struct dram_info *dram_info = &i915->dram_info; - u32 dram_channels; - u32 mem_freq_khz, val; - u8 num_active_channels, valid_ranks = 0; + u32 val; + u8 valid_ranks = 0; int i; - val = intel_uncore_read(&i915->uncore, BXT_P_CR_MC_BIOS_REQ_0_0_0); - mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) * - BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000); - - dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK; - num_active_channels = hweight32(dram_channels); - - if (mem_freq_khz * num_active_channels == 0) { - drm_info(&i915->drm, - "Couldn't get system memory bandwidth\n"); - return -EINVAL; - } - /* * Now read each DUNIT8/9/10/11 to check the rank of each dimms. */ From d73b17465d6da0a94bc0fcc86b150e1e923e8f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Oct 2021 12:09:41 +0300 Subject: [PATCH 334/554] drm/i915: Fix oops on platforms w/o hpd support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't have hpd support on i8xx/i915 which means hotplug_funcs==NULL. Let's not oops when loading the driver on one those machines. v2: Drop the redundant function pointer check (Jani) Cc: Dave Airlie Cc: Jani Nikula Fixes: cd030c7c11a4 ("drm/i915: constify hotplug function vtable.") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_hotplug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 3c1cec953b42..955f6d07b0e1 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -215,7 +215,7 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) static void intel_hpd_irq_setup(struct drm_i915_private *i915) { - if (i915->display_irqs_enabled && i915->hotplug_funcs->hpd_irq_setup) + if (i915->display_irqs_enabled && i915->hotplug_funcs) i915->hotplug_funcs->hpd_irq_setup(i915); } From ea673f17ab7638793a8b9e7fe04b4cb758fa01f1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Tue, 12 Oct 2021 15:12:45 -0700 Subject: [PATCH 335/554] drm/i915/uapi: Add comment clarifying purpose of I915_TILING_* values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The I915_TILING_* values in our uapi header are intended solely for use with the old get_tiling/set_tiling ioctls that operate on hardware de-tiling fences; all other uapi communication about tiling types is done via framebuffer modifiers rather than with these old values. On newer Intel platforms detiling fences no longer exist so the old get_tiling/set_tiling ioctls are no longer usable and will always return -EOPNOTSUPP. This means there's no reason to add new tiling types (such as the Tile4 format introduced by Xe_HP) to the uapi header here. Any kernel-internal code that needs to represent tiling format should either rely on framebuffer modifiers (as the display code does) or use some kind of non-uapi enum (as the GEM blt selftest now does). References: https://patchwork.freedesktop.org/patch/456656/?series=95308 Cc: Ville Syrjälä Signed-off-by: Matt Roper Reviewed-by: Caz Yokoyama Link: https://patchwork.freedesktop.org/patch/msgid/20211012221245.2609670-1-matthew.d.roper@intel.com --- include/uapi/drm/i915_drm.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index aa2a7eccfb94..9b8e61163c39 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1522,6 +1522,12 @@ struct drm_i915_gem_caching { #define I915_TILING_NONE 0 #define I915_TILING_X 1 #define I915_TILING_Y 2 +/* + * Do not add new tiling types here. The I915_TILING_* values are for + * de-tiling fence registers that no longer exist on modern platforms. Although + * the hardware may support new types of tiling in general (e.g., Tile4), we + * do not need to add them to the uapi that is specific to now-defunct ioctls. + */ #define I915_TILING_LAST I915_TILING_Y #define I915_BIT_6_SWIZZLE_NONE 0 From b0179f0d18dd7e6fb6b1c52c49ac21365257e97e Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Sep 2021 18:50:39 -0700 Subject: [PATCH 336/554] drm/i915: fix blank screen booting crashes 5.15-rc1 crashes with blank screen when booting up on two ThinkPads using i915. Bisections converge convincingly, but arrive at different and surprising "culprits", none of them the actual culprit. netconsole (with init_netconsole() hacked to call i915_init() when logging has started, instead of by module_init()) tells the story: kernel BUG at drivers/gpu/drm/i915/i915_sw_fence.c:245! with RSI: ffffffff814d408b pointing to sw_fence_dummy_notify(). I've been building with CONFIG_CC_OPTIMIZE_FOR_SIZE=y, and that function needs to be 4-byte aligned. v2: (Jani Nikula) - Change BUG_ON to WARN_ON v3: (Jani / Tvrtko) - Short circuit __i915_sw_fence_init on WARN_ON v4: (Lucas) - Break WARN_ON changes out in a different patch Fixes: 62eaf0ae217d ("drm/i915/guc: Support request cancellation") Signed-off-by: Hugh Dickins Signed-off-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20210922015039.26411-1-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index e9a0cad5c34d..e1bba4cfc0ff 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -362,8 +362,8 @@ static int __intel_context_active(struct i915_active *active) return 0; } -static int sw_fence_dummy_notify(struct i915_sw_fence *sf, - enum i915_sw_fence_notify state) +static int __i915_sw_fence_call +sw_fence_dummy_notify(struct i915_sw_fence *sf, enum i915_sw_fence_notify state) { return NOTIFY_DONE; } From 82a149a62b6b50ecd21b6e5e9cbdc8f6064a55d2 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Wed, 13 Oct 2021 00:17:38 +0200 Subject: [PATCH 337/554] drm/i915/gt: move remaining debugfs interfaces into gt The following interfaces: i915_wedged i915_forcewake_user are dependent on gt values. Put them inside gt/ and drop the "i915_" prefix name. This would be the new structure: dri/0/gt | +-- forcewake_user | \-- reset For backwards compatibility with existing igt (and the slight semantic difference between operating on the i915 abi entry points and the deep gt info): dri/0 | +-- i915_wedged | \-- i915_forcewake_user remain at the top level. Signed-off-by: Andi Shyti Cc: Tvrtko Ursulin Cc: Chris Wilson Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20211012221738.16029-1-andi@etezian.org --- drivers/gpu/drm/i915/gt/intel_gt_debugfs.c | 55 +++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_debugfs.h | 4 ++ drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 41 ++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h | 4 ++ drivers/gpu/drm/i915/i915_debugfs.c | 43 +++------------ 5 files changed, 111 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c index 1fe19ccd2794..f103664b71d4 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c @@ -13,6 +13,59 @@ #include "pxp/intel_pxp_debugfs.h" #include "uc/intel_uc_debugfs.h" +int intel_gt_debugfs_reset_show(struct intel_gt *gt, u64 *val) +{ + int ret = intel_gt_terminally_wedged(gt); + + switch (ret) { + case -EIO: + *val = 1; + return 0; + case 0: + *val = 0; + return 0; + default: + return ret; + } +} + +int intel_gt_debugfs_reset_store(struct intel_gt *gt, u64 val) +{ + /* Flush any previous reset before applying for a new one */ + wait_event(gt->reset.queue, + !test_bit(I915_RESET_BACKOFF, >->reset.flags)); + + intel_gt_handle_error(gt, val, I915_ERROR_CAPTURE, + "Manually reset engine mask to %llx", val); + return 0; +} + +/* + * keep the interface clean where the first parameter + * is a 'struct intel_gt *' instead of 'void *' + */ +static int __intel_gt_debugfs_reset_show(void *data, u64 *val) +{ + return intel_gt_debugfs_reset_show(data, val); +} + +static int __intel_gt_debugfs_reset_store(void *data, u64 val) +{ + return intel_gt_debugfs_reset_store(data, val); +} + +DEFINE_SIMPLE_ATTRIBUTE(reset_fops, __intel_gt_debugfs_reset_show, + __intel_gt_debugfs_reset_store, "%llu\n"); + +static void gt_debugfs_register(struct intel_gt *gt, struct dentry *root) +{ + static const struct intel_gt_debugfs_file files[] = { + { "reset", &reset_fops, NULL }, + }; + + intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt); +} + void intel_gt_debugfs_register(struct intel_gt *gt) { struct dentry *root; @@ -24,6 +77,8 @@ void intel_gt_debugfs_register(struct intel_gt *gt) if (IS_ERR(root)) return; + gt_debugfs_register(gt, root); + intel_gt_engines_debugfs_register(gt, root); intel_gt_pm_debugfs_register(gt, root); intel_sseu_debugfs_register(gt, root); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h index 8b6fca09897c..e307ceb99031 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.h @@ -35,4 +35,8 @@ void intel_gt_debugfs_register_files(struct dentry *root, const struct intel_gt_debugfs_file *files, unsigned long count, void *data); +/* functions that need to be accessed by the upper level non-gt interfaces */ +int intel_gt_debugfs_reset_show(struct intel_gt *gt, u64 *val); +int intel_gt_debugfs_reset_store(struct intel_gt *gt, u64 val); + #endif /* INTEL_GT_DEBUGFS_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 5f84ad602642..0bc1454f38dd 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -19,6 +19,46 @@ #include "intel_sideband.h" #include "intel_uncore.h" +int intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) +{ + atomic_inc(>->user_wakeref); + intel_gt_pm_get(gt); + if (GRAPHICS_VER(gt->i915) >= 6) + intel_uncore_forcewake_user_get(gt->uncore); + + return 0; +} + +int intel_gt_pm_debugfs_forcewake_user_release(struct intel_gt *gt) +{ + if (GRAPHICS_VER(gt->i915) >= 6) + intel_uncore_forcewake_user_put(gt->uncore); + intel_gt_pm_put(gt); + atomic_dec(>->user_wakeref); + + return 0; +} + +static int forcewake_user_open(struct inode *inode, struct file *file) +{ + struct intel_gt *gt = inode->i_private; + + return intel_gt_pm_debugfs_forcewake_user_open(gt); +} + +static int forcewake_user_release(struct inode *inode, struct file *file) +{ + struct intel_gt *gt = inode->i_private; + + return intel_gt_pm_debugfs_forcewake_user_release(gt); +} + +static const struct file_operations forcewake_user_fops = { + .owner = THIS_MODULE, + .open = forcewake_user_open, + .release = forcewake_user_release, +}; + static int fw_domains_show(struct seq_file *m, void *data) { struct intel_gt *gt = m->private; @@ -627,6 +667,7 @@ void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) { "drpc", &drpc_fops, NULL }, { "frequency", &frequency_fops, NULL }, { "forcewake", &fw_domains_fops, NULL }, + { "forcewake_user", &forcewake_user_fops, NULL}, { "llc", &llc_fops, llc_eval }, { "rps_boost", &rps_boost_fops, rps_eval }, }; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h index 2b824289582b..a8457887ec65 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.h @@ -13,4 +13,8 @@ struct drm_printer; void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root); void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *m); +/* functions that need to be accessed by the upper level non-gt interfaces */ +int intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt); +int intel_gt_pm_debugfs_forcewake_user_release(struct intel_gt *gt); + #endif /* INTEL_GT_PM_DEBUGFS_H */ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index fdbd46ff59e0..636cc3cf88be 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -35,6 +35,7 @@ #include "gt/intel_gt.h" #include "gt/intel_gt_buffer_pool.h" #include "gt/intel_gt_clock_utils.h" +#include "gt/intel_gt_debugfs.h" #include "gt/intel_gt_pm.h" #include "gt/intel_gt_pm_debugfs.h" #include "gt/intel_gt_requests.h" @@ -554,36 +555,18 @@ static int i915_wa_registers(struct seq_file *m, void *unused) return 0; } -static int -i915_wedged_get(void *data, u64 *val) +static int i915_wedged_get(void *data, u64 *val) { struct drm_i915_private *i915 = data; - int ret = intel_gt_terminally_wedged(&i915->gt); - switch (ret) { - case -EIO: - *val = 1; - return 0; - case 0: - *val = 0; - return 0; - default: - return ret; - } + return intel_gt_debugfs_reset_show(&i915->gt, val); } -static int -i915_wedged_set(void *data, u64 val) +static int i915_wedged_set(void *data, u64 val) { struct drm_i915_private *i915 = data; - /* Flush any previous reset before applying for a new one */ - wait_event(i915->gt.reset.queue, - !test_bit(I915_RESET_BACKOFF, &i915->gt.reset.flags)); - - intel_gt_handle_error(&i915->gt, val, I915_ERROR_CAPTURE, - "Manually set wedged engine mask = %llx", val); - return 0; + return intel_gt_debugfs_reset_store(&i915->gt, val); } DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops, @@ -728,27 +711,15 @@ static int i915_sseu_status(struct seq_file *m, void *unused) static int i915_forcewake_open(struct inode *inode, struct file *file) { struct drm_i915_private *i915 = inode->i_private; - struct intel_gt *gt = &i915->gt; - atomic_inc(>->user_wakeref); - intel_gt_pm_get(gt); - if (GRAPHICS_VER(i915) >= 6) - intel_uncore_forcewake_user_get(gt->uncore); - - return 0; + return intel_gt_pm_debugfs_forcewake_user_open(&i915->gt); } static int i915_forcewake_release(struct inode *inode, struct file *file) { struct drm_i915_private *i915 = inode->i_private; - struct intel_gt *gt = &i915->gt; - if (GRAPHICS_VER(i915) >= 6) - intel_uncore_forcewake_user_put(&i915->uncore); - intel_gt_pm_put(gt); - atomic_dec(>->user_wakeref); - - return 0; + return intel_gt_pm_debugfs_forcewake_user_release(&i915->gt); } static const struct file_operations i915_forcewake_fops = { From 0ea92ace8b95f67224ee26c4955efc7104d8e8e1 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:41 -0700 Subject: [PATCH 338/554] drm/i915/guc: Move GuC guc_id allocation under submission state sub-struct Move guc_id allocation under submission state sub-struct as a future patch will reuse the spin lock as a global submission state lock. Moving this into sub-struct makes ownership of fields / lock clear. v2: (Docs) - Add comment for submission_state sub-structure v3: (John Harrison) - Fixup a few comments v4: (John Harrison) - Fix typo Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-2-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context_types.h | 6 +-- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 28 +++++++---- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 46 ++++++++++--------- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 12252c411159..e7e3984aab78 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -197,18 +197,18 @@ struct intel_context { struct { /** * @id: handle which is used to uniquely identify this context - * with the GuC, protected by guc->contexts_lock + * with the GuC, protected by guc->submission_state.lock */ u16 id; /** * @ref: the number of references to the guc_id, when * transitioning in and out of zero protected by - * guc->contexts_lock + * guc->submission_state.lock */ atomic_t ref; /** * @link: in guc->guc_id_list when the guc_id has no refs but is - * still valid, protected by guc->contexts_lock + * still valid, protected by guc->submission_state.lock */ struct list_head link; } guc_id; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 5dd174babf7a..82e248c2290c 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -71,16 +71,26 @@ struct intel_guc { } interrupts; /** - * @contexts_lock: protects guc_ids, guc_id_list, ce->guc_id.id, and - * ce->guc_id.ref when transitioning in and out of zero + * @submission_state: sub-structure for submission state protected by + * single lock */ - spinlock_t contexts_lock; - /** @guc_ids: used to allocate unique ce->guc_id.id values */ - struct ida guc_ids; - /** - * @guc_id_list: list of intel_context with valid guc_ids but no refs - */ - struct list_head guc_id_list; + struct { + /** + * @lock: protects everything in submission_state, + * ce->guc_id.id, and ce->guc_id.ref when transitioning in and + * out of zero + */ + spinlock_t lock; + /** + * @guc_ids: used to allocate new guc_ids + */ + struct ida guc_ids; + /** + * @guc_id_list: list of intel_context with valid guc_ids but no + * refs + */ + struct list_head guc_id_list; + } submission_state; /** * @submission_supported: tracks whether we support GuC submission on diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index ba0de35f6323..48bdcdb823b3 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -68,7 +68,7 @@ * fence is used to stall all requests associated with this guc_id until the * corresponding G2H returns indicating the guc_id has been deregistered. * - * guc_ids: + * submission_state.guc_ids: * Unique number associated with private GuC context data passed in during * context registration / submission / deregistration. 64k available. Simple ida * is used for allocation. @@ -89,7 +89,7 @@ * sched_engine can be submitting at a time. Currently only one sched_engine is * used for all of GuC submission but that could change in the future. * - * guc->contexts_lock + * guc->submission_state.lock * Protects guc_id allocation for the given GuC, i.e. only one context can be * doing guc_id allocation operations at a time for each GuC in the system. * @@ -103,7 +103,7 @@ * * Lock ordering rules: * sched_engine->lock -> ce->guc_state.lock - * guc->contexts_lock -> ce->guc_state.lock + * guc->submission_state.lock -> ce->guc_state.lock * * Reset races: * When a full GT reset is triggered it is assumed that some G2H responses to @@ -1148,9 +1148,9 @@ int intel_guc_submission_init(struct intel_guc *guc) xa_init_flags(&guc->context_lookup, XA_FLAGS_LOCK_IRQ); - spin_lock_init(&guc->contexts_lock); - INIT_LIST_HEAD(&guc->guc_id_list); - ida_init(&guc->guc_ids); + spin_lock_init(&guc->submission_state.lock); + INIT_LIST_HEAD(&guc->submission_state.guc_id_list); + ida_init(&guc->submission_state.guc_ids); return 0; } @@ -1215,7 +1215,7 @@ static void guc_submit_request(struct i915_request *rq) static int new_guc_id(struct intel_guc *guc) { - return ida_simple_get(&guc->guc_ids, 0, + return ida_simple_get(&guc->submission_state.guc_ids, 0, GUC_MAX_LRC_DESCRIPTORS, GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); } @@ -1223,7 +1223,8 @@ static int new_guc_id(struct intel_guc *guc) static void __release_guc_id(struct intel_guc *guc, struct intel_context *ce) { if (!context_guc_id_invalid(ce)) { - ida_simple_remove(&guc->guc_ids, ce->guc_id.id); + ida_simple_remove(&guc->submission_state.guc_ids, + ce->guc_id.id); reset_lrc_desc(guc, ce->guc_id.id); set_context_guc_id_invalid(ce); } @@ -1235,9 +1236,9 @@ static void release_guc_id(struct intel_guc *guc, struct intel_context *ce) { unsigned long flags; - spin_lock_irqsave(&guc->contexts_lock, flags); + spin_lock_irqsave(&guc->submission_state.lock, flags); __release_guc_id(guc, ce); - spin_unlock_irqrestore(&guc->contexts_lock, flags); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); } static int steal_guc_id(struct intel_guc *guc) @@ -1245,10 +1246,10 @@ static int steal_guc_id(struct intel_guc *guc) struct intel_context *ce; int guc_id; - lockdep_assert_held(&guc->contexts_lock); + lockdep_assert_held(&guc->submission_state.lock); - if (!list_empty(&guc->guc_id_list)) { - ce = list_first_entry(&guc->guc_id_list, + if (!list_empty(&guc->submission_state.guc_id_list)) { + ce = list_first_entry(&guc->submission_state.guc_id_list, struct intel_context, guc_id.link); @@ -1273,7 +1274,7 @@ static int assign_guc_id(struct intel_guc *guc, u16 *out) { int ret; - lockdep_assert_held(&guc->contexts_lock); + lockdep_assert_held(&guc->submission_state.lock); ret = new_guc_id(guc); if (unlikely(ret < 0)) { @@ -1295,7 +1296,7 @@ static int pin_guc_id(struct intel_guc *guc, struct intel_context *ce) GEM_BUG_ON(atomic_read(&ce->guc_id.ref)); try_again: - spin_lock_irqsave(&guc->contexts_lock, flags); + spin_lock_irqsave(&guc->submission_state.lock, flags); might_lock(&ce->guc_state.lock); @@ -1310,7 +1311,7 @@ try_again: atomic_inc(&ce->guc_id.ref); out_unlock: - spin_unlock_irqrestore(&guc->contexts_lock, flags); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); /* * -EAGAIN indicates no guc_id are available, let's retire any @@ -1346,11 +1347,12 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce) if (unlikely(context_guc_id_invalid(ce))) return; - spin_lock_irqsave(&guc->contexts_lock, flags); + spin_lock_irqsave(&guc->submission_state.lock, flags); if (!context_guc_id_invalid(ce) && list_empty(&ce->guc_id.link) && !atomic_read(&ce->guc_id.ref)) - list_add_tail(&ce->guc_id.link, &guc->guc_id_list); - spin_unlock_irqrestore(&guc->contexts_lock, flags); + list_add_tail(&ce->guc_id.link, + &guc->submission_state.guc_id_list); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); } static int __guc_action_register_context(struct intel_guc *guc, @@ -1921,16 +1923,16 @@ static void guc_context_destroy(struct kref *kref) * returns indicating this context has been deregistered the guc_id is * returned to the pool of available guc_id. */ - spin_lock_irqsave(&guc->contexts_lock, flags); + spin_lock_irqsave(&guc->submission_state.lock, flags); if (context_guc_id_invalid(ce)) { - spin_unlock_irqrestore(&guc->contexts_lock, flags); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); __guc_context_destroy(ce); return; } if (!list_empty(&ce->guc_id.link)) list_del_init(&ce->guc_id.link); - spin_unlock_irqrestore(&guc->contexts_lock, flags); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); /* Seal race with Reset */ spin_lock_irqsave(&ce->guc_state.lock, flags); From 1a52faed3131147c10bb7f908d0f7a29b94f59ae Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:42 -0700 Subject: [PATCH 339/554] drm/i915/guc: Take GT PM ref when deregistering context Taking a PM reference to prevent intel_gt_wait_for_idle from short circuiting while a deregister context H2G is in flight. To do this must issue the deregister H2G from a worker as context can be destroyed from an atomic context and taking GT PM ref blows up. Previously we took a runtime PM from this atomic context which worked but will stop working once runtime pm autosuspend in enabled. So this patch is two fold, stop intel_gt_wait_for_idle from short circuting and fix runtime pm autosuspend. v2: (John Harrison) - Split structure changes out in different patch (Tvrtko) - Don't drop lock in deregister_destroyed_contexts v3: (John Harrison) - Flush destroyed contexts before destroying context reg pool Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-3-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 2 + drivers/gpu/drm/i915/gt/intel_context_types.h | 7 + drivers/gpu/drm/i915/gt/intel_engine_pm.h | 5 + drivers/gpu/drm/i915/gt/intel_gt_pm.h | 4 + drivers/gpu/drm/i915/gt/uc/intel_guc.h | 11 ++ .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 146 +++++++++++------- 6 files changed, 121 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index e1bba4cfc0ff..0f25d07e55e5 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -399,6 +399,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine) ce->guc_id.id = GUC_INVALID_LRC_ID; INIT_LIST_HEAD(&ce->guc_id.link); + INIT_LIST_HEAD(&ce->destroyed_link); + /* * Initialize fence to be complete as this is expected to be complete * unless there is a pending schedule disable outstanding. diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index e7e3984aab78..4613d027cbc3 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -213,6 +213,13 @@ struct intel_context { struct list_head link; } guc_id; + /** + * @destroyed_link: link in guc->submission_state.destroyed_contexts, in + * list when context is pending to be destroyed (deregistered with the + * GuC), protected by guc->submission_state.lock + */ + struct list_head destroyed_link; + #ifdef CONFIG_DRM_I915_SELFTEST /** * @drop_schedule_enable: Force drop of schedule enable G2H for selftest diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h index 8520c595f5e1..6fdeae668e6e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h @@ -16,6 +16,11 @@ intel_engine_pm_is_awake(const struct intel_engine_cs *engine) return intel_wakeref_is_active(&engine->wakeref); } +static inline void __intel_engine_pm_get(struct intel_engine_cs *engine) +{ + __intel_wakeref_get(&engine->wakeref); +} + static inline void intel_engine_pm_get(struct intel_engine_cs *engine) { intel_wakeref_get(&engine->wakeref); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h index d0588d8aaa44..05de6c1af25b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -41,6 +41,10 @@ static inline void intel_gt_pm_put_async(struct intel_gt *gt) intel_wakeref_put_async(>->wakeref); } +#define with_intel_gt_pm(gt, tmp) \ + for (tmp = 1, intel_gt_pm_get(gt); tmp; \ + intel_gt_pm_put(gt), tmp = 0) + static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt) { return intel_wakeref_wait_for_idle(>->wakeref); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 82e248c2290c..74f071a0b6d5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -90,6 +90,17 @@ struct intel_guc { * refs */ struct list_head guc_id_list; + /** + * @destroyed_contexts: list of contexts waiting to be destroyed + * (deregistered with the GuC) + */ + struct list_head destroyed_contexts; + /** + * @destroyed_worker: worker to deregister contexts, need as we + * need to take a GT PM reference and can't from destroy + * function as it might be in an atomic context (no sleeping) + */ + struct work_struct destroyed_worker; } submission_state; /** diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 48bdcdb823b3..5c53428032b5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -90,8 +90,8 @@ * used for all of GuC submission but that could change in the future. * * guc->submission_state.lock - * Protects guc_id allocation for the given GuC, i.e. only one context can be - * doing guc_id allocation operations at a time for each GuC in the system. + * Global lock for GuC submission state. Protects guc_ids and destroyed contexts + * list. * * ce->guc_state.lock * Protects everything under ce->guc_state. Ensures that a context is in the @@ -719,6 +719,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc) if (deregister) guc_signal_context_fence(ce); if (destroyed) { + intel_gt_pm_put_async(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } @@ -797,6 +798,8 @@ static void guc_flush_submissions(struct intel_guc *guc) spin_unlock_irqrestore(&sched_engine->lock, flags); } +static void guc_flush_destroyed_contexts(struct intel_guc *guc); + void intel_guc_submission_reset_prepare(struct intel_guc *guc) { int i; @@ -815,6 +818,7 @@ void intel_guc_submission_reset_prepare(struct intel_guc *guc) spin_unlock_irq(&guc_to_gt(guc)->irq_lock); guc_flush_submissions(guc); + guc_flush_destroyed_contexts(guc); /* * Handle any outstanding G2Hs before reset. Call IRQ handler directly @@ -1126,6 +1130,8 @@ void intel_guc_submission_reset_finish(struct intel_guc *guc) intel_gt_unpark_heartbeats(guc_to_gt(guc)); } +static void destroyed_worker_func(struct work_struct *w); + /* * Set up the memory resources to be shared with the GuC (via the GGTT) * at firmware loading time. @@ -1151,6 +1157,9 @@ int intel_guc_submission_init(struct intel_guc *guc) spin_lock_init(&guc->submission_state.lock); INIT_LIST_HEAD(&guc->submission_state.guc_id_list); ida_init(&guc->submission_state.guc_ids); + INIT_LIST_HEAD(&guc->submission_state.destroyed_contexts); + INIT_WORK(&guc->submission_state.destroyed_worker, + destroyed_worker_func); return 0; } @@ -1160,6 +1169,7 @@ void intel_guc_submission_fini(struct intel_guc *guc) if (!guc->lrc_desc_pool) return; + guc_flush_destroyed_contexts(guc); guc_lrc_desc_pool_destroy(guc); i915_sched_engine_put(guc->sched_engine); } @@ -1859,11 +1869,30 @@ unpin: static inline void guc_lrc_desc_unpin(struct intel_context *ce) { struct intel_guc *guc = ce_to_guc(ce); + struct intel_gt *gt = guc_to_gt(guc); + unsigned long flags; + bool disabled; + GEM_BUG_ON(!intel_gt_pm_is_awake(gt)); GEM_BUG_ON(!lrc_desc_registered(guc, ce->guc_id.id)); GEM_BUG_ON(ce != __get_context(guc, ce->guc_id.id)); GEM_BUG_ON(context_enabled(ce)); + /* Seal race with Reset */ + spin_lock_irqsave(&ce->guc_state.lock, flags); + disabled = submission_disabled(guc); + if (likely(!disabled)) { + __intel_gt_pm_get(gt); + set_context_destroyed(ce); + clr_context_registered(ce); + } + spin_unlock_irqrestore(&ce->guc_state.lock, flags); + if (unlikely(disabled)) { + release_guc_id(guc, ce); + __guc_context_destroy(ce); + return; + } + deregister_context(ce, ce->guc_id.id); } @@ -1891,78 +1920,86 @@ static void __guc_context_destroy(struct intel_context *ce) } } +static void guc_flush_destroyed_contexts(struct intel_guc *guc) +{ + struct intel_context *ce, *cn; + unsigned long flags; + + GEM_BUG_ON(!submission_disabled(guc) && + guc_submission_initialized(guc)); + + spin_lock_irqsave(&guc->submission_state.lock, flags); + list_for_each_entry_safe(ce, cn, + &guc->submission_state.destroyed_contexts, + destroyed_link) { + list_del_init(&ce->destroyed_link); + __release_guc_id(guc, ce); + __guc_context_destroy(ce); + } + spin_unlock_irqrestore(&guc->submission_state.lock, flags); +} + +static void deregister_destroyed_contexts(struct intel_guc *guc) +{ + struct intel_context *ce, *cn; + unsigned long flags; + + spin_lock_irqsave(&guc->submission_state.lock, flags); + list_for_each_entry_safe(ce, cn, + &guc->submission_state.destroyed_contexts, + destroyed_link) { + list_del_init(&ce->destroyed_link); + guc_lrc_desc_unpin(ce); + } + spin_unlock_irqrestore(&guc->submission_state.lock, flags); +} + +static void destroyed_worker_func(struct work_struct *w) +{ + struct intel_guc *guc = container_of(w, struct intel_guc, + submission_state.destroyed_worker); + struct intel_gt *gt = guc_to_gt(guc); + int tmp; + + with_intel_gt_pm(gt, tmp) + deregister_destroyed_contexts(guc); +} + static void guc_context_destroy(struct kref *kref) { struct intel_context *ce = container_of(kref, typeof(*ce), ref); - struct intel_runtime_pm *runtime_pm = ce->engine->uncore->rpm; struct intel_guc *guc = ce_to_guc(ce); - intel_wakeref_t wakeref; unsigned long flags; - bool disabled; + bool destroy; /* * If the guc_id is invalid this context has been stolen and we can free * it immediately. Also can be freed immediately if the context is not * registered with the GuC or the GuC is in the middle of a reset. */ - if (context_guc_id_invalid(ce)) { - __guc_context_destroy(ce); - return; - } else if (submission_disabled(guc) || - !lrc_desc_registered(guc, ce->guc_id.id)) { - release_guc_id(guc, ce); - __guc_context_destroy(ce); - return; - } - - /* - * We have to acquire the context spinlock and check guc_id again, if it - * is valid it hasn't been stolen and needs to be deregistered. We - * delete this context from the list of unpinned guc_id available to - * steal to seal a race with guc_lrc_desc_pin(). When the G2H CTB - * returns indicating this context has been deregistered the guc_id is - * returned to the pool of available guc_id. - */ spin_lock_irqsave(&guc->submission_state.lock, flags); - if (context_guc_id_invalid(ce)) { - spin_unlock_irqrestore(&guc->submission_state.lock, flags); - __guc_context_destroy(ce); - return; + destroy = submission_disabled(guc) || context_guc_id_invalid(ce) || + !lrc_desc_registered(guc, ce->guc_id.id); + if (likely(!destroy)) { + if (!list_empty(&ce->guc_id.link)) + list_del_init(&ce->guc_id.link); + list_add_tail(&ce->destroyed_link, + &guc->submission_state.destroyed_contexts); + } else { + __release_guc_id(guc, ce); } - - if (!list_empty(&ce->guc_id.link)) - list_del_init(&ce->guc_id.link); spin_unlock_irqrestore(&guc->submission_state.lock, flags); - - /* Seal race with Reset */ - spin_lock_irqsave(&ce->guc_state.lock, flags); - disabled = submission_disabled(guc); - if (likely(!disabled)) { - set_context_destroyed(ce); - clr_context_registered(ce); - } - spin_unlock_irqrestore(&ce->guc_state.lock, flags); - if (unlikely(disabled)) { - release_guc_id(guc, ce); + if (unlikely(destroy)) { __guc_context_destroy(ce); return; } /* - * We defer GuC context deregistration until the context is destroyed - * in order to save on CTBs. With this optimization ideally we only need - * 1 CTB to register the context during the first pin and 1 CTB to - * deregister the context when the context is destroyed. Without this - * optimization, a CTB would be needed every pin & unpin. - * - * XXX: Need to acqiure the runtime wakeref as this can be triggered - * from context_free_worker when runtime wakeref is not held. - * guc_lrc_desc_unpin requires the runtime as a GuC register is written - * in H2G CTB to deregister the context. A future patch may defer this - * H2G CTB if the runtime wakeref is zero. + * We use a worker to issue the H2G to deregister the context as we can + * take the GT PM for the first time which isn't allowed from an atomic + * context. */ - with_intel_runtime_pm(runtime_pm, wakeref) - guc_lrc_desc_unpin(ce); + queue_work(system_unbound_wq, &guc->submission_state.destroyed_worker); } static int guc_context_alloc(struct intel_context *ce) @@ -2798,6 +2835,7 @@ int intel_guc_deregister_done_process_msg(struct intel_guc *guc, intel_context_put(ce); } else if (context_destroyed(ce)) { /* Context has been destroyed */ + intel_gt_pm_put_async(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } From f61eae1815705494aa1cd7a8a94f3442fea328d7 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:43 -0700 Subject: [PATCH 340/554] drm/i915/guc: Take engine PM when a context is pinned with GuC submission Taking a PM reference to prevent intel_gt_wait_for_idle from short circuiting while any user context has scheduling enabled. Returning GT idle when it is not can cause all sorts of issues throughout the stack. v2: (Daniel Vetter) - Add might_lock annotations to pin / unpin function v3: (CI) - Drop intel_engine_pm_might_put from unpin path as an async put is used v4: (John Harrison) - Make intel_engine_pm_might_get/put work with GuC virtual engines - Update commit message v5: - Update commit message again Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-4-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 2 ++ drivers/gpu/drm/i915/gt/intel_engine_pm.h | 32 +++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_pm.h | 10 ++++++ .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 36 +++++++++++++++++-- drivers/gpu/drm/i915/intel_wakeref.h | 12 +++++++ 5 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 0f25d07e55e5..7a7cd2448277 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -240,6 +240,8 @@ int __intel_context_do_pin_ww(struct intel_context *ce, if (err) goto err_post_unpin; + intel_engine_pm_might_get(ce->engine); + if (unlikely(intel_context_is_closed(ce))) { err = -ENOENT; goto err_unlock; diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h index 6fdeae668e6e..d68675925b79 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h @@ -6,9 +6,11 @@ #ifndef INTEL_ENGINE_PM_H #define INTEL_ENGINE_PM_H +#include "i915_drv.h" #include "i915_request.h" #include "intel_engine_types.h" #include "intel_wakeref.h" +#include "intel_gt_pm.h" static inline bool intel_engine_pm_is_awake(const struct intel_engine_cs *engine) @@ -31,6 +33,21 @@ static inline bool intel_engine_pm_get_if_awake(struct intel_engine_cs *engine) return intel_wakeref_get_if_active(&engine->wakeref); } +static inline void intel_engine_pm_might_get(struct intel_engine_cs *engine) +{ + if (!intel_engine_is_virtual(engine)) { + intel_wakeref_might_get(&engine->wakeref); + } else { + struct intel_gt *gt = engine->gt; + struct intel_engine_cs *tengine; + intel_engine_mask_t tmp, mask = engine->mask; + + for_each_engine_masked(tengine, gt, mask, tmp) + intel_wakeref_might_get(&tengine->wakeref); + } + intel_gt_pm_might_get(engine->gt); +} + static inline void intel_engine_pm_put(struct intel_engine_cs *engine) { intel_wakeref_put(&engine->wakeref); @@ -52,6 +69,21 @@ static inline void intel_engine_pm_flush(struct intel_engine_cs *engine) intel_wakeref_unlock_wait(&engine->wakeref); } +static inline void intel_engine_pm_might_put(struct intel_engine_cs *engine) +{ + if (!intel_engine_is_virtual(engine)) { + intel_wakeref_might_put(&engine->wakeref); + } else { + struct intel_gt *gt = engine->gt; + struct intel_engine_cs *tengine; + intel_engine_mask_t tmp, mask = engine->mask; + + for_each_engine_masked(tengine, gt, mask, tmp) + intel_wakeref_might_put(&tengine->wakeref); + } + intel_gt_pm_might_put(engine->gt); +} + static inline struct i915_request * intel_engine_create_kernel_request(struct intel_engine_cs *engine) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h index 05de6c1af25b..bc898df7a48c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -31,6 +31,11 @@ static inline bool intel_gt_pm_get_if_awake(struct intel_gt *gt) return intel_wakeref_get_if_active(>->wakeref); } +static inline void intel_gt_pm_might_get(struct intel_gt *gt) +{ + intel_wakeref_might_get(>->wakeref); +} + static inline void intel_gt_pm_put(struct intel_gt *gt) { intel_wakeref_put(>->wakeref); @@ -41,6 +46,11 @@ static inline void intel_gt_pm_put_async(struct intel_gt *gt) intel_wakeref_put_async(>->wakeref); } +static inline void intel_gt_pm_might_put(struct intel_gt *gt) +{ + intel_wakeref_might_put(>->wakeref); +} + #define with_intel_gt_pm(gt, tmp) \ for (tmp = 1, intel_gt_pm_get(gt); tmp; \ intel_gt_pm_put(gt), tmp = 0) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 5c53428032b5..795cc071d05d 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1571,7 +1571,12 @@ static int guc_context_pre_pin(struct intel_context *ce, static int guc_context_pin(struct intel_context *ce, void *vaddr) { - return __guc_context_pin(ce, ce->engine, vaddr); + int ret = __guc_context_pin(ce, ce->engine, vaddr); + + if (likely(!ret && !intel_context_is_barrier(ce))) + intel_engine_pm_get(ce->engine); + + return ret; } static void guc_context_unpin(struct intel_context *ce) @@ -1580,6 +1585,9 @@ static void guc_context_unpin(struct intel_context *ce) unpin_guc_id(guc, ce); lrc_unpin(ce); + + if (likely(!intel_context_is_barrier(ce))) + intel_engine_pm_put_async(ce->engine); } static void guc_context_post_unpin(struct intel_context *ce) @@ -2341,8 +2349,30 @@ static int guc_virtual_context_pre_pin(struct intel_context *ce, static int guc_virtual_context_pin(struct intel_context *ce, void *vaddr) { struct intel_engine_cs *engine = guc_virtual_get_sibling(ce->engine, 0); + int ret = __guc_context_pin(ce, engine, vaddr); + intel_engine_mask_t tmp, mask = ce->engine->mask; - return __guc_context_pin(ce, engine, vaddr); + if (likely(!ret)) + for_each_engine_masked(engine, ce->engine->gt, mask, tmp) + intel_engine_pm_get(engine); + + return ret; +} + +static void guc_virtual_context_unpin(struct intel_context *ce) +{ + intel_engine_mask_t tmp, mask = ce->engine->mask; + struct intel_engine_cs *engine; + struct intel_guc *guc = ce_to_guc(ce); + + GEM_BUG_ON(context_enabled(ce)); + GEM_BUG_ON(intel_context_is_barrier(ce)); + + unpin_guc_id(guc, ce); + lrc_unpin(ce); + + for_each_engine_masked(engine, ce->engine->gt, mask, tmp) + intel_engine_pm_put_async(engine); } static void guc_virtual_context_enter(struct intel_context *ce) @@ -2379,7 +2409,7 @@ static const struct intel_context_ops virtual_guc_context_ops = { .pre_pin = guc_virtual_context_pre_pin, .pin = guc_virtual_context_pin, - .unpin = guc_context_unpin, + .unpin = guc_virtual_context_unpin, .post_unpin = guc_context_post_unpin, .ban = guc_context_ban, diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h index 545c8f277c46..4f4c2e15e736 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -123,6 +123,12 @@ enum { __INTEL_WAKEREF_PUT_LAST_BIT__ }; +static inline void +intel_wakeref_might_get(struct intel_wakeref *wf) +{ + might_lock(&wf->mutex); +} + /** * intel_wakeref_put_flags: Release the wakeref * @wf: the wakeref @@ -170,6 +176,12 @@ intel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay) FIELD_PREP(INTEL_WAKEREF_PUT_DELAY, delay)); } +static inline void +intel_wakeref_might_put(struct intel_wakeref *wf) +{ + might_lock(&wf->mutex); +} + /** * intel_wakeref_lock: Lock the wakeref (mutex) * @wf: the wakeref From 3633242927101b4bcff14cb0f718ecd4d346c5b1 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:44 -0700 Subject: [PATCH 341/554] drm/i915/guc: Don't call switch_to_kernel_context with GuC submission Calling switch_to_kernel_context isn't needed if the engine PM reference is taken while all user contexts are pinned as if don't have PM ref that guarantees that all user contexts scheduling is disabled. By not calling switch_to_kernel_context we save on issuing a request to the engine. v2: (Daniel Vetter) - Add FIXME comment about pushing switch_to_kernel_context to backend v3: (John Harrison) - Update commit message - Fix workding comment Signed-off-by: Matthew Brost Reviewed-by: Daniel Vetter Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-5-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_pm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index dacd62773735..a1334b48dde7 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -162,6 +162,19 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine) unsigned long flags; bool result = true; + /* + * This is execlist specific behaviour intended to ensure the GPU is + * idle by switching to a known 'safe' context. With GuC submission, the + * same idle guarantee is achieved by other means (disabling + * scheduling). Further, switching to a 'safe' context has no effect + * with GuC submission as the scheduler can just switch back again. + * + * FIXME: Move this backend scheduler specific behaviour into the + * scheduler backend. + */ + if (intel_engine_uses_guc(engine)) + return true; + /* GPU is pointing to the void, as good as in the kernel context. */ if (intel_gt_is_wedged(engine->gt)) return true; From 4f3059dc2dbbc5547684558f18565719c365b30e Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:45 -0700 Subject: [PATCH 342/554] drm/i915: Add logical engine mapping Add logical engine mapping. This is required for split-frame, as workloads need to be placed on engines in a logically contiguous manner. v2: (Daniel Vetter) - Add kernel doc for new fields v3: (Tvrtko) - Update comment for new logical_mask field v4: (John Harrison) - Update comment for new logical_mask field Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-6-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 60 ++++++++++++++++--- drivers/gpu/drm/i915/gt/intel_engine_types.h | 7 +++ .../drm/i915/gt/intel_execlists_submission.c | 1 + drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 2 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 21 +------ 5 files changed, 62 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 2ae57e4656a3..2eb798ad068b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -290,7 +290,8 @@ static void nop_irq_handler(struct intel_engine_cs *engine, u16 iir) GEM_DEBUG_WARN_ON(iir); } -static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id) +static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, + u8 logical_instance) { const struct engine_info *info = &intel_engines[id]; struct drm_i915_private *i915 = gt->i915; @@ -335,6 +336,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id) engine->class = info->class; engine->instance = info->instance; + engine->logical_mask = BIT(logical_instance); __sprint_engine_name(engine); engine->props.heartbeat_interval_ms = @@ -588,6 +590,37 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) return info->engine_mask; } +static void populate_logical_ids(struct intel_gt *gt, u8 *logical_ids, + u8 class, const u8 *map, u8 num_instances) +{ + int i, j; + u8 current_logical_id = 0; + + for (j = 0; j < num_instances; ++j) { + for (i = 0; i < ARRAY_SIZE(intel_engines); ++i) { + if (!HAS_ENGINE(gt, i) || + intel_engines[i].class != class) + continue; + + if (intel_engines[i].instance == map[j]) { + logical_ids[intel_engines[i].instance] = + current_logical_id++; + break; + } + } + } +} + +static void setup_logical_ids(struct intel_gt *gt, u8 *logical_ids, u8 class) +{ + int i; + u8 map[MAX_ENGINE_INSTANCE + 1]; + + for (i = 0; i < MAX_ENGINE_INSTANCE + 1; ++i) + map[i] = i; + populate_logical_ids(gt, logical_ids, class, map, ARRAY_SIZE(map)); +} + /** * intel_engines_init_mmio() - allocate and prepare the Engine Command Streamers * @gt: pointer to struct intel_gt @@ -599,7 +632,8 @@ int intel_engines_init_mmio(struct intel_gt *gt) struct drm_i915_private *i915 = gt->i915; const unsigned int engine_mask = init_engine_mask(gt); unsigned int mask = 0; - unsigned int i; + unsigned int i, class; + u8 logical_ids[MAX_ENGINE_INSTANCE + 1]; int err; drm_WARN_ON(&i915->drm, engine_mask == 0); @@ -609,15 +643,23 @@ int intel_engines_init_mmio(struct intel_gt *gt) if (i915_inject_probe_failure(i915)) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(intel_engines); i++) { - if (!HAS_ENGINE(gt, i)) - continue; + for (class = 0; class < MAX_ENGINE_CLASS + 1; ++class) { + setup_logical_ids(gt, logical_ids, class); - err = intel_engine_setup(gt, i); - if (err) - goto cleanup; + for (i = 0; i < ARRAY_SIZE(intel_engines); ++i) { + u8 instance = intel_engines[i].instance; - mask |= BIT(i); + if (intel_engines[i].class != class || + !HAS_ENGINE(gt, i)) + continue; + + err = intel_engine_setup(gt, i, + logical_ids[instance]); + if (err) + goto cleanup; + + mask |= BIT(i); + } } /* diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index 9167ce52487c..e0f773585c29 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -269,6 +269,13 @@ struct intel_engine_cs { unsigned int guc_id; intel_engine_mask_t mask; + /** + * @logical_mask: logical mask of engine, reported to user space via + * query IOCTL and used to communicate with the GuC in logical space. + * The logical instance of a physical engine can change based on product + * and fusing. + */ + intel_engine_mask_t logical_mask; u8 class; u8 instance; diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 73a79c2acd3a..43a74b216efb 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -3877,6 +3877,7 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count) ve->siblings[ve->num_siblings++] = sibling; ve->base.mask |= sibling->mask; + ve->base.logical_mask |= sibling->logical_mask; /* * All physical engines must be compatible for their emission diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 2c6ea64af7ec..621c893a009f 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -176,7 +176,7 @@ static void guc_mapping_table_init(struct intel_gt *gt, for_each_engine(engine, gt, id) { u8 guc_class = engine_class_to_guc_class(engine->class); - system_info->mapping_table[guc_class][engine->instance] = + system_info->mapping_table[guc_class][ilog2(engine->logical_mask)] = engine->instance; } } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 795cc071d05d..fd6594bc1b96 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1423,23 +1423,6 @@ static int deregister_context(struct intel_context *ce, u32 guc_id) return __guc_action_deregister_context(guc, guc_id); } -static intel_engine_mask_t adjust_engine_mask(u8 class, intel_engine_mask_t mask) -{ - switch (class) { - case RENDER_CLASS: - return mask >> RCS0; - case VIDEO_ENHANCEMENT_CLASS: - return mask >> VECS0; - case VIDEO_DECODE_CLASS: - return mask >> VCS0; - case COPY_ENGINE_CLASS: - return mask >> BCS0; - default: - MISSING_CASE(class); - return 0; - } -} - static void guc_context_policy_init(struct intel_engine_cs *engine, struct guc_lrc_desc *desc) { @@ -1481,8 +1464,7 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop) desc = __get_lrc_desc(guc, desc_idx); desc->engine_class = engine_class_to_guc_class(engine->class); - desc->engine_submit_mask = adjust_engine_mask(engine->class, - engine->mask); + desc->engine_submit_mask = engine->logical_mask; desc->hw_context_desc = ce->lrc.lrca; desc->priority = ce->guc_state.prio; desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD; @@ -3271,6 +3253,7 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count) } ve->base.mask |= sibling->mask; + ve->base.logical_mask |= sibling->logical_mask; if (n != 0 && ve->base.class != sibling->class) { DRM_DEBUG("invalid mixing of engine class, sibling %d, already %d\n", From 9409eb35942713d0cdd471e5ff99c93929d6a749 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:46 -0700 Subject: [PATCH 343/554] drm/i915: Expose logical engine instance to user Expose logical engine instance to user via query engine info IOCTL. This is required for split-frame workloads as these needs to be placed on engines in a logically contiguous order. The logical mapping can change based on fusing. Rather than having user have knowledge of the fusing we simply just expose the logical mapping with the existing query engine info IOCTL. IGT: https://patchwork.freedesktop.org/patch/445637/?series=92854&rev=1 media UMD: https://github.com/intel/media-driver/pull/1252 v2: (Daniel Vetter) - Add IGT link, placeholder for media UMD Cc: Tvrtko Ursulin Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-7-matthew.brost@intel.com --- drivers/gpu/drm/i915/i915_query.c | 2 ++ include/uapi/drm/i915_drm.h | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 5e2b909827f4..51b368be0fc4 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -124,7 +124,9 @@ query_engine_info(struct drm_i915_private *i915, for_each_uabi_engine(engine, i915) { info.engine.engine_class = engine->uabi_class; info.engine.engine_instance = engine->uabi_instance; + info.flags = I915_ENGINE_INFO_HAS_LOGICAL_INSTANCE; info.capabilities = engine->uabi_capabilities; + info.logical_instance = ilog2(engine->logical_mask); if (copy_to_user(info_ptr, &info, sizeof(info))) return -EFAULT; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index aa2a7eccfb94..0179f92e0916 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -2775,14 +2775,20 @@ struct drm_i915_engine_info { /** @flags: Engine flags. */ __u64 flags; +#define I915_ENGINE_INFO_HAS_LOGICAL_INSTANCE (1 << 0) /** @capabilities: Capabilities of this engine. */ __u64 capabilities; #define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) #define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) + /** @logical_instance: Logical instance of engine */ + __u16 logical_instance; + /** @rsvd1: Reserved fields. */ - __u64 rsvd1[4]; + __u16 rsvd1[3]; + /** @rsvd2: Reserved fields. */ + __u64 rsvd2[3]; }; /** From 3897df4c0187d0f38fff6944c3beab4b6aa92a1b Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:47 -0700 Subject: [PATCH 344/554] drm/i915/guc: Introduce context parent-child relationship Introduce context parent-child relationship. Once this relationship is created all pinning / unpinning operations are directed to the parent context. The parent context is responsible for pinning all of its children and itself. This is a precursor to the full GuC multi-lrc implementation but aligns to how GuC mutli-lrc interface is defined - a single H2G is used register / deregister all of the contexts simultaneously. Subsequent patches in the series will implement the pinning / unpinning operations for parent / child contexts. v2: (Daniel Vetter) - Add kernel doc, add wrapper to access parent to ensure safety v3: (John Harrison) - Fix comment explaing GEM_BUG_ON in to_parent() - Make variable names generic (non-GuC specific) v4: (John Harrison) - s/its'/its/g Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-8-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 29 +++++++++++++ drivers/gpu/drm/i915/gt/intel_context.h | 41 +++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_context_types.h | 21 ++++++++++ 3 files changed, 91 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 7a7cd2448277..4d95053855c9 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -403,6 +403,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine) INIT_LIST_HEAD(&ce->destroyed_link); + INIT_LIST_HEAD(&ce->parallel.child_list); + /* * Initialize fence to be complete as this is expected to be complete * unless there is a pending schedule disable outstanding. @@ -417,10 +419,17 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine) void intel_context_fini(struct intel_context *ce) { + struct intel_context *child, *next; + if (ce->timeline) intel_timeline_put(ce->timeline); i915_vm_put(ce->vm); + /* Need to put the creation ref for the children */ + if (intel_context_is_parent(ce)) + for_each_child_safe(ce, child, next) + intel_context_put(child); + mutex_destroy(&ce->pin_mutex); i915_active_fini(&ce->active); i915_sw_fence_fini(&ce->guc_state.blocked); @@ -537,6 +546,26 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce) return active; } +void intel_context_bind_parent_child(struct intel_context *parent, + struct intel_context *child) +{ + /* + * Callers responsibility to validate that this function is used + * correctly but we use GEM_BUG_ON here ensure that they do. + */ + GEM_BUG_ON(!intel_engine_uses_guc(parent->engine)); + GEM_BUG_ON(intel_context_is_pinned(parent)); + GEM_BUG_ON(intel_context_is_child(parent)); + GEM_BUG_ON(intel_context_is_pinned(child)); + GEM_BUG_ON(intel_context_is_child(child)); + GEM_BUG_ON(intel_context_is_parent(child)); + + parent->parallel.number_children++; + list_add_tail(&child->parallel.child_link, + &parent->parallel.child_list); + child->parallel.parent = parent; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_context.c" #endif diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index c41098950746..b63c10a144af 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -44,6 +44,47 @@ void intel_context_free(struct intel_context *ce); int intel_context_reconfigure_sseu(struct intel_context *ce, const struct intel_sseu sseu); +static inline bool intel_context_is_child(struct intel_context *ce) +{ + return !!ce->parallel.parent; +} + +static inline bool intel_context_is_parent(struct intel_context *ce) +{ + return !!ce->parallel.number_children; +} + +static inline bool intel_context_is_pinned(struct intel_context *ce); + +static inline struct intel_context * +intel_context_to_parent(struct intel_context *ce) +{ + if (intel_context_is_child(ce)) { + /* + * The parent holds ref count to the child so it is always safe + * for the parent to access the child, but the child has a + * pointer to the parent without a ref. To ensure this is safe + * the child should only access the parent pointer while the + * parent is pinned. + */ + GEM_BUG_ON(!intel_context_is_pinned(ce->parallel.parent)); + + return ce->parallel.parent; + } else { + return ce; + } +} + +void intel_context_bind_parent_child(struct intel_context *parent, + struct intel_context *child); + +#define for_each_child(parent, ce)\ + list_for_each_entry(ce, &(parent)->parallel.child_list,\ + parallel.child_link) +#define for_each_child_safe(parent, ce, cn)\ + list_for_each_entry_safe(ce, cn, &(parent)->parallel.child_list,\ + parallel.child_link) + /** * intel_context_lock_pinned - Stablises the 'pinned' status of the HW context * @ce - the context diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 4613d027cbc3..76dfca57cb45 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -220,6 +220,27 @@ struct intel_context { */ struct list_head destroyed_link; + /** @parallel: sub-structure for parallel submission members */ + struct { + union { + /** + * @child_list: parent's list of children + * contexts, no protection as immutable after context + * creation + */ + struct list_head child_list; + /** + * @child_link: child's link into parent's list of + * children + */ + struct list_head child_link; + }; + /** @parent: pointer to parent if child */ + struct intel_context *parent; + /** @number_children: number of children if parent */ + u8 number_children; + } parallel; + #ifdef CONFIG_DRM_I915_SELFTEST /** * @drop_schedule_enable: Force drop of schedule enable G2H for selftest From c2aa552ff09daf78944f44e98d366009b27f1b63 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:48 -0700 Subject: [PATCH 345/554] drm/i915/guc: Add multi-lrc context registration Add multi-lrc context registration H2G. In addition a workqueue and process descriptor are setup during multi-lrc context registration as these data structures are needed for multi-lrc submission. v2: (John Harrison) - Move GuC specific fields into sub-struct - Clean up WQ defines - Add comment explaining math to derive WQ / PD address v3: (John Harrison) - Add PARENT_SCRATCH_SIZE define - Update comment explaining multi-lrc register v4: (John Harrison) - Move PARENT_SCRATCH_SIZE to common file Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-9-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.h | 2 + drivers/gpu/drm/i915/gt/intel_context_types.h | 12 ++ drivers/gpu/drm/i915/gt/intel_lrc.c | 5 + .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h | 1 + drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 2 - .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 115 +++++++++++++++++- 6 files changed, 134 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index b63c10a144af..9f0995150a7a 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -44,6 +44,8 @@ void intel_context_free(struct intel_context *ce); int intel_context_reconfigure_sseu(struct intel_context *ce, const struct intel_sseu sseu); +#define PARENT_SCRATCH_SIZE PAGE_SIZE + static inline bool intel_context_is_child(struct intel_context *ce) { return !!ce->parallel.parent; diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 76dfca57cb45..48decb5ee954 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -239,6 +239,18 @@ struct intel_context { struct intel_context *parent; /** @number_children: number of children if parent */ u8 number_children; + /** @guc: GuC specific members for parallel submission */ + struct { + /** @wqi_head: head pointer in work queue */ + u16 wqi_head; + /** @wqi_tail: tail pointer in work queue */ + u16 wqi_tail; + /** + * @parent_page: page in context state (ce->state) used + * by parent for work queue, process descriptor + */ + u8 parent_page; + } guc; } parallel; #ifdef CONFIG_DRM_I915_SELFTEST diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 3ef9eaf8c50e..56156cf18c41 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -942,6 +942,11 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) context_size += PAGE_SIZE; } + if (intel_context_is_parent(ce) && intel_engine_uses_guc(engine)) { + ce->parallel.guc.parent_page = context_size / PAGE_SIZE; + context_size += PARENT_SCRATCH_SIZE; + } + obj = i915_gem_object_create_lmem(engine->i915, context_size, I915_BO_ALLOC_PM_VOLATILE); if (IS_ERR(obj)) diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h index 8ff582222aff..ba10bd374cee 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h @@ -142,6 +142,7 @@ enum intel_guc_action { INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER = 0x4505, INTEL_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER = 0x4506, INTEL_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600, + INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601, INTEL_GUC_ACTION_RESET_CLIENT = 0x5507, INTEL_GUC_ACTION_LIMIT }; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index fa4be13c8854..0eeb2a9feeed 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -52,8 +52,6 @@ #define GUC_DOORBELL_INVALID 256 -#define GUC_WQ_SIZE (PAGE_SIZE * 2) - /* Work queue item header definitions */ #define WQ_STATUS_ACTIVE 1 #define WQ_STATUS_SUSPENDED 2 diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index fd6594bc1b96..d9f5be00e586 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -344,6 +344,46 @@ static inline struct i915_priolist *to_priolist(struct rb_node *rb) return rb_entry(rb, struct i915_priolist, node); } +/* + * When using multi-lrc submission a scratch memory area is reserved in the + * parent's context state for the process descriptor and work queue. Currently + * the scratch area is sized to a page. + * + * The layout of this scratch area is below: + * 0 guc_process_desc + * ... unused + * PARENT_SCRATCH_SIZE / 2 work queue start + * ... work queue + * PARENT_SCRATCH_SIZE - 1 work queue end + */ +#define WQ_SIZE (PARENT_SCRATCH_SIZE / 2) +#define WQ_OFFSET (PARENT_SCRATCH_SIZE - WQ_SIZE) +static u32 __get_process_desc_offset(struct intel_context *ce) +{ + GEM_BUG_ON(!ce->parallel.guc.parent_page); + + return ce->parallel.guc.parent_page * PAGE_SIZE; +} + +static u32 __get_wq_offset(struct intel_context *ce) +{ + return __get_process_desc_offset(ce) + WQ_OFFSET; +} + +static struct guc_process_desc * +__get_process_desc(struct intel_context *ce) +{ + /* + * Need to subtract LRC_STATE_OFFSET here as the + * parallel.guc.parent_page is the offset into ce->state while + * ce->lrc_reg_reg is ce->state + LRC_STATE_OFFSET. + */ + return (struct guc_process_desc *) + (ce->lrc_reg_state + + ((__get_process_desc_offset(ce) - + LRC_STATE_OFFSET) / sizeof(u32))); +} + static struct guc_lrc_desc *__get_lrc_desc(struct intel_guc *guc, u32 index) { struct guc_lrc_desc *base = guc->lrc_desc_pool_vaddr; @@ -1365,6 +1405,30 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce) spin_unlock_irqrestore(&guc->submission_state.lock, flags); } +static int __guc_action_register_multi_lrc(struct intel_guc *guc, + struct intel_context *ce, + u32 guc_id, + u32 offset, + bool loop) +{ + struct intel_context *child; + u32 action[4 + MAX_ENGINE_INSTANCE]; + int len = 0; + + GEM_BUG_ON(ce->parallel.number_children > MAX_ENGINE_INSTANCE); + + action[len++] = INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC; + action[len++] = guc_id; + action[len++] = ce->parallel.number_children + 1; + action[len++] = offset; + for_each_child(ce, child) { + offset += sizeof(struct guc_lrc_desc); + action[len++] = offset; + } + + return guc_submission_send_busy_loop(guc, action, len, 0, loop); +} + static int __guc_action_register_context(struct intel_guc *guc, u32 guc_id, u32 offset, @@ -1387,9 +1451,15 @@ static int register_context(struct intel_context *ce, bool loop) ce->guc_id.id * sizeof(struct guc_lrc_desc); int ret; + GEM_BUG_ON(intel_context_is_child(ce)); trace_intel_context_register(ce); - ret = __guc_action_register_context(guc, ce->guc_id.id, offset, loop); + if (intel_context_is_parent(ce)) + ret = __guc_action_register_multi_lrc(guc, ce, ce->guc_id.id, + offset, loop); + else + ret = __guc_action_register_context(guc, ce->guc_id.id, offset, + loop); if (likely(!ret)) { unsigned long flags; @@ -1418,6 +1488,7 @@ static int deregister_context(struct intel_context *ce, u32 guc_id) { struct intel_guc *guc = ce_to_guc(ce); + GEM_BUG_ON(intel_context_is_child(ce)); trace_intel_context_deregister(ce); return __guc_action_deregister_context(guc, guc_id); @@ -1445,6 +1516,7 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop) struct guc_lrc_desc *desc; bool context_registered; intel_wakeref_t wakeref; + struct intel_context *child; int ret = 0; GEM_BUG_ON(!engine->mask); @@ -1470,6 +1542,41 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop) desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD; guc_context_policy_init(engine, desc); + /* + * If context is a parent, we need to register a process descriptor + * describing a work queue and register all child contexts. + */ + if (intel_context_is_parent(ce)) { + struct guc_process_desc *pdesc; + + ce->parallel.guc.wqi_tail = 0; + ce->parallel.guc.wqi_head = 0; + + desc->process_desc = i915_ggtt_offset(ce->state) + + __get_process_desc_offset(ce); + desc->wq_addr = i915_ggtt_offset(ce->state) + + __get_wq_offset(ce); + desc->wq_size = WQ_SIZE; + + pdesc = __get_process_desc(ce); + memset(pdesc, 0, sizeof(*(pdesc))); + pdesc->stage_id = ce->guc_id.id; + pdesc->wq_base_addr = desc->wq_addr; + pdesc->wq_size_bytes = desc->wq_size; + pdesc->wq_status = WQ_STATUS_ACTIVE; + + for_each_child(ce, child) { + desc = __get_lrc_desc(guc, child->guc_id.id); + + desc->engine_class = + engine_class_to_guc_class(engine->class); + desc->hw_context_desc = child->lrc.lrca; + desc->priority = ce->guc_state.prio; + desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD; + guc_context_policy_init(engine, desc); + } + } + /* * The context_lookup xarray is used to determine if the hardware * context is currently registered. There are two cases in which it @@ -2804,6 +2911,12 @@ g2h_context_lookup(struct intel_guc *guc, u32 desc_idx) return NULL; } + if (unlikely(intel_context_is_child(ce))) { + drm_err(&guc_to_gt(guc)->i915->drm, + "Context is child, desc_idx %u", desc_idx); + return NULL; + } + return ce; } From 44d25fec1a5d9615fab25fa90a3e70eef21e5d05 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:49 -0700 Subject: [PATCH 346/554] drm/i915/guc: Ensure GuC schedule operations do not operate on child contexts In GuC parent-child contexts the parent context controls the scheduling, ensure only the parent does the scheduling operations. Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-10-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index d9f5be00e586..fbcf2dc2b2de 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -324,6 +324,12 @@ static inline void decr_context_committed_requests(struct intel_context *ce) GEM_BUG_ON(ce->guc_state.number_committed_requests < 0); } +static struct intel_context * +request_to_scheduling_context(struct i915_request *rq) +{ + return intel_context_to_parent(rq->context); +} + static inline bool context_guc_id_invalid(struct intel_context *ce) { return ce->guc_id.id == GUC_INVALID_LRC_ID; @@ -1711,6 +1717,7 @@ static void __guc_context_sched_disable(struct intel_guc *guc, GEM_BUG_ON(guc_id == GUC_INVALID_LRC_ID); + GEM_BUG_ON(intel_context_is_child(ce)); trace_intel_context_sched_disable(ce); guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), @@ -1936,6 +1943,8 @@ static void guc_context_sched_disable(struct intel_context *ce) intel_wakeref_t wakeref; u16 guc_id; + GEM_BUG_ON(intel_context_is_child(ce)); + spin_lock_irqsave(&ce->guc_state.lock, flags); /* @@ -2304,6 +2313,8 @@ static void guc_signal_context_fence(struct intel_context *ce) { unsigned long flags; + GEM_BUG_ON(intel_context_is_child(ce)); + spin_lock_irqsave(&ce->guc_state.lock, flags); clr_context_wait_for_deregister_to_register(ce); __guc_signal_context_fence(ce); @@ -2334,7 +2345,7 @@ static void guc_context_init(struct intel_context *ce) static int guc_request_alloc(struct i915_request *rq) { - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); struct intel_guc *guc = ce_to_guc(ce); unsigned long flags; int ret; From 09c5e3a5e509bb10249c8252dc10c0d8a842e4ae Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:50 -0700 Subject: [PATCH 347/554] drm/i915/guc: Assign contexts in parent-child relationship consecutive guc_ids Assign contexts in parent-child relationship consecutive guc_ids. This is accomplished by partitioning guc_id space between ones that need to be consecutive (1/16 available guc_ids) and ones that do not (15/16 of available guc_ids). The consecutive search is implemented via the bitmap API. This is a precursor to the full GuC multi-lrc implementation but aligns to how GuC mutli-lrc interface is defined - guc_ids must be consecutive when using the GuC multi-lrc interface. v2: (Daniel Vetter) - Explicitly state why we assign consecutive guc_ids v3: (John Harrison) - Bring back in spin lock Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-11-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 6 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 104 ++++++++++++++---- 2 files changed, 86 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 74f071a0b6d5..4ca197f400ba 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -82,9 +82,13 @@ struct intel_guc { */ spinlock_t lock; /** - * @guc_ids: used to allocate new guc_ids + * @guc_ids: used to allocate new guc_ids, single-lrc */ struct ida guc_ids; + /** + * @guc_ids_bitmap: used to allocate new guc_ids, multi-lrc + */ + unsigned long *guc_ids_bitmap; /** * @guc_id_list: list of intel_context with valid guc_ids but no * refs diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index fbcf2dc2b2de..7ba4f1d6f69c 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -128,6 +128,16 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count); #define GUC_REQUEST_SIZE 64 /* bytes */ +/* + * We reserve 1/16 of the guc_ids for multi-lrc as these need to be contiguous + * per the GuC submission interface. A different allocation algorithm is used + * (bitmap vs. ida) between multi-lrc and single-lrc hence the reason to + * partition the guc_id space. We believe the number of multi-lrc contexts in + * use should be low and 1/16 should be sufficient. Minimum of 32 guc_ids for + * multi-lrc. + */ +#define NUMBER_MULTI_LRC_GUC_ID (GUC_MAX_LRC_DESCRIPTORS / 16) + /* * Below is a set of functions which control the GuC scheduling state which * require a lock. @@ -1207,6 +1217,11 @@ int intel_guc_submission_init(struct intel_guc *guc) INIT_WORK(&guc->submission_state.destroyed_worker, destroyed_worker_func); + guc->submission_state.guc_ids_bitmap = + bitmap_zalloc(NUMBER_MULTI_LRC_GUC_ID, GFP_KERNEL); + if (!guc->submission_state.guc_ids_bitmap) + return -ENOMEM; + return 0; } @@ -1218,6 +1233,7 @@ void intel_guc_submission_fini(struct intel_guc *guc) guc_flush_destroyed_contexts(guc); guc_lrc_desc_pool_destroy(guc); i915_sched_engine_put(guc->sched_engine); + bitmap_free(guc->submission_state.guc_ids_bitmap); } static inline void queue_request(struct i915_sched_engine *sched_engine, @@ -1269,18 +1285,43 @@ static void guc_submit_request(struct i915_request *rq) spin_unlock_irqrestore(&sched_engine->lock, flags); } -static int new_guc_id(struct intel_guc *guc) +static int new_guc_id(struct intel_guc *guc, struct intel_context *ce) { - return ida_simple_get(&guc->submission_state.guc_ids, 0, - GUC_MAX_LRC_DESCRIPTORS, GFP_KERNEL | - __GFP_RETRY_MAYFAIL | __GFP_NOWARN); + int ret; + + GEM_BUG_ON(intel_context_is_child(ce)); + + if (intel_context_is_parent(ce)) + ret = bitmap_find_free_region(guc->submission_state.guc_ids_bitmap, + NUMBER_MULTI_LRC_GUC_ID, + order_base_2(ce->parallel.number_children + + 1)); + else + ret = ida_simple_get(&guc->submission_state.guc_ids, + NUMBER_MULTI_LRC_GUC_ID, + GUC_MAX_LRC_DESCRIPTORS, + GFP_KERNEL | __GFP_RETRY_MAYFAIL | + __GFP_NOWARN); + if (unlikely(ret < 0)) + return ret; + + ce->guc_id.id = ret; + return 0; } static void __release_guc_id(struct intel_guc *guc, struct intel_context *ce) { + GEM_BUG_ON(intel_context_is_child(ce)); + if (!context_guc_id_invalid(ce)) { - ida_simple_remove(&guc->submission_state.guc_ids, - ce->guc_id.id); + if (intel_context_is_parent(ce)) + bitmap_release_region(guc->submission_state.guc_ids_bitmap, + ce->guc_id.id, + order_base_2(ce->parallel.number_children + + 1)); + else + ida_simple_remove(&guc->submission_state.guc_ids, + ce->guc_id.id); reset_lrc_desc(guc, ce->guc_id.id); set_context_guc_id_invalid(ce); } @@ -1297,49 +1338,64 @@ static void release_guc_id(struct intel_guc *guc, struct intel_context *ce) spin_unlock_irqrestore(&guc->submission_state.lock, flags); } -static int steal_guc_id(struct intel_guc *guc) +static int steal_guc_id(struct intel_guc *guc, struct intel_context *ce) { - struct intel_context *ce; - int guc_id; + struct intel_context *cn; lockdep_assert_held(&guc->submission_state.lock); + GEM_BUG_ON(intel_context_is_child(ce)); + GEM_BUG_ON(intel_context_is_parent(ce)); if (!list_empty(&guc->submission_state.guc_id_list)) { - ce = list_first_entry(&guc->submission_state.guc_id_list, + cn = list_first_entry(&guc->submission_state.guc_id_list, struct intel_context, guc_id.link); - GEM_BUG_ON(atomic_read(&ce->guc_id.ref)); - GEM_BUG_ON(context_guc_id_invalid(ce)); + GEM_BUG_ON(atomic_read(&cn->guc_id.ref)); + GEM_BUG_ON(context_guc_id_invalid(cn)); + GEM_BUG_ON(intel_context_is_child(cn)); + GEM_BUG_ON(intel_context_is_parent(cn)); - list_del_init(&ce->guc_id.link); - guc_id = ce->guc_id.id; + list_del_init(&cn->guc_id.link); + ce->guc_id = cn->guc_id; spin_lock(&ce->guc_state.lock); - clr_context_registered(ce); + clr_context_registered(cn); spin_unlock(&ce->guc_state.lock); - set_context_guc_id_invalid(ce); - return guc_id; + set_context_guc_id_invalid(cn); + + return 0; } else { return -EAGAIN; } } -static int assign_guc_id(struct intel_guc *guc, u16 *out) +static int assign_guc_id(struct intel_guc *guc, struct intel_context *ce) { int ret; lockdep_assert_held(&guc->submission_state.lock); + GEM_BUG_ON(intel_context_is_child(ce)); - ret = new_guc_id(guc); + ret = new_guc_id(guc, ce); if (unlikely(ret < 0)) { - ret = steal_guc_id(guc); + if (intel_context_is_parent(ce)) + return -ENOSPC; + + ret = steal_guc_id(guc, ce); if (ret < 0) return ret; } - *out = ret; + if (intel_context_is_parent(ce)) { + struct intel_context *child; + int i = 1; + + for_each_child(ce, child) + child->guc_id.id = ce->guc_id.id + i++; + } + return 0; } @@ -1357,7 +1413,7 @@ try_again: might_lock(&ce->guc_state.lock); if (context_guc_id_invalid(ce)) { - ret = assign_guc_id(guc, &ce->guc_id.id); + ret = assign_guc_id(guc, ce); if (ret) goto out_unlock; ret = 1; /* Indidcates newly assigned guc_id */ @@ -1399,8 +1455,10 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce) unsigned long flags; GEM_BUG_ON(atomic_read(&ce->guc_id.ref) < 0); + GEM_BUG_ON(intel_context_is_child(ce)); - if (unlikely(context_guc_id_invalid(ce))) + if (unlikely(context_guc_id_invalid(ce) || + intel_context_is_parent(ce))) return; spin_lock_irqsave(&guc->submission_state.lock, flags); From 99b47aaddfa985681496366e131daa69e282bb2a Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:51 -0700 Subject: [PATCH 348/554] drm/i915/guc: Implement parallel context pin / unpin functions Parallel contexts are perma-pinned by the upper layers which makes the backend implementation rather simple. The parent pins the guc_id and children increment the parent's pin count on pin to ensure all the contexts are unpinned before we disable scheduling with the GuC / or deregister the context. v2: (Daniel Vetter) - Perma-pin parallel contexts Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-12-matthew.brost@intel.com --- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 7ba4f1d6f69c..a412593342db 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2584,6 +2584,76 @@ static const struct intel_context_ops virtual_guc_context_ops = { .get_sibling = guc_virtual_get_sibling, }; +/* Future patches will use this function */ +__maybe_unused +static int guc_parent_context_pin(struct intel_context *ce, void *vaddr) +{ + struct intel_engine_cs *engine = guc_virtual_get_sibling(ce->engine, 0); + struct intel_guc *guc = ce_to_guc(ce); + int ret; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + + ret = pin_guc_id(guc, ce); + if (unlikely(ret < 0)) + return ret; + + return __guc_context_pin(ce, engine, vaddr); +} + +/* Future patches will use this function */ +__maybe_unused +static int guc_child_context_pin(struct intel_context *ce, void *vaddr) +{ + struct intel_engine_cs *engine = guc_virtual_get_sibling(ce->engine, 0); + + GEM_BUG_ON(!intel_context_is_child(ce)); + GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + + __intel_context_pin(ce->parallel.parent); + return __guc_context_pin(ce, engine, vaddr); +} + +/* Future patches will use this function */ +__maybe_unused +static void guc_parent_context_unpin(struct intel_context *ce) +{ + struct intel_guc *guc = ce_to_guc(ce); + + GEM_BUG_ON(context_enabled(ce)); + GEM_BUG_ON(intel_context_is_barrier(ce)); + GEM_BUG_ON(!intel_context_is_parent(ce)); + GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + + unpin_guc_id(guc, ce); + lrc_unpin(ce); +} + +/* Future patches will use this function */ +__maybe_unused +static void guc_child_context_unpin(struct intel_context *ce) +{ + GEM_BUG_ON(context_enabled(ce)); + GEM_BUG_ON(intel_context_is_barrier(ce)); + GEM_BUG_ON(!intel_context_is_child(ce)); + GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + + lrc_unpin(ce); +} + +/* Future patches will use this function */ +__maybe_unused +static void guc_child_context_post_unpin(struct intel_context *ce) +{ + GEM_BUG_ON(!intel_context_is_child(ce)); + GEM_BUG_ON(!intel_context_is_pinned(ce->parallel.parent)); + GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + + lrc_post_unpin(ce); + intel_context_unpin(ce->parallel.parent); +} + static bool guc_irq_enable_breadcrumbs(struct intel_breadcrumbs *b) { From 6b540bf6f14362a912fd79e0e200bf4fa2b6b547 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:52 -0700 Subject: [PATCH 349/554] drm/i915/guc: Implement multi-lrc submission Implement multi-lrc submission via a single workqueue entry and single H2G. The workqueue entry contains an updated tail value for each request, of all the contexts in the multi-lrc submission, and updates these values simultaneously. As such, the tasklet and bypass path have been updated to coalesce requests into a single submission. v2: (John Harrison) - s/wqe/wqi - Use FIELD_PREP macros - Add GEM_BUG_ONs ensures length fits within field - Add comment / white space to intel_guc_write_barrier (Kernel test robot) - Make need_tasklet a static function v3: (Docs) - A comment for submission_stall_reason v4: (Kernel test robot) - Initialize return value in bypass tasklt submit function (John Harrison) - Add comment near work queue defs - Add BUILD_BUG_ON to ensure WQ_SIZE is a power of 2 - Update write_barrier comment to talk about work queue v5: (John Harrison) - Fix typo in work queue comment Reviewed-by: John Harrison Signed-off-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-13-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc.c | 29 ++ drivers/gpu/drm/i915/gt/uc/intel_guc.h | 11 + drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 24 +- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 28 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 323 +++++++++++++++--- drivers/gpu/drm/i915/i915_request.h | 8 + 6 files changed, 349 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 8f8182bf7c11..6e228343e8cb 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -756,3 +756,32 @@ void intel_guc_load_status(struct intel_guc *guc, struct drm_printer *p) } } } + +void intel_guc_write_barrier(struct intel_guc *guc) +{ + struct intel_gt *gt = guc_to_gt(guc); + + if (i915_gem_object_is_lmem(guc->ct.vma->obj)) { + /* + * Ensure intel_uncore_write_fw can be used rather than + * intel_uncore_write. + */ + GEM_BUG_ON(guc->send_regs.fw_domains); + + /* + * This register is used by the i915 and GuC for MMIO based + * communication. Once we are in this code CTBs are the only + * method the i915 uses to communicate with the GuC so it is + * safe to write to this register (a value of 0 is NOP for MMIO + * communication). If we ever start mixing CTBs and MMIOs a new + * register will have to be chosen. This function is also used + * to enforce ordering of a work queue item write and an update + * to the process descriptor. When a work queue is being used, + * CTBs are also the only mechanism of communication. + */ + intel_uncore_write_fw(gt->uncore, GEN11_SOFT_SCRATCH(0), 0); + } else { + /* wmb() sufficient for a barrier if in smem */ + wmb(); + } +} diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 4ca197f400ba..31cf9fb48c7e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -46,6 +46,15 @@ struct intel_guc { * submitted until the stalled request is processed. */ struct i915_request *stalled_request; + /** + * @submission_stall_reason: reason why submission is stalled + */ + enum { + STALL_NONE, + STALL_REGISTER_CONTEXT, + STALL_MOVE_LRC_TAIL, + STALL_ADD_REQUEST, + } submission_stall_reason; /* intel_guc_recv interrupt related state */ /** @irq_lock: protects GuC irq state */ @@ -367,4 +376,6 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc); void intel_guc_load_status(struct intel_guc *guc, struct drm_printer *p); +void intel_guc_write_barrier(struct intel_guc *guc); + #endif diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 0a3504bc0b61..a0cc34be7b56 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -383,28 +383,6 @@ static u32 ct_get_next_fence(struct intel_guc_ct *ct) return ++ct->requests.last_fence; } -static void write_barrier(struct intel_guc_ct *ct) -{ - struct intel_guc *guc = ct_to_guc(ct); - struct intel_gt *gt = guc_to_gt(guc); - - if (i915_gem_object_is_lmem(guc->ct.vma->obj)) { - GEM_BUG_ON(guc->send_regs.fw_domains); - /* - * This register is used by the i915 and GuC for MMIO based - * communication. Once we are in this code CTBs are the only - * method the i915 uses to communicate with the GuC so it is - * safe to write to this register (a value of 0 is NOP for MMIO - * communication). If we ever start mixing CTBs and MMIOs a new - * register will have to be chosen. - */ - intel_uncore_write_fw(gt->uncore, GEN11_SOFT_SCRATCH(0), 0); - } else { - /* wmb() sufficient for a barrier if in smem */ - wmb(); - } -} - static int ct_write(struct intel_guc_ct *ct, const u32 *action, u32 len /* in dwords */, @@ -474,7 +452,7 @@ static int ct_write(struct intel_guc_ct *ct, * make sure H2G buffer update and LRC tail update (if this triggering a * submission) are visible before updating the descriptor tail */ - write_barrier(ct); + intel_guc_write_barrier(ct_to_guc(ct)); /* update local copies */ ctb->tail = tail; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 0eeb2a9feeed..18da67cfcd92 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -52,25 +52,27 @@ #define GUC_DOORBELL_INVALID 256 -/* Work queue item header definitions */ +/* + * Work queue item header definitions + * + * Work queue is circular buffer used to submit complex (multi-lrc) submissions + * to the GuC. A work queue item is an entry in the circular buffer. + */ #define WQ_STATUS_ACTIVE 1 #define WQ_STATUS_SUSPENDED 2 #define WQ_STATUS_CMD_ERROR 3 #define WQ_STATUS_ENGINE_ID_NOT_USED 4 #define WQ_STATUS_SUSPENDED_FROM_RESET 5 -#define WQ_TYPE_SHIFT 0 -#define WQ_TYPE_BATCH_BUF (0x1 << WQ_TYPE_SHIFT) -#define WQ_TYPE_PSEUDO (0x2 << WQ_TYPE_SHIFT) -#define WQ_TYPE_INORDER (0x3 << WQ_TYPE_SHIFT) -#define WQ_TYPE_NOOP (0x4 << WQ_TYPE_SHIFT) -#define WQ_TARGET_SHIFT 10 -#define WQ_LEN_SHIFT 16 -#define WQ_NO_WCFLUSH_WAIT (1 << 27) -#define WQ_PRESENT_WORKLOAD (1 << 28) +#define WQ_TYPE_BATCH_BUF 0x1 +#define WQ_TYPE_PSEUDO 0x2 +#define WQ_TYPE_INORDER 0x3 +#define WQ_TYPE_NOOP 0x4 +#define WQ_TYPE_MULTI_LRC 0x5 +#define WQ_TYPE_MASK GENMASK(7, 0) +#define WQ_LEN_MASK GENMASK(26, 16) -#define WQ_RING_TAIL_SHIFT 20 -#define WQ_RING_TAIL_MAX 0x7FF /* 2^11 QWords */ -#define WQ_RING_TAIL_MASK (WQ_RING_TAIL_MAX << WQ_RING_TAIL_SHIFT) +#define WQ_GUC_ID_MASK GENMASK(15, 0) +#define WQ_RING_TAIL_MASK GENMASK(28, 18) #define GUC_STAGE_DESC_ATTR_ACTIVE BIT(0) #define GUC_STAGE_DESC_ATTR_PENDING_DB BIT(1) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index a412593342db..71ae5eb69849 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -400,6 +400,29 @@ __get_process_desc(struct intel_context *ce) LRC_STATE_OFFSET) / sizeof(u32))); } +static u32 *get_wq_pointer(struct guc_process_desc *desc, + struct intel_context *ce, + u32 wqi_size) +{ + /* + * Check for space in work queue. Caching a value of head pointer in + * intel_context structure in order reduce the number accesses to shared + * GPU memory which may be across a PCIe bus. + */ +#define AVAILABLE_SPACE \ + CIRC_SPACE(ce->parallel.guc.wqi_tail, ce->parallel.guc.wqi_head, WQ_SIZE) + if (wqi_size > AVAILABLE_SPACE) { + ce->parallel.guc.wqi_head = READ_ONCE(desc->head); + + if (wqi_size > AVAILABLE_SPACE) + return NULL; + } +#undef AVAILABLE_SPACE + + return ((u32 *)__get_process_desc(ce)) + + ((WQ_OFFSET + ce->parallel.guc.wqi_tail) / sizeof(u32)); +} + static struct guc_lrc_desc *__get_lrc_desc(struct intel_guc *guc, u32 index) { struct guc_lrc_desc *base = guc->lrc_desc_pool_vaddr; @@ -559,10 +582,10 @@ int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout) static int guc_lrc_desc_pin(struct intel_context *ce, bool loop); -static int guc_add_request(struct intel_guc *guc, struct i915_request *rq) +static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq) { int err = 0; - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); u32 action[3]; int len = 0; u32 g2h_len_dw = 0; @@ -583,26 +606,17 @@ static int guc_add_request(struct intel_guc *guc, struct i915_request *rq) GEM_BUG_ON(!atomic_read(&ce->guc_id.ref)); GEM_BUG_ON(context_guc_id_invalid(ce)); - /* - * Corner case where the GuC firmware was blown away and reloaded while - * this context was pinned. - */ - if (unlikely(!lrc_desc_registered(guc, ce->guc_id.id))) { - err = guc_lrc_desc_pin(ce, false); - if (unlikely(err)) - return err; - } - spin_lock(&ce->guc_state.lock); /* * The request / context will be run on the hardware when scheduling - * gets enabled in the unblock. + * gets enabled in the unblock. For multi-lrc we still submit the + * context to move the LRC tails. */ - if (unlikely(context_blocked(ce))) + if (unlikely(context_blocked(ce) && !intel_context_is_parent(ce))) goto out; - enabled = context_enabled(ce); + enabled = context_enabled(ce) || context_blocked(ce); if (!enabled) { action[len++] = INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_SET; @@ -621,6 +635,18 @@ static int guc_add_request(struct intel_guc *guc, struct i915_request *rq) trace_intel_context_sched_enable(ce); atomic_inc(&guc->outstanding_submission_g2h); set_context_enabled(ce); + + /* + * Without multi-lrc KMD does the submission step (moving the + * lrc tail) so enabling scheduling is sufficient to submit the + * context. This isn't the case in multi-lrc submission as the + * GuC needs to move the tails, hence the need for another H2G + * to submit a multi-lrc context after enabling scheduling. + */ + if (intel_context_is_parent(ce)) { + action[0] = INTEL_GUC_ACTION_SCHED_CONTEXT; + err = intel_guc_send_nb(guc, action, len - 1, 0); + } } else if (!enabled) { clr_context_pending_enable(ce); intel_context_put(ce); @@ -633,6 +659,18 @@ out: return err; } +static int guc_add_request(struct intel_guc *guc, struct i915_request *rq) +{ + int ret = __guc_add_request(guc, rq); + + if (unlikely(ret == -EBUSY)) { + guc->stalled_request = rq; + guc->submission_stall_reason = STALL_ADD_REQUEST; + } + + return ret; +} + static inline void guc_set_lrc_tail(struct i915_request *rq) { rq->context->lrc_reg_state[CTX_RING_TAIL] = @@ -644,6 +682,136 @@ static inline int rq_prio(const struct i915_request *rq) return rq->sched.attr.priority; } +static bool is_multi_lrc_rq(struct i915_request *rq) +{ + return intel_context_is_child(rq->context) || + intel_context_is_parent(rq->context); +} + +static bool can_merge_rq(struct i915_request *rq, + struct i915_request *last) +{ + return request_to_scheduling_context(rq) == + request_to_scheduling_context(last); +} + +static u32 wq_space_until_wrap(struct intel_context *ce) +{ + return (WQ_SIZE - ce->parallel.guc.wqi_tail); +} + +static void write_wqi(struct guc_process_desc *desc, + struct intel_context *ce, + u32 wqi_size) +{ + BUILD_BUG_ON(!is_power_of_2(WQ_SIZE)); + + /* + * Ensure WQI are visible before updating tail + */ + intel_guc_write_barrier(ce_to_guc(ce)); + + ce->parallel.guc.wqi_tail = (ce->parallel.guc.wqi_tail + wqi_size) & + (WQ_SIZE - 1); + WRITE_ONCE(desc->tail, ce->parallel.guc.wqi_tail); +} + +static int guc_wq_noop_append(struct intel_context *ce) +{ + struct guc_process_desc *desc = __get_process_desc(ce); + u32 *wqi = get_wq_pointer(desc, ce, wq_space_until_wrap(ce)); + u32 len_dw = wq_space_until_wrap(ce) / sizeof(u32) - 1; + + if (!wqi) + return -EBUSY; + + GEM_BUG_ON(!FIELD_FIT(WQ_LEN_MASK, len_dw)); + + *wqi = FIELD_PREP(WQ_TYPE_MASK, WQ_TYPE_NOOP) | + FIELD_PREP(WQ_LEN_MASK, len_dw); + ce->parallel.guc.wqi_tail = 0; + + return 0; +} + +static int __guc_wq_item_append(struct i915_request *rq) +{ + struct intel_context *ce = request_to_scheduling_context(rq); + struct intel_context *child; + struct guc_process_desc *desc = __get_process_desc(ce); + unsigned int wqi_size = (ce->parallel.number_children + 4) * + sizeof(u32); + u32 *wqi; + u32 len_dw = (wqi_size / sizeof(u32)) - 1; + int ret; + + /* Ensure context is in correct state updating work queue */ + GEM_BUG_ON(!atomic_read(&ce->guc_id.ref)); + GEM_BUG_ON(context_guc_id_invalid(ce)); + GEM_BUG_ON(context_wait_for_deregister_to_register(ce)); + GEM_BUG_ON(!lrc_desc_registered(ce_to_guc(ce), ce->guc_id.id)); + + /* Insert NOOP if this work queue item will wrap the tail pointer. */ + if (wqi_size > wq_space_until_wrap(ce)) { + ret = guc_wq_noop_append(ce); + if (ret) + return ret; + } + + wqi = get_wq_pointer(desc, ce, wqi_size); + if (!wqi) + return -EBUSY; + + GEM_BUG_ON(!FIELD_FIT(WQ_LEN_MASK, len_dw)); + + *wqi++ = FIELD_PREP(WQ_TYPE_MASK, WQ_TYPE_MULTI_LRC) | + FIELD_PREP(WQ_LEN_MASK, len_dw); + *wqi++ = ce->lrc.lrca; + *wqi++ = FIELD_PREP(WQ_GUC_ID_MASK, ce->guc_id.id) | + FIELD_PREP(WQ_RING_TAIL_MASK, ce->ring->tail / sizeof(u64)); + *wqi++ = 0; /* fence_id */ + for_each_child(ce, child) + *wqi++ = child->ring->tail / sizeof(u64); + + write_wqi(desc, ce, wqi_size); + + return 0; +} + +static int guc_wq_item_append(struct intel_guc *guc, + struct i915_request *rq) +{ + struct intel_context *ce = request_to_scheduling_context(rq); + int ret = 0; + + if (likely(!intel_context_is_banned(ce))) { + ret = __guc_wq_item_append(rq); + + if (unlikely(ret == -EBUSY)) { + guc->stalled_request = rq; + guc->submission_stall_reason = STALL_MOVE_LRC_TAIL; + } + } + + return ret; +} + +static bool multi_lrc_submit(struct i915_request *rq) +{ + struct intel_context *ce = request_to_scheduling_context(rq); + + intel_ring_set_tail(rq->ring, rq->tail); + + /* + * We expect the front end (execbuf IOCTL) to set this flag on the last + * request generated from a multi-BB submission. This indicates to the + * backend (GuC interface) that we should submit this context thus + * submitting all the requests generated in parallel. + */ + return test_bit(I915_FENCE_FLAG_SUBMIT_PARALLEL, &rq->fence.flags) || + intel_context_is_banned(ce); +} + static int guc_dequeue_one_context(struct intel_guc *guc) { struct i915_sched_engine * const sched_engine = guc->sched_engine; @@ -657,7 +825,17 @@ static int guc_dequeue_one_context(struct intel_guc *guc) if (guc->stalled_request) { submit = true; last = guc->stalled_request; - goto resubmit; + + switch (guc->submission_stall_reason) { + case STALL_REGISTER_CONTEXT: + goto register_context; + case STALL_MOVE_LRC_TAIL: + goto move_lrc_tail; + case STALL_ADD_REQUEST: + goto add_request; + default: + MISSING_CASE(guc->submission_stall_reason); + } } while ((rb = rb_first_cached(&sched_engine->queue))) { @@ -665,8 +843,8 @@ static int guc_dequeue_one_context(struct intel_guc *guc) struct i915_request *rq, *rn; priolist_for_each_request_consume(rq, rn, p) { - if (last && rq->context != last->context) - goto done; + if (last && !can_merge_rq(rq, last)) + goto register_context; list_del_init(&rq->sched.link); @@ -674,33 +852,84 @@ static int guc_dequeue_one_context(struct intel_guc *guc) trace_i915_request_in(rq, 0); last = rq; - submit = true; + + if (is_multi_lrc_rq(rq)) { + /* + * We need to coalesce all multi-lrc requests in + * a relationship into a single H2G. We are + * guaranteed that all of these requests will be + * submitted sequentially. + */ + if (multi_lrc_submit(rq)) { + submit = true; + goto register_context; + } + } else { + submit = true; + } } rb_erase_cached(&p->node, &sched_engine->queue); i915_priolist_free(p); } -done: + +register_context: if (submit) { - guc_set_lrc_tail(last); -resubmit: + struct intel_context *ce = request_to_scheduling_context(last); + + if (unlikely(!lrc_desc_registered(guc, ce->guc_id.id) && + !intel_context_is_banned(ce))) { + ret = guc_lrc_desc_pin(ce, false); + if (unlikely(ret == -EPIPE)) { + goto deadlk; + } else if (ret == -EBUSY) { + guc->stalled_request = last; + guc->submission_stall_reason = + STALL_REGISTER_CONTEXT; + goto schedule_tasklet; + } else if (ret != 0) { + GEM_WARN_ON(ret); /* Unexpected */ + goto deadlk; + } + } + +move_lrc_tail: + if (is_multi_lrc_rq(last)) { + ret = guc_wq_item_append(guc, last); + if (ret == -EBUSY) { + goto schedule_tasklet; + } else if (ret != 0) { + GEM_WARN_ON(ret); /* Unexpected */ + goto deadlk; + } + } else { + guc_set_lrc_tail(last); + } + +add_request: ret = guc_add_request(guc, last); - if (unlikely(ret == -EPIPE)) + if (unlikely(ret == -EPIPE)) { + goto deadlk; + } else if (ret == -EBUSY) { + goto schedule_tasklet; + } else if (ret != 0) { + GEM_WARN_ON(ret); /* Unexpected */ goto deadlk; - else if (ret == -EBUSY) { - tasklet_schedule(&sched_engine->tasklet); - guc->stalled_request = last; - return false; } } guc->stalled_request = NULL; + guc->submission_stall_reason = STALL_NONE; return submit; deadlk: sched_engine->tasklet.callback = NULL; tasklet_disable_nosync(&sched_engine->tasklet); return false; + +schedule_tasklet: + tasklet_schedule(&sched_engine->tasklet); + return false; } static void guc_submission_tasklet(struct tasklet_struct *t) @@ -1250,16 +1479,22 @@ static inline void queue_request(struct i915_sched_engine *sched_engine, static int guc_bypass_tasklet_submit(struct intel_guc *guc, struct i915_request *rq) { - int ret; + int ret = 0; __i915_request_submit(rq); trace_i915_request_in(rq, 0); - guc_set_lrc_tail(rq); - ret = guc_add_request(guc, rq); - if (ret == -EBUSY) - guc->stalled_request = rq; + if (is_multi_lrc_rq(rq)) { + if (multi_lrc_submit(rq)) { + ret = guc_wq_item_append(guc, rq); + if (!ret) + ret = guc_add_request(guc, rq); + } + } else { + guc_set_lrc_tail(rq); + ret = guc_add_request(guc, rq); + } if (unlikely(ret == -EPIPE)) disable_submission(guc); @@ -1267,6 +1502,16 @@ static int guc_bypass_tasklet_submit(struct intel_guc *guc, return ret; } +static bool need_tasklet(struct intel_guc *guc, struct i915_request *rq) +{ + struct i915_sched_engine *sched_engine = rq->engine->sched_engine; + struct intel_context *ce = request_to_scheduling_context(rq); + + return submission_disabled(guc) || guc->stalled_request || + !i915_sched_engine_is_empty(sched_engine) || + !lrc_desc_registered(guc, ce->guc_id.id); +} + static void guc_submit_request(struct i915_request *rq) { struct i915_sched_engine *sched_engine = rq->engine->sched_engine; @@ -1276,8 +1521,7 @@ static void guc_submit_request(struct i915_request *rq) /* Will be called from irq-context when using foreign fences. */ spin_lock_irqsave(&sched_engine->lock, flags); - if (submission_disabled(guc) || guc->stalled_request || - !i915_sched_engine_is_empty(sched_engine)) + if (need_tasklet(guc, rq)) queue_request(sched_engine, rq, rq_prio(rq)); else if (guc_bypass_tasklet_submit(guc, rq) == -EBUSY) tasklet_hi_schedule(&sched_engine->tasklet); @@ -2259,9 +2503,10 @@ static inline bool new_guc_prio_higher(u8 old_guc_prio, u8 new_guc_prio) static void add_to_context(struct i915_request *rq) { - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); u8 new_guc_prio = map_i915_prio_to_guc_prio(rq_prio(rq)); + GEM_BUG_ON(intel_context_is_child(ce)); GEM_BUG_ON(rq->guc_prio == GUC_PRIO_FINI); spin_lock(&ce->guc_state.lock); @@ -2294,7 +2539,9 @@ static void guc_prio_fini(struct i915_request *rq, struct intel_context *ce) static void remove_from_context(struct i915_request *rq) { - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); + + GEM_BUG_ON(intel_context_is_child(ce)); spin_lock_irq(&ce->guc_state.lock); @@ -2713,7 +2960,7 @@ static void guc_init_breadcrumbs(struct intel_engine_cs *engine) static void guc_bump_inflight_request_prio(struct i915_request *rq, int prio) { - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); u8 new_guc_prio = map_i915_prio_to_guc_prio(prio); /* Short circuit function */ @@ -2736,7 +2983,7 @@ static void guc_bump_inflight_request_prio(struct i915_request *rq, static void guc_retire_inflight_request_prio(struct i915_request *rq) { - struct intel_context *ce = rq->context; + struct intel_context *ce = request_to_scheduling_context(rq); spin_lock(&ce->guc_state.lock); guc_prio_fini(rq, ce); diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 7bd9ed20623e..8950785e55d6 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -139,6 +139,14 @@ enum { * the GPU. Here we track such boost requests on a per-request basis. */ I915_FENCE_FLAG_BOOST, + + /* + * I915_FENCE_FLAG_SUBMIT_PARALLEL - request with a context in a + * parent-child relationship (parallel submission, multi-lrc) should + * trigger a submission to the GuC rather than just moving the context + * tail. + */ + I915_FENCE_FLAG_SUBMIT_PARALLEL, }; /** From bc955204919ea8152b7443e7d48a48cc18dea448 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:53 -0700 Subject: [PATCH 350/554] drm/i915/guc: Insert submit fences between requests in parent-child relationship The GuC must receive requests in the order submitted for contexts in a parent-child relationship to function correctly. To ensure this, insert a submit fence between the current request and last request submitted for requests / contexts in a parent child relationship. This is conceptually similar to a single timeline. Signed-off-by: Matthew Brost Cc: John Harrison Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-14-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.h | 5 + drivers/gpu/drm/i915/gt/intel_context_types.h | 6 + .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 5 +- drivers/gpu/drm/i915/i915_request.c | 130 +++++++++++++----- 4 files changed, 113 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index 9f0995150a7a..edf12caaade3 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -77,6 +77,11 @@ intel_context_to_parent(struct intel_context *ce) } } +static inline bool intel_context_is_parallel(struct intel_context *ce) +{ + return intel_context_is_child(ce) || intel_context_is_parent(ce); +} + void intel_context_bind_parent_child(struct intel_context *parent, struct intel_context *child); diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 48decb5ee954..8309d1141d0a 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -237,6 +237,12 @@ struct intel_context { }; /** @parent: pointer to parent if child */ struct intel_context *parent; + /** + * @last_rq: last request submitted on a parallel context, used + * to insert submit fences between requests in the parallel + * context + */ + struct i915_request *last_rq; /** @number_children: number of children if parent */ u8 number_children; /** @guc: GuC specific members for parallel submission */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 71ae5eb69849..ebb64fb50396 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -684,8 +684,7 @@ static inline int rq_prio(const struct i915_request *rq) static bool is_multi_lrc_rq(struct i915_request *rq) { - return intel_context_is_child(rq->context) || - intel_context_is_parent(rq->context); + return intel_context_is_parallel(rq->context); } static bool can_merge_rq(struct i915_request *rq, @@ -2873,6 +2872,8 @@ static void guc_parent_context_unpin(struct intel_context *ce) GEM_BUG_ON(!intel_context_is_parent(ce)); GEM_BUG_ON(!intel_engine_is_virtual(ce->engine)); + if (ce->parallel.last_rq) + i915_request_put(ce->parallel.last_rq); unpin_guc_id(guc, ce); lrc_unpin(ce); } diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index ed64fa9defdf..d29e46a001b4 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1549,6 +1549,91 @@ i915_request_await_object(struct i915_request *to, return ret; } +static inline bool is_parallel_rq(struct i915_request *rq) +{ + return intel_context_is_parallel(rq->context); +} + +static inline struct intel_context *request_to_parent(struct i915_request *rq) +{ + return intel_context_to_parent(rq->context); +} + +static struct i915_request * +__i915_request_ensure_parallel_ordering(struct i915_request *rq, + struct intel_timeline *timeline) +{ + struct i915_request *prev; + + GEM_BUG_ON(!is_parallel_rq(rq)); + + prev = request_to_parent(rq)->parallel.last_rq; + if (prev) { + if (!__i915_request_is_complete(prev)) { + i915_sw_fence_await_sw_fence(&rq->submit, + &prev->submit, + &rq->submitq); + + if (rq->engine->sched_engine->schedule) + __i915_sched_node_add_dependency(&rq->sched, + &prev->sched, + &rq->dep, + 0); + } + i915_request_put(prev); + } + + request_to_parent(rq)->parallel.last_rq = i915_request_get(rq); + + return to_request(__i915_active_fence_set(&timeline->last_request, + &rq->fence)); +} + +static struct i915_request * +__i915_request_ensure_ordering(struct i915_request *rq, + struct intel_timeline *timeline) +{ + struct i915_request *prev; + + GEM_BUG_ON(is_parallel_rq(rq)); + + prev = to_request(__i915_active_fence_set(&timeline->last_request, + &rq->fence)); + + if (prev && !__i915_request_is_complete(prev)) { + bool uses_guc = intel_engine_uses_guc(rq->engine); + bool pow2 = is_power_of_2(READ_ONCE(prev->engine)->mask | + rq->engine->mask); + bool same_context = prev->context == rq->context; + + /* + * The requests are supposed to be kept in order. However, + * we need to be wary in case the timeline->last_request + * is used as a barrier for external modification to this + * context. + */ + GEM_BUG_ON(same_context && + i915_seqno_passed(prev->fence.seqno, + rq->fence.seqno)); + + if ((same_context && uses_guc) || (!uses_guc && pow2)) + i915_sw_fence_await_sw_fence(&rq->submit, + &prev->submit, + &rq->submitq); + else + __i915_sw_fence_await_dma_fence(&rq->submit, + &prev->fence, + &rq->dmaq); + if (rq->engine->sched_engine->schedule) + __i915_sched_node_add_dependency(&rq->sched, + &prev->sched, + &rq->dep, + 0); + } + + return prev; +} + static struct i915_request * __i915_request_add_to_timeline(struct i915_request *rq) { @@ -1574,38 +1659,21 @@ __i915_request_add_to_timeline(struct i915_request *rq) * complete (to maximise our greedy late load balancing) and this * precludes optimising to use semaphores serialisation of a single * timeline across engines. + * + * We do not order parallel submission requests on the timeline as each + * parallel submission context has its own timeline and the ordering + * rules for parallel requests are that they must be submitted in the + * order received from the execbuf IOCTL. So rather than using the + * timeline we store a pointer to last request submitted in the + * relationship in the gem context and insert a submission fence + * between that request and request passed into this function or + * alternatively we use completion fence if gem context has a single + * timeline and this is the first submission of an execbuf IOCTL. */ - prev = to_request(__i915_active_fence_set(&timeline->last_request, - &rq->fence)); - if (prev && !__i915_request_is_complete(prev)) { - bool uses_guc = intel_engine_uses_guc(rq->engine); - - /* - * The requests are supposed to be kept in order. However, - * we need to be wary in case the timeline->last_request - * is used as a barrier for external modification to this - * context. - */ - GEM_BUG_ON(prev->context == rq->context && - i915_seqno_passed(prev->fence.seqno, - rq->fence.seqno)); - - if ((!uses_guc && - is_power_of_2(READ_ONCE(prev->engine)->mask | rq->engine->mask)) || - (uses_guc && prev->context == rq->context)) - i915_sw_fence_await_sw_fence(&rq->submit, - &prev->submit, - &rq->submitq); - else - __i915_sw_fence_await_dma_fence(&rq->submit, - &prev->fence, - &rq->dmaq); - if (rq->engine->sched_engine->schedule) - __i915_sched_node_add_dependency(&rq->sched, - &prev->sched, - &rq->dep, - 0); - } + if (likely(!is_parallel_rq(rq))) + prev = __i915_request_ensure_ordering(rq, timeline); + else + prev = __i915_request_ensure_parallel_ordering(rq, timeline); /* * Make sure that no request gazumped us - if it was allocated after From 872758dbdb93324ba60d58e70ea2ee04cc7cbad8 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:54 -0700 Subject: [PATCH 351/554] drm/i915/guc: Implement multi-lrc reset Update context and full GPU reset to work with multi-lrc. The idea is parent context tracks all the active requests inflight for itself and its children. The parent context owns the reset replaying / canceling requests as needed. v2: (John Harrison) - Simply loop in find active request - Add comments to find ative request / reset loop v3: (John Harrison) - s/its'/its/g - Fix comment when searching for active request - Reorder if state in __guc_reset_context v4: (Kernel test robot) - Delete unused is_multi_lrc function Reviewed-by: John Harrison Signed-off-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-15-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 15 +++- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 68 +++++++++++++------ 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 4d95053855c9..709c433a2dcc 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -528,20 +528,29 @@ retry: struct i915_request *intel_context_find_active_request(struct intel_context *ce) { + struct intel_context *parent = intel_context_to_parent(ce); struct i915_request *rq, *active = NULL; unsigned long flags; GEM_BUG_ON(!intel_engine_uses_guc(ce->engine)); - spin_lock_irqsave(&ce->guc_state.lock, flags); - list_for_each_entry_reverse(rq, &ce->guc_state.requests, + /* + * We search the parent list to find an active request on the submitted + * context. The parent list contains the requests for all the contexts + * in the relationship so we have to do a compare of each request's + * context. + */ + spin_lock_irqsave(&parent->guc_state.lock, flags); + list_for_each_entry_reverse(rq, &parent->guc_state.requests, sched.link) { + if (rq->context != ce) + continue; if (i915_request_completed(rq)) break; active = rq; } - spin_unlock_irqrestore(&ce->guc_state.lock, flags); + spin_unlock_irqrestore(&parent->guc_state.lock, flags); return active; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index ebb64fb50396..112b5e6fe39d 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1217,10 +1217,15 @@ __unwind_incomplete_requests(struct intel_context *ce) static void __guc_reset_context(struct intel_context *ce, bool stalled) { + bool local_stalled; struct i915_request *rq; unsigned long flags; u32 head; + int i, number_children = ce->parallel.number_children; bool skip = false; + struct intel_context *parent = ce; + + GEM_BUG_ON(intel_context_is_child(ce)); intel_context_get(ce); @@ -1246,25 +1251,38 @@ static void __guc_reset_context(struct intel_context *ce, bool stalled) if (unlikely(skip)) goto out_put; - rq = intel_context_find_active_request(ce); - if (!rq) { - head = ce->ring->tail; - stalled = false; - goto out_replay; + /* + * For each context in the relationship find the hanging request + * resetting each context / request as needed + */ + for (i = 0; i < number_children + 1; ++i) { + if (!intel_context_is_pinned(ce)) + goto next_context; + + local_stalled = false; + rq = intel_context_find_active_request(ce); + if (!rq) { + head = ce->ring->tail; + goto out_replay; + } + + if (i915_request_started(rq)) + local_stalled = true; + + GEM_BUG_ON(i915_active_is_idle(&ce->active)); + head = intel_ring_wrap(ce->ring, rq->head); + + __i915_request_reset(rq, local_stalled && stalled); +out_replay: + guc_reset_state(ce, head, local_stalled && stalled); +next_context: + if (i != number_children) + ce = list_next_entry(ce, parallel.child_link); } - if (!i915_request_started(rq)) - stalled = false; - - GEM_BUG_ON(i915_active_is_idle(&ce->active)); - head = intel_ring_wrap(ce->ring, rq->head); - __i915_request_reset(rq, stalled); - -out_replay: - guc_reset_state(ce, head, stalled); - __unwind_incomplete_requests(ce); + __unwind_incomplete_requests(parent); out_put: - intel_context_put(ce); + intel_context_put(parent); } void intel_guc_submission_reset(struct intel_guc *guc, bool stalled) @@ -1285,7 +1303,8 @@ void intel_guc_submission_reset(struct intel_guc *guc, bool stalled) xa_unlock(&guc->context_lookup); - if (intel_context_is_pinned(ce)) + if (intel_context_is_pinned(ce) && + !intel_context_is_child(ce)) __guc_reset_context(ce, stalled); intel_context_put(ce); @@ -1377,7 +1396,8 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc) xa_unlock(&guc->context_lookup); - if (intel_context_is_pinned(ce)) + if (intel_context_is_pinned(ce) && + !intel_context_is_child(ce)) guc_cancel_context_requests(ce); intel_context_put(ce); @@ -2070,6 +2090,8 @@ static struct i915_sw_fence *guc_context_block(struct intel_context *ce) u16 guc_id; bool enabled; + GEM_BUG_ON(intel_context_is_child(ce)); + spin_lock_irqsave(&ce->guc_state.lock, flags); incr_context_blocked(ce); @@ -2124,6 +2146,7 @@ static void guc_context_unblock(struct intel_context *ce) bool enable; GEM_BUG_ON(context_enabled(ce)); + GEM_BUG_ON(intel_context_is_child(ce)); spin_lock_irqsave(&ce->guc_state.lock, flags); @@ -2150,11 +2173,14 @@ static void guc_context_unblock(struct intel_context *ce) static void guc_context_cancel_request(struct intel_context *ce, struct i915_request *rq) { + struct intel_context *block_context = + request_to_scheduling_context(rq); + if (i915_sw_fence_signaled(&rq->submit)) { struct i915_sw_fence *fence; intel_context_get(ce); - fence = guc_context_block(ce); + fence = guc_context_block(block_context); i915_sw_fence_wait(fence); if (!i915_request_completed(rq)) { __i915_request_skip(rq); @@ -2168,7 +2194,7 @@ static void guc_context_cancel_request(struct intel_context *ce, */ flush_work(&ce_to_guc(ce)->ct.requests.worker); - guc_context_unblock(ce); + guc_context_unblock(block_context); intel_context_put(ce); } } @@ -2194,6 +2220,8 @@ static void guc_context_ban(struct intel_context *ce, struct i915_request *rq) intel_wakeref_t wakeref; unsigned long flags; + GEM_BUG_ON(intel_context_is_child(ce)); + guc_flush_submissions(guc); spin_lock_irqsave(&ce->guc_state.lock, flags); From d38a9294491dcc38b0508c865b59604f66fb08c4 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:55 -0700 Subject: [PATCH 352/554] drm/i915/guc: Update debugfs for GuC multi-lrc Display the workqueue status in debugfs for GuC contexts that are in parent-child relationship. v2: (John Harrison) - Output number children in debugfs Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-16-matthew.brost@intel.com --- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 112b5e6fe39d..938dc34e8d3a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -3702,6 +3702,25 @@ static inline void guc_log_context_priority(struct drm_printer *p, drm_printf(p, "\n"); } +static inline void guc_log_context(struct drm_printer *p, + struct intel_context *ce) +{ + drm_printf(p, "GuC lrc descriptor %u:\n", ce->guc_id.id); + drm_printf(p, "\tHW Context Desc: 0x%08x\n", ce->lrc.lrca); + drm_printf(p, "\t\tLRC Head: Internal %u, Memory %u\n", + ce->ring->head, + ce->lrc_reg_state[CTX_RING_HEAD]); + drm_printf(p, "\t\tLRC Tail: Internal %u, Memory %u\n", + ce->ring->tail, + ce->lrc_reg_state[CTX_RING_TAIL]); + drm_printf(p, "\t\tContext Pin Count: %u\n", + atomic_read(&ce->pin_count)); + drm_printf(p, "\t\tGuC ID Ref Count: %u\n", + atomic_read(&ce->guc_id.ref)); + drm_printf(p, "\t\tSchedule State: 0x%x\n\n", + ce->guc_state.sched_state); +} + void intel_guc_submission_print_context_info(struct intel_guc *guc, struct drm_printer *p) { @@ -3711,22 +3730,27 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc, xa_lock_irqsave(&guc->context_lookup, flags); xa_for_each(&guc->context_lookup, index, ce) { - drm_printf(p, "GuC lrc descriptor %u:\n", ce->guc_id.id); - drm_printf(p, "\tHW Context Desc: 0x%08x\n", ce->lrc.lrca); - drm_printf(p, "\t\tLRC Head: Internal %u, Memory %u\n", - ce->ring->head, - ce->lrc_reg_state[CTX_RING_HEAD]); - drm_printf(p, "\t\tLRC Tail: Internal %u, Memory %u\n", - ce->ring->tail, - ce->lrc_reg_state[CTX_RING_TAIL]); - drm_printf(p, "\t\tContext Pin Count: %u\n", - atomic_read(&ce->pin_count)); - drm_printf(p, "\t\tGuC ID Ref Count: %u\n", - atomic_read(&ce->guc_id.ref)); - drm_printf(p, "\t\tSchedule State: 0x%x\n\n", - ce->guc_state.sched_state); + GEM_BUG_ON(intel_context_is_child(ce)); + guc_log_context(p, ce); guc_log_context_priority(p, ce); + + if (intel_context_is_parent(ce)) { + struct guc_process_desc *desc = __get_process_desc(ce); + struct intel_context *child; + + drm_printf(p, "\t\tNumber children: %u\n", + ce->parallel.number_children); + drm_printf(p, "\t\tWQI Head: %u\n", + READ_ONCE(desc->head)); + drm_printf(p, "\t\tWQI Tail: %u\n", + READ_ONCE(desc->tail)); + drm_printf(p, "\t\tWQI Status: %u\n\n", + READ_ONCE(desc->wq_status)); + + for_each_child(ce, child) + guc_log_context(p, child); + } } xa_unlock_irqrestore(&guc->context_lookup, flags); } From e5e32171a2cf1e434d4f88e12467f3e47d0ec618 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:56 -0700 Subject: [PATCH 353/554] drm/i915/guc: Connect UAPI to GuC multi-lrc interface Introduce 'set parallel submit' extension to connect UAPI to GuC multi-lrc interface. Kernel doc in new uAPI should explain it all. IGT: https://patchwork.freedesktop.org/patch/447008/?series=93071&rev=1 media UMD: https://github.com/intel/media-driver/pull/1252 v2: (Daniel Vetter) - Add IGT link and placeholder for media UMD link v3: (Kernel test robot) - Fix warning in unpin engines call (John Harrison) - Reword a bunch of the kernel doc v4: (John Harrison) - Add comment why perma-pin is done after setting gem context - Update some comments / docs for proto contexts v5: (John Harrison) - Rework perma-pin comment - Add BUG_IN if context is pinned when setting gem context Cc: Tvrtko Ursulin Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-17-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 230 +++++++++++++++++- .../gpu/drm/i915/gem/i915_gem_context_types.h | 16 +- drivers/gpu/drm/i915/gt/intel_context_types.h | 9 +- drivers/gpu/drm/i915/gt/intel_engine.h | 12 +- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 6 +- .../drm/i915/gt/intel_execlists_submission.c | 6 +- drivers/gpu/drm/i915/gt/selftest_execlists.c | 12 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 114 ++++++++- include/uapi/drm/i915_drm.h | 131 ++++++++++ 9 files changed, 505 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index d225d3dd0b40..9a00f11fef46 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -556,9 +556,150 @@ set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data) return 0; } +static int +set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base, + void *data) +{ + struct i915_context_engines_parallel_submit __user *ext = + container_of_user(base, typeof(*ext), base); + const struct set_proto_ctx_engines *set = data; + struct drm_i915_private *i915 = set->i915; + u64 flags; + int err = 0, n, i, j; + u16 slot, width, num_siblings; + struct intel_engine_cs **siblings = NULL; + intel_engine_mask_t prev_mask; + + /* Disabling for now */ + return -ENODEV; + + /* FIXME: This is NIY for execlists */ + if (!(intel_uc_uses_guc_submission(&i915->gt.uc))) + return -ENODEV; + + if (get_user(slot, &ext->engine_index)) + return -EFAULT; + + if (get_user(width, &ext->width)) + return -EFAULT; + + if (get_user(num_siblings, &ext->num_siblings)) + return -EFAULT; + + if (slot >= set->num_engines) { + drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n", + slot, set->num_engines); + return -EINVAL; + } + + if (set->engines[slot].type != I915_GEM_ENGINE_TYPE_INVALID) { + drm_dbg(&i915->drm, + "Invalid placement[%d], already occupied\n", slot); + return -EINVAL; + } + + if (get_user(flags, &ext->flags)) + return -EFAULT; + + if (flags) { + drm_dbg(&i915->drm, "Unknown flags 0x%02llx", flags); + return -EINVAL; + } + + for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) { + err = check_user_mbz(&ext->mbz64[n]); + if (err) + return err; + } + + if (width < 2) { + drm_dbg(&i915->drm, "Width (%d) < 2\n", width); + return -EINVAL; + } + + if (num_siblings < 1) { + drm_dbg(&i915->drm, "Number siblings (%d) < 1\n", + num_siblings); + return -EINVAL; + } + + siblings = kmalloc_array(num_siblings * width, + sizeof(*siblings), + GFP_KERNEL); + if (!siblings) + return -ENOMEM; + + /* Create contexts / engines */ + for (i = 0; i < width; ++i) { + intel_engine_mask_t current_mask = 0; + struct i915_engine_class_instance prev_engine; + + for (j = 0; j < num_siblings; ++j) { + struct i915_engine_class_instance ci; + + n = i * num_siblings + j; + if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) { + err = -EFAULT; + goto out_err; + } + + siblings[n] = + intel_engine_lookup_user(i915, ci.engine_class, + ci.engine_instance); + if (!siblings[n]) { + drm_dbg(&i915->drm, + "Invalid sibling[%d]: { class:%d, inst:%d }\n", + n, ci.engine_class, ci.engine_instance); + err = -EINVAL; + goto out_err; + } + + if (n) { + if (prev_engine.engine_class != + ci.engine_class) { + drm_dbg(&i915->drm, + "Mismatched class %d, %d\n", + prev_engine.engine_class, + ci.engine_class); + err = -EINVAL; + goto out_err; + } + } + + prev_engine = ci; + current_mask |= siblings[n]->logical_mask; + } + + if (i > 0) { + if (current_mask != prev_mask << 1) { + drm_dbg(&i915->drm, + "Non contiguous logical mask 0x%x, 0x%x\n", + prev_mask, current_mask); + err = -EINVAL; + goto out_err; + } + } + prev_mask = current_mask; + } + + set->engines[slot].type = I915_GEM_ENGINE_TYPE_PARALLEL; + set->engines[slot].num_siblings = num_siblings; + set->engines[slot].width = width; + set->engines[slot].siblings = siblings; + + return 0; + +out_err: + kfree(siblings); + + return err; +} + static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = { [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance, [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond, + [I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT] = + set_proto_ctx_engines_parallel_submit, }; static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv, @@ -794,6 +935,7 @@ static int intel_context_set_gem(struct intel_context *ce, GEM_BUG_ON(rcu_access_pointer(ce->gem_context)); RCU_INIT_POINTER(ce->gem_context, ctx); + GEM_BUG_ON(intel_context_is_pinned(ce)); ce->ring_size = SZ_16K; i915_vm_put(ce->vm); @@ -818,6 +960,25 @@ static int intel_context_set_gem(struct intel_context *ce, return ret; } +static void __unpin_engines(struct i915_gem_engines *e, unsigned int count) +{ + while (count--) { + struct intel_context *ce = e->engines[count], *child; + + if (!ce || !test_bit(CONTEXT_PERMA_PIN, &ce->flags)) + continue; + + for_each_child(ce, child) + intel_context_unpin(child); + intel_context_unpin(ce); + } +} + +static void unpin_engines(struct i915_gem_engines *e) +{ + __unpin_engines(e, e->num_engines); +} + static void __free_engines(struct i915_gem_engines *e, unsigned int count) { while (count--) { @@ -933,6 +1094,40 @@ free_engines: return err; } +static int perma_pin_contexts(struct intel_context *ce) +{ + struct intel_context *child; + int i = 0, j = 0, ret; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + ret = intel_context_pin(ce); + if (unlikely(ret)) + return ret; + + for_each_child(ce, child) { + ret = intel_context_pin(child); + if (unlikely(ret)) + goto unwind; + ++i; + } + + set_bit(CONTEXT_PERMA_PIN, &ce->flags); + + return 0; + +unwind: + intel_context_unpin(ce); + for_each_child(ce, child) { + if (j++ < i) + intel_context_unpin(child); + else + break; + } + + return ret; +} + static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, unsigned int num_engines, struct i915_gem_proto_engine *pe) @@ -946,7 +1141,7 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, e->num_engines = num_engines; for (n = 0; n < num_engines; n++) { - struct intel_context *ce; + struct intel_context *ce, *child; int ret; switch (pe[n].type) { @@ -956,7 +1151,13 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, case I915_GEM_ENGINE_TYPE_BALANCED: ce = intel_engine_create_virtual(pe[n].siblings, - pe[n].num_siblings); + pe[n].num_siblings, 0); + break; + + case I915_GEM_ENGINE_TYPE_PARALLEL: + ce = intel_engine_create_parallel(pe[n].siblings, + pe[n].num_siblings, + pe[n].width); break; case I915_GEM_ENGINE_TYPE_INVALID: @@ -977,6 +1178,30 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx, err = ERR_PTR(ret); goto free_engines; } + for_each_child(ce, child) { + ret = intel_context_set_gem(child, ctx, pe->sseu); + if (ret) { + err = ERR_PTR(ret); + goto free_engines; + } + } + + /* + * XXX: Must be done after calling intel_context_set_gem as that + * function changes the ring size. The ring is allocated when + * the context is pinned. If the ring size is changed after + * allocation we have a mismatch of the ring size and will cause + * the context to hang. Presumably with a bit of reordering we + * could move the perma-pin step to the backend function + * intel_engine_create_parallel. + */ + if (pe[n].type == I915_GEM_ENGINE_TYPE_PARALLEL) { + ret = perma_pin_contexts(ce); + if (ret) { + err = ERR_PTR(ret); + goto free_engines; + } + } } return e; @@ -1219,6 +1444,7 @@ static void context_close(struct i915_gem_context *ctx) /* Flush any concurrent set_engines() */ mutex_lock(&ctx->engines_mutex); + unpin_engines(__context_engines_static(ctx)); engines_idle_release(ctx, rcu_replace_pointer(ctx->engines, NULL, 1)); i915_gem_context_set_closed(ctx); mutex_unlock(&ctx->engines_mutex); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h index a627b09c4680..282cdb8a5c5a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h @@ -78,13 +78,16 @@ enum i915_gem_engine_type { /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */ I915_GEM_ENGINE_TYPE_BALANCED, + + /** @I915_GEM_ENGINE_TYPE_PARALLEL: A parallel engine set */ + I915_GEM_ENGINE_TYPE_PARALLEL, }; /** * struct i915_gem_proto_engine - prototype engine * * This struct describes an engine that a context may contain. Engines - * have three types: + * have four types: * * - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they * show up as a NULL in i915_gem_engines::engines[i] and any attempt to @@ -97,6 +100,10 @@ enum i915_gem_engine_type { * * - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described * i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings. + * + * - I915_GEM_ENGINE_TYPE_PARALLEL: A parallel submission engine set, described + * i915_gem_proto_engine::width, i915_gem_proto_engine::num_siblings, and + * i915_gem_proto_engine::siblings. */ struct i915_gem_proto_engine { /** @type: Type of this engine */ @@ -105,10 +112,13 @@ struct i915_gem_proto_engine { /** @engine: Engine, for physical */ struct intel_engine_cs *engine; - /** @num_siblings: Number of balanced siblings */ + /** @num_siblings: Number of balanced or parallel siblings */ unsigned int num_siblings; - /** @siblings: Balanced siblings */ + /** @width: Width of each sibling */ + unsigned int width; + + /** @siblings: Balanced siblings or num_siblings * width for parallel */ struct intel_engine_cs **siblings; /** @sseu: Client-set SSEU parameters */ diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 8309d1141d0a..1d880303a7e4 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -55,9 +55,13 @@ struct intel_context_ops { void (*reset)(struct intel_context *ce); void (*destroy)(struct kref *kref); - /* virtual engine/context interface */ + /* virtual/parallel engine/context interface */ struct intel_context *(*create_virtual)(struct intel_engine_cs **engine, - unsigned int count); + unsigned int count, + unsigned long flags); + struct intel_context *(*create_parallel)(struct intel_engine_cs **engines, + unsigned int num_siblings, + unsigned int width); struct intel_engine_cs *(*get_sibling)(struct intel_engine_cs *engine, unsigned int sibling); }; @@ -113,6 +117,7 @@ struct intel_context { #define CONTEXT_NOPREEMPT 8 #define CONTEXT_LRCA_DIRTY 9 #define CONTEXT_GUC_INIT 10 +#define CONTEXT_PERMA_PIN 11 struct { u64 timeout_us; diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index d5ac49c0691e..08559ace0ada 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -282,9 +282,19 @@ intel_engine_has_preempt_reset(const struct intel_engine_cs *engine) return intel_engine_has_preemption(engine); } +#define FORCE_VIRTUAL BIT(0) struct intel_context * intel_engine_create_virtual(struct intel_engine_cs **siblings, - unsigned int count); + unsigned int count, unsigned long flags); + +static inline struct intel_context * +intel_engine_create_parallel(struct intel_engine_cs **engines, + unsigned int num_engines, + unsigned int width) +{ + GEM_BUG_ON(!engines[0]->cops->create_parallel); + return engines[0]->cops->create_parallel(engines, num_engines, width); +} static inline bool intel_virtual_engine_has_heartbeat(const struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 2eb798ad068b..ff6753ccb129 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1953,16 +1953,16 @@ ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine, ktime_t *now) struct intel_context * intel_engine_create_virtual(struct intel_engine_cs **siblings, - unsigned int count) + unsigned int count, unsigned long flags) { if (count == 0) return ERR_PTR(-EINVAL); - if (count == 1) + if (count == 1 && !(flags & FORCE_VIRTUAL)) return intel_context_create(siblings[0]); GEM_BUG_ON(!siblings[0]->cops->create_virtual); - return siblings[0]->cops->create_virtual(siblings, count); + return siblings[0]->cops->create_virtual(siblings, count, flags); } struct i915_request * diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 43a74b216efb..bedb80057046 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -201,7 +201,8 @@ static struct virtual_engine *to_virtual_engine(struct intel_engine_cs *engine) } static struct intel_context * -execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count); +execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count, + unsigned long flags); static struct i915_request * __active_request(const struct intel_timeline * const tl, @@ -3784,7 +3785,8 @@ unlock: } static struct intel_context * -execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count) +execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count, + unsigned long flags) { struct virtual_engine *ve; unsigned int n; diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c index 25a8c4f62b0d..b367ecfa42de 100644 --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c @@ -3733,7 +3733,7 @@ static int nop_virtual_engine(struct intel_gt *gt, GEM_BUG_ON(!nctx || nctx > ARRAY_SIZE(ve)); for (n = 0; n < nctx; n++) { - ve[n] = intel_engine_create_virtual(siblings, nsibling); + ve[n] = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ve[n])) { err = PTR_ERR(ve[n]); nctx = n; @@ -3929,7 +3929,7 @@ static int mask_virtual_engine(struct intel_gt *gt, * restrict it to our desired engine within the virtual engine. */ - ve = intel_engine_create_virtual(siblings, nsibling); + ve = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ve)) { err = PTR_ERR(ve); goto out_close; @@ -4060,7 +4060,7 @@ static int slicein_virtual_engine(struct intel_gt *gt, i915_request_add(rq); } - ce = intel_engine_create_virtual(siblings, nsibling); + ce = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ce)) { err = PTR_ERR(ce); goto out; @@ -4112,7 +4112,7 @@ static int sliceout_virtual_engine(struct intel_gt *gt, /* XXX We do not handle oversubscription and fairness with normal rq */ for (n = 0; n < nsibling; n++) { - ce = intel_engine_create_virtual(siblings, nsibling); + ce = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ce)) { err = PTR_ERR(ce); goto out; @@ -4214,7 +4214,7 @@ static int preserved_virtual_engine(struct intel_gt *gt, if (err) goto out_scratch; - ve = intel_engine_create_virtual(siblings, nsibling); + ve = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ve)) { err = PTR_ERR(ve); goto out_scratch; @@ -4354,7 +4354,7 @@ static int reset_virtual_engine(struct intel_gt *gt, if (igt_spinner_init(&spin, gt)) return -ENOMEM; - ve = intel_engine_create_virtual(siblings, nsibling); + ve = intel_engine_create_virtual(siblings, nsibling, 0); if (IS_ERR(ve)) { err = PTR_ERR(ve); goto out_spin; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 938dc34e8d3a..7c12364a017a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -124,7 +124,13 @@ struct guc_virtual_engine { }; static struct intel_context * -guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count); +guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count, + unsigned long flags); + +static struct intel_context * +guc_create_parallel(struct intel_engine_cs **engines, + unsigned int num_siblings, + unsigned int width); #define GUC_REQUEST_SIZE 64 /* bytes */ @@ -2609,6 +2615,7 @@ static const struct intel_context_ops guc_context_ops = { .destroy = guc_context_destroy, .create_virtual = guc_create_virtual, + .create_parallel = guc_create_parallel, }; static void submit_work_cb(struct irq_work *wrk) @@ -2858,8 +2865,6 @@ static const struct intel_context_ops virtual_guc_context_ops = { .get_sibling = guc_virtual_get_sibling, }; -/* Future patches will use this function */ -__maybe_unused static int guc_parent_context_pin(struct intel_context *ce, void *vaddr) { struct intel_engine_cs *engine = guc_virtual_get_sibling(ce->engine, 0); @@ -2876,8 +2881,6 @@ static int guc_parent_context_pin(struct intel_context *ce, void *vaddr) return __guc_context_pin(ce, engine, vaddr); } -/* Future patches will use this function */ -__maybe_unused static int guc_child_context_pin(struct intel_context *ce, void *vaddr) { struct intel_engine_cs *engine = guc_virtual_get_sibling(ce->engine, 0); @@ -2889,8 +2892,6 @@ static int guc_child_context_pin(struct intel_context *ce, void *vaddr) return __guc_context_pin(ce, engine, vaddr); } -/* Future patches will use this function */ -__maybe_unused static void guc_parent_context_unpin(struct intel_context *ce) { struct intel_guc *guc = ce_to_guc(ce); @@ -2906,8 +2907,6 @@ static void guc_parent_context_unpin(struct intel_context *ce) lrc_unpin(ce); } -/* Future patches will use this function */ -__maybe_unused static void guc_child_context_unpin(struct intel_context *ce) { GEM_BUG_ON(context_enabled(ce)); @@ -2918,8 +2917,6 @@ static void guc_child_context_unpin(struct intel_context *ce) lrc_unpin(ce); } -/* Future patches will use this function */ -__maybe_unused static void guc_child_context_post_unpin(struct intel_context *ce) { GEM_BUG_ON(!intel_context_is_child(ce)); @@ -2930,6 +2927,98 @@ static void guc_child_context_post_unpin(struct intel_context *ce) intel_context_unpin(ce->parallel.parent); } +static void guc_child_context_destroy(struct kref *kref) +{ + struct intel_context *ce = container_of(kref, typeof(*ce), ref); + + __guc_context_destroy(ce); +} + +static const struct intel_context_ops virtual_parent_context_ops = { + .alloc = guc_virtual_context_alloc, + + .pre_pin = guc_context_pre_pin, + .pin = guc_parent_context_pin, + .unpin = guc_parent_context_unpin, + .post_unpin = guc_context_post_unpin, + + .ban = guc_context_ban, + + .cancel_request = guc_context_cancel_request, + + .enter = guc_virtual_context_enter, + .exit = guc_virtual_context_exit, + + .sched_disable = guc_context_sched_disable, + + .destroy = guc_context_destroy, + + .get_sibling = guc_virtual_get_sibling, +}; + +static const struct intel_context_ops virtual_child_context_ops = { + .alloc = guc_virtual_context_alloc, + + .pre_pin = guc_context_pre_pin, + .pin = guc_child_context_pin, + .unpin = guc_child_context_unpin, + .post_unpin = guc_child_context_post_unpin, + + .cancel_request = guc_context_cancel_request, + + .enter = guc_virtual_context_enter, + .exit = guc_virtual_context_exit, + + .destroy = guc_child_context_destroy, + + .get_sibling = guc_virtual_get_sibling, +}; + +static struct intel_context * +guc_create_parallel(struct intel_engine_cs **engines, + unsigned int num_siblings, + unsigned int width) +{ + struct intel_engine_cs **siblings = NULL; + struct intel_context *parent = NULL, *ce, *err; + int i, j; + + siblings = kmalloc_array(num_siblings, + sizeof(*siblings), + GFP_KERNEL); + if (!siblings) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < width; ++i) { + for (j = 0; j < num_siblings; ++j) + siblings[j] = engines[i * num_siblings + j]; + + ce = intel_engine_create_virtual(siblings, num_siblings, + FORCE_VIRTUAL); + if (!ce) { + err = ERR_PTR(-ENOMEM); + goto unwind; + } + + if (i == 0) { + parent = ce; + parent->ops = &virtual_parent_context_ops; + } else { + ce->ops = &virtual_child_context_ops; + intel_context_bind_parent_child(parent, ce); + } + } + + kfree(siblings); + return parent; + +unwind: + if (parent) + intel_context_put(parent); + kfree(siblings); + return err; +} + static bool guc_irq_enable_breadcrumbs(struct intel_breadcrumbs *b) { @@ -3756,7 +3845,8 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc, } static struct intel_context * -guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count) +guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count, + unsigned long flags) { struct guc_virtual_engine *ve; struct intel_guc *guc; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 0179f92e0916..c2a63e1584cb 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1824,6 +1824,7 @@ struct drm_i915_gem_context_param { * Extensions: * i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE) * i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND) + * i915_context_engines_parallel_submit (I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT) */ #define I915_CONTEXT_PARAM_ENGINES 0xa @@ -2098,6 +2099,135 @@ struct i915_context_engines_bond { struct i915_engine_class_instance engines[N__]; \ } __attribute__((packed)) name__ +/** + * struct i915_context_engines_parallel_submit - Configure engine for + * parallel submission. + * + * Setup a slot in the context engine map to allow multiple BBs to be submitted + * in a single execbuf IOCTL. Those BBs will then be scheduled to run on the GPU + * in parallel. Multiple hardware contexts are created internally in the i915 to + * run these BBs. Once a slot is configured for N BBs only N BBs can be + * submitted in each execbuf IOCTL and this is implicit behavior e.g. The user + * doesn't tell the execbuf IOCTL there are N BBs, the execbuf IOCTL knows how + * many BBs there are based on the slot's configuration. The N BBs are the last + * N buffer objects or first N if I915_EXEC_BATCH_FIRST is set. + * + * The default placement behavior is to create implicit bonds between each + * context if each context maps to more than 1 physical engine (e.g. context is + * a virtual engine). Also we only allow contexts of same engine class and these + * contexts must be in logically contiguous order. Examples of the placement + * behavior are described below. Lastly, the default is to not allow BBs to be + * preempted mid-batch. Rather insert coordinated preemption points on all + * hardware contexts between each set of BBs. Flags could be added in the future + * to change both of these default behaviors. + * + * Returns -EINVAL if hardware context placement configuration is invalid or if + * the placement configuration isn't supported on the platform / submission + * interface. + * Returns -ENODEV if extension isn't supported on the platform / submission + * interface. + * + * .. code-block:: none + * + * Examples syntax: + * CS[X] = generic engine of same class, logical instance X + * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE + * + * Example 1 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=1, + * engines=CS[0],CS[1]) + * + * Results in the following valid placement: + * CS[0], CS[1] + * + * Example 2 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[2],CS[1],CS[3]) + * + * Results in the following valid placements: + * CS[0], CS[1] + * CS[2], CS[3] + * + * This can be thought of as two virtual engines, each containing two + * engines thereby making a 2D array. However, there are bonds tying the + * entries together and placing restrictions on how they can be scheduled. + * Specifically, the scheduler can choose only vertical columns from the 2D + * array. That is, CS[0] is bonded to CS[1] and CS[2] to CS[3]. So if the + * scheduler wants to submit to CS[0], it must also choose CS[1] and vice + * versa. Same for CS[2] requires also using CS[3]. + * VE[0] = CS[0], CS[2] + * VE[1] = CS[1], CS[3] + * + * Example 3 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[1],CS[1],CS[3]) + * + * Results in the following valid and invalid placements: + * CS[0], CS[1] + * CS[1], CS[3] - Not logically contiguous, return -EINVAL + */ +struct i915_context_engines_parallel_submit { + /** + * @base: base user extension. + */ + struct i915_user_extension base; + + /** + * @engine_index: slot for parallel engine + */ + __u16 engine_index; + + /** + * @width: number of contexts per parallel engine or in other words the + * number of batches in each submission + */ + __u16 width; + + /** + * @num_siblings: number of siblings per context or in other words the + * number of possible placements for each submission + */ + __u16 num_siblings; + + /** + * @mbz16: reserved for future use; must be zero + */ + __u16 mbz16; + + /** + * @flags: all undefined flags must be zero, currently not defined flags + */ + __u64 flags; + + /** + * @mbz64: reserved for future use; must be zero + */ + __u64 mbz64[3]; + + /** + * @engines: 2-d array of engine instances to configure parallel engine + * + * length = width (i) * num_siblings (j) + * index = j + i * num_siblings + */ + struct i915_engine_class_instance engines[0]; + +} __packed; + +#define I915_DEFINE_CONTEXT_ENGINES_PARALLEL_SUBMIT(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 width; \ + __u16 num_siblings; \ + __u16 mbz16; \ + __u64 flags; \ + __u64 mbz64[3]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + /** * DOC: Context Engine Map uAPI * @@ -2157,6 +2287,7 @@ struct i915_context_param_engines { __u64 extensions; /* linked chain of extension blocks, 0 terminates */ #define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ #define I915_CONTEXT_ENGINES_EXT_BOND 1 /* see i915_context_engines_bond */ +#define I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT 2 /* see i915_context_engines_parallel_submit */ struct i915_engine_class_instance engines[0]; } __attribute__((packed)); From 0d7502fcd420b7212efcbeca95e1ce7952dc9c33 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:57 -0700 Subject: [PATCH 354/554] drm/i915/doc: Update parallel submit doc to point to i915_drm.h Update parallel submit doc to point to i915_drm.h Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-18-matthew.brost@intel.com --- Documentation/gpu/rfc/i915_parallel_execbuf.h | 122 ------------------ Documentation/gpu/rfc/i915_scheduler.rst | 4 +- 2 files changed, 2 insertions(+), 124 deletions(-) delete mode 100644 Documentation/gpu/rfc/i915_parallel_execbuf.h diff --git a/Documentation/gpu/rfc/i915_parallel_execbuf.h b/Documentation/gpu/rfc/i915_parallel_execbuf.h deleted file mode 100644 index 8cbe2c4e0172..000000000000 --- a/Documentation/gpu/rfc/i915_parallel_execbuf.h +++ /dev/null @@ -1,122 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2021 Intel Corporation - */ - -#define I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT 2 /* see i915_context_engines_parallel_submit */ - -/** - * struct drm_i915_context_engines_parallel_submit - Configure engine for - * parallel submission. - * - * Setup a slot in the context engine map to allow multiple BBs to be submitted - * in a single execbuf IOCTL. Those BBs will then be scheduled to run on the GPU - * in parallel. Multiple hardware contexts are created internally in the i915 - * run these BBs. Once a slot is configured for N BBs only N BBs can be - * submitted in each execbuf IOCTL and this is implicit behavior e.g. The user - * doesn't tell the execbuf IOCTL there are N BBs, the execbuf IOCTL knows how - * many BBs there are based on the slot's configuration. The N BBs are the last - * N buffer objects or first N if I915_EXEC_BATCH_FIRST is set. - * - * The default placement behavior is to create implicit bonds between each - * context if each context maps to more than 1 physical engine (e.g. context is - * a virtual engine). Also we only allow contexts of same engine class and these - * contexts must be in logically contiguous order. Examples of the placement - * behavior described below. Lastly, the default is to not allow BBs to - * preempted mid BB rather insert coordinated preemption on all hardware - * contexts between each set of BBs. Flags may be added in the future to change - * both of these default behaviors. - * - * Returns -EINVAL if hardware context placement configuration is invalid or if - * the placement configuration isn't supported on the platform / submission - * interface. - * Returns -ENODEV if extension isn't supported on the platform / submission - * interface. - * - * .. code-block:: none - * - * Example 1 pseudo code: - * CS[X] = generic engine of same class, logical instance X - * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE - * set_engines(INVALID) - * set_parallel(engine_index=0, width=2, num_siblings=1, - * engines=CS[0],CS[1]) - * - * Results in the following valid placement: - * CS[0], CS[1] - * - * Example 2 pseudo code: - * CS[X] = generic engine of same class, logical instance X - * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE - * set_engines(INVALID) - * set_parallel(engine_index=0, width=2, num_siblings=2, - * engines=CS[0],CS[2],CS[1],CS[3]) - * - * Results in the following valid placements: - * CS[0], CS[1] - * CS[2], CS[3] - * - * This can also be thought of as 2 virtual engines described by 2-D array - * in the engines the field with bonds placed between each index of the - * virtual engines. e.g. CS[0] is bonded to CS[1], CS[2] is bonded to - * CS[3]. - * VE[0] = CS[0], CS[2] - * VE[1] = CS[1], CS[3] - * - * Example 3 pseudo code: - * CS[X] = generic engine of same class, logical instance X - * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE - * set_engines(INVALID) - * set_parallel(engine_index=0, width=2, num_siblings=2, - * engines=CS[0],CS[1],CS[1],CS[3]) - * - * Results in the following valid and invalid placements: - * CS[0], CS[1] - * CS[1], CS[3] - Not logical contiguous, return -EINVAL - */ -struct drm_i915_context_engines_parallel_submit { - /** - * @base: base user extension. - */ - struct i915_user_extension base; - - /** - * @engine_index: slot for parallel engine - */ - __u16 engine_index; - - /** - * @width: number of contexts per parallel engine - */ - __u16 width; - - /** - * @num_siblings: number of siblings per context - */ - __u16 num_siblings; - - /** - * @mbz16: reserved for future use; must be zero - */ - __u16 mbz16; - - /** - * @flags: all undefined flags must be zero, currently not defined flags - */ - __u64 flags; - - /** - * @mbz64: reserved for future use; must be zero - */ - __u64 mbz64[3]; - - /** - * @engines: 2-d array of engine instances to configure parallel engine - * - * length = width (i) * num_siblings (j) - * index = j + i * num_siblings - */ - struct i915_engine_class_instance engines[0]; - -} __packed; - diff --git a/Documentation/gpu/rfc/i915_scheduler.rst b/Documentation/gpu/rfc/i915_scheduler.rst index cbda75065dad..d630f15ab795 100644 --- a/Documentation/gpu/rfc/i915_scheduler.rst +++ b/Documentation/gpu/rfc/i915_scheduler.rst @@ -135,8 +135,8 @@ Add I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT and drm_i915_context_engines_parallel_submit to the uAPI to implement this extension. -.. kernel-doc:: Documentation/gpu/rfc/i915_parallel_execbuf.h - :functions: drm_i915_context_engines_parallel_submit +.. kernel-doc:: include/uapi/drm/i915_drm.h + :functions: i915_context_engines_parallel_submit Extend execbuf2 IOCTL to support submitting N BBs in a single IOCTL ------------------------------------------------------------------- From f9d72092cb4902af8b5d4e647589deb248cfb44d Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:58 -0700 Subject: [PATCH 355/554] drm/i915/guc: Add basic GuC multi-lrc selftest Add very basic (single submission) multi-lrc selftest. Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-19-matthew.brost@intel.com --- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 1 + .../drm/i915/gt/uc/selftest_guc_multi_lrc.c | 179 ++++++++++++++++++ .../drm/i915/selftests/i915_live_selftests.h | 1 + 3 files changed, 181 insertions(+) create mode 100644 drivers/gpu/drm/i915/gt/uc/selftest_guc_multi_lrc.c diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 7c12364a017a..57eb5f8bc8bb 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -3954,4 +3954,5 @@ bool intel_guc_virtual_engine_has_heartbeat(const struct intel_engine_cs *ve) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_guc.c" +#include "selftest_guc_multi_lrc.c" #endif diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc_multi_lrc.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc_multi_lrc.c new file mode 100644 index 000000000000..50953c8e8b53 --- /dev/null +++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc_multi_lrc.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright �� 2019 Intel Corporation + */ + +#include "selftests/igt_spinner.h" +#include "selftests/igt_reset.h" +#include "selftests/intel_scheduler_helpers.h" +#include "gt/intel_engine_heartbeat.h" +#include "gem/selftests/mock_context.h" + +static void logical_sort(struct intel_engine_cs **engines, int num_engines) +{ + struct intel_engine_cs *sorted[MAX_ENGINE_INSTANCE + 1]; + int i, j; + + for (i = 0; i < num_engines; ++i) + for (j = 0; j < MAX_ENGINE_INSTANCE + 1; ++j) { + if (engines[j]->logical_mask & BIT(i)) { + sorted[i] = engines[j]; + break; + } + } + + memcpy(*engines, *sorted, + sizeof(struct intel_engine_cs *) * num_engines); +} + +static struct intel_context * +multi_lrc_create_parent(struct intel_gt *gt, u8 class, + unsigned long flags) +{ + struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1]; + struct intel_engine_cs *engine; + enum intel_engine_id id; + int i = 0; + + for_each_engine(engine, gt, id) { + if (engine->class != class) + continue; + + siblings[i++] = engine; + } + + if (i <= 1) + return ERR_PTR(0); + + logical_sort(siblings, i); + + return intel_engine_create_parallel(siblings, 1, i); +} + +static void multi_lrc_context_unpin(struct intel_context *ce) +{ + struct intel_context *child; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + for_each_child(ce, child) + intel_context_unpin(child); + intel_context_unpin(ce); +} + +static void multi_lrc_context_put(struct intel_context *ce) +{ + GEM_BUG_ON(!intel_context_is_parent(ce)); + + /* + * Only the parent gets the creation ref put in the uAPI, the parent + * itself is responsible for creation ref put on the children. + */ + intel_context_put(ce); +} + +static struct i915_request * +multi_lrc_nop_request(struct intel_context *ce) +{ + struct intel_context *child; + struct i915_request *rq, *child_rq; + int i = 0; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) + return rq; + + i915_request_get(rq); + i915_request_add(rq); + + for_each_child(ce, child) { + child_rq = intel_context_create_request(child); + if (IS_ERR(child_rq)) + goto child_error; + + if (++i == ce->parallel.number_children) + set_bit(I915_FENCE_FLAG_SUBMIT_PARALLEL, + &child_rq->fence.flags); + i915_request_add(child_rq); + } + + return rq; + +child_error: + i915_request_put(rq); + + return ERR_PTR(-ENOMEM); +} + +static int __intel_guc_multi_lrc_basic(struct intel_gt *gt, unsigned int class) +{ + struct intel_context *parent; + struct i915_request *rq; + int ret; + + parent = multi_lrc_create_parent(gt, class, 0); + if (IS_ERR(parent)) { + pr_err("Failed creating contexts: %ld", PTR_ERR(parent)); + return PTR_ERR(parent); + } else if (!parent) { + pr_debug("Not enough engines in class: %d", class); + return 0; + } + + rq = multi_lrc_nop_request(parent); + if (IS_ERR(rq)) { + ret = PTR_ERR(rq); + pr_err("Failed creating requests: %d", ret); + goto out; + } + + ret = intel_selftest_wait_for_rq(rq); + if (ret) + pr_err("Failed waiting on request: %d", ret); + + i915_request_put(rq); + + if (ret >= 0) { + ret = intel_gt_wait_for_idle(gt, HZ * 5); + if (ret < 0) + pr_err("GT failed to idle: %d\n", ret); + } + +out: + multi_lrc_context_unpin(parent); + multi_lrc_context_put(parent); + return ret; +} + +static int intel_guc_multi_lrc_basic(void *arg) +{ + struct intel_gt *gt = arg; + unsigned int class; + int ret; + + for (class = 0; class < MAX_ENGINE_CLASS + 1; ++class) { + ret = __intel_guc_multi_lrc_basic(gt, class); + if (ret) + return ret; + } + + return 0; +} + +int intel_guc_multi_lrc_live_selftests(struct drm_i915_private *i915) +{ + static const struct i915_subtest tests[] = { + SUBTEST(intel_guc_multi_lrc_basic), + }; + struct intel_gt *gt = &i915->gt; + + if (intel_gt_is_wedged(gt)) + return 0; + + if (!intel_uc_uses_guc_submission(>->uc)) + return 0; + + return intel_gt_live_subtests(tests, gt); +} diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h index 3cf6758931f9..bdd290f2bf3c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h @@ -48,5 +48,6 @@ selftest(ring_submission, intel_ring_submission_live_selftests) selftest(perf, i915_perf_live_selftests) selftest(slpc, intel_slpc_live_selftests) selftest(guc, intel_guc_live_selftests) +selftest(guc_multi_lrc, intel_guc_multi_lrc_live_selftests) /* Here be dragons: keep last to run last! */ selftest(late_gt_pm, intel_gt_pm_late_selftests) From 5851387a422c2949cb19b52efd9616ff8b18bddd Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:19:59 -0700 Subject: [PATCH 356/554] drm/i915/guc: Implement no mid batch preemption for multi-lrc For some users of multi-lrc, e.g. split frame, it isn't safe to preempt mid BB. To safely enable preemption at the BB boundary, a handshake between parent and child is needed, syncing the set of BBs at the beginning and end of each batch. This is implemented via custom emit_bb_start & emit_fini_breadcrumb functions and enabled by default if a context is configured by set parallel extension. Lastly, this patch updates the process descriptor to the correct size as the memory used in the handshake is directly after the process descriptor. v2: (John Harrison) - Fix a few comments wording - Add struture for parent page layout v3: (John Harrison) - A structure for sync semaphore - Use offsetof to calc address - Update commit message v4: (John Harrison) - Fix typos in comment explaining memory map of scratch page Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-20-matthew.brost@intel.com --- drivers/gpu/drm/i915/gt/intel_context.c | 2 +- drivers/gpu/drm/i915/gt/intel_context_types.h | 2 + drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 2 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 333 +++++++++++++++++- 4 files changed, 326 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 709c433a2dcc..488acd39ff67 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -569,7 +569,7 @@ void intel_context_bind_parent_child(struct intel_context *parent, GEM_BUG_ON(intel_context_is_child(child)); GEM_BUG_ON(intel_context_is_parent(child)); - parent->parallel.number_children++; + parent->parallel.child_index = parent->parallel.number_children++; list_add_tail(&child->parallel.child_link, &parent->parallel.child_list); child->parallel.parent = parent; diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 1d880303a7e4..95a5b94b4ece 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -250,6 +250,8 @@ struct intel_context { struct i915_request *last_rq; /** @number_children: number of children if parent */ u8 number_children; + /** @child_index: index into child_list if child */ + u8 child_index; /** @guc: GuC specific members for parallel submission */ struct { /** @wqi_head: head pointer in work queue */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 18da67cfcd92..722933e26347 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -186,7 +186,7 @@ struct guc_process_desc { u32 wq_status; u32 engine_presence; u32 priority; - u32 reserved[30]; + u32 reserved[36]; } __packed; #define CONTEXT_REGISTRATION_FLAG_KMD BIT(0) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 57eb5f8bc8bb..50f0f4eba03b 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -11,6 +11,7 @@ #include "gt/intel_context.h" #include "gt/intel_engine_pm.h" #include "gt/intel_engine_heartbeat.h" +#include "gt/intel_gpu_commands.h" #include "gt/intel_gt.h" #include "gt/intel_gt_irq.h" #include "gt/intel_gt_pm.h" @@ -368,11 +369,16 @@ static inline struct i915_priolist *to_priolist(struct rb_node *rb) /* * When using multi-lrc submission a scratch memory area is reserved in the - * parent's context state for the process descriptor and work queue. Currently - * the scratch area is sized to a page. + * parent's context state for the process descriptor, work queue, and handshake + * between the parent + children contexts to insert safe preemption points + * between each of the BBs. Currently the scratch area is sized to a page. * * The layout of this scratch area is below: * 0 guc_process_desc + * + sizeof(struct guc_process_desc) child go + * + CACHELINE_BYTES child join[0] + * ... + * + CACHELINE_BYTES child join[n - 1] * ... unused * PARENT_SCRATCH_SIZE / 2 work queue start * ... work queue @@ -380,7 +386,25 @@ static inline struct i915_priolist *to_priolist(struct rb_node *rb) */ #define WQ_SIZE (PARENT_SCRATCH_SIZE / 2) #define WQ_OFFSET (PARENT_SCRATCH_SIZE - WQ_SIZE) -static u32 __get_process_desc_offset(struct intel_context *ce) + +struct sync_semaphore { + u32 semaphore; + u8 unused[CACHELINE_BYTES - sizeof(u32)]; +}; + +struct parent_scratch { + struct guc_process_desc pdesc; + + struct sync_semaphore go; + struct sync_semaphore join[MAX_ENGINE_INSTANCE + 1]; + + u8 unused[WQ_OFFSET - sizeof(struct guc_process_desc) - + sizeof(struct sync_semaphore) * (MAX_ENGINE_INSTANCE + 2)]; + + u32 wq[WQ_SIZE / sizeof(u32)]; +}; + +static u32 __get_parent_scratch_offset(struct intel_context *ce) { GEM_BUG_ON(!ce->parallel.guc.parent_page); @@ -389,23 +413,36 @@ static u32 __get_process_desc_offset(struct intel_context *ce) static u32 __get_wq_offset(struct intel_context *ce) { - return __get_process_desc_offset(ce) + WQ_OFFSET; + BUILD_BUG_ON(offsetof(struct parent_scratch, wq) != WQ_OFFSET); + + return __get_parent_scratch_offset(ce) + WQ_OFFSET; } -static struct guc_process_desc * -__get_process_desc(struct intel_context *ce) +static struct parent_scratch * +__get_parent_scratch(struct intel_context *ce) { + BUILD_BUG_ON(sizeof(struct parent_scratch) != PARENT_SCRATCH_SIZE); + BUILD_BUG_ON(sizeof(struct sync_semaphore) != CACHELINE_BYTES); + /* * Need to subtract LRC_STATE_OFFSET here as the * parallel.guc.parent_page is the offset into ce->state while * ce->lrc_reg_reg is ce->state + LRC_STATE_OFFSET. */ - return (struct guc_process_desc *) + return (struct parent_scratch *) (ce->lrc_reg_state + - ((__get_process_desc_offset(ce) - + ((__get_parent_scratch_offset(ce) - LRC_STATE_OFFSET) / sizeof(u32))); } +static struct guc_process_desc * +__get_process_desc(struct intel_context *ce) +{ + struct parent_scratch *ps = __get_parent_scratch(ce); + + return &ps->pdesc; +} + static u32 *get_wq_pointer(struct guc_process_desc *desc, struct intel_context *ce, u32 wqi_size) @@ -425,8 +462,7 @@ static u32 *get_wq_pointer(struct guc_process_desc *desc, } #undef AVAILABLE_SPACE - return ((u32 *)__get_process_desc(ce)) + - ((WQ_OFFSET + ce->parallel.guc.wqi_tail) / sizeof(u32)); + return &__get_parent_scratch(ce)->wq[ce->parallel.guc.wqi_tail / sizeof(u32)]; } static struct guc_lrc_desc *__get_lrc_desc(struct intel_guc *guc, u32 index) @@ -1827,6 +1863,27 @@ static int deregister_context(struct intel_context *ce, u32 guc_id) return __guc_action_deregister_context(guc, guc_id); } +static inline void clear_children_join_go_memory(struct intel_context *ce) +{ + struct parent_scratch *ps = __get_parent_scratch(ce); + int i; + + ps->go.semaphore = 0; + for (i = 0; i < ce->parallel.number_children + 1; ++i) + ps->join[i].semaphore = 0; +} + +static inline u32 get_children_go_value(struct intel_context *ce) +{ + return __get_parent_scratch(ce)->go.semaphore; +} + +static inline u32 get_children_join_value(struct intel_context *ce, + u8 child_index) +{ + return __get_parent_scratch(ce)->join[child_index].semaphore; +} + static void guc_context_policy_init(struct intel_engine_cs *engine, struct guc_lrc_desc *desc) { @@ -1886,7 +1943,7 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop) ce->parallel.guc.wqi_head = 0; desc->process_desc = i915_ggtt_offset(ce->state) + - __get_process_desc_offset(ce); + __get_parent_scratch_offset(ce); desc->wq_addr = i915_ggtt_offset(ce->state) + __get_wq_offset(ce); desc->wq_size = WQ_SIZE; @@ -1908,6 +1965,8 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop) desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD; guc_context_policy_init(engine, desc); } + + clear_children_join_go_memory(ce); } /* @@ -2974,6 +3033,31 @@ static const struct intel_context_ops virtual_child_context_ops = { .get_sibling = guc_virtual_get_sibling, }; +/* + * The below override of the breadcrumbs is enabled when the user configures a + * context for parallel submission (multi-lrc, parent-child). + * + * The overridden breadcrumbs implements an algorithm which allows the GuC to + * safely preempt all the hw contexts configured for parallel submission + * between each BB. The contract between the i915 and GuC is if the parent + * context can be preempted, all the children can be preempted, and the GuC will + * always try to preempt the parent before the children. A handshake between the + * parent / children breadcrumbs ensures the i915 holds up its end of the deal + * creating a window to preempt between each set of BBs. + */ +static int emit_bb_start_parent_no_preempt_mid_batch(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags); +static int emit_bb_start_child_no_preempt_mid_batch(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags); +static u32 * +emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs); +static u32 * +emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs); + static struct intel_context * guc_create_parallel(struct intel_engine_cs **engines, unsigned int num_siblings, @@ -3009,6 +3093,20 @@ guc_create_parallel(struct intel_engine_cs **engines, } } + parent->engine->emit_bb_start = + emit_bb_start_parent_no_preempt_mid_batch; + parent->engine->emit_fini_breadcrumb = + emit_fini_breadcrumb_parent_no_preempt_mid_batch; + parent->engine->emit_fini_breadcrumb_dw = + 12 + 4 * parent->parallel.number_children; + for_each_child(parent, ce) { + ce->engine->emit_bb_start = + emit_bb_start_child_no_preempt_mid_batch; + ce->engine->emit_fini_breadcrumb = + emit_fini_breadcrumb_child_no_preempt_mid_batch; + ce->engine->emit_fini_breadcrumb_dw = 16; + } + kfree(siblings); return parent; @@ -3837,6 +3935,17 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc, drm_printf(p, "\t\tWQI Status: %u\n\n", READ_ONCE(desc->wq_status)); + if (ce->engine->emit_bb_start == + emit_bb_start_parent_no_preempt_mid_batch) { + u8 i; + + drm_printf(p, "\t\tChildren Go: %u\n\n", + get_children_go_value(ce)); + for (i = 0; i < ce->parallel.number_children; ++i) + drm_printf(p, "\t\tChildren Join: %u\n", + get_children_join_value(ce, i)); + } + for_each_child(ce, child) guc_log_context(p, child); } @@ -3844,6 +3953,208 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc, xa_unlock_irqrestore(&guc->context_lookup, flags); } +static inline u32 get_children_go_addr(struct intel_context *ce) +{ + GEM_BUG_ON(!intel_context_is_parent(ce)); + + return i915_ggtt_offset(ce->state) + + __get_parent_scratch_offset(ce) + + offsetof(struct parent_scratch, go.semaphore); +} + +static inline u32 get_children_join_addr(struct intel_context *ce, + u8 child_index) +{ + GEM_BUG_ON(!intel_context_is_parent(ce)); + + return i915_ggtt_offset(ce->state) + + __get_parent_scratch_offset(ce) + + offsetof(struct parent_scratch, join[child_index].semaphore); +} + +#define PARENT_GO_BB 1 +#define PARENT_GO_FINI_BREADCRUMB 0 +#define CHILD_GO_BB 1 +#define CHILD_GO_FINI_BREADCRUMB 0 +static int emit_bb_start_parent_no_preempt_mid_batch(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags) +{ + struct intel_context *ce = rq->context; + u32 *cs; + u8 i; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + cs = intel_ring_begin(rq, 10 + 4 * ce->parallel.number_children); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + /* Wait on children */ + for (i = 0; i < ce->parallel.number_children; ++i) { + *cs++ = (MI_SEMAPHORE_WAIT | + MI_SEMAPHORE_GLOBAL_GTT | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD); + *cs++ = PARENT_GO_BB; + *cs++ = get_children_join_addr(ce, i); + *cs++ = 0; + } + + /* Turn off preemption */ + *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; + *cs++ = MI_NOOP; + + /* Tell children go */ + cs = gen8_emit_ggtt_write(cs, + CHILD_GO_BB, + get_children_go_addr(ce), + 0); + + /* Jump to batch */ + *cs++ = MI_BATCH_BUFFER_START_GEN8 | + (flags & I915_DISPATCH_SECURE ? 0 : BIT(8)); + *cs++ = lower_32_bits(offset); + *cs++ = upper_32_bits(offset); + *cs++ = MI_NOOP; + + intel_ring_advance(rq, cs); + + return 0; +} + +static int emit_bb_start_child_no_preempt_mid_batch(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags) +{ + struct intel_context *ce = rq->context; + struct intel_context *parent = intel_context_to_parent(ce); + u32 *cs; + + GEM_BUG_ON(!intel_context_is_child(ce)); + + cs = intel_ring_begin(rq, 12); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + /* Signal parent */ + cs = gen8_emit_ggtt_write(cs, + PARENT_GO_BB, + get_children_join_addr(parent, + ce->parallel.child_index), + 0); + + /* Wait on parent for go */ + *cs++ = (MI_SEMAPHORE_WAIT | + MI_SEMAPHORE_GLOBAL_GTT | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD); + *cs++ = CHILD_GO_BB; + *cs++ = get_children_go_addr(parent); + *cs++ = 0; + + /* Turn off preemption */ + *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; + + /* Jump to batch */ + *cs++ = MI_BATCH_BUFFER_START_GEN8 | + (flags & I915_DISPATCH_SECURE ? 0 : BIT(8)); + *cs++ = lower_32_bits(offset); + *cs++ = upper_32_bits(offset); + + intel_ring_advance(rq, cs); + + return 0; +} + +static u32 * +emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs) +{ + struct intel_context *ce = rq->context; + u8 i; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + /* Wait on children */ + for (i = 0; i < ce->parallel.number_children; ++i) { + *cs++ = (MI_SEMAPHORE_WAIT | + MI_SEMAPHORE_GLOBAL_GTT | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD); + *cs++ = PARENT_GO_FINI_BREADCRUMB; + *cs++ = get_children_join_addr(ce, i); + *cs++ = 0; + } + + /* Turn on preemption */ + *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; + *cs++ = MI_NOOP; + + /* Tell children go */ + cs = gen8_emit_ggtt_write(cs, + CHILD_GO_FINI_BREADCRUMB, + get_children_go_addr(ce), + 0); + + /* Emit fini breadcrumb */ + cs = gen8_emit_ggtt_write(cs, + rq->fence.seqno, + i915_request_active_timeline(rq)->hwsp_offset, + 0); + + /* User interrupt */ + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + rq->tail = intel_ring_offset(rq, cs); + + return cs; +} + +static u32 * +emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, u32 *cs) +{ + struct intel_context *ce = rq->context; + struct intel_context *parent = intel_context_to_parent(ce); + + GEM_BUG_ON(!intel_context_is_child(ce)); + + /* Turn on preemption */ + *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; + *cs++ = MI_NOOP; + + /* Signal parent */ + cs = gen8_emit_ggtt_write(cs, + PARENT_GO_FINI_BREADCRUMB, + get_children_join_addr(parent, + ce->parallel.child_index), + 0); + + /* Wait parent on for go */ + *cs++ = (MI_SEMAPHORE_WAIT | + MI_SEMAPHORE_GLOBAL_GTT | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD); + *cs++ = CHILD_GO_FINI_BREADCRUMB; + *cs++ = get_children_go_addr(parent); + *cs++ = 0; + + /* Emit fini breadcrumb */ + cs = gen8_emit_ggtt_write(cs, + rq->fence.seqno, + i915_request_active_timeline(rq)->hwsp_offset, + 0); + + /* User interrupt */ + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + rq->tail = intel_ring_offset(rq, cs); + + return cs; +} + static struct intel_context * guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count, unsigned long flags) From 544460c33821b44c2f0c643121303c3dc3f66ef1 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:20:00 -0700 Subject: [PATCH 357/554] drm/i915: Multi-BB execbuf Allow multiple batch buffers to be submitted in a single execbuf IOCTL after a context has been configured with the 'set_parallel' extension. The number batches is implicit based on the contexts configuration. This is implemented with a series of loops. First a loop is used to find all the batches, a loop to pin all the HW contexts, a loop to create all the requests, a loop to submit (emit BB start, etc...) all the requests, a loop to tie the requests to the VMAs they touch, and finally a loop to commit the requests to the backend. A composite fence is also created for the generated requests to return to the user and to stick in dma resv slots. No behavior from the existing IOCTL should be changed aside from when throttling because the ring for a context is full. In this situation, i915 will now wait while holding the object locks. This change was done because the code is much simpler to wait while holding the locks and we believe there isn't a huge benefit of dropping these locks. If this proves false we can restructure the code to drop the locks during the wait. IGT: https://patchwork.freedesktop.org/patch/447008/?series=93071&rev=1 media UMD: https://github.com/intel/media-driver/pull/1252 v2: (Matthew Brost) - Return proper error value if i915_request_create fails v3: (John Harrison) - Add comment explaining create / add order loops + locking - Update commit message explaining different in IOCTL behavior - Line wrap some comments - eb_add_request returns void - Return -EINVAL rather triggering BUG_ON if cmd parser used (Checkpatch) - Check eb->batch_len[*current_batch] v4: (CI) - Set batch len if passed if via execbuf args - Call __i915_request_skip after __i915_request_commit (Kernel test robot) - Initialize rq to NULL in eb_pin_timeline v5: (John Harrison) - Fix typo in comments near bb order loops Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-21-matthew.brost@intel.com --- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 783 ++++++++++++------ drivers/gpu/drm/i915/gt/intel_context.h | 8 +- drivers/gpu/drm/i915/gt/intel_context_types.h | 10 + .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 2 + drivers/gpu/drm/i915/i915_request.h | 9 + drivers/gpu/drm/i915/i915_vma.c | 21 +- drivers/gpu/drm/i915/i915_vma.h | 13 +- 7 files changed, 595 insertions(+), 251 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 8b3a25bd93e6..1cb241298d9b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -246,17 +246,25 @@ struct i915_execbuffer { struct drm_i915_gem_exec_object2 *exec; /** ioctl execobj[] */ struct eb_vma *vma; - struct intel_engine_cs *engine; /** engine to queue the request to */ + struct intel_gt *gt; /* gt for the execbuf */ struct intel_context *context; /* logical state for the request */ struct i915_gem_context *gem_context; /** caller's context */ - struct i915_request *request; /** our request to build */ - struct eb_vma *batch; /** identity of the batch obj/vma */ + /** our requests to build */ + struct i915_request *requests[MAX_ENGINE_INSTANCE + 1]; + /** identity of the batch obj/vma */ + struct eb_vma *batches[MAX_ENGINE_INSTANCE + 1]; struct i915_vma *trampoline; /** trampoline used for chaining */ + /** used for excl fence in dma_resv objects when > 1 BB submitted */ + struct dma_fence *composite_fence; + /** actual size of execobj[] as we may extend it for the cmdparser */ unsigned int buffer_count; + /* number of batches in execbuf IOCTL */ + unsigned int num_batches; + /** list of vma not yet bound during reservation phase */ struct list_head unbound; @@ -283,7 +291,8 @@ struct i915_execbuffer { u64 invalid_flags; /** Set of execobj.flags that are invalid */ - u64 batch_len; /** Length of batch within object */ + /** Length of batch within object */ + u64 batch_len[MAX_ENGINE_INSTANCE + 1]; u32 batch_start_offset; /** Location within object of batch */ u32 batch_flags; /** Flags composed for emit_bb_start() */ struct intel_gt_buffer_pool_node *batch_pool; /** pool node for batch buffer */ @@ -301,14 +310,13 @@ struct i915_execbuffer { }; static int eb_parse(struct i915_execbuffer *eb); -static struct i915_request *eb_pin_engine(struct i915_execbuffer *eb, - bool throttle); +static int eb_pin_engine(struct i915_execbuffer *eb, bool throttle); static void eb_unpin_engine(struct i915_execbuffer *eb); static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb) { - return intel_engine_requires_cmd_parser(eb->engine) || - (intel_engine_using_cmd_parser(eb->engine) && + return intel_engine_requires_cmd_parser(eb->context->engine) || + (intel_engine_using_cmd_parser(eb->context->engine) && eb->args->batch_len); } @@ -535,11 +543,21 @@ eb_validate_vma(struct i915_execbuffer *eb, return 0; } -static void +static inline bool +is_batch_buffer(struct i915_execbuffer *eb, unsigned int buffer_idx) +{ + return eb->args->flags & I915_EXEC_BATCH_FIRST ? + buffer_idx < eb->num_batches : + buffer_idx >= eb->args->buffer_count - eb->num_batches; +} + +static int eb_add_vma(struct i915_execbuffer *eb, - unsigned int i, unsigned batch_idx, + unsigned int *current_batch, + unsigned int i, struct i915_vma *vma) { + struct drm_i915_private *i915 = eb->i915; struct drm_i915_gem_exec_object2 *entry = &eb->exec[i]; struct eb_vma *ev = &eb->vma[i]; @@ -566,15 +584,43 @@ eb_add_vma(struct i915_execbuffer *eb, * Note that actual hangs have only been observed on gen7, but for * paranoia do it everywhere. */ - if (i == batch_idx) { + if (is_batch_buffer(eb, i)) { if (entry->relocation_count && !(ev->flags & EXEC_OBJECT_PINNED)) ev->flags |= __EXEC_OBJECT_NEEDS_BIAS; if (eb->reloc_cache.has_fence) ev->flags |= EXEC_OBJECT_NEEDS_FENCE; - eb->batch = ev; + eb->batches[*current_batch] = ev; + + if (unlikely(ev->flags & EXEC_OBJECT_WRITE)) { + drm_dbg(&i915->drm, + "Attempting to use self-modifying batch buffer\n"); + return -EINVAL; + } + + if (range_overflows_t(u64, + eb->batch_start_offset, + eb->args->batch_len, + ev->vma->size)) { + drm_dbg(&i915->drm, "Attempting to use out-of-bounds batch\n"); + return -EINVAL; + } + + if (eb->args->batch_len == 0) + eb->batch_len[*current_batch] = ev->vma->size - + eb->batch_start_offset; + else + eb->batch_len[*current_batch] = eb->args->batch_len; + if (unlikely(eb->batch_len[*current_batch] == 0)) { /* impossible! */ + drm_dbg(&i915->drm, "Invalid batch length\n"); + return -EINVAL; + } + + ++*current_batch; } + + return 0; } static inline int use_cpu_reloc(const struct reloc_cache *cache, @@ -718,14 +764,6 @@ static int eb_reserve(struct i915_execbuffer *eb) } while (1); } -static unsigned int eb_batch_index(const struct i915_execbuffer *eb) -{ - if (eb->args->flags & I915_EXEC_BATCH_FIRST) - return 0; - else - return eb->buffer_count - 1; -} - static int eb_select_context(struct i915_execbuffer *eb) { struct i915_gem_context *ctx; @@ -846,9 +884,7 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle) static int eb_lookup_vmas(struct i915_execbuffer *eb) { - struct drm_i915_private *i915 = eb->i915; - unsigned int batch = eb_batch_index(eb); - unsigned int i; + unsigned int i, current_batch = 0; int err = 0; INIT_LIST_HEAD(&eb->relocs); @@ -868,7 +904,9 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) goto err; } - eb_add_vma(eb, i, batch, vma); + err = eb_add_vma(eb, ¤t_batch, i, vma); + if (err) + return err; if (i915_gem_object_is_userptr(vma->obj)) { err = i915_gem_object_userptr_submit_init(vma->obj); @@ -891,26 +929,6 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) } } - if (unlikely(eb->batch->flags & EXEC_OBJECT_WRITE)) { - drm_dbg(&i915->drm, - "Attempting to use self-modifying batch buffer\n"); - return -EINVAL; - } - - if (range_overflows_t(u64, - eb->batch_start_offset, eb->batch_len, - eb->batch->vma->size)) { - drm_dbg(&i915->drm, "Attempting to use out-of-bounds batch\n"); - return -EINVAL; - } - - if (eb->batch_len == 0) - eb->batch_len = eb->batch->vma->size - eb->batch_start_offset; - if (unlikely(eb->batch_len == 0)) { /* impossible! */ - drm_dbg(&i915->drm, "Invalid batch length\n"); - return -EINVAL; - } - return 0; err: @@ -1643,8 +1661,7 @@ static int eb_reinit_userptr(struct i915_execbuffer *eb) return 0; } -static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb, - struct i915_request *rq) +static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb) { bool have_copy = false; struct eb_vma *ev; @@ -1660,21 +1677,6 @@ repeat: eb_release_vmas(eb, false); i915_gem_ww_ctx_fini(&eb->ww); - if (rq) { - /* nonblocking is always false */ - if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, - MAX_SCHEDULE_TIMEOUT) < 0) { - i915_request_put(rq); - rq = NULL; - - err = -EINTR; - goto err_relock; - } - - i915_request_put(rq); - rq = NULL; - } - /* * We take 3 passes through the slowpatch. * @@ -1701,28 +1703,21 @@ repeat: if (!err) err = eb_reinit_userptr(eb); -err_relock: i915_gem_ww_ctx_init(&eb->ww, true); if (err) goto out; /* reacquire the objects */ repeat_validate: - rq = eb_pin_engine(eb, false); - if (IS_ERR(rq)) { - err = PTR_ERR(rq); - rq = NULL; + err = eb_pin_engine(eb, false); + if (err) goto err; - } - - /* We didn't throttle, should be NULL */ - GEM_WARN_ON(rq); err = eb_validate_vmas(eb); if (err) goto err; - GEM_BUG_ON(!eb->batch); + GEM_BUG_ON(!eb->batches[0]); list_for_each_entry(ev, &eb->relocs, reloc_link) { if (!have_copy) { @@ -1786,46 +1781,23 @@ out: } } - if (rq) - i915_request_put(rq); - return err; } static int eb_relocate_parse(struct i915_execbuffer *eb) { int err; - struct i915_request *rq = NULL; bool throttle = true; retry: - rq = eb_pin_engine(eb, throttle); - if (IS_ERR(rq)) { - err = PTR_ERR(rq); - rq = NULL; + err = eb_pin_engine(eb, throttle); + if (err) { if (err != -EDEADLK) return err; goto err; } - if (rq) { - bool nonblock = eb->file->filp->f_flags & O_NONBLOCK; - - /* Need to drop all locks now for throttling, take slowpath */ - err = i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, 0); - if (err == -ETIME) { - if (nonblock) { - err = -EWOULDBLOCK; - i915_request_put(rq); - goto err; - } - goto slow; - } - i915_request_put(rq); - rq = NULL; - } - /* only throttle once, even if we didn't need to throttle */ throttle = false; @@ -1865,7 +1837,7 @@ err: return err; slow: - err = eb_relocate_parse_slow(eb, rq); + err = eb_relocate_parse_slow(eb); if (err) /* * If the user expects the execobject.offset and @@ -1879,11 +1851,40 @@ slow: return err; } +/* + * Using two helper loops for the order of which requests / batches are created + * and added the to backend. Requests are created in order from the parent to + * the last child. Requests are added in the reverse order, from the last child + * to parent. This is done for locking reasons as the timeline lock is acquired + * during request creation and released when the request is added to the + * backend. To make lockdep happy (see intel_context_timeline_lock) this must be + * the ordering. + */ +#define for_each_batch_create_order(_eb, _i) \ + for ((_i) = 0; (_i) < (_eb)->num_batches; ++(_i)) +#define for_each_batch_add_order(_eb, _i) \ + BUILD_BUG_ON(!typecheck(int, _i)); \ + for ((_i) = (_eb)->num_batches - 1; (_i) >= 0; --(_i)) + +static struct i915_request * +eb_find_first_request_added(struct i915_execbuffer *eb) +{ + int i; + + for_each_batch_add_order(eb, i) + if (eb->requests[i]) + return eb->requests[i]; + + GEM_BUG_ON("Request not found"); + + return NULL; +} + static int eb_move_to_gpu(struct i915_execbuffer *eb) { const unsigned int count = eb->buffer_count; unsigned int i = count; - int err = 0; + int err = 0, j; while (i--) { struct eb_vma *ev = &eb->vma[i]; @@ -1896,11 +1897,17 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) if (flags & EXEC_OBJECT_CAPTURE) { struct i915_capture_list *capture; - capture = kmalloc(sizeof(*capture), GFP_KERNEL); - if (capture) { - capture->next = eb->request->capture_list; - capture->vma = vma; - eb->request->capture_list = capture; + for_each_batch_create_order(eb, j) { + if (!eb->requests[j]) + break; + + capture = kmalloc(sizeof(*capture), GFP_KERNEL); + if (capture) { + capture->next = + eb->requests[j]->capture_list; + capture->vma = vma; + eb->requests[j]->capture_list = capture; + } } } @@ -1921,14 +1928,26 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) flags &= ~EXEC_OBJECT_ASYNC; } + /* We only need to await on the first request */ if (err == 0 && !(flags & EXEC_OBJECT_ASYNC)) { err = i915_request_await_object - (eb->request, obj, flags & EXEC_OBJECT_WRITE); + (eb_find_first_request_added(eb), obj, + flags & EXEC_OBJECT_WRITE); } - if (err == 0) - err = i915_vma_move_to_active(vma, eb->request, - flags | __EXEC_OBJECT_NO_RESERVE); + for_each_batch_add_order(eb, j) { + if (err) + break; + if (!eb->requests[j]) + continue; + + err = _i915_vma_move_to_active(vma, eb->requests[j], + j ? NULL : + eb->composite_fence ? + eb->composite_fence : + &eb->requests[j]->fence, + flags | __EXEC_OBJECT_NO_RESERVE); + } } #ifdef CONFIG_MMU_NOTIFIER @@ -1959,11 +1978,16 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) goto err_skip; /* Unconditionally flush any chipset caches (for streaming writes). */ - intel_gt_chipset_flush(eb->engine->gt); + intel_gt_chipset_flush(eb->gt); return 0; err_skip: - i915_request_set_error_once(eb->request, err); + for_each_batch_create_order(eb, j) { + if (!eb->requests[j]) + break; + + i915_request_set_error_once(eb->requests[j], err); + } return err; } @@ -2058,14 +2082,17 @@ static int eb_parse(struct i915_execbuffer *eb) int err; if (!eb_use_cmdparser(eb)) { - batch = eb_dispatch_secure(eb, eb->batch->vma); + batch = eb_dispatch_secure(eb, eb->batches[0]->vma); if (IS_ERR(batch)) return PTR_ERR(batch); goto secure_batch; } - len = eb->batch_len; + if (intel_context_is_parallel(eb->context)) + return -EINVAL; + + len = eb->batch_len[0]; if (!CMDPARSER_USES_GGTT(eb->i915)) { /* * ppGTT backed shadow buffers must be mapped RO, to prevent @@ -2079,11 +2106,11 @@ static int eb_parse(struct i915_execbuffer *eb) } else { len += I915_CMD_PARSER_TRAMPOLINE_SIZE; } - if (unlikely(len < eb->batch_len)) /* last paranoid check of overflow */ + if (unlikely(len < eb->batch_len[0])) /* last paranoid check of overflow */ return -EINVAL; if (!pool) { - pool = intel_gt_get_buffer_pool(eb->engine->gt, len, + pool = intel_gt_get_buffer_pool(eb->gt, len, I915_MAP_WB); if (IS_ERR(pool)) return PTR_ERR(pool); @@ -2108,7 +2135,7 @@ static int eb_parse(struct i915_execbuffer *eb) trampoline = shadow; shadow = shadow_batch_pin(eb, pool->obj, - &eb->engine->gt->ggtt->vm, + &eb->gt->ggtt->vm, PIN_GLOBAL); if (IS_ERR(shadow)) { err = PTR_ERR(shadow); @@ -2130,26 +2157,29 @@ static int eb_parse(struct i915_execbuffer *eb) if (err) goto err_trampoline; - err = intel_engine_cmd_parser(eb->engine, - eb->batch->vma, + err = intel_engine_cmd_parser(eb->context->engine, + eb->batches[0]->vma, eb->batch_start_offset, - eb->batch_len, + eb->batch_len[0], shadow, trampoline); if (err) goto err_unpin_batch; - eb->batch = &eb->vma[eb->buffer_count++]; - eb->batch->vma = i915_vma_get(shadow); - eb->batch->flags = __EXEC_OBJECT_HAS_PIN; + eb->batches[0] = &eb->vma[eb->buffer_count++]; + eb->batches[0]->vma = i915_vma_get(shadow); + eb->batches[0]->flags = __EXEC_OBJECT_HAS_PIN; eb->trampoline = trampoline; eb->batch_start_offset = 0; secure_batch: if (batch) { - eb->batch = &eb->vma[eb->buffer_count++]; - eb->batch->flags = __EXEC_OBJECT_HAS_PIN; - eb->batch->vma = i915_vma_get(batch); + if (intel_context_is_parallel(eb->context)) + return -EINVAL; + + eb->batches[0] = &eb->vma[eb->buffer_count++]; + eb->batches[0]->flags = __EXEC_OBJECT_HAS_PIN; + eb->batches[0]->vma = i915_vma_get(batch); } return 0; @@ -2165,19 +2195,18 @@ err: return err; } -static int eb_submit(struct i915_execbuffer *eb, struct i915_vma *batch) +static int eb_request_submit(struct i915_execbuffer *eb, + struct i915_request *rq, + struct i915_vma *batch, + u64 batch_len) { int err; - if (intel_context_nopreempt(eb->context)) - __set_bit(I915_FENCE_FLAG_NOPREEMPT, &eb->request->fence.flags); - - err = eb_move_to_gpu(eb); - if (err) - return err; + if (intel_context_nopreempt(rq->context)) + __set_bit(I915_FENCE_FLAG_NOPREEMPT, &rq->fence.flags); if (eb->args->flags & I915_EXEC_GEN7_SOL_RESET) { - err = i915_reset_gen7_sol_offsets(eb->request); + err = i915_reset_gen7_sol_offsets(rq); if (err) return err; } @@ -2188,26 +2217,26 @@ static int eb_submit(struct i915_execbuffer *eb, struct i915_vma *batch) * allows us to determine if the batch is still waiting on the GPU * or actually running by checking the breadcrumb. */ - if (eb->engine->emit_init_breadcrumb) { - err = eb->engine->emit_init_breadcrumb(eb->request); + if (rq->context->engine->emit_init_breadcrumb) { + err = rq->context->engine->emit_init_breadcrumb(rq); if (err) return err; } - err = eb->engine->emit_bb_start(eb->request, - batch->node.start + - eb->batch_start_offset, - eb->batch_len, - eb->batch_flags); + err = rq->context->engine->emit_bb_start(rq, + batch->node.start + + eb->batch_start_offset, + batch_len, + eb->batch_flags); if (err) return err; if (eb->trampoline) { + GEM_BUG_ON(intel_context_is_parallel(rq->context)); GEM_BUG_ON(eb->batch_start_offset); - err = eb->engine->emit_bb_start(eb->request, - eb->trampoline->node.start + - eb->batch_len, - 0, 0); + err = rq->context->engine->emit_bb_start(rq, + eb->trampoline->node.start + + batch_len, 0, 0); if (err) return err; } @@ -2215,6 +2244,27 @@ static int eb_submit(struct i915_execbuffer *eb, struct i915_vma *batch) return 0; } +static int eb_submit(struct i915_execbuffer *eb) +{ + unsigned int i; + int err; + + err = eb_move_to_gpu(eb); + + for_each_batch_create_order(eb, i) { + if (!eb->requests[i]) + break; + + trace_i915_request_queue(eb->requests[i], eb->batch_flags); + if (!err) + err = eb_request_submit(eb, eb->requests[i], + eb->batches[i]->vma, + eb->batch_len[i]); + } + + return err; +} + static int num_vcs_engines(const struct drm_i915_private *i915) { return hweight_long(VDBOX_MASK(&i915->gt)); @@ -2280,26 +2330,11 @@ static struct i915_request *eb_throttle(struct i915_execbuffer *eb, struct intel return i915_request_get(rq); } -static struct i915_request *eb_pin_engine(struct i915_execbuffer *eb, bool throttle) +static int eb_pin_timeline(struct i915_execbuffer *eb, struct intel_context *ce, + bool throttle) { - struct intel_context *ce = eb->context; struct intel_timeline *tl; struct i915_request *rq = NULL; - int err; - - GEM_BUG_ON(eb->args->flags & __EXEC_ENGINE_PINNED); - - if (unlikely(intel_context_is_banned(ce))) - return ERR_PTR(-EIO); - - /* - * Pinning the contexts may generate requests in order to acquire - * GGTT space, so do this first before we reserve a seqno for - * ourselves. - */ - err = intel_context_pin_ww(ce, &eb->ww); - if (err) - return ERR_PTR(err); /* * Take a local wakeref for preparing to dispatch the execbuf as @@ -2310,33 +2345,108 @@ static struct i915_request *eb_pin_engine(struct i915_execbuffer *eb, bool throt * taken on the engine, and the parent device. */ tl = intel_context_timeline_lock(ce); - if (IS_ERR(tl)) { - intel_context_unpin(ce); - return ERR_CAST(tl); - } + if (IS_ERR(tl)) + return PTR_ERR(tl); intel_context_enter(ce); if (throttle) rq = eb_throttle(eb, ce); intel_context_timeline_unlock(tl); + if (rq) { + bool nonblock = eb->file->filp->f_flags & O_NONBLOCK; + long timeout = nonblock ? 0 : MAX_SCHEDULE_TIMEOUT; + + if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, + timeout) < 0) { + i915_request_put(rq); + + tl = intel_context_timeline_lock(ce); + intel_context_exit(ce); + intel_context_timeline_unlock(tl); + + if (nonblock) + return -EWOULDBLOCK; + else + return -EINTR; + } + i915_request_put(rq); + } + + return 0; +} + +static int eb_pin_engine(struct i915_execbuffer *eb, bool throttle) +{ + struct intel_context *ce = eb->context, *child; + int err; + int i = 0, j = 0; + + GEM_BUG_ON(eb->args->flags & __EXEC_ENGINE_PINNED); + + if (unlikely(intel_context_is_banned(ce))) + return -EIO; + + /* + * Pinning the contexts may generate requests in order to acquire + * GGTT space, so do this first before we reserve a seqno for + * ourselves. + */ + err = intel_context_pin_ww(ce, &eb->ww); + if (err) + return err; + for_each_child(ce, child) { + err = intel_context_pin_ww(child, &eb->ww); + GEM_BUG_ON(err); /* perma-pinned should incr a counter */ + } + + for_each_child(ce, child) { + err = eb_pin_timeline(eb, child, throttle); + if (err) + goto unwind; + ++i; + } + err = eb_pin_timeline(eb, ce, throttle); + if (err) + goto unwind; + eb->args->flags |= __EXEC_ENGINE_PINNED; - return rq; + return 0; + +unwind: + for_each_child(ce, child) { + if (j++ < i) { + mutex_lock(&child->timeline->mutex); + intel_context_exit(child); + mutex_unlock(&child->timeline->mutex); + } + } + for_each_child(ce, child) + intel_context_unpin(child); + intel_context_unpin(ce); + return err; } static void eb_unpin_engine(struct i915_execbuffer *eb) { - struct intel_context *ce = eb->context; - struct intel_timeline *tl = ce->timeline; + struct intel_context *ce = eb->context, *child; if (!(eb->args->flags & __EXEC_ENGINE_PINNED)) return; eb->args->flags &= ~__EXEC_ENGINE_PINNED; - mutex_lock(&tl->mutex); + for_each_child(ce, child) { + mutex_lock(&child->timeline->mutex); + intel_context_exit(child); + mutex_unlock(&child->timeline->mutex); + + intel_context_unpin(child); + } + + mutex_lock(&ce->timeline->mutex); intel_context_exit(ce); - mutex_unlock(&tl->mutex); + mutex_unlock(&ce->timeline->mutex); intel_context_unpin(ce); } @@ -2387,7 +2497,7 @@ eb_select_legacy_ring(struct i915_execbuffer *eb) static int eb_select_engine(struct i915_execbuffer *eb) { - struct intel_context *ce; + struct intel_context *ce, *child; unsigned int idx; int err; @@ -2400,6 +2510,20 @@ eb_select_engine(struct i915_execbuffer *eb) if (IS_ERR(ce)) return PTR_ERR(ce); + if (intel_context_is_parallel(ce)) { + if (eb->buffer_count < ce->parallel.number_children + 1) { + intel_context_put(ce); + return -EINVAL; + } + if (eb->batch_start_offset || eb->args->batch_len) { + intel_context_put(ce); + return -EINVAL; + } + } + eb->num_batches = ce->parallel.number_children + 1; + + for_each_child(ce, child) + intel_context_get(child); intel_gt_pm_get(ce->engine->gt); if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { @@ -2407,6 +2531,13 @@ eb_select_engine(struct i915_execbuffer *eb) if (err) goto err; } + for_each_child(ce, child) { + if (!test_bit(CONTEXT_ALLOC_BIT, &child->flags)) { + err = intel_context_alloc_state(child); + if (err) + goto err; + } + } /* * ABI: Before userspace accesses the GPU (e.g. execbuffer), report @@ -2417,7 +2548,7 @@ eb_select_engine(struct i915_execbuffer *eb) goto err; eb->context = ce; - eb->engine = ce->engine; + eb->gt = ce->engine->gt; /* * Make sure engine pool stays alive even if we call intel_context_put @@ -2428,6 +2559,8 @@ eb_select_engine(struct i915_execbuffer *eb) err: intel_gt_pm_put(ce->engine->gt); + for_each_child(ce, child) + intel_context_put(child); intel_context_put(ce); return err; } @@ -2435,7 +2568,11 @@ err: static void eb_put_engine(struct i915_execbuffer *eb) { - intel_gt_pm_put(eb->engine->gt); + struct intel_context *child; + + intel_gt_pm_put(eb->gt); + for_each_child(eb->context, child) + intel_context_put(child); intel_context_put(eb->context); } @@ -2658,7 +2795,8 @@ static void put_fence_array(struct eb_fence *fences, int num_fences) } static int -await_fence_array(struct i915_execbuffer *eb) +await_fence_array(struct i915_execbuffer *eb, + struct i915_request *rq) { unsigned int n; int err; @@ -2672,8 +2810,7 @@ await_fence_array(struct i915_execbuffer *eb) if (!eb->fences[n].dma_fence) continue; - err = i915_request_await_dma_fence(eb->request, - eb->fences[n].dma_fence); + err = i915_request_await_dma_fence(rq, eb->fences[n].dma_fence); if (err < 0) return err; } @@ -2681,9 +2818,9 @@ await_fence_array(struct i915_execbuffer *eb) return 0; } -static void signal_fence_array(const struct i915_execbuffer *eb) +static void signal_fence_array(const struct i915_execbuffer *eb, + struct dma_fence * const fence) { - struct dma_fence * const fence = &eb->request->fence; unsigned int n; for (n = 0; n < eb->num_fences; n++) { @@ -2731,9 +2868,9 @@ static void retire_requests(struct intel_timeline *tl, struct i915_request *end) break; } -static int eb_request_add(struct i915_execbuffer *eb, int err) +static int eb_request_add(struct i915_execbuffer *eb, struct i915_request *rq, + int err, bool last_parallel) { - struct i915_request *rq = eb->request; struct intel_timeline * const tl = i915_request_timeline(rq); struct i915_sched_attr attr = {}; struct i915_request *prev; @@ -2755,6 +2892,17 @@ static int eb_request_add(struct i915_execbuffer *eb, int err) err = -ENOENT; /* override any transient errors */ } + if (intel_context_is_parallel(eb->context)) { + if (err) { + __i915_request_skip(rq); + set_bit(I915_FENCE_FLAG_SKIP_PARALLEL, + &rq->fence.flags); + } + if (last_parallel) + set_bit(I915_FENCE_FLAG_SUBMIT_PARALLEL, + &rq->fence.flags); + } + __i915_request_queue(rq, &attr); /* Try to clean up the client's timeline after submitting the request */ @@ -2766,6 +2914,25 @@ static int eb_request_add(struct i915_execbuffer *eb, int err) return err; } +static int eb_requests_add(struct i915_execbuffer *eb, int err) +{ + int i; + + /* + * We iterate in reverse order of creation to release timeline mutexes in + * same order. + */ + for_each_batch_add_order(eb, i) { + struct i915_request *rq = eb->requests[i]; + + if (!rq) + continue; + err |= eb_request_add(eb, rq, err, i == 0); + } + + return err; +} + static const i915_user_extension_fn execbuf_extensions[] = { [DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES] = parse_timeline_fences, }; @@ -2792,6 +2959,182 @@ parse_execbuf2_extensions(struct drm_i915_gem_execbuffer2 *args, eb); } +static void eb_requests_get(struct i915_execbuffer *eb) +{ + unsigned int i; + + for_each_batch_create_order(eb, i) { + if (!eb->requests[i]) + break; + + i915_request_get(eb->requests[i]); + } +} + +static void eb_requests_put(struct i915_execbuffer *eb) +{ + unsigned int i; + + for_each_batch_create_order(eb, i) { + if (!eb->requests[i]) + break; + + i915_request_put(eb->requests[i]); + } +} + +static struct sync_file * +eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd) +{ + struct sync_file *out_fence = NULL; + struct dma_fence_array *fence_array; + struct dma_fence **fences; + unsigned int i; + + GEM_BUG_ON(!intel_context_is_parent(eb->context)); + + fences = kmalloc_array(eb->num_batches, sizeof(*fences), GFP_KERNEL); + if (!fences) + return ERR_PTR(-ENOMEM); + + for_each_batch_create_order(eb, i) + fences[i] = &eb->requests[i]->fence; + + fence_array = dma_fence_array_create(eb->num_batches, + fences, + eb->context->parallel.fence_context, + eb->context->parallel.seqno, + false); + if (!fence_array) { + kfree(fences); + return ERR_PTR(-ENOMEM); + } + + /* Move ownership to the dma_fence_array created above */ + for_each_batch_create_order(eb, i) + dma_fence_get(fences[i]); + + if (out_fence_fd != -1) { + out_fence = sync_file_create(&fence_array->base); + /* sync_file now owns fence_arry, drop creation ref */ + dma_fence_put(&fence_array->base); + if (!out_fence) + return ERR_PTR(-ENOMEM); + } + + eb->composite_fence = &fence_array->base; + + return out_fence; +} + +static struct sync_file * +eb_fences_add(struct i915_execbuffer *eb, struct i915_request *rq, + struct dma_fence *in_fence, int out_fence_fd) +{ + struct sync_file *out_fence = NULL; + int err; + + if (unlikely(eb->gem_context->syncobj)) { + struct dma_fence *fence; + + fence = drm_syncobj_fence_get(eb->gem_context->syncobj); + err = i915_request_await_dma_fence(rq, fence); + dma_fence_put(fence); + if (err) + return ERR_PTR(err); + } + + if (in_fence) { + if (eb->args->flags & I915_EXEC_FENCE_SUBMIT) + err = i915_request_await_execution(rq, in_fence); + else + err = i915_request_await_dma_fence(rq, in_fence); + if (err < 0) + return ERR_PTR(err); + } + + if (eb->fences) { + err = await_fence_array(eb, rq); + if (err) + return ERR_PTR(err); + } + + if (intel_context_is_parallel(eb->context)) { + out_fence = eb_composite_fence_create(eb, out_fence_fd); + if (IS_ERR(out_fence)) + return ERR_PTR(-ENOMEM); + } else if (out_fence_fd != -1) { + out_fence = sync_file_create(&rq->fence); + if (!out_fence) + return ERR_PTR(-ENOMEM); + } + + return out_fence; +} + +static struct intel_context * +eb_find_context(struct i915_execbuffer *eb, unsigned int context_number) +{ + struct intel_context *child; + + if (likely(context_number == 0)) + return eb->context; + + for_each_child(eb->context, child) + if (!--context_number) + return child; + + GEM_BUG_ON("Context not found"); + + return NULL; +} + +static struct sync_file * +eb_requests_create(struct i915_execbuffer *eb, struct dma_fence *in_fence, + int out_fence_fd) +{ + struct sync_file *out_fence = NULL; + unsigned int i; + + for_each_batch_create_order(eb, i) { + /* Allocate a request for this batch buffer nice and early. */ + eb->requests[i] = i915_request_create(eb_find_context(eb, i)); + if (IS_ERR(eb->requests[i])) { + out_fence = ERR_PTR(PTR_ERR(eb->requests[i])); + eb->requests[i] = NULL; + return out_fence; + } + + /* + * Only the first request added (committed to backend) has to + * take the in fences into account as all subsequent requests + * will have fences inserted inbetween them. + */ + if (i + 1 == eb->num_batches) { + out_fence = eb_fences_add(eb, eb->requests[i], + in_fence, out_fence_fd); + if (IS_ERR(out_fence)) + return out_fence; + } + + /* + * Whilst this request exists, batch_obj will be on the + * active_list, and so will hold the active reference. Only when + * this request is retired will the batch_obj be moved onto + * the inactive_list and lose its active reference. Hence we do + * not need to explicitly hold another reference here. + */ + eb->requests[i]->batch = eb->batches[i]->vma; + if (eb->batch_pool) { + GEM_BUG_ON(intel_context_is_parallel(eb->context)); + intel_gt_buffer_pool_mark_active(eb->batch_pool, + eb->requests[i]); + } + } + + return out_fence; +} + static int i915_gem_do_execbuffer(struct drm_device *dev, struct drm_file *file, @@ -2802,7 +3145,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, struct i915_execbuffer eb; struct dma_fence *in_fence = NULL; struct sync_file *out_fence = NULL; - struct i915_vma *batch; int out_fence_fd = -1; int err; @@ -2826,12 +3168,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.buffer_count = args->buffer_count; eb.batch_start_offset = args->batch_start_offset; - eb.batch_len = args->batch_len; eb.trampoline = NULL; eb.fences = NULL; eb.num_fences = 0; + memset(eb.requests, 0, sizeof(struct i915_request *) * + ARRAY_SIZE(eb.requests)); + eb.composite_fence = NULL; + eb.batch_flags = 0; if (args->flags & I915_EXEC_SECURE) { if (GRAPHICS_VER(i915) >= 11) @@ -2915,70 +3260,25 @@ i915_gem_do_execbuffer(struct drm_device *dev, ww_acquire_done(&eb.ww.ctx); - batch = eb.batch->vma; - - /* Allocate a request for this batch buffer nice and early. */ - eb.request = i915_request_create(eb.context); - if (IS_ERR(eb.request)) { - err = PTR_ERR(eb.request); - goto err_vma; - } - - if (unlikely(eb.gem_context->syncobj)) { - struct dma_fence *fence; - - fence = drm_syncobj_fence_get(eb.gem_context->syncobj); - err = i915_request_await_dma_fence(eb.request, fence); - dma_fence_put(fence); - if (err) - goto err_ext; - } - - if (in_fence) { - if (args->flags & I915_EXEC_FENCE_SUBMIT) - err = i915_request_await_execution(eb.request, - in_fence); + out_fence = eb_requests_create(&eb, in_fence, out_fence_fd); + if (IS_ERR(out_fence)) { + err = PTR_ERR(out_fence); + if (eb.requests[0]) + goto err_request; else - err = i915_request_await_dma_fence(eb.request, - in_fence); - if (err < 0) - goto err_request; + goto err_vma; } - if (eb.fences) { - err = await_fence_array(&eb); - if (err) - goto err_request; - } - - if (out_fence_fd != -1) { - out_fence = sync_file_create(&eb.request->fence); - if (!out_fence) { - err = -ENOMEM; - goto err_request; - } - } - - /* - * Whilst this request exists, batch_obj will be on the - * active_list, and so will hold the active reference. Only when this - * request is retired will the the batch_obj be moved onto the - * inactive_list and lose its active reference. Hence we do not need - * to explicitly hold another reference here. - */ - eb.request->batch = batch; - if (eb.batch_pool) - intel_gt_buffer_pool_mark_active(eb.batch_pool, eb.request); - - trace_i915_request_queue(eb.request, eb.batch_flags); - err = eb_submit(&eb, batch); + err = eb_submit(&eb); err_request: - i915_request_get(eb.request); - err = eb_request_add(&eb, err); + eb_requests_get(&eb); + err = eb_requests_add(&eb, err); if (eb.fences) - signal_fence_array(&eb); + signal_fence_array(&eb, eb.composite_fence ? + eb.composite_fence : + &eb.requests[0]->fence); if (out_fence) { if (err == 0) { @@ -2993,10 +3293,15 @@ err_request: if (unlikely(eb.gem_context->syncobj)) { drm_syncobj_replace_fence(eb.gem_context->syncobj, - &eb.request->fence); + eb.composite_fence ? + eb.composite_fence : + &eb.requests[0]->fence); } - i915_request_put(eb.request); + if (!out_fence && eb.composite_fence) + dma_fence_put(eb.composite_fence); + + eb_requests_put(&eb); err_vma: eb_release_vmas(&eb, true); diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index edf12caaade3..246c37d72cd7 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -241,7 +241,13 @@ intel_context_timeline_lock(struct intel_context *ce) struct intel_timeline *tl = ce->timeline; int err; - err = mutex_lock_interruptible(&tl->mutex); + if (intel_context_is_parent(ce)) + err = mutex_lock_interruptible_nested(&tl->mutex, 0); + else if (intel_context_is_child(ce)) + err = mutex_lock_interruptible_nested(&tl->mutex, + ce->parallel.child_index + 1); + else + err = mutex_lock_interruptible(&tl->mutex); if (err) return ERR_PTR(err); diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 95a5b94b4ece..9e0177dc5484 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -248,6 +248,16 @@ struct intel_context { * context */ struct i915_request *last_rq; + /** + * @fence_context: fence context composite fence when doing + * parallel submission + */ + u64 fence_context; + /** + * @seqno: seqno for composite fence when doing parallel + * submission + */ + u32 seqno; /** @number_children: number of children if parent */ u8 number_children; /** @child_index: index into child_list if child */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 50f0f4eba03b..361fab2cae99 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -3093,6 +3093,8 @@ guc_create_parallel(struct intel_engine_cs **engines, } } + parent->parallel.fence_context = dma_fence_context_alloc(1); + parent->engine->emit_bb_start = emit_bb_start_parent_no_preempt_mid_batch; parent->engine->emit_fini_breadcrumb = diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 8950785e55d6..24db8459376b 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -147,6 +147,15 @@ enum { * tail. */ I915_FENCE_FLAG_SUBMIT_PARALLEL, + + /* + * I915_FENCE_FLAG_SKIP_PARALLEL - request with a context in a + * parent-child relationship (parallel submission, multi-lrc) that + * hit an error while generating requests in the execbuf IOCTL. + * Indicates this request should be skipped as another request in + * submission / relationship encoutered an error. + */ + I915_FENCE_FLAG_SKIP_PARALLEL, }; /** diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 4b7fc4647e46..90546fa58fc1 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1234,9 +1234,10 @@ int __i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq) return i915_active_add_request(&vma->active, rq); } -int i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags) +int _i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + struct dma_fence *fence, + unsigned int flags) { struct drm_i915_gem_object *obj = vma->obj; int err; @@ -1257,9 +1258,11 @@ int i915_vma_move_to_active(struct i915_vma *vma, intel_frontbuffer_put(front); } - dma_resv_add_excl_fence(vma->resv, &rq->fence); - obj->write_domain = I915_GEM_DOMAIN_RENDER; - obj->read_domains = 0; + if (fence) { + dma_resv_add_excl_fence(vma->resv, fence); + obj->write_domain = I915_GEM_DOMAIN_RENDER; + obj->read_domains = 0; + } } else { if (!(flags & __EXEC_OBJECT_NO_RESERVE)) { err = dma_resv_reserve_shared(vma->resv, 1); @@ -1267,8 +1270,10 @@ int i915_vma_move_to_active(struct i915_vma *vma, return err; } - dma_resv_add_shared_fence(vma->resv, &rq->fence); - obj->write_domain = 0; + if (fence) { + dma_resv_add_shared_fence(vma->resv, fence); + obj->write_domain = 0; + } } if (flags & EXEC_OBJECT_NEEDS_FENCE && vma->fence) diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index ed69f66c7ab0..648dbe744c96 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -57,9 +57,16 @@ static inline bool i915_vma_is_active(const struct i915_vma *vma) int __must_check __i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq); -int __must_check i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags); +int __must_check _i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + struct dma_fence *fence, + unsigned int flags); +static inline int __must_check +i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq, + unsigned int flags) +{ + return _i915_vma_move_to_active(vma, rq, &rq->fence, flags); +} #define __i915_vma_flags(v) ((unsigned long *)&(v)->flags.counter) From 28c7023332ceb95c19d9f19914a63f88d15ab427 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:20:01 -0700 Subject: [PATCH 358/554] drm/i915/guc: Handle errors in multi-lrc requests If an error occurs in the front end when multi-lrc requests are getting generated we need to skip these in the backend but we still need to emit the breadcrumbs seqno. An issues arises because with multi-lrc breadcrumbs there is a handshake between the parent and children to make forward progress. If all the requests are not present this handshake doesn't work. To work around this, if multi-lrc request has an error we skip the handshake but still emit the breadcrumbs seqno. v2: (John Harrison) - Add comment explaining the skipping of the handshake logic - Fix typos in the commit message v3: (John Harrison) - Fix up some comments about the math to NOP the ring Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-22-matthew.brost@intel.com --- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 361fab2cae99..d7710debcd47 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -4070,8 +4070,8 @@ static int emit_bb_start_child_no_preempt_mid_batch(struct i915_request *rq, } static u32 * -emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, - u32 *cs) +__emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs) { struct intel_context *ce = rq->context; u8 i; @@ -4099,6 +4099,45 @@ emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, get_children_go_addr(ce), 0); + return cs; +} + +/* + * If this true, a submission of multi-lrc requests had an error and the + * requests need to be skipped. The front end (execuf IOCTL) should've called + * i915_request_skip which squashes the BB but we still need to emit the fini + * breadrcrumbs seqno write. At this point we don't know how many of the + * requests in the multi-lrc submission were generated so we can't do the + * handshake between the parent and children (e.g. if 4 requests should be + * generated but 2nd hit an error only 1 would be seen by the GuC backend). + * Simply skip the handshake, but still emit the breadcrumbd seqno, if an error + * has occurred on any of the requests in submission / relationship. + */ +static inline bool skip_handshake(struct i915_request *rq) +{ + return test_bit(I915_FENCE_FLAG_SKIP_PARALLEL, &rq->fence.flags); +} + +static u32 * +emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs) +{ + struct intel_context *ce = rq->context; + + GEM_BUG_ON(!intel_context_is_parent(ce)); + + if (unlikely(skip_handshake(rq))) { + /* + * NOP everything in __emit_fini_breadcrumb_parent_no_preempt_mid_batch, + * the -6 comes from the length of the emits below. + */ + memset(cs, 0, sizeof(u32) * + (ce->engine->emit_fini_breadcrumb_dw - 6)); + cs += ce->engine->emit_fini_breadcrumb_dw - 6; + } else { + cs = __emit_fini_breadcrumb_parent_no_preempt_mid_batch(rq, cs); + } + /* Emit fini breadcrumb */ cs = gen8_emit_ggtt_write(cs, rq->fence.seqno, @@ -4115,7 +4154,8 @@ emit_fini_breadcrumb_parent_no_preempt_mid_batch(struct i915_request *rq, } static u32 * -emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, u32 *cs) +__emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs) { struct intel_context *ce = rq->context; struct intel_context *parent = intel_context_to_parent(ce); @@ -4142,6 +4182,29 @@ emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, u32 *cs *cs++ = get_children_go_addr(parent); *cs++ = 0; + return cs; +} + +static u32 * +emit_fini_breadcrumb_child_no_preempt_mid_batch(struct i915_request *rq, + u32 *cs) +{ + struct intel_context *ce = rq->context; + + GEM_BUG_ON(!intel_context_is_child(ce)); + + if (unlikely(skip_handshake(rq))) { + /* + * NOP everything in __emit_fini_breadcrumb_child_no_preempt_mid_batch, + * the -6 comes from the length of the emits below. + */ + memset(cs, 0, sizeof(u32) * + (ce->engine->emit_fini_breadcrumb_dw - 6)); + cs += ce->engine->emit_fini_breadcrumb_dw - 6; + } else { + cs = __emit_fini_breadcrumb_child_no_preempt_mid_batch(rq, cs); + } + /* Emit fini breadcrumb */ cs = gen8_emit_ggtt_write(cs, rq->fence.seqno, From afc76f307e60c865c436e3828a7756e0c358fe0d Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:20:02 -0700 Subject: [PATCH 359/554] drm/i915: Make request conflict tracking understand parallel submits If an object in the excl or shared slot is a composite fence from a parallel submit and the current request in the conflict tracking is from the same parallel context there is no need to enforce ordering as the ordering is already implicit. Make the request conflict tracking understand this by comparing a parallel submit's parent context and skipping conflict insertion if the values match. v2: (John Harrison) - Reword commit message Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-23-matthew.brost@intel.com --- drivers/gpu/drm/i915/i915_request.c | 43 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index d29e46a001b4..2c3cd6e635b5 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1335,6 +1335,25 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence) return err; } +static inline bool is_parallel_rq(struct i915_request *rq) +{ + return intel_context_is_parallel(rq->context); +} + +static inline struct intel_context *request_to_parent(struct i915_request *rq) +{ + return intel_context_to_parent(rq->context); +} + +static bool is_same_parallel_context(struct i915_request *to, + struct i915_request *from) +{ + if (is_parallel_rq(to)) + return request_to_parent(to) == request_to_parent(from); + + return false; +} + int i915_request_await_execution(struct i915_request *rq, struct dma_fence *fence) @@ -1366,11 +1385,14 @@ i915_request_await_execution(struct i915_request *rq, * want to run our callback in all cases. */ - if (dma_fence_is_i915(fence)) + if (dma_fence_is_i915(fence)) { + if (is_same_parallel_context(rq, to_request(fence))) + continue; ret = __i915_request_await_execution(rq, to_request(fence)); - else + } else { ret = i915_request_await_external(rq, fence); + } if (ret < 0) return ret; } while (--nchild); @@ -1471,10 +1493,13 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence) fence)) continue; - if (dma_fence_is_i915(fence)) + if (dma_fence_is_i915(fence)) { + if (is_same_parallel_context(rq, to_request(fence))) + continue; ret = i915_request_await_request(rq, to_request(fence)); - else + } else { ret = i915_request_await_external(rq, fence); + } if (ret < 0) return ret; @@ -1549,16 +1574,6 @@ i915_request_await_object(struct i915_request *to, return ret; } -static inline bool is_parallel_rq(struct i915_request *rq) -{ - return intel_context_is_parallel(rq->context); -} - -static inline struct intel_context *request_to_parent(struct i915_request *rq) -{ - return intel_context_to_parent(rq->context); -} - static struct i915_request * __i915_request_ensure_parallel_ordering(struct i915_request *rq, struct intel_timeline *timeline) From 7647f0096ee87376c96a47357373e02694baa3ec Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:20:03 -0700 Subject: [PATCH 360/554] drm/i915: Update I915_GEM_BUSY IOCTL to understand composite fences Parallel submission create composite fences (dma_fence_array) for excl / shared slots in objects. The I915_GEM_BUSY IOCTL checks these slots to determine the busyness of the object. Prior to patch it only check if the fence in the slot was a i915_request. Update the check to understand composite fences and correctly report the busyness. v2: (Tvrtko) - Remove duplicate BUILD_BUG_ON Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Matthew Brost Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-24-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_busy.c | 59 +++++++++++++++---- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 5 +- drivers/gpu/drm/i915/i915_request.h | 6 ++ 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_busy.c b/drivers/gpu/drm/i915/gem/i915_gem_busy.c index 6234e17259c1..7358bebef15c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_busy.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_busy.c @@ -4,6 +4,8 @@ * Copyright © 2014-2016 Intel Corporation */ +#include + #include "gt/intel_engine.h" #include "i915_gem_ioctls.h" @@ -36,7 +38,7 @@ static __always_inline u32 __busy_write_id(u16 id) } static __always_inline unsigned int -__busy_set_if_active(const struct dma_fence *fence, u32 (*flag)(u16 id)) +__busy_set_if_active(struct dma_fence *fence, u32 (*flag)(u16 id)) { const struct i915_request *rq; @@ -46,29 +48,60 @@ __busy_set_if_active(const struct dma_fence *fence, u32 (*flag)(u16 id)) * to eventually flush us, but to minimise latency just ask the * hardware. * - * Note we only report on the status of native fences. + * Note we only report on the status of native fences and we currently + * have two native fences: + * + * 1. A composite fence (dma_fence_array) constructed of i915 requests + * created during a parallel submission. In this case we deconstruct the + * composite fence into individual i915 requests and check the status of + * each request. + * + * 2. A single i915 request. */ - if (!dma_fence_is_i915(fence)) - return 0; + if (dma_fence_is_array(fence)) { + struct dma_fence_array *array = to_dma_fence_array(fence); + struct dma_fence **child = array->fences; + unsigned int nchild = array->num_fences; - /* opencode to_request() in order to avoid const warnings */ - rq = container_of(fence, const struct i915_request, fence); - if (i915_request_completed(rq)) - return 0; + do { + struct dma_fence *current_fence = *child++; - /* Beware type-expansion follies! */ - BUILD_BUG_ON(!typecheck(u16, rq->engine->uabi_class)); - return flag(rq->engine->uabi_class); + /* Not an i915 fence, can't be busy per above */ + if (!dma_fence_is_i915(current_fence) || + !test_bit(I915_FENCE_FLAG_COMPOSITE, + ¤t_fence->flags)) { + return 0; + } + + rq = to_request(current_fence); + if (!i915_request_completed(rq)) + return flag(rq->engine->uabi_class); + } while (--nchild); + + /* All requests in array complete, not busy */ + return 0; + } else { + if (!dma_fence_is_i915(fence)) + return 0; + + rq = to_request(fence); + if (i915_request_completed(rq)) + return 0; + + /* Beware type-expansion follies! */ + BUILD_BUG_ON(!typecheck(u16, rq->engine->uabi_class)); + return flag(rq->engine->uabi_class); + } } static __always_inline unsigned int -busy_check_reader(const struct dma_fence *fence) +busy_check_reader(struct dma_fence *fence) { return __busy_set_if_active(fence, __busy_read_flag); } static __always_inline unsigned int -busy_check_writer(const struct dma_fence *fence) +busy_check_writer(struct dma_fence *fence) { if (!fence) return 0; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 1cb241298d9b..f20a3a5b3c84 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2997,8 +2997,11 @@ eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd) if (!fences) return ERR_PTR(-ENOMEM); - for_each_batch_create_order(eb, i) + for_each_batch_create_order(eb, i) { fences[i] = &eb->requests[i]->fence; + __set_bit(I915_FENCE_FLAG_COMPOSITE, + &eb->requests[i]->fence.flags); + } fence_array = dma_fence_array_create(eb->num_batches, fences, diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 24db8459376b..dc359242d1ae 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -156,6 +156,12 @@ enum { * submission / relationship encoutered an error. */ I915_FENCE_FLAG_SKIP_PARALLEL, + + /* + * I915_FENCE_FLAG_COMPOSITE - Indicates fence is part of a composite + * fence (dma_fence_array) and i915 generated for parallel submission. + */ + I915_FENCE_FLAG_COMPOSITE, }; /** From 4eb61ddc1b67dcb450d3ddbcfef8dfe2c4279a45 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 14 Oct 2021 10:20:04 -0700 Subject: [PATCH 361/554] drm/i915: Enable multi-bb execbuf Enable multi-bb execbuf by enabling the set_parallel extension. Signed-off-by: Matthew Brost Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20211014172005.27155-25-matthew.brost@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 9a00f11fef46..fb33d0322960 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -570,9 +570,6 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base, struct intel_engine_cs **siblings = NULL; intel_engine_mask_t prev_mask; - /* Disabling for now */ - return -ENODEV; - /* FIXME: This is NIY for execlists */ if (!(intel_uc_uses_guc_submission(&i915->gt.uc))) return -ENODEV; From c974cf01b248c6f4220bfadd57cce74058453aea Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 14 Oct 2021 13:12:54 -0400 Subject: [PATCH 362/554] drm/i915: Clean up PXP Kconfig info. During the review I focused on stop the using of the "+" to reference the newer platforms, but I forgot that we are in a process of making things more clear and differentiate graphics and display versions. So, let me to clean up this a bit. Also, we don't need any version mentioned in the config menu entry, only in the help. Cc: Alan Previn Cc: Daniele Ceraolo Spurio Signed-off-by: Rodrigo Vivi Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20211015090916.82968-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 8859444943a0..bf041b26ffec 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -132,15 +132,15 @@ config DRM_I915_GVT_KVMGT Intel GVT-g. config DRM_I915_PXP - bool "Enable Intel PXP support for Intel Gen12 and newer platform" + bool "Enable Intel PXP support" depends on DRM_I915 depends on INTEL_MEI && INTEL_MEI_PXP default n help - PXP (Protected Xe Path) is an i915 component, available on GEN12 and - newer GPUs, that helps to establish the hardware protected session and - manage the status of the alive software session, as well as its life - cycle. + PXP (Protected Xe Path) is an i915 component, available on graphics + version 12 and newer GPUs, that helps to establish the hardware + protected session and manage the status of the alive software session, + as well as its life cycle. menu "drm/i915 Debugging" depends on DRM_I915 From a73033619ea90405895b4fca6af8033dbdaa64bf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jun 2021 01:20:23 +0300 Subject: [PATCH 363/554] drm/msm/dpu: squash dpu_core_irq into dpu_hw_interrupts With dpu_core_irq being the wrapper around dpu_hw_interrupts, there is little sense in having them separate. Squash them together to remove another layer of abstraction (hw_intr ops). Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20210617222029.463045-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c | 256 ----------------- .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 269 ++++++++++++++---- .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 87 ------ 4 files changed, 214 insertions(+), 399 deletions(-) delete mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 904535eda0c4..40577f8856d8 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -51,7 +51,6 @@ msm-y := \ disp/mdp5/mdp5_mixer.o \ disp/mdp5/mdp5_plane.o \ disp/mdp5/mdp5_smp.o \ - disp/dpu1/dpu_core_irq.o \ disp/dpu1/dpu_core_perf.o \ disp/dpu1/dpu_crtc.o \ disp/dpu1/dpu_encoder.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c deleted file mode 100644 index d2457490930b..000000000000 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c +++ /dev/null @@ -1,256 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - */ - -#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ - -#include -#include -#include -#include - -#include "dpu_core_irq.h" -#include "dpu_trace.h" - -/** - * dpu_core_irq_callback_handler - dispatch core interrupts - * @arg: private data of callback handler - * @irq_idx: interrupt index - */ -static void dpu_core_irq_callback_handler(void *arg, int irq_idx) -{ - struct dpu_kms *dpu_kms = arg; - struct dpu_irq *irq_obj = &dpu_kms->irq_obj; - struct dpu_irq_callback *cb; - - VERB("irq_idx=%d\n", irq_idx); - - if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) - DRM_ERROR("no registered cb, idx:%d\n", irq_idx); - - atomic_inc(&irq_obj->irq_counts[irq_idx]); - - /* - * Perform registered function callback - */ - list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) - if (cb->func) - cb->func(cb->arg, irq_idx); -} - -u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx, bool clear) -{ - if (!dpu_kms->hw_intr || - !dpu_kms->hw_intr->ops.get_interrupt_status) - return 0; - - if (irq_idx < 0) { - DPU_ERROR("[%pS] invalid irq_idx=%d\n", - __builtin_return_address(0), irq_idx); - return 0; - } - - return dpu_kms->hw_intr->ops.get_interrupt_status(dpu_kms->hw_intr, - irq_idx, clear); -} - -int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, - struct dpu_irq_callback *register_irq_cb) -{ - unsigned long irq_flags; - - if (!dpu_kms->irq_obj.irq_cb_tbl) { - DPU_ERROR("invalid params\n"); - return -EINVAL; - } - - if (!register_irq_cb || !register_irq_cb->func) { - DPU_ERROR("invalid irq_cb:%d func:%d\n", - register_irq_cb != NULL, - register_irq_cb ? - register_irq_cb->func != NULL : -1); - return -EINVAL; - } - - if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { - DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); - - irq_flags = dpu_kms->hw_intr->ops.lock(dpu_kms->hw_intr); - trace_dpu_core_irq_register_callback(irq_idx, register_irq_cb); - list_del_init(®ister_irq_cb->list); - list_add_tail(®ister_irq_cb->list, - &dpu_kms->irq_obj.irq_cb_tbl[irq_idx]); - if (list_is_first(®ister_irq_cb->list, - &dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { - int ret = dpu_kms->hw_intr->ops.enable_irq_locked( - dpu_kms->hw_intr, - irq_idx); - if (ret) - DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", - irq_idx); - } - dpu_kms->hw_intr->ops.unlock(dpu_kms->hw_intr, irq_flags); - - return 0; -} - -int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, - struct dpu_irq_callback *register_irq_cb) -{ - unsigned long irq_flags; - - if (!dpu_kms->irq_obj.irq_cb_tbl) { - DPU_ERROR("invalid params\n"); - return -EINVAL; - } - - if (!register_irq_cb || !register_irq_cb->func) { - DPU_ERROR("invalid irq_cb:%d func:%d\n", - register_irq_cb != NULL, - register_irq_cb ? - register_irq_cb->func != NULL : -1); - return -EINVAL; - } - - if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { - DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); - - irq_flags = dpu_kms->hw_intr->ops.lock(dpu_kms->hw_intr); - trace_dpu_core_irq_unregister_callback(irq_idx, register_irq_cb); - list_del_init(®ister_irq_cb->list); - /* empty callback list but interrupt is still enabled */ - if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { - int ret = dpu_kms->hw_intr->ops.disable_irq_locked( - dpu_kms->hw_intr, - irq_idx); - if (ret) - DPU_ERROR("Fail to disable IRQ for irq_idx:%d\n", - irq_idx); - VERB("irq_idx=%d ret=%d\n", irq_idx, ret); - } - dpu_kms->hw_intr->ops.unlock(dpu_kms->hw_intr, irq_flags); - - return 0; -} - -static void dpu_clear_all_irqs(struct dpu_kms *dpu_kms) -{ - if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.clear_all_irqs) - return; - - dpu_kms->hw_intr->ops.clear_all_irqs(dpu_kms->hw_intr); -} - -static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) -{ - if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.disable_all_irqs) - return; - - dpu_kms->hw_intr->ops.disable_all_irqs(dpu_kms->hw_intr); -} - -#ifdef CONFIG_DEBUG_FS -static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) -{ - struct dpu_kms *dpu_kms = s->private; - struct dpu_irq *irq_obj = &dpu_kms->irq_obj; - struct dpu_irq_callback *cb; - unsigned long irq_flags; - int i, irq_count, cb_count; - - if (WARN_ON(!irq_obj->irq_cb_tbl)) - return 0; - - for (i = 0; i < irq_obj->total_irqs; i++) { - irq_flags = dpu_kms->hw_intr->ops.lock(dpu_kms->hw_intr); - cb_count = 0; - irq_count = atomic_read(&irq_obj->irq_counts[i]); - list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list) - cb_count++; - dpu_kms->hw_intr->ops.unlock(dpu_kms->hw_intr, irq_flags); - - if (irq_count || cb_count) - seq_printf(s, "idx:%d irq:%d cb:%d\n", - i, irq_count, cb_count); - } - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq); - -void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, - struct dentry *parent) -{ - debugfs_create_file("core_irq", 0600, parent, dpu_kms, - &dpu_debugfs_core_irq_fops); -} -#endif - -void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) -{ - int i; - - pm_runtime_get_sync(&dpu_kms->pdev->dev); - dpu_clear_all_irqs(dpu_kms); - dpu_disable_all_irqs(dpu_kms); - pm_runtime_put_sync(&dpu_kms->pdev->dev); - - /* Create irq callbacks for all possible irq_idx */ - dpu_kms->irq_obj.total_irqs = dpu_kms->hw_intr->total_irqs; - dpu_kms->irq_obj.irq_cb_tbl = kcalloc(dpu_kms->irq_obj.total_irqs, - sizeof(struct list_head), GFP_KERNEL); - dpu_kms->irq_obj.irq_counts = kcalloc(dpu_kms->irq_obj.total_irqs, - sizeof(atomic_t), GFP_KERNEL); - for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) { - INIT_LIST_HEAD(&dpu_kms->irq_obj.irq_cb_tbl[i]); - atomic_set(&dpu_kms->irq_obj.irq_counts[i], 0); - } -} - -void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) -{ - int i; - - pm_runtime_get_sync(&dpu_kms->pdev->dev); - for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) - if (!list_empty(&dpu_kms->irq_obj.irq_cb_tbl[i])) - DPU_ERROR("irq_idx=%d still enabled/registered\n", i); - - dpu_clear_all_irqs(dpu_kms); - dpu_disable_all_irqs(dpu_kms); - pm_runtime_put_sync(&dpu_kms->pdev->dev); - - kfree(dpu_kms->irq_obj.irq_cb_tbl); - kfree(dpu_kms->irq_obj.irq_counts); - dpu_kms->irq_obj.irq_cb_tbl = NULL; - dpu_kms->irq_obj.irq_counts = NULL; - dpu_kms->irq_obj.total_irqs = 0; -} - -irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms) -{ - /* - * Dispatch to HW driver to handle interrupt lookup that is being - * fired. When matching interrupt is located, HW driver will call to - * dpu_core_irq_callback_handler with the irq_idx from the lookup table. - * dpu_core_irq_callback_handler will perform the registered function - * callback, and do the interrupt status clearing once the registered - * callback is finished. - * Function will also clear the interrupt status after reading. - */ - dpu_kms->hw_intr->ops.dispatch_irqs( - dpu_kms->hw_intr, - dpu_core_irq_callback_handler, - dpu_kms); - - return IRQ_HANDLED; -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 2e816f232e85..2437b0c7c073 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -3,12 +3,15 @@ */ #include +#include #include +#include "dpu_core_irq.h" #include "dpu_kms.h" #include "dpu_hw_interrupts.h" #include "dpu_hw_util.h" #include "dpu_hw_mdss.h" +#include "dpu_trace.h" /** * Register offsets in MDSS register file for the interrupt registers @@ -132,10 +135,34 @@ static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr, wmb(); } -static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, - void (*cbfunc)(void *, int), - void *arg) +/** + * dpu_core_irq_callback_handler - dispatch core interrupts + * @arg: private data of callback handler + * @irq_idx: interrupt index + */ +static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx) { + struct dpu_irq *irq_obj = &dpu_kms->irq_obj; + struct dpu_irq_callback *cb; + + VERB("irq_idx=%d\n", irq_idx); + + if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) + DRM_ERROR("no registered cb, idx:%d\n", irq_idx); + + atomic_inc(&irq_obj->irq_counts[irq_idx]); + + /* + * Perform registered function callback + */ + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) + if (cb->func) + cb->func(cb->arg, irq_idx); +} + +irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms) +{ + struct dpu_hw_intr *intr = dpu_kms->hw_intr; int reg_idx; int irq_idx; u32 irq_status; @@ -144,13 +171,8 @@ static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, unsigned long irq_flags; if (!intr) - return; + return IRQ_NONE; - /* - * The dispatcher will save the IRQ status before calling here. - * Now need to go through each IRQ status and find matching - * irq lookup index. - */ spin_lock_irqsave(&intr->irq_lock, irq_flags); for (reg_idx = 0; reg_idx < ARRAY_SIZE(dpu_intr_set); reg_idx++) { if (!test_bit(reg_idx, &intr->irq_mask)) @@ -178,15 +200,8 @@ static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, */ while ((bit = ffs(irq_status)) != 0) { irq_idx = DPU_IRQ_IDX(reg_idx, bit - 1); - /* - * Once a match on irq mask, perform a callback - * to the given cbfunc. cbfunc will take care - * the interrupt status clearing. If cbfunc is - * not provided, then the interrupt clearing - * is here. - */ - if (cbfunc) - cbfunc(arg, irq_idx); + + dpu_core_irq_callback_handler(dpu_kms, irq_idx); dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx); @@ -203,6 +218,8 @@ static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, wmb(); spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + return IRQ_HANDLED; } static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) @@ -303,12 +320,13 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) return 0; } -static int dpu_hw_intr_clear_irqs(struct dpu_hw_intr *intr) +static void dpu_clear_irqs(struct dpu_kms *dpu_kms) { + struct dpu_hw_intr *intr = dpu_kms->hw_intr; int i; if (!intr) - return -EINVAL; + return; for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { if (test_bit(i, &intr->irq_mask)) @@ -318,16 +336,15 @@ static int dpu_hw_intr_clear_irqs(struct dpu_hw_intr *intr) /* ensure register writes go through */ wmb(); - - return 0; } -static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr) +static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) { + struct dpu_hw_intr *intr = dpu_kms->hw_intr; int i; if (!intr) - return -EINVAL; + return; for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { if (test_bit(i, &intr->irq_mask)) @@ -337,13 +354,11 @@ static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr) /* ensure register writes go through */ wmb(); - - return 0; } -static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, - int irq_idx, bool clear) +u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx, bool clear) { + struct dpu_hw_intr *intr = dpu_kms->hw_intr; int reg_idx; unsigned long irq_flags; u32 intr_status; @@ -351,6 +366,12 @@ static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, if (!intr) return 0; + if (irq_idx < 0) { + DPU_ERROR("[%pS] invalid irq_idx=%d\n", + __builtin_return_address(0), irq_idx); + return 0; + } + if (irq_idx < 0 || irq_idx >= intr->total_irqs) { pr_err("invalid IRQ index: [%d]\n", irq_idx); return 0; @@ -374,32 +395,6 @@ static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, return intr_status; } -static unsigned long dpu_hw_intr_lock(struct dpu_hw_intr *intr) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&intr->irq_lock, irq_flags); - - return irq_flags; -} - -static void dpu_hw_intr_unlock(struct dpu_hw_intr *intr, unsigned long irq_flags) -{ - spin_unlock_irqrestore(&intr->irq_lock, irq_flags); -} - -static void __setup_intr_ops(struct dpu_hw_intr_ops *ops) -{ - ops->enable_irq_locked = dpu_hw_intr_enable_irq_locked; - ops->disable_irq_locked = dpu_hw_intr_disable_irq_locked; - ops->dispatch_irqs = dpu_hw_intr_dispatch_irq; - ops->clear_all_irqs = dpu_hw_intr_clear_irqs; - ops->disable_all_irqs = dpu_hw_intr_disable_irqs; - ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status; - ops->lock = dpu_hw_intr_lock; - ops->unlock = dpu_hw_intr_unlock; -} - static void __intr_offset(struct dpu_mdss_cfg *m, void __iomem *addr, struct dpu_hw_blk_reg_map *hw) { @@ -421,7 +416,6 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, return ERR_PTR(-ENOMEM); __intr_offset(m, addr, &intr->hw); - __setup_intr_ops(&intr->ops); intr->total_irqs = ARRAY_SIZE(dpu_intr_set) * 32; @@ -447,3 +441,168 @@ void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) } } +int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, + struct dpu_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!dpu_kms->irq_obj.irq_cb_tbl) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + DPU_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + trace_dpu_core_irq_register_callback(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + list_add_tail(®ister_irq_cb->list, + &dpu_kms->irq_obj.irq_cb_tbl[irq_idx]); + if (list_is_first(®ister_irq_cb->list, + &dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { + int ret = dpu_hw_intr_enable_irq_locked( + dpu_kms->hw_intr, + irq_idx); + if (ret) + DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", + irq_idx); + } + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + return 0; +} + +int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, + struct dpu_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!dpu_kms->irq_obj.irq_cb_tbl) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + DPU_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + trace_dpu_core_irq_unregister_callback(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + /* empty callback list but interrupt is still enabled */ + if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { + int ret = dpu_hw_intr_disable_irq_locked( + dpu_kms->hw_intr, + irq_idx); + if (ret) + DPU_ERROR("Fail to disable IRQ for irq_idx:%d\n", + irq_idx); + VERB("irq_idx=%d ret=%d\n", irq_idx, ret); + } + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) +{ + struct dpu_kms *dpu_kms = s->private; + struct dpu_irq *irq_obj = &dpu_kms->irq_obj; + struct dpu_irq_callback *cb; + unsigned long irq_flags; + int i, irq_count, cb_count; + + if (WARN_ON(!irq_obj->irq_cb_tbl)) + return 0; + + for (i = 0; i < irq_obj->total_irqs; i++) { + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + cb_count = 0; + irq_count = atomic_read(&irq_obj->irq_counts[i]); + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list) + cb_count++; + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + if (irq_count || cb_count) + seq_printf(s, "idx:%d irq:%d cb:%d\n", + i, irq_count, cb_count); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq); + +void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + struct dentry *parent) +{ + debugfs_create_file("core_irq", 0600, parent, dpu_kms, + &dpu_debugfs_core_irq_fops); +} +#endif + +void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) +{ + int i; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + dpu_clear_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + /* Create irq callbacks for all possible irq_idx */ + dpu_kms->irq_obj.total_irqs = dpu_kms->hw_intr->total_irqs; + dpu_kms->irq_obj.irq_cb_tbl = kcalloc(dpu_kms->irq_obj.total_irqs, + sizeof(struct list_head), GFP_KERNEL); + dpu_kms->irq_obj.irq_counts = kcalloc(dpu_kms->irq_obj.total_irqs, + sizeof(atomic_t), GFP_KERNEL); + for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) { + INIT_LIST_HEAD(&dpu_kms->irq_obj.irq_cb_tbl[i]); + atomic_set(&dpu_kms->irq_obj.irq_counts[i], 0); + } +} + +void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) +{ + int i; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) + if (!list_empty(&dpu_kms->irq_obj.irq_cb_tbl[i])) + DPU_ERROR("irq_idx=%d still enabled/registered\n", i); + + dpu_clear_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + kfree(dpu_kms->irq_obj.irq_cb_tbl); + kfree(dpu_kms->irq_obj.irq_counts); + dpu_kms->irq_obj.irq_cb_tbl = NULL; + dpu_kms->irq_obj.irq_counts = NULL; + dpu_kms->irq_obj.total_irqs = 0; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index ac83c1159815..99ab01f54aa6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -32,92 +32,6 @@ enum dpu_hw_intr_reg { #define DPU_IRQ_IDX(reg_idx, offset) (reg_idx * 32 + offset) -struct dpu_hw_intr; - -/** - * Interrupt operations. - */ -struct dpu_hw_intr_ops { - - /** - * enable_irq - Enable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*enable_irq_locked)( - struct dpu_hw_intr *intr, - int irq_idx); - - /** - * disable_irq - Disable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*disable_irq_locked)( - struct dpu_hw_intr *intr, - int irq_idx); - - /** - * clear_all_irqs - Clears all the interrupts (i.e. acknowledges - * any asserted IRQs). Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*clear_all_irqs)( - struct dpu_hw_intr *intr); - - /** - * disable_all_irqs - Disables all the interrupts. Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*disable_all_irqs)( - struct dpu_hw_intr *intr); - - /** - * dispatch_irqs - IRQ dispatcher will call the given callback - * function when a matching interrupt status bit is - * found in the irq mapping table. - * @intr: HW interrupt handle - * @cbfunc: Callback function pointer - * @arg: Argument to pass back during callback - */ - void (*dispatch_irqs)( - struct dpu_hw_intr *intr, - void (*cbfunc)(void *arg, int irq_idx), - void *arg); - - /** - * get_interrupt_status - Gets HW interrupt status, and clear if set, - * based on given lookup IRQ index. - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @clear: True to clear irq after read - */ - u32 (*get_interrupt_status)( - struct dpu_hw_intr *intr, - int irq_idx, - bool clear); - - /** - * lock - take the IRQ lock - * @intr: HW interrupt handle - * @return: irq_flags for the taken spinlock - */ - unsigned long (*lock)( - struct dpu_hw_intr *intr); - - /** - * unlock - take the IRQ lock - * @intr: HW interrupt handle - * @irq_flags: the irq_flags returned from lock - */ - void (*unlock)( - struct dpu_hw_intr *intr, unsigned long irq_flags); -}; - /** * struct dpu_hw_intr: hw interrupts handling data structure * @hw: virtual address mapping @@ -129,7 +43,6 @@ struct dpu_hw_intr_ops { */ struct dpu_hw_intr { struct dpu_hw_blk_reg_map hw; - struct dpu_hw_intr_ops ops; u32 *cache_irq_mask; u32 *save_irq_status; u32 total_irqs; From 6087623e7c904de4c8ff48f78dc70cc05ddb8e40 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jun 2021 01:20:24 +0300 Subject: [PATCH 364/554] drm/msm/dpu: don't clear IRQ register twice We already clear the IRQ status register before processing IRQs, so do not clear the register again. Especially do not clear the IRQ status _after_ processing the IRQ as this way we can loose the event. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20210617222029.463045-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 2437b0c7c073..28e9b0d448db 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -120,21 +120,6 @@ static const struct dpu_intr_reg dpu_intr_set[] = { #define DPU_IRQ_REG(irq_idx) (irq_idx / 32) #define DPU_IRQ_MASK(irq_idx) (BIT(irq_idx % 32)) -static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr, - int irq_idx) -{ - int reg_idx; - - if (!intr) - return; - - reg_idx = DPU_IRQ_REG(irq_idx); - DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off, DPU_IRQ_MASK(irq_idx)); - - /* ensure register writes go through */ - wmb(); -} - /** * dpu_core_irq_callback_handler - dispatch core interrupts * @arg: private data of callback handler @@ -203,8 +188,6 @@ irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms) dpu_core_irq_callback_handler(dpu_kms, irq_idx); - dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx); - /* * When callback finish, clear the irq_status * with the matching mask. Once irq_status From f25f656608e3a54ac3e0747be415cf3d4a69cef8 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jun 2021 01:20:25 +0300 Subject: [PATCH 365/554] drm/msm/dpu: merge struct dpu_irq into struct dpu_hw_intr As dpu_core_irq was merged into dpu_hw_intr, merge data structures too, removing the need for a separate data structure. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20210617222029.463045-4-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 51 +++++++++---------- .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 5 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 13 ----- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 28e9b0d448db..d2b6dca487e3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -127,20 +127,19 @@ static const struct dpu_intr_reg dpu_intr_set[] = { */ static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx) { - struct dpu_irq *irq_obj = &dpu_kms->irq_obj; struct dpu_irq_callback *cb; VERB("irq_idx=%d\n", irq_idx); - if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) + if (list_empty(&dpu_kms->hw_intr->irq_cb_tbl[irq_idx])) DRM_ERROR("no registered cb, idx:%d\n", irq_idx); - atomic_inc(&irq_obj->irq_counts[irq_idx]); + atomic_inc(&dpu_kms->hw_intr->irq_counts[irq_idx]); /* * Perform registered function callback */ - list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) + list_for_each_entry(cb, &dpu_kms->hw_intr->irq_cb_tbl[irq_idx], list) if (cb->func) cb->func(cb->arg, irq_idx); } @@ -420,6 +419,10 @@ void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) { if (intr) { kfree(intr->cache_irq_mask); + + kfree(intr->irq_cb_tbl); + kfree(intr->irq_counts); + kfree(intr); } } @@ -429,7 +432,7 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, { unsigned long irq_flags; - if (!dpu_kms->irq_obj.irq_cb_tbl) { + if (!dpu_kms->hw_intr->irq_cb_tbl) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -453,9 +456,9 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, trace_dpu_core_irq_register_callback(irq_idx, register_irq_cb); list_del_init(®ister_irq_cb->list); list_add_tail(®ister_irq_cb->list, - &dpu_kms->irq_obj.irq_cb_tbl[irq_idx]); + &dpu_kms->hw_intr->irq_cb_tbl[irq_idx]); if (list_is_first(®ister_irq_cb->list, - &dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { + &dpu_kms->hw_intr->irq_cb_tbl[irq_idx])) { int ret = dpu_hw_intr_enable_irq_locked( dpu_kms->hw_intr, irq_idx); @@ -473,7 +476,7 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, { unsigned long irq_flags; - if (!dpu_kms->irq_obj.irq_cb_tbl) { + if (!dpu_kms->hw_intr->irq_cb_tbl) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -497,7 +500,7 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, trace_dpu_core_irq_unregister_callback(irq_idx, register_irq_cb); list_del_init(®ister_irq_cb->list); /* empty callback list but interrupt is still enabled */ - if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) { + if (list_empty(&dpu_kms->hw_intr->irq_cb_tbl[irq_idx])) { int ret = dpu_hw_intr_disable_irq_locked( dpu_kms->hw_intr, irq_idx); @@ -515,19 +518,18 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) { struct dpu_kms *dpu_kms = s->private; - struct dpu_irq *irq_obj = &dpu_kms->irq_obj; struct dpu_irq_callback *cb; unsigned long irq_flags; int i, irq_count, cb_count; - if (WARN_ON(!irq_obj->irq_cb_tbl)) + if (WARN_ON(!dpu_kms->hw_intr->irq_cb_tbl)) return 0; - for (i = 0; i < irq_obj->total_irqs; i++) { + for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) { spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); cb_count = 0; - irq_count = atomic_read(&irq_obj->irq_counts[i]); - list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list) + irq_count = atomic_read(&dpu_kms->hw_intr->irq_counts[i]); + list_for_each_entry(cb, &dpu_kms->hw_intr->irq_cb_tbl[i], list) cb_count++; spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); @@ -559,14 +561,13 @@ void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) pm_runtime_put_sync(&dpu_kms->pdev->dev); /* Create irq callbacks for all possible irq_idx */ - dpu_kms->irq_obj.total_irqs = dpu_kms->hw_intr->total_irqs; - dpu_kms->irq_obj.irq_cb_tbl = kcalloc(dpu_kms->irq_obj.total_irqs, + dpu_kms->hw_intr->irq_cb_tbl = kcalloc(dpu_kms->hw_intr->total_irqs, sizeof(struct list_head), GFP_KERNEL); - dpu_kms->irq_obj.irq_counts = kcalloc(dpu_kms->irq_obj.total_irqs, + dpu_kms->hw_intr->irq_counts = kcalloc(dpu_kms->hw_intr->total_irqs, sizeof(atomic_t), GFP_KERNEL); - for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) { - INIT_LIST_HEAD(&dpu_kms->irq_obj.irq_cb_tbl[i]); - atomic_set(&dpu_kms->irq_obj.irq_counts[i], 0); + for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) { + INIT_LIST_HEAD(&dpu_kms->hw_intr->irq_cb_tbl[i]); + atomic_set(&dpu_kms->hw_intr->irq_counts[i], 0); } } @@ -575,17 +576,11 @@ void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) int i; pm_runtime_get_sync(&dpu_kms->pdev->dev); - for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) - if (!list_empty(&dpu_kms->irq_obj.irq_cb_tbl[i])) + for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) + if (!list_empty(&dpu_kms->hw_intr->irq_cb_tbl[i])) DPU_ERROR("irq_idx=%d still enabled/registered\n", i); dpu_clear_irqs(dpu_kms); dpu_disable_all_irqs(dpu_kms); pm_runtime_put_sync(&dpu_kms->pdev->dev); - - kfree(dpu_kms->irq_obj.irq_cb_tbl); - kfree(dpu_kms->irq_obj.irq_counts); - dpu_kms->irq_obj.irq_cb_tbl = NULL; - dpu_kms->irq_obj.irq_counts = NULL; - dpu_kms->irq_obj.total_irqs = 0; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index 99ab01f54aa6..d50e78c9f148 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -40,6 +40,8 @@ enum dpu_hw_intr_reg { * @save_irq_status: array of IRQ status reg storage created during init * @total_irqs: total number of irq_idx mapped in the hw_interrupts * @irq_lock: spinlock for accessing IRQ resources + * @irq_cb_tbl: array of IRQ callbacks lists + * @irq_counts: array of IRQ counts */ struct dpu_hw_intr { struct dpu_hw_blk_reg_map hw; @@ -48,6 +50,9 @@ struct dpu_hw_intr { u32 total_irqs; spinlock_t irq_lock; unsigned long irq_mask; + + struct list_head *irq_cb_tbl; + atomic_t *irq_counts; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 323a6bce9e64..775bcbda860f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -78,18 +78,6 @@ struct dpu_irq_callback { void *arg; }; -/** - * struct dpu_irq: IRQ structure contains callback registration info - * @total_irq: total number of irq_idx obtained from HW interrupts mapping - * @irq_cb_tbl: array of IRQ callbacks setting - * @debugfs_file: debugfs file for irq statistics - */ -struct dpu_irq { - u32 total_irqs; - struct list_head *irq_cb_tbl; - atomic_t *irq_counts; -}; - struct dpu_kms { struct msm_kms base; struct drm_device *dev; @@ -104,7 +92,6 @@ struct dpu_kms { struct regulator *venus; struct dpu_hw_intr *hw_intr; - struct dpu_irq irq_obj; struct dpu_core_perf perf; From 885455d6bf829e71a9cfe51fca06ade509c088d6 Mon Sep 17 00:00:00 2001 From: Mark Yacoub Date: Mon, 30 Aug 2021 14:13:59 -0400 Subject: [PATCH 366/554] drm/msm: Change dpu_crtc_get_vblank_counter to use vsync count. [why] vsync_cnt atomic counter increments for every hw vsync. On the other hand, frame count is a register that increments when the frame gets actually pushed out. We cannnot read this register whenever the timing engine is off, but vblank counter should still return a valid number. This behavior also matches the downstream driver. [How] Read the encoder vsync count instead of the dpu_encoder_phys frame count. Suggested-by: Abhinav Kumar CC: Rob Clark Signed-off-by: Mark Yacoub Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20210830181359.124267-1-markyacoub@chromium.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 8 +++----- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 ++++------------ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 4 ++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 768012243b44..eecfa88517e0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -72,15 +72,13 @@ static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) { - struct drm_encoder *encoder; - - encoder = get_encoder_from_crtc(crtc); + struct drm_encoder *encoder = get_encoder_from_crtc(crtc); if (!encoder) { DRM_ERROR("no encoder found for crtc %d\n", crtc->index); - return false; + return 0; } - return dpu_encoder_get_frame_count(encoder); + return dpu_encoder_get_vsync_count(encoder); } static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 0e9d3fa1544b..f564cef948f0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -395,19 +395,11 @@ int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc, return 0; } -int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc) +int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc) { - struct dpu_encoder_virt *dpu_enc; - struct dpu_encoder_phys *phys; - int framecount = 0; - - dpu_enc = to_dpu_encoder_virt(drm_enc); - phys = dpu_enc ? dpu_enc->cur_master : NULL; - - if (phys && phys->ops.get_frame_count) - framecount = phys->ops.get_frame_count(phys); - - return framecount; + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + struct dpu_encoder_phys *phys = dpu_enc ? dpu_enc->cur_master : NULL; + return phys ? atomic_read(&phys->vsync_cnt) : 0; } int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 99a5d73c9b88..e241914a9677 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -163,9 +163,9 @@ void dpu_encoder_set_idle_timeout(struct drm_encoder *drm_enc, int dpu_encoder_get_linecount(struct drm_encoder *drm_enc); /** - * dpu_encoder_get_frame_count - get interface frame count for the encoder. + * dpu_encoder_get_vsync_count - get vsync count for the encoder. * @drm_enc: Pointer to previously created drm encoder structure */ -int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc); +int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc); #endif /* __DPU_ENCODER_H__ */ From 803e66f40a15da6abe2bf5afe6f6465d01c38efa Mon Sep 17 00:00:00 2001 From: Chi Minghao Date: Tue, 31 Aug 2021 04:51:27 -0700 Subject: [PATCH 367/554] drm/msm: remove unneeded variable Fix the following coccicheck REVIEW: ./drivers/gpu/drm/msm/edp/edp_ctrl.c:1245:5-8 Unneeded variable Reported-by: Zeal Robot Signed-off-by: Chi Minghao Reviewed-by: Lyude Paul Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210831115127.18236-1-chi.minghao@zte.com.cn Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index fe1366b4c49f..6ef4bee8fa86 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -1243,8 +1243,6 @@ bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, struct drm_connector *connector, struct edid **edid) { - int ret = 0; - mutex_lock(&ctrl->dev_mutex); if (ctrl->edid) { @@ -1279,7 +1277,7 @@ disable_ret: } unlock_ret: mutex_unlock(&ctrl->dev_mutex); - return ret; + return 0; } int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, From 5369f3c50995b7dc91cfba23679bb3a71f613a0d Mon Sep 17 00:00:00 2001 From: zhaoxiao Date: Mon, 6 Sep 2021 14:43:15 +0800 Subject: [PATCH 368/554] drm/msm: Remove initialization of static variables Address the following checkpatch errors: ERROR: do not initialise statics to false FILE: :drivers/gpu/drm/msm/msm_drv.c:21: -static bool reglog = false; FILE: :drivers/gpu/drm/msm/msm_drv.c:31: -bool dumpstate = false; Signed-off-by: zhaoxiao Link: https://lore.kernel.org/r/20210906064315.4975-1-long870912@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d4e09703a87d..145ab040c117 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -58,7 +58,7 @@ static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = { }; #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING -static bool reglog = false; +static bool reglog; MODULE_PARM_DESC(reglog, "Enable register read/write logging"); module_param(reglog, bool, 0600); #else @@ -75,7 +75,7 @@ static char *vram = "16m"; MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU)"); module_param(vram, charp, 0); -bool dumpstate = false; +bool dumpstate; MODULE_PARM_DESC(dumpstate, "Dump KMS state on errors"); module_param(dumpstate, bool, 0600); From a377da4b0e9ae248f99932dc74ec356dd4c5db15 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Mon, 11 Oct 2021 22:16:40 +0200 Subject: [PATCH 369/554] drm/msm/dsi: Use division result from div_u64_rem in 7nm and 14nm PLL div_u64_rem provides the result of the division and additionally the remainder; don't use this function to solely calculate the remainder while calculating the division again with div_u64. A similar improvement was applied earlier to the 10nm pll in 5c191fef4ce2 ("drm/msm/dsi_pll_10nm: Fix dividing the same numbers twice"). Signed-off-by: Marijn Suijten Reviewed-By: AngeloGioacchino Del Regno Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211011201642.167700-1-marijn.suijten@somainline.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 4 +--- drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index 5b4e991f220d..c62d90361bd2 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -213,9 +213,7 @@ static void pll_14nm_dec_frac_calc(struct dsi_pll_14nm *pll, struct dsi_pll_conf DBG("vco_clk_rate=%lld ref_clk_rate=%lld", vco_clk_rate, fref); dec_start_multiple = div_u64(vco_clk_rate * multiplier, fref); - div_u64_rem(dec_start_multiple, multiplier, &div_frac_start); - - dec_start = div_u64(dec_start_multiple, multiplier); + dec_start = div_u64_rem(dec_start_multiple, multiplier, &div_frac_start); pconf->dec_start = (u32)dec_start; pconf->div_frac_start = div_frac_start; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index cb297b08458e..079613d2aaa9 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -114,9 +114,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config multiplier = 1 << FRAC_BITS; dec_multiple = div_u64(pll_freq * multiplier, divider); - div_u64_rem(dec_multiple, multiplier, &frac); - - dec = div_u64(dec_multiple, multiplier); + dec = div_u64_rem(dec_multiple, multiplier, &frac); if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1)) config->pll_clock_inverters = 0x28; From 64739f33ee465e4065b72eb07dbc27ad9c92a938 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Mon, 20 Sep 2021 23:20:14 +0200 Subject: [PATCH 370/554] drm: msm: hdmi: Constify static structs The only usage of hdmi_8996_pll_ops is to assign its address to the ops field in the clk_init_data struct, and the only usage of pll_init is to assign its address to the init field in the clk_hw struct, both which are pointers to const. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210920212014.40520-1-rikard.falkeborn@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c index a8f3b2cbfdc5..99c7853353fd 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c @@ -682,7 +682,7 @@ static int hdmi_8996_pll_is_enabled(struct clk_hw *hw) return pll_locked; } -static struct clk_ops hdmi_8996_pll_ops = { +static const struct clk_ops hdmi_8996_pll_ops = { .set_rate = hdmi_8996_pll_set_clk_rate, .round_rate = hdmi_8996_pll_round_rate, .recalc_rate = hdmi_8996_pll_recalc_rate, @@ -695,7 +695,7 @@ static const char * const hdmi_pll_parents[] = { "xo", }; -static struct clk_init_data pll_init = { +static const struct clk_init_data pll_init = { .name = "hdmipll", .ops = &hdmi_8996_pll_ops, .parent_names = hdmi_pll_parents, From 63885c16d6e2077d23abdf9cb67f5507ded35967 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 20 Sep 2021 15:57:58 -0700 Subject: [PATCH 371/554] drm/msm/dsi: Support NO_CONNECTOR bridges For now, since we have a mix of bridges which support this flag, which which do *not* support this flag, or work both ways, try it once with NO_CONNECTOR and then fall back to the old way if that doesn't work. Eventually we can drop the fallback path. v2: Add missing drm_connector_attach_encoder() so display actually comes up when the bridge properly handles the NO_CONNECTOR flag Signed-off-by: Rob Clark Reviewed-by: Laurent Pinchart Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210920225801.227211-2-robdclark@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 2 ++ drivers/gpu/drm/msm/dsi/dsi_manager.c | 50 ++++++++++++++++++++------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index e9c6af78b1d7..36e5ba3ccc28 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -14,6 +14,8 @@ config DRM_MSM select REGULATOR select DRM_KMS_HELPER select DRM_PANEL + select DRM_BRIDGE + select DRM_PANEL_BRIDGE select DRM_SCHED select SHMEM select TMPFS diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index c41d39f5b7cf..e25877073d31 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -3,6 +3,8 @@ * Copyright (c) 2015, The Linux Foundation. All rights reserved. */ +#include "drm/drm_bridge_connector.h" + #include "msm_kms.h" #include "dsi.h" @@ -688,10 +690,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) { struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct drm_device *dev = msm_dsi->dev; + struct drm_connector *connector; struct drm_encoder *encoder; struct drm_bridge *int_bridge, *ext_bridge; - struct drm_connector *connector; - struct list_head *connector_list; + int ret; int_bridge = msm_dsi->bridge; ext_bridge = msm_dsi->external_bridge = @@ -699,22 +701,44 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) encoder = msm_dsi->encoder; - /* link the internal dsi bridge to the external bridge */ - drm_bridge_attach(encoder, ext_bridge, int_bridge, 0); - /* - * we need the drm_connector created by the external bridge - * driver (or someone else) to feed it to our driver's - * priv->connector[] list, mainly for msm_fbdev_init() + * Try first to create the bridge without it creating its own + * connector.. currently some bridges support this, and others + * do not (and some support both modes) */ - connector_list = &dev->mode_config.connector_list; + ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret == -EINVAL) { + struct drm_connector *connector; + struct list_head *connector_list; - list_for_each_entry(connector, connector_list, head) { - if (drm_connector_has_possible_encoder(connector, encoder)) - return connector; + /* link the internal dsi bridge to the external bridge */ + drm_bridge_attach(encoder, ext_bridge, int_bridge, 0); + + /* + * we need the drm_connector created by the external bridge + * driver (or someone else) to feed it to our driver's + * priv->connector[] list, mainly for msm_fbdev_init() + */ + connector_list = &dev->mode_config.connector_list; + + list_for_each_entry(connector, connector_list, head) { + if (drm_connector_has_possible_encoder(connector, encoder)) + return connector; + } + + return ERR_PTR(-ENODEV); } - return ERR_PTR(-ENODEV); + connector = drm_bridge_connector_init(dev, encoder); + if (IS_ERR(connector)) { + DRM_ERROR("Unable to create bridge connector\n"); + return ERR_CAST(connector); + } + + drm_connector_attach_encoder(connector, encoder); + + return connector; } void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) From 9960f7a899f1ce526a34f646a95ff6964229d6ac Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 28 Sep 2021 09:28:59 -0700 Subject: [PATCH 372/554] drm/msm/dpu: Remove some nonsense These aren't used. And if we add use for them later, we should probably do something a bit more structured than string parsing. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210928162903.1104847-1-robdclark@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 6 ------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 8 -------- 2 files changed, 14 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 700d65e39feb..e0bf12df3611 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -958,12 +958,6 @@ static const struct dpu_perf_cfg sdm845_perf_data = { .min_core_ib = 2400000, .min_llcc_ib = 800000, .min_dram_ib = 800000, - .core_ib_ff = "6.0", - .core_clk_ff = "1.0", - .comp_ratio_rt = - "NV12/5/1/1.23 AB24/5/1/1.23 XB24/5/1/1.23", - .comp_ratio_nrt = - "NV12/5/1/1.25 AB24/5/1/1.25 XB24/5/1/1.25", .undersized_prefill_lines = 2, .xtra_prefill_lines = 2, .dest_scale_prefill_lines = 3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index d2a945a27cfa..4ade44bbd37e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -676,10 +676,6 @@ struct dpu_perf_cdp_cfg { * @min_core_ib minimum mnoc ib vote in kbps * @min_llcc_ib minimum llcc ib vote in kbps * @min_dram_ib minimum dram ib vote in kbps - * @core_ib_ff core instantaneous bandwidth fudge factor - * @core_clk_ff core clock fudge factor - * @comp_ratio_rt string of 0 or more of /// - * @comp_ratio_nrt string of 0 or more of /// * @undersized_prefill_lines undersized prefill in lines * @xtra_prefill_lines extra prefill latency in lines * @dest_scale_prefill_lines destination scaler latency in lines @@ -702,10 +698,6 @@ struct dpu_perf_cfg { u32 min_core_ib; u32 min_llcc_ib; u32 min_dram_ib; - const char *core_ib_ff; - const char *core_clk_ff; - const char *comp_ratio_rt; - const char *comp_ratio_nrt; u32 undersized_prefill_lines; u32 xtra_prefill_lines; u32 dest_scale_prefill_lines; From 76544e4bb1a05818181bc36d093a561f287afeba Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 29 Sep 2021 11:54:58 +0100 Subject: [PATCH 373/554] drm/msm/dp: Remove redundant initialization of variable bpp The variable bpp is being initialized with a value that is never read, it is being updated later on in both paths of an if statement. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210929105458.209895-1-colin.king@canonical.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 2181b60e1d1d..71db10c0f262 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -234,7 +234,7 @@ u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, u32 mode_edid_bpp, u32 mode_pclk_khz) { struct dp_panel_private *panel; - u32 bpp = mode_edid_bpp; + u32 bpp; if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { DRM_ERROR("invalid input\n"); From b220c154832c5cd0df34cbcbcc19d7135c16e823 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Wed, 29 Sep 2021 10:25:54 -0600 Subject: [PATCH 374/554] drm/msm: prevent NULL dereference in msm_gpu_crashstate_capture() Coverity complains of a possible NULL dereference: CID 120718 (#1 of 1): Dereference null return value (NULL_RETURNS) 23. dereference: Dereferencing a pointer that might be NULL state->bos when calling msm_gpu_crashstate_get_bo. [show details] 301 msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, 302 submit->bos[i].iova, submit->bos[i].flags); Fix this by employing the same state->bos NULL check as is used in the next for loop. Cc: Rob Clark Cc: Sean Paul Cc: David Airlie Cc: Daniel Vetter Cc: linux-arm-msm@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Tim Gardner Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210929162554.14295-1-tim.gardner@canonical.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8a3a592da3a4..2c46cd968ac4 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -296,7 +296,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, state->bos = kcalloc(nr, sizeof(struct msm_gpu_state_bo), GFP_KERNEL); - for (i = 0; i < submit->nr_bos; i++) { + for (i = 0; state->bos && i < submit->nr_bos; i++) { if (should_dump(submit, i)) { msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, submit->bos[i].iova, submit->bos[i].flags); From c9ef97b694b9bf1bfd8869c8b78de840785e5934 Mon Sep 17 00:00:00 2001 From: Bernard Zhao Date: Sun, 9 May 2021 20:12:27 -0700 Subject: [PATCH 375/554] drm/msm: fix warning "using plain integer as NULL pointer" Fix sparse warning: drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1195:41: warning: Using plain integer as NULL pointer drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1348:32: warning: Using plain integer as NULL pointer Signed-off-by: Bernard Zhao Link: https://lore.kernel.org/r/20210510031250.5303-1-bernard@vivo.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index c989621209aa..a3e3b9d1b82e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1193,7 +1193,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) if (DPU_FORMAT_IS_YUV(fmt)) _dpu_plane_setup_csc(pdpu); else - pdpu->csc_ptr = 0; + pdpu->csc_ptr = NULL; } _dpu_plane_set_qos_lut(plane, fb); @@ -1330,7 +1330,7 @@ static void dpu_plane_reset(struct drm_plane *plane) /* remove previous state, if present */ if (plane->state) { dpu_plane_destroy_state(plane, plane->state); - plane->state = 0; + plane->state = NULL; } pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); From d2a7107d3a8ef4d7e62c85db50bebf032fe5a3b6 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 31 Dec 2020 09:41:55 +0000 Subject: [PATCH 376/554] drm/msm/mdp4: Remove redundant null check before clk_prepare_enable/clk_disable_unprepare Because clk_prepare_enable() and clk_disable_unprepare() already checked NULL clock parameter, so the additional checks are unnecessary, just remove them. Signed-off-by: Xu Wang Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20201231094155.25481-1-vulab@iscas.ac.cn Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index cdcaf470f148..5a33bb148e9e 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -173,12 +173,9 @@ int mdp4_disable(struct mdp4_kms *mdp4_kms) DBG(""); clk_disable_unprepare(mdp4_kms->clk); - if (mdp4_kms->pclk) - clk_disable_unprepare(mdp4_kms->pclk); - if (mdp4_kms->lut_clk) - clk_disable_unprepare(mdp4_kms->lut_clk); - if (mdp4_kms->axi_clk) - clk_disable_unprepare(mdp4_kms->axi_clk); + clk_disable_unprepare(mdp4_kms->pclk); + clk_disable_unprepare(mdp4_kms->lut_clk); + clk_disable_unprepare(mdp4_kms->axi_clk); return 0; } @@ -188,12 +185,9 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms) DBG(""); clk_prepare_enable(mdp4_kms->clk); - if (mdp4_kms->pclk) - clk_prepare_enable(mdp4_kms->pclk); - if (mdp4_kms->lut_clk) - clk_prepare_enable(mdp4_kms->lut_clk); - if (mdp4_kms->axi_clk) - clk_prepare_enable(mdp4_kms->axi_clk); + clk_prepare_enable(mdp4_kms->pclk); + clk_prepare_enable(mdp4_kms->lut_clk); + clk_prepare_enable(mdp4_kms->axi_clk); return 0; } From 993247ffdd3ed5ac3319a5edcd251bef1d65083e Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 31 Dec 2020 09:56:16 +0000 Subject: [PATCH 377/554] drm/msm: dsi: Remove redundant null check before clk_prepare_enable/clk_disable_unprepare Because clk_prepare_enable() and clk_disable_unprepare() already checked NULL clock parameter, so the additional checks are unnecessary, just remove them. Signed-off-by: Xu Wang Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20201231095616.25973-1-vulab@iscas.ac.cn Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index c86b5090fae6..7878030e4396 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -558,13 +558,11 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto pixel_clk_err; } - if (msm_host->byte_intf_clk) { - ret = clk_prepare_enable(msm_host->byte_intf_clk); - if (ret) { - pr_err("%s: Failed to enable byte intf clk\n", - __func__); - goto byte_intf_clk_err; - } + ret = clk_prepare_enable(msm_host->byte_intf_clk); + if (ret) { + pr_err("%s: Failed to enable byte intf clk\n", + __func__); + goto byte_intf_clk_err; } return 0; @@ -660,8 +658,7 @@ void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) dev_pm_opp_set_rate(&msm_host->pdev->dev, 0); clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); - if (msm_host->byte_intf_clk) - clk_disable_unprepare(msm_host->byte_intf_clk); + clk_disable_unprepare(msm_host->byte_intf_clk); clk_disable_unprepare(msm_host->byte_clk); } From 442f59b9c0dec876ccbad7e9839b3e969fcacd14 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 31 Dec 2020 09:49:35 +0000 Subject: [PATCH 378/554] drm/msm/mdp5: Remove redundant null check before clk_prepare_enable/clk_disable_unprepare Because clk_prepare_enable() and clk_disable_unprepare() already checked NULL clock parameter, so the additional checks are unnecessary, just remove them. Signed-off-by: Xu Wang Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20201231094935.25737-1-vulab@iscas.ac.cn Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 18 ++++++------------ drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c | 12 ++++-------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index b3b42672b2d4..7b242246d4e7 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -295,15 +295,12 @@ static int mdp5_disable(struct mdp5_kms *mdp5_kms) mdp5_kms->enable_count--; WARN_ON(mdp5_kms->enable_count < 0); - if (mdp5_kms->tbu_rt_clk) - clk_disable_unprepare(mdp5_kms->tbu_rt_clk); - if (mdp5_kms->tbu_clk) - clk_disable_unprepare(mdp5_kms->tbu_clk); + clk_disable_unprepare(mdp5_kms->tbu_rt_clk); + clk_disable_unprepare(mdp5_kms->tbu_clk); clk_disable_unprepare(mdp5_kms->ahb_clk); clk_disable_unprepare(mdp5_kms->axi_clk); clk_disable_unprepare(mdp5_kms->core_clk); - if (mdp5_kms->lut_clk) - clk_disable_unprepare(mdp5_kms->lut_clk); + clk_disable_unprepare(mdp5_kms->lut_clk); return 0; } @@ -317,12 +314,9 @@ static int mdp5_enable(struct mdp5_kms *mdp5_kms) clk_prepare_enable(mdp5_kms->ahb_clk); clk_prepare_enable(mdp5_kms->axi_clk); clk_prepare_enable(mdp5_kms->core_clk); - if (mdp5_kms->lut_clk) - clk_prepare_enable(mdp5_kms->lut_clk); - if (mdp5_kms->tbu_clk) - clk_prepare_enable(mdp5_kms->tbu_clk); - if (mdp5_kms->tbu_rt_clk) - clk_prepare_enable(mdp5_kms->tbu_rt_clk); + clk_prepare_enable(mdp5_kms->lut_clk); + clk_prepare_enable(mdp5_kms->tbu_clk); + clk_prepare_enable(mdp5_kms->tbu_rt_clk); return 0; } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c index 2f4895bcb0b0..0ea53420bc40 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c @@ -136,10 +136,8 @@ static int mdp5_mdss_enable(struct msm_mdss *mdss) DBG(""); clk_prepare_enable(mdp5_mdss->ahb_clk); - if (mdp5_mdss->axi_clk) - clk_prepare_enable(mdp5_mdss->axi_clk); - if (mdp5_mdss->vsync_clk) - clk_prepare_enable(mdp5_mdss->vsync_clk); + clk_prepare_enable(mdp5_mdss->axi_clk); + clk_prepare_enable(mdp5_mdss->vsync_clk); return 0; } @@ -149,10 +147,8 @@ static int mdp5_mdss_disable(struct msm_mdss *mdss) struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(mdss); DBG(""); - if (mdp5_mdss->vsync_clk) - clk_disable_unprepare(mdp5_mdss->vsync_clk); - if (mdp5_mdss->axi_clk) - clk_disable_unprepare(mdp5_mdss->axi_clk); + clk_disable_unprepare(mdp5_mdss->vsync_clk); + clk_disable_unprepare(mdp5_mdss->axi_clk); clk_disable_unprepare(mdp5_mdss->ahb_clk); return 0; From f8f57a38a60bf3fbc5e1e6a5785fc3026f0db72b Mon Sep 17 00:00:00 2001 From: Bernard Date: Tue, 10 Nov 2020 16:10:27 +0800 Subject: [PATCH 379/554] drm/msm: delete conversion from bool value to bool return Delete the conversion from bool value to bool function return. Signed-off-by: Bernard Zhao Link: https://lore.kernel.org/r/AI*ANACSDfnjQejyeNXUnKoQ.1.1604995827401.Hmail.bernard@vivo.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index aa01698d6b25..34a6940d12c5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -42,7 +42,7 @@ static bool dpu_encoder_phys_cmd_is_master(struct dpu_encoder_phys *phys_enc) { - return (phys_enc->split_role != ENC_ROLE_SLAVE) ? true : false; + return (phys_enc->split_role != ENC_ROLE_SLAVE); } static bool dpu_encoder_phys_cmd_mode_fixup( From 2c477ff336cb74988fc0f9c97b042b5341e45429 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 30 Oct 2020 00:32:41 +0530 Subject: [PATCH 380/554] drm: msm: adreno: use DEFINE_DEBUGFS_ATTRIBUTE with debugfs_create_file_unsafe() Using DEFINE_DEBUGFS_ATTRIBUTE macro with debugfs_create_file_unsafe() function in place of the debugfs_create_file() function will make the file operation struct "reset" aware of the file's lifetime. Additional details here: https://lists.archive.carbon60.com/linux/kernel/2369498 Issue reported by Coccinelle script: scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci Signed-off-by: Deepak R Varma Link: https://lore.kernel.org/r/9ca2c2e4cbd9ebb282b90f742305fd9b481aacc2.1603998014.git.mh12gx2825@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c index c9d11d57aed6..dd593ec2bc56 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -138,7 +138,7 @@ reset_set(void *data, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) @@ -154,6 +154,6 @@ void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) ARRAY_SIZE(a5xx_debugfs_list), minor->debugfs_root, minor); - debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev, - &reset_fops); + debugfs_create_file_unsafe("reset", S_IWUGO, minor->debugfs_root, dev, + &reset_fops); } From 39b14bb5915f5c68585161339d75d2f47d2a7e20 Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Fri, 6 Nov 2020 10:45:12 +0800 Subject: [PATCH 381/554] drm: Use IS_ERR() instead of IS_ERR_OR_NULL() dev_pm_opp_find_freq_exact never return null but ERR_PTR(),so we should use IS_ERR() to clarify and avoid compilation warnings. Signed-off-by: Wang Qing Link: https://lore.kernel.org/r/1604630714-6163-1-git-send-email-wangqing@vivo.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 8b73f70766a4..049f7b464439 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -891,7 +891,7 @@ static void a6xx_gmu_set_initial_freq(struct msm_gpu *gpu, struct a6xx_gmu *gmu) unsigned long gpu_freq = gmu->gpu_freqs[gmu->current_perf_index]; gpu_opp = dev_pm_opp_find_freq_exact(&gpu->pdev->dev, gpu_freq, true); - if (IS_ERR_OR_NULL(gpu_opp)) + if (IS_ERR(gpu_opp)) return; gmu->freq = 0; /* so a6xx_gmu_set_freq() doesn't exit early */ @@ -905,7 +905,7 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu) unsigned long gpu_freq = gmu->gpu_freqs[gmu->current_perf_index]; gpu_opp = dev_pm_opp_find_freq_exact(&gpu->pdev->dev, gpu_freq, true); - if (IS_ERR_OR_NULL(gpu_opp)) + if (IS_ERR(gpu_opp)) return; dev_pm_opp_set_opp(&gpu->pdev->dev, gpu_opp); From 0fdf204d8746c484abc3a0e3763671a0fa438098 Mon Sep 17 00:00:00 2001 From: Sireesh Kodali Date: Tue, 28 Sep 2021 18:49:27 +0530 Subject: [PATCH 382/554] dt-bindings: msm: dsi: Add MSM8953 dsi phy SoCs based on the MSM8953 platform use the 14nm DSI PHY driver Signed-off-by: Sireesh Kodali Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210928131929.18567-2-sireeshkodali1@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml index 064df50e21a5..81dbee4803c0 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml @@ -17,6 +17,7 @@ properties: enum: - qcom,dsi-phy-14nm - qcom,dsi-phy-14nm-660 + - qcom,dsi-phy-14nm-8953 reg: items: From 90a06f134c844dd8789f8d39845201289b94c37c Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Tue, 28 Sep 2021 18:49:28 +0530 Subject: [PATCH 383/554] drm/msm/dsi: Add phy configuration for MSM8953 Add phy configuration for 14nm dsi phy found on MSM8953 SoC. Only difference from existing configurations are io_start addresses. Signed-off-by: Vladimir Lypak Reviewed-by: Dmitry Baryshkov Signed-off-by: Sireesh Kodali Link: https://lore.kernel.org/r/20210928131929.18567-3-sireeshkodali1@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 ++ drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 8c65ef6968ca..9842e04b5858 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -627,6 +627,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_14nm_cfgs }, { .compatible = "qcom,dsi-phy-14nm-660", .data = &dsi_phy_14nm_660_cfgs }, + { .compatible = "qcom,dsi-phy-14nm-8953", + .data = &dsi_phy_14nm_8953_cfgs }, #endif #ifdef CONFIG_DRM_MSM_DSI_10NM_PHY { .compatible = "qcom,dsi-phy-10nm", diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index b91303ada74f..4c8257581bfc 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -48,6 +48,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index c62d90361bd2..7414966f198e 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -1063,3 +1063,24 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs = { .io_start = { 0xc994400, 0xc996000 }, .num_dsi_phy = 2, }; + +const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs = { + .has_phy_lane = true, + .reg_cfg = { + .num = 1, + .regs = { + {"vcca", 17000, 32}, + }, + }, + .ops = { + .enable = dsi_14nm_phy_enable, + .disable = dsi_14nm_phy_disable, + .pll_init = dsi_pll_14nm_init, + .save_pll_state = dsi_14nm_pll_save_state, + .restore_pll_state = dsi_14nm_pll_restore_state, + }, + .min_pll_rate = VCO_MIN_RATE, + .max_pll_rate = VCO_MAX_RATE, + .io_start = { 0x1a94400, 0x1a96400 }, + .num_dsi_phy = 2, +}; From fb25d4474fa009dab169be2eb11d122852dd0684 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Tue, 28 Sep 2021 18:49:29 +0530 Subject: [PATCH 384/554] drm/msm/mdp5: Add configuration for MDP v1.16 MDP version v1.16 is almost identical to v1.15 with most significant difference being presence of second DSI interface. MDP v1.16 is found on SoCs such as MSM8x53, SDM450, SDM632 (All with Adreno 506). Signed-off-by: Vladimir Lypak Signed-off-by: Sireesh Kodali Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210928131929.18567-4-sireeshkodali1@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c | 89 ++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index 9741544ffc35..1bf9ff5dbabc 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c @@ -752,6 +752,94 @@ const struct mdp5_cfg_hw msm8x76_config = { .max_clk = 360000000, }; +static const struct mdp5_cfg_hw msm8x53_config = { + .name = "msm8x53", + .mdp = { + .count = 1, + .caps = MDP_CAP_CDM | + MDP_CAP_SRC_SPLIT, + }, + .ctl = { + .count = 3, + .base = { 0x01000, 0x01200, 0x01400 }, + .flush_hw_mask = 0xffffffff, + }, + .pipe_vig = { + .count = 1, + .base = { 0x04000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_CSC | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_rgb = { + .count = 2, + .base = { 0x14000, 0x16000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_dma = { + .count = 1, + .base = { 0x24000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_cursor = { + .count = 1, + .base = { 0x34000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + MDP_PIPE_CAP_CURSOR | + 0, + }, + + .lm = { + .count = 3, + .base = { 0x44000, 0x45000 }, + .instances = { + { .id = 0, .pp = 0, .dspp = 0, + .caps = MDP_LM_CAP_DISPLAY | + MDP_LM_CAP_PAIR }, + { .id = 1, .pp = 1, .dspp = -1, + .caps = MDP_LM_CAP_DISPLAY }, + }, + .nb_stages = 5, + .max_width = 2048, + .max_height = 0xFFFF, + }, + .dspp = { + .count = 1, + .base = { 0x54000 }, + + }, + .pp = { + .count = 2, + .base = { 0x70000, 0x70800 }, + }, + .cdm = { + .count = 1, + .base = { 0x79200 }, + }, + .intf = { + .base = { 0x6a000, 0x6a800, 0x6b000 }, + .connect = { + [0] = INTF_DISABLED, + [1] = INTF_DSI, + [2] = INTF_DSI, + }, + }, + .max_clk = 400000000, +}; + static const struct mdp5_cfg_hw msm8917_config = { .name = "msm8917", .mdp = { @@ -1151,6 +1239,7 @@ static const struct mdp5_cfg_handler cfg_handlers_v1[] = { { .revision = 7, .config = { .hw = &msm8x96_config } }, { .revision = 11, .config = { .hw = &msm8x76_config } }, { .revision = 15, .config = { .hw = &msm8917_config } }, + { .revision = 16, .config = { .hw = &msm8x53_config } }, }; static const struct mdp5_cfg_handler cfg_handlers_v3[] = { From bf94ec093d05e3ed3142d9291b876eeb9997ba5c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Oct 2021 04:08:30 +0300 Subject: [PATCH 385/554] drm/msm/dsi: do not enable irq handler before powering up the host The DSI host might be left in some state by the bootloader. If this state generates an IRQ, it might hang the system by holding the interrupt line before the driver sets up the DSI host to the known state. Move the request_irq into msm_dsi_host_init and pass IRQF_NO_AUTOEN to it. Call enable/disable_irq after msm_dsi_host_power_on/_off() functions, so that we can be sure that the interrupt is delivered when the host is in the known state. It is not possible to defer the interrupt enablement to a later point, because drm_panel_prepare might need to communicate with the panel over the DSI link and that requires working interrupt. Fixes: a689554ba6ed ("drm/msm: Initial add DSI connector support") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20211002010830.647416-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi.h | 2 ++ drivers/gpu/drm/msm/dsi/dsi_host.c | 48 +++++++++++++++++---------- drivers/gpu/drm/msm/dsi/dsi_manager.c | 16 +++++++++ 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index b50db91cb8a7..569c8ff062ba 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -107,6 +107,8 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base, u32 len); int msm_dsi_host_enable(struct mipi_dsi_host *host); int msm_dsi_host_disable(struct mipi_dsi_host *host); +void msm_dsi_host_enable_irq(struct mipi_dsi_host *host); +void msm_dsi_host_disable_irq(struct mipi_dsi_host *host); int msm_dsi_host_power_on(struct mipi_dsi_host *host, struct msm_dsi_phy_shared_timings *phy_shared_timings, bool is_bonded_dsi, struct msm_dsi_phy *phy); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 7878030e4396..77553d75088f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1895,6 +1895,23 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) return ret; } + msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (msm_host->irq < 0) { + ret = msm_host->irq; + dev_err(&pdev->dev, "failed to get irq: %d\n", ret); + return ret; + } + + /* do not autoenable, will be enabled later */ + ret = devm_request_irq(&pdev->dev, msm_host->irq, dsi_host_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN, + "dsi_isr", msm_host); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request IRQ%u: %d\n", + msm_host->irq, ret); + return ret; + } + init_completion(&msm_host->dma_comp); init_completion(&msm_host->video_comp); mutex_init(&msm_host->dev_mutex); @@ -1938,25 +1955,8 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - struct platform_device *pdev = msm_host->pdev; int ret; - msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (msm_host->irq < 0) { - ret = msm_host->irq; - DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret); - return ret; - } - - ret = devm_request_irq(&pdev->dev, msm_host->irq, - dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "dsi_isr", msm_host); - if (ret < 0) { - DRM_DEV_ERROR(&pdev->dev, "failed to request IRQ%u: %d\n", - msm_host->irq, ret); - return ret; - } - msm_host->dev = dev; ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); if (ret) { @@ -2312,6 +2312,20 @@ void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host, clk_req->escclk_rate = msm_host->esc_clk_rate; } +void msm_dsi_host_enable_irq(struct mipi_dsi_host *host) +{ + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + + enable_irq(msm_host->irq); +} + +void msm_dsi_host_disable_irq(struct mipi_dsi_host *host) +{ + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + + disable_irq(msm_host->irq); +} + int msm_dsi_host_enable(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index e25877073d31..20c4d650fd80 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -379,6 +379,14 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) } } + /* + * Enable before preparing the panel, disable after unpreparing, so + * that the panel can communicate over the DSI link. + */ + msm_dsi_host_enable_irq(host); + if (is_bonded_dsi && msm_dsi1) + msm_dsi_host_enable_irq(msm_dsi1->host); + /* Always call panel functions once, because even for dual panels, * there is only one drm_panel instance. */ @@ -413,6 +421,10 @@ host_en_fail: if (panel) drm_panel_unprepare(panel); panel_prep_fail: + msm_dsi_host_disable_irq(host); + if (is_bonded_dsi && msm_dsi1) + msm_dsi_host_disable_irq(msm_dsi1->host); + if (is_bonded_dsi && msm_dsi1) msm_dsi_host_power_off(msm_dsi1->host); host1_on_fail: @@ -525,6 +537,10 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) id, ret); } + msm_dsi_host_disable_irq(host); + if (is_bonded_dsi && msm_dsi1) + msm_dsi_host_disable_irq(msm_dsi1->host); + /* Save PHY status if it is a clock source */ msm_dsi_phy_pll_save_state(msm_dsi->phy); From 3d91e50ff58364f6572ad268b508175d27800e51 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2021 16:45:30 +0300 Subject: [PATCH 386/554] drm/msm: Fix potential Oops in a6xx_gmu_rpmh_init() There are two problems here: 1) The "seqptr" is used uninitalized when we free it at the end. 2) The a6xx_gmu_get_mmio() function returns error pointers. It never returns true. Fixes: 64245fc55172 ("drm/msm/a6xx: use AOP-initialized PDC for a650") Fixes: f8fc924e088e ("drm/msm/a6xx: Fix PDC register overlap") Signed-off-by: Dan Carpenter Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211004134530.GB11689@kili Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 049f7b464439..71e52b2b2025 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -516,11 +516,11 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct platform_device *pdev = to_platform_device(gmu->dev); void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); - void __iomem *seqptr; + void __iomem *seqptr = NULL; uint32_t pdc_address_offset; bool pdc_in_aop = false; - if (!pdcptr) + if (IS_ERR(pdcptr)) goto err; if (adreno_is_a650(adreno_gpu) || adreno_is_a660_family(adreno_gpu)) @@ -532,7 +532,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) if (!pdc_in_aop) { seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); - if (!seqptr) + if (IS_ERR(seqptr)) goto err; } From b6816441a14bbe356ba8590de79cfea2de6a085c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2021 13:38:06 +0300 Subject: [PATCH 387/554] drm/msm: potential error pointer dereference in init() The msm_iommu_new() returns error pointers on failure so check for that to avoid an Oops. Fixes: ccac7ce373c1 ("drm/msm: Refactor address space initialization") Signed-off-by: Dan Carpenter Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211004103806.GD25015@kili Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index ae48f41821cf..ad247c06e198 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -908,6 +908,10 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) return 0; mmu = msm_iommu_new(dpu_kms->dev->dev, domain); + if (IS_ERR(mmu)) { + iommu_domain_free(domain); + return PTR_ERR(mmu); + } aspace = msm_gem_address_space_create(mmu, "dpu1", 0x1000, 0x100000000 - 0x1000); From 687825c402f19f74861514771d2a37eca178bbd6 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 1 Oct 2021 10:43:56 -0700 Subject: [PATCH 388/554] dt-bindings: msm/dp: Change reg definition reg was defined as one region covering the entire DP block, but the memory map is actually split in 4 regions and obviously the size of these regions differs between platforms. Switch the reg to require that all four regions are specified instead. It is expected that the implementation will handle existing DTBs, even though the schema defines the new layout. Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211001174400.981707-2-bjorn.andersson@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- .../bindings/display/msm/dp-controller.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 64d8d9e5e47a..f915dc080cbc 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -19,7 +19,12 @@ properties: - qcom,sc7180-dp reg: - maxItems: 1 + items: + - description: ahb register block + - description: aux register block + - description: link register block + - description: p0 register block + - description: p1 register block interrupts: maxItems: 1 @@ -100,7 +105,11 @@ examples: displayport-controller@ae90000 { compatible = "qcom,sc7180-dp"; - reg = <0xae90000 0x1400>; + reg = <0xae90000 0x200>, + <0xae90200 0x200>, + <0xae90400 0xc00>, + <0xae91000 0x400>, + <0xae91400 0x400>; interrupt-parent = <&mdss>; interrupts = <12>; clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, From 17b019e3b0045113a36ddada2abc3dfc1a153ebb Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 1 Oct 2021 10:43:57 -0700 Subject: [PATCH 389/554] drm/msm/dp: Use devres for ioremap() The non-devres version of ioremap is used, which requires manual cleanup. But the code paths leading here is mixed with other devres users, so rely on this for ioremap as well to simplify the code. Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211001174400.981707-3-bjorn.andersson@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_parser.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index 0519dd3ac3c3..c064ced78278 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -32,7 +32,7 @@ static int msm_dss_ioremap(struct platform_device *pdev, } io_data->len = (u32)resource_size(res); - io_data->base = ioremap(res->start, io_data->len); + io_data->base = devm_ioremap(&pdev->dev, res->start, io_data->len); if (!io_data->base) { DRM_ERROR("%pS->%s: ioremap failed\n", __builtin_return_address(0), __func__); @@ -42,22 +42,6 @@ static int msm_dss_ioremap(struct platform_device *pdev, return 0; } -static void msm_dss_iounmap(struct dss_io_data *io_data) -{ - if (io_data->base) { - iounmap(io_data->base); - io_data->base = NULL; - } - io_data->len = 0; -} - -static void dp_parser_unmap_io_resources(struct dp_parser *parser) -{ - struct dp_io *io = &parser->io; - - msm_dss_iounmap(&io->dp_controller); -} - static int dp_parser_ctrl_res(struct dp_parser *parser) { int rc = 0; @@ -67,19 +51,14 @@ static int dp_parser_ctrl_res(struct dp_parser *parser) rc = msm_dss_ioremap(pdev, &io->dp_controller); if (rc) { DRM_ERROR("unable to remap dp io resources, rc=%d\n", rc); - goto err; + return rc; } io->phy = devm_phy_get(&pdev->dev, "dp"); - if (IS_ERR(io->phy)) { - rc = PTR_ERR(io->phy); - goto err; - } + if (IS_ERR(io->phy)) + return PTR_ERR(io->phy); return 0; -err: - dp_parser_unmap_io_resources(parser); - return rc; } static int dp_parser_misc(struct dp_parser *parser) From ef501dbf84cb36a9d5fb3971d8dd1b71eb20a5f8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 1 Oct 2021 10:43:58 -0700 Subject: [PATCH 390/554] drm/msm/dp: Refactor ioremap wrapper In order to deal with multiple memory ranges in the following commit change the ioremap wrapper to not poke directly into the dss_io_data struct. While at it, devm_ioremap_resource() already prints useful error messages on failure, so omit the unnecessary prints from the caller. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211001174400.981707-4-bjorn.andersson@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_parser.c | 35 ++++++++++-------------------- drivers/gpu/drm/msm/dp/dp_parser.h | 2 +- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index c064ced78278..c05ba1990218 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -19,40 +19,27 @@ static const struct dp_regulator_cfg sdm845_dp_reg_cfg = { }, }; -static int msm_dss_ioremap(struct platform_device *pdev, - struct dss_io_data *io_data) +static void __iomem *dp_ioremap(struct platform_device *pdev, int idx, size_t *len) { - struct resource *res = NULL; + struct resource *res; + void __iomem *base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - DRM_ERROR("%pS->%s: msm_dss_get_res failed\n", - __builtin_return_address(0), __func__); - return -ENODEV; - } + base = devm_platform_get_and_ioremap_resource(pdev, idx, &res); + if (!IS_ERR(base)) + *len = resource_size(res); - io_data->len = (u32)resource_size(res); - io_data->base = devm_ioremap(&pdev->dev, res->start, io_data->len); - if (!io_data->base) { - DRM_ERROR("%pS->%s: ioremap failed\n", - __builtin_return_address(0), __func__); - return -EIO; - } - - return 0; + return base; } static int dp_parser_ctrl_res(struct dp_parser *parser) { - int rc = 0; struct platform_device *pdev = parser->pdev; struct dp_io *io = &parser->io; + struct dss_io_data *dss = &io->dp_controller; - rc = msm_dss_ioremap(pdev, &io->dp_controller); - if (rc) { - DRM_ERROR("unable to remap dp io resources, rc=%d\n", rc); - return rc; - } + dss->base = dp_ioremap(pdev, 0, &dss->len); + if (IS_ERR(dss->base)) + return PTR_ERR(dss->base); io->phy = devm_phy_get(&pdev->dev, "dp"); if (IS_ERR(io->phy)) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index 34b49628bbaf..dc62e70b1640 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -26,7 +26,7 @@ enum dp_pm_type { }; struct dss_io_data { - u32 len; + size_t len; void __iomem *base; }; From 060c160fbb99887b31320e7c7693d4da3fc81dfe Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 1 Oct 2021 10:43:59 -0700 Subject: [PATCH 391/554] drm/msm/dp: Store each subblock in the io region Not all platforms has DP_P0 at offset 0x1000 from the beginning of the DP block. So split the dss_io_data memory region into a set of sub-regions, to make it possible in the next patch to specify each of the sub-regions individually. Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211001174400.981707-5-bjorn.andersson@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_catalog.c | 64 +++++++++-------------------- drivers/gpu/drm/msm/dp/dp_parser.c | 28 +++++++++++-- drivers/gpu/drm/msm/dp/dp_parser.h | 9 +++- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index cc2bb8295329..6ae9b29044b6 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -24,15 +24,6 @@ #define DP_INTERRUPT_STATUS_ACK_SHIFT 1 #define DP_INTERRUPT_STATUS_MASK_SHIFT 2 -#define MSM_DP_CONTROLLER_AHB_OFFSET 0x0000 -#define MSM_DP_CONTROLLER_AHB_SIZE 0x0200 -#define MSM_DP_CONTROLLER_AUX_OFFSET 0x0200 -#define MSM_DP_CONTROLLER_AUX_SIZE 0x0200 -#define MSM_DP_CONTROLLER_LINK_OFFSET 0x0400 -#define MSM_DP_CONTROLLER_LINK_SIZE 0x0C00 -#define MSM_DP_CONTROLLER_P0_OFFSET 0x1000 -#define MSM_DP_CONTROLLER_P0_SIZE 0x0400 - #define DP_INTERRUPT_STATUS1 \ (DP_INTR_AUX_I2C_DONE| \ DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \ @@ -66,82 +57,77 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *d { struct dp_catalog_private *catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + struct dss_io_data *dss = &catalog->io->dp_controller; - msm_disp_snapshot_add_block(disp_state, catalog->io->dp_controller.len, - catalog->io->dp_controller.base, "dp_ctrl"); + msm_disp_snapshot_add_block(disp_state, dss->ahb.len, dss->ahb.base, "dp_ahb"); + msm_disp_snapshot_add_block(disp_state, dss->aux.len, dss->aux.base, "dp_aux"); + msm_disp_snapshot_add_block(disp_state, dss->link.len, dss->link.base, "dp_link"); + msm_disp_snapshot_add_block(disp_state, dss->p0.len, dss->p0.base, "dp_p0"); } static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset) { - offset += MSM_DP_CONTROLLER_AUX_OFFSET; - return readl_relaxed(catalog->io->dp_controller.base + offset); + return readl_relaxed(catalog->io->dp_controller.aux.base + offset); } static inline void dp_write_aux(struct dp_catalog_private *catalog, u32 offset, u32 data) { - offset += MSM_DP_CONTROLLER_AUX_OFFSET; /* * To make sure aux reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, catalog->io->dp_controller.base + offset); + writel(data, catalog->io->dp_controller.aux.base + offset); } static inline u32 dp_read_ahb(struct dp_catalog_private *catalog, u32 offset) { - offset += MSM_DP_CONTROLLER_AHB_OFFSET; - return readl_relaxed(catalog->io->dp_controller.base + offset); + return readl_relaxed(catalog->io->dp_controller.ahb.base + offset); } static inline void dp_write_ahb(struct dp_catalog_private *catalog, u32 offset, u32 data) { - offset += MSM_DP_CONTROLLER_AHB_OFFSET; /* * To make sure phy reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, catalog->io->dp_controller.base + offset); + writel(data, catalog->io->dp_controller.ahb.base + offset); } static inline void dp_write_p0(struct dp_catalog_private *catalog, u32 offset, u32 data) { - offset += MSM_DP_CONTROLLER_P0_OFFSET; /* * To make sure interface reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, catalog->io->dp_controller.base + offset); + writel(data, catalog->io->dp_controller.p0.base + offset); } static inline u32 dp_read_p0(struct dp_catalog_private *catalog, u32 offset) { - offset += MSM_DP_CONTROLLER_P0_OFFSET; /* * To make sure interface reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - return readl_relaxed(catalog->io->dp_controller.base + offset); + return readl_relaxed(catalog->io->dp_controller.p0.base + offset); } static inline u32 dp_read_link(struct dp_catalog_private *catalog, u32 offset) { - offset += MSM_DP_CONTROLLER_LINK_OFFSET; - return readl_relaxed(catalog->io->dp_controller.base + offset); + return readl_relaxed(catalog->io->dp_controller.link.base + offset); } static inline void dp_write_link(struct dp_catalog_private *catalog, u32 offset, u32 data) { - offset += MSM_DP_CONTROLLER_LINK_OFFSET; /* * To make sure link reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, catalog->io->dp_controller.base + offset); + writel(data, catalog->io->dp_controller.link.base + offset); } /* aux related catalog functions */ @@ -276,29 +262,21 @@ static void dump_regs(void __iomem *base, int len) void dp_catalog_dump_regs(struct dp_catalog *dp_catalog) { - u32 offset, len; struct dp_catalog_private *catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + struct dss_io_data *io = &catalog->io->dp_controller; pr_info("AHB regs\n"); - offset = MSM_DP_CONTROLLER_AHB_OFFSET; - len = MSM_DP_CONTROLLER_AHB_SIZE; - dump_regs(catalog->io->dp_controller.base + offset, len); + dump_regs(io->ahb.base, io->ahb.len); pr_info("AUXCLK regs\n"); - offset = MSM_DP_CONTROLLER_AUX_OFFSET; - len = MSM_DP_CONTROLLER_AUX_SIZE; - dump_regs(catalog->io->dp_controller.base + offset, len); + dump_regs(io->aux.base, io->aux.len); pr_info("LCLK regs\n"); - offset = MSM_DP_CONTROLLER_LINK_OFFSET; - len = MSM_DP_CONTROLLER_LINK_SIZE; - dump_regs(catalog->io->dp_controller.base + offset, len); + dump_regs(io->link.base, io->link.len); pr_info("P0CLK regs\n"); - offset = MSM_DP_CONTROLLER_P0_OFFSET; - len = MSM_DP_CONTROLLER_P0_SIZE; - dump_regs(catalog->io->dp_controller.base + offset, len); + dump_regs(io->p0.base, io->p0.len); } u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog) @@ -493,8 +471,7 @@ int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog, bit = BIT(pattern - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT; /* Poll for mainlink ready status */ - ret = readx_poll_timeout(readl, catalog->io->dp_controller.base + - MSM_DP_CONTROLLER_LINK_OFFSET + + ret = readx_poll_timeout(readl, catalog->io->dp_controller.link.base + REG_DP_MAINLINK_READY, data, data & bit, POLLING_SLEEP_US, POLLING_TIMEOUT_US); @@ -541,8 +518,7 @@ bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog) struct dp_catalog_private, dp_catalog); /* Poll for mainlink ready status */ - ret = readl_poll_timeout(catalog->io->dp_controller.base + - MSM_DP_CONTROLLER_LINK_OFFSET + + ret = readl_poll_timeout(catalog->io->dp_controller.link.base + REG_DP_MAINLINK_READY, data, data & DP_MAINLINK_READY_FOR_VIDEO, POLLING_SLEEP_US, POLLING_TIMEOUT_US); diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index c05ba1990218..1f084b2b5bd3 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -11,6 +11,15 @@ #include "dp_parser.h" #include "dp_reg.h" +#define DP_DEFAULT_AHB_OFFSET 0x0000 +#define DP_DEFAULT_AHB_SIZE 0x0200 +#define DP_DEFAULT_AUX_OFFSET 0x0200 +#define DP_DEFAULT_AUX_SIZE 0x0200 +#define DP_DEFAULT_LINK_OFFSET 0x0400 +#define DP_DEFAULT_LINK_SIZE 0x0C00 +#define DP_DEFAULT_P0_OFFSET 0x1000 +#define DP_DEFAULT_P0_SIZE 0x0400 + static const struct dp_regulator_cfg sdm845_dp_reg_cfg = { .num = 2, .regs = { @@ -37,9 +46,22 @@ static int dp_parser_ctrl_res(struct dp_parser *parser) struct dp_io *io = &parser->io; struct dss_io_data *dss = &io->dp_controller; - dss->base = dp_ioremap(pdev, 0, &dss->len); - if (IS_ERR(dss->base)) - return PTR_ERR(dss->base); + dss->ahb.base = dp_ioremap(pdev, 0, &dss->ahb.len); + if (IS_ERR(dss->ahb.base)) + return PTR_ERR(dss->ahb.base); + + if (dss->ahb.len < DP_DEFAULT_P0_OFFSET + DP_DEFAULT_P0_SIZE) { + DRM_ERROR("legacy memory region not large enough\n"); + return -EINVAL; + } + + dss->ahb.len = DP_DEFAULT_AHB_SIZE; + dss->aux.base = dss->ahb.base + DP_DEFAULT_AUX_OFFSET; + dss->aux.len = DP_DEFAULT_AUX_SIZE; + dss->link.base = dss->ahb.base + DP_DEFAULT_LINK_OFFSET; + dss->link.len = DP_DEFAULT_LINK_SIZE; + dss->p0.base = dss->ahb.base + DP_DEFAULT_P0_OFFSET; + dss->p0.len = DP_DEFAULT_P0_SIZE; io->phy = devm_phy_get(&pdev->dev, "dp"); if (IS_ERR(io->phy)) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index dc62e70b1640..dac10923abde 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -25,11 +25,18 @@ enum dp_pm_type { DP_MAX_PM }; -struct dss_io_data { +struct dss_io_region { size_t len; void __iomem *base; }; +struct dss_io_data { + struct dss_io_region ahb; + struct dss_io_region aux; + struct dss_io_region link; + struct dss_io_region p0; +}; + static inline const char *dp_parser_pm_name(enum dp_pm_type module) { switch (module) { From 415f36903be7be16bc0563f3624b0d0927739860 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 1 Oct 2021 10:44:00 -0700 Subject: [PATCH 392/554] drm/msm/dp: Allow sub-regions to be specified in DT Not all platforms has P0 at an offset of 0x1000 from the base address, so add support for specifying each sub-region in DT. The code falls back to the predefined offsets in the case that only a single reg is specified, in order to support existing DT. Reviewed-by: Stephen Boyd Reviewed-by: Abhinav Kumar Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211001174400.981707-6-bjorn.andersson@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_parser.c | 49 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index 1f084b2b5bd3..a431b4e7f385 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -50,18 +50,45 @@ static int dp_parser_ctrl_res(struct dp_parser *parser) if (IS_ERR(dss->ahb.base)) return PTR_ERR(dss->ahb.base); - if (dss->ahb.len < DP_DEFAULT_P0_OFFSET + DP_DEFAULT_P0_SIZE) { - DRM_ERROR("legacy memory region not large enough\n"); - return -EINVAL; - } + dss->aux.base = dp_ioremap(pdev, 1, &dss->aux.len); + if (IS_ERR(dss->aux.base)) { + /* + * The initial binding had a single reg, but in order to + * support variation in the sub-region sizes this was split. + * dp_ioremap() will fail with -EINVAL here if only a single + * reg is specified, so fill in the sub-region offsets and + * lengths based on this single region. + */ + if (PTR_ERR(dss->aux.base) == -EINVAL) { + if (dss->ahb.len < DP_DEFAULT_P0_OFFSET + DP_DEFAULT_P0_SIZE) { + DRM_ERROR("legacy memory region not large enough\n"); + return -EINVAL; + } - dss->ahb.len = DP_DEFAULT_AHB_SIZE; - dss->aux.base = dss->ahb.base + DP_DEFAULT_AUX_OFFSET; - dss->aux.len = DP_DEFAULT_AUX_SIZE; - dss->link.base = dss->ahb.base + DP_DEFAULT_LINK_OFFSET; - dss->link.len = DP_DEFAULT_LINK_SIZE; - dss->p0.base = dss->ahb.base + DP_DEFAULT_P0_OFFSET; - dss->p0.len = DP_DEFAULT_P0_SIZE; + dss->ahb.len = DP_DEFAULT_AHB_SIZE; + dss->aux.base = dss->ahb.base + DP_DEFAULT_AUX_OFFSET; + dss->aux.len = DP_DEFAULT_AUX_SIZE; + dss->link.base = dss->ahb.base + DP_DEFAULT_LINK_OFFSET; + dss->link.len = DP_DEFAULT_LINK_SIZE; + dss->p0.base = dss->ahb.base + DP_DEFAULT_P0_OFFSET; + dss->p0.len = DP_DEFAULT_P0_SIZE; + } else { + DRM_ERROR("unable to remap aux region: %pe\n", dss->aux.base); + return PTR_ERR(dss->aux.base); + } + } else { + dss->link.base = dp_ioremap(pdev, 2, &dss->link.len); + if (IS_ERR(dss->link.base)) { + DRM_ERROR("unable to remap link region: %pe\n", dss->link.base); + return PTR_ERR(dss->link.base); + } + + dss->p0.base = dp_ioremap(pdev, 3, &dss->p0.len); + if (IS_ERR(dss->p0.base)) { + DRM_ERROR("unable to remap p0 region: %pe\n", dss->p0.base); + return PTR_ERR(dss->p0.base); + } + } io->phy = devm_phy_get(&pdev->dev, "dp"); if (IS_ERR(io->phy)) From ddb6e37a50e02736f3c9f1a9f8f873989b22af54 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 27 Sep 2021 16:04:53 -0700 Subject: [PATCH 393/554] drm/msm: Add hrtimer + kthread_work helper Before open-coding this a 2nd time, add a helper. Signed-off-by: Rob Clark Link: https://lore.kernel.org/r/20210927230455.1066297-1-robdclark@gmail.com Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_atomic.c | 21 ++++++--------------- drivers/gpu/drm/msm/msm_drv.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_drv.h | 22 ++++++++++++++++++++++ drivers/gpu/drm/msm/msm_kms.h | 3 +-- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index fab09e7c6efc..27c9ae563f2f 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -116,20 +116,10 @@ out: trace_msm_atomic_async_commit_finish(crtc_mask); } -static enum hrtimer_restart msm_atomic_pending_timer(struct hrtimer *t) -{ - struct msm_pending_timer *timer = container_of(t, - struct msm_pending_timer, timer); - - kthread_queue_work(timer->worker, &timer->work); - - return HRTIMER_NORESTART; -} - static void msm_atomic_pending_work(struct kthread_work *work) { struct msm_pending_timer *timer = container_of(work, - struct msm_pending_timer, work); + struct msm_pending_timer, work.work); msm_atomic_async_commit(timer->kms, timer->crtc_idx); } @@ -139,8 +129,6 @@ int msm_atomic_init_pending_timer(struct msm_pending_timer *timer, { timer->kms = kms; timer->crtc_idx = crtc_idx; - hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - timer->timer.function = msm_atomic_pending_timer; timer->worker = kthread_create_worker(0, "atomic-worker-%d", crtc_idx); if (IS_ERR(timer->worker)) { @@ -149,7 +137,10 @@ int msm_atomic_init_pending_timer(struct msm_pending_timer *timer, return ret; } sched_set_fifo(timer->worker->task); - kthread_init_work(&timer->work, msm_atomic_pending_work); + + msm_hrtimer_work_init(&timer->work, timer->worker, + msm_atomic_pending_work, + CLOCK_MONOTONIC, HRTIMER_MODE_ABS); return 0; } @@ -258,7 +249,7 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) vsync_time = kms->funcs->vsync_time(kms, async_crtc); wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1)); - hrtimer_start(&timer->timer, wakeup_time, + msm_hrtimer_queue_work(&timer->work, wakeup_time, HRTIMER_MODE_ABS); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 145ab040c117..7936e8d498dd 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -200,6 +200,35 @@ void msm_rmw(void __iomem *addr, u32 mask, u32 or) msm_writel(val | or, addr); } +static enum hrtimer_restart msm_hrtimer_worktimer(struct hrtimer *t) +{ + struct msm_hrtimer_work *work = container_of(t, + struct msm_hrtimer_work, timer); + + kthread_queue_work(work->worker, &work->work); + + return HRTIMER_NORESTART; +} + +void msm_hrtimer_queue_work(struct msm_hrtimer_work *work, + ktime_t wakeup_time, + enum hrtimer_mode mode) +{ + hrtimer_start(&work->timer, wakeup_time, mode); +} + +void msm_hrtimer_work_init(struct msm_hrtimer_work *work, + struct kthread_worker *worker, + kthread_work_func_t fn, + clockid_t clock_id, + enum hrtimer_mode mode) +{ + hrtimer_init(&work->timer, clock_id, mode); + work->timer.function = msm_hrtimer_worktimer; + work->worker = worker; + kthread_init_work(&work->work, fn); +} + static irqreturn_t msm_irq(int irq, void *arg) { struct drm_device *dev = arg; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index c552f0c3890c..205cc937dafa 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -480,6 +480,28 @@ void msm_writel(u32 data, void __iomem *addr); u32 msm_readl(const void __iomem *addr); void msm_rmw(void __iomem *addr, u32 mask, u32 or); +/** + * struct msm_hrtimer_work - a helper to combine an hrtimer with kthread_work + * + * @timer: hrtimer to control when the kthread work is triggered + * @work: the kthread work + * @worker: the kthread worker the work will be scheduled on + */ +struct msm_hrtimer_work { + struct hrtimer timer; + struct kthread_work work; + struct kthread_worker *worker; +}; + +void msm_hrtimer_queue_work(struct msm_hrtimer_work *work, + ktime_t wakeup_time, + enum hrtimer_mode mode); +void msm_hrtimer_work_init(struct msm_hrtimer_work *work, + struct kthread_worker *worker, + kthread_work_func_t fn, + clockid_t clock_id, + enum hrtimer_mode mode); + #define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) #define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index de2bc3467bb5..6a42b819abc4 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -136,8 +136,7 @@ struct msm_kms; * shortly before vblank to flush pending async updates. */ struct msm_pending_timer { - struct hrtimer timer; - struct kthread_work work; + struct msm_hrtimer_work work; struct kthread_worker *worker; struct msm_kms *kms; unsigned crtc_idx; From 658f4c8296888c135e394cc21f94386958c36ac7 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 27 Sep 2021 16:04:54 -0700 Subject: [PATCH 394/554] drm/msm/devfreq: Add 1ms delay before clamping freq Add a short delay before clamping to idle frequency on active->idle transition. It takes ~0.5ms to increase the freq again on the next idle->active transition, so this helps avoid extra freq transitions on workloads that bounce between CPU and GPU. Signed-off-by: Rob Clark Link: https://lore.kernel.org/r/20210927230455.1066297-2-robdclark@gmail.com Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.h | 7 +++++ drivers/gpu/drm/msm/msm_gpu_devfreq.c | 38 +++++++++++++++++++++------ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 030f82f149c2..59870095ea41 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -112,6 +112,13 @@ struct msm_gpu_devfreq { * it is inactive. */ unsigned long idle_freq; + + /** + * idle_work: + * + * Used to delay clamping to idle freq on active->idle transition. + */ + struct msm_hrtimer_work idle_work; }; struct msm_gpu { diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 84e98c07c900..d32b729b4616 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -88,8 +88,12 @@ static struct devfreq_dev_profile msm_devfreq_profile = { .get_cur_freq = msm_devfreq_get_cur_freq, }; +static void msm_devfreq_idle_work(struct kthread_work *work); + void msm_devfreq_init(struct msm_gpu *gpu) { + struct msm_gpu_devfreq *df = &gpu->devfreq; + /* We need target support to do devfreq */ if (!gpu->funcs->gpu_busy) return; @@ -105,25 +109,27 @@ void msm_devfreq_init(struct msm_gpu *gpu) msm_devfreq_profile.freq_table = NULL; msm_devfreq_profile.max_state = 0; - gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev, + df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev, &msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); - if (IS_ERR(gpu->devfreq.devfreq)) { + if (IS_ERR(df->devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); - gpu->devfreq.devfreq = NULL; + df->devfreq = NULL; return; } - devfreq_suspend_device(gpu->devfreq.devfreq); + devfreq_suspend_device(df->devfreq); - gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node, - gpu->devfreq.devfreq); + gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node, df->devfreq); if (IS_ERR(gpu->cooling)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't register GPU cooling device\n"); gpu->cooling = NULL; } + + msm_hrtimer_work_init(&df->idle_work, gpu->worker, msm_devfreq_idle_work, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); } void msm_devfreq_cleanup(struct msm_gpu *gpu) @@ -154,6 +160,11 @@ void msm_devfreq_active(struct msm_gpu *gpu) if (!df->devfreq) return; + /* + * Cancel any pending transition to idle frequency: + */ + hrtimer_cancel(&df->idle_work.timer); + /* * Hold devfreq lock to synchronize with get_dev_status()/ * target() callbacks @@ -184,9 +195,12 @@ void msm_devfreq_active(struct msm_gpu *gpu) mutex_unlock(&df->devfreq->lock); } -void msm_devfreq_idle(struct msm_gpu *gpu) + +static void msm_devfreq_idle_work(struct kthread_work *work) { - struct msm_gpu_devfreq *df = &gpu->devfreq; + struct msm_gpu_devfreq *df = container_of(work, + struct msm_gpu_devfreq, idle_work.work); + struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); unsigned long idle_freq, target_freq = 0; if (!df->devfreq) @@ -207,3 +221,11 @@ void msm_devfreq_idle(struct msm_gpu *gpu) mutex_unlock(&df->devfreq->lock); } + +void msm_devfreq_idle(struct msm_gpu *gpu) +{ + struct msm_gpu_devfreq *df = &gpu->devfreq; + + msm_hrtimer_queue_work(&df->idle_work, ms_to_ktime(1), + HRTIMER_MODE_ABS); +} From d9fbb54d6641cfb1ef3042676d0126df59ad52ce Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Oct 2021 04:27:15 +0300 Subject: [PATCH 395/554] drm/msm/dsi: use bulk clk API Use clk_bulk_* API instead of hand-coding them. Note, this drops support for legacy clk naming (e.g. "iface_clk" instead of just "iface"), however all in-kernel device trees were converted long long ago. The warning is present there since 2017. Signed-off-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211002012715.691406-1-dmitry.baryshkov@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 59 ++++++------------------------ 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 77553d75088f..734a209071d9 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -106,7 +106,8 @@ struct msm_dsi_host { phys_addr_t ctrl_size; struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; - struct clk *bus_clks[DSI_BUS_CLK_MAX]; + int num_bus_clks; + struct clk_bulk_data bus_clks[DSI_BUS_CLK_MAX]; struct clk *byte_clk; struct clk *esc_clk; @@ -374,15 +375,14 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) int i, ret = 0; /* get bus clocks */ - for (i = 0; i < cfg->num_bus_clks; i++) { - msm_host->bus_clks[i] = msm_clk_get(pdev, - cfg->bus_clk_names[i]); - if (IS_ERR(msm_host->bus_clks[i])) { - ret = PTR_ERR(msm_host->bus_clks[i]); - pr_err("%s: Unable to get %s clock, ret = %d\n", - __func__, cfg->bus_clk_names[i], ret); - goto exit; - } + for (i = 0; i < cfg->num_bus_clks; i++) + msm_host->bus_clks[i].id = cfg->bus_clk_names[i]; + msm_host->num_bus_clks = cfg->num_bus_clks; + + ret = devm_clk_bulk_get(&pdev->dev, msm_host->num_bus_clks, msm_host->bus_clks); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to get clocks, ret = %d\n", ret); + goto exit; } /* get link and source clocks */ @@ -433,41 +433,6 @@ exit: return ret; } -static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host) -{ - const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; - int i, ret; - - DBG("id=%d", msm_host->id); - - for (i = 0; i < cfg->num_bus_clks; i++) { - ret = clk_prepare_enable(msm_host->bus_clks[i]); - if (ret) { - pr_err("%s: failed to enable bus clock %d ret %d\n", - __func__, i, ret); - goto err; - } - } - - return 0; -err: - while (--i >= 0) - clk_disable_unprepare(msm_host->bus_clks[i]); - - return ret; -} - -static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host) -{ - const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; - int i; - - DBG(""); - - for (i = cfg->num_bus_clks - 1; i >= 0; i--) - clk_disable_unprepare(msm_host->bus_clks[i]); -} - int msm_dsi_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -478,7 +443,7 @@ int msm_dsi_runtime_suspend(struct device *dev) if (!msm_host->cfg_hnd) return 0; - dsi_bus_clk_disable(msm_host); + clk_bulk_disable_unprepare(msm_host->num_bus_clks, msm_host->bus_clks); return 0; } @@ -493,7 +458,7 @@ int msm_dsi_runtime_resume(struct device *dev) if (!msm_host->cfg_hnd) return 0; - return dsi_bus_clk_enable(msm_host); + return clk_bulk_prepare_enable(msm_host->num_bus_clks, msm_host->bus_clks); } int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) From 1c8e5748fa349dacee0ed9d151c1fa76089e1d54 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 2 Oct 2021 21:31:18 +0300 Subject: [PATCH 396/554] drm/msm/a6xx: correct cx_debugbus_read arguments First argument of cx_debugbus_read() should be 'void __iomem *' rather than 'void * __iomem' to make sparse happy. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211002183118.748841-1-dmitry.baryshkov@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index e8f65cd8eca6..7501849ed15d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -180,7 +180,7 @@ static int debugbus_read(struct msm_gpu *gpu, u32 block, u32 offset, msm_readl((ptr) + ((offset) << 2)) /* read a value from the CX debug bus */ -static int cx_debugbus_read(void *__iomem cxdbg, u32 block, u32 offset, +static int cx_debugbus_read(void __iomem *cxdbg, u32 block, u32 offset, u32 *data) { u32 reg = A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_INDEX(offset) | From 899b2608d8d4b675cb54a026a27e28b4e1bcbf61 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 15 Oct 2021 16:22:13 -0700 Subject: [PATCH 397/554] drm/msm/dp: Use the connector passed to dp_debug_get() The debugfs code is provided an array of a single drm_connector. Then to access the connector, the list of all connectors of the DRM device is traversed and all non-DisplayPort connectors are skipped, to find the one and only DisplayPort connector. But as we move to support multiple DisplayPort controllers this will now find multiple connectors and has no way to distinguish them. Pass the single connector to dp_debug_get() and use this in the debugfs functions instead, both to simplify the code and the support the multiple instances. Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211015232213.1839472-1-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_debug.c | 129 ++++++++++------------------ drivers/gpu/drm/msm/dp/dp_debug.h | 4 +- drivers/gpu/drm/msm/dp/dp_display.c | 2 +- 3 files changed, 46 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 2f6247e80e9d..4963d21fcdd9 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -24,7 +24,7 @@ struct dp_debug_private { struct dp_usbpd *usbpd; struct dp_link *link; struct dp_panel *panel; - struct drm_connector **connector; + struct drm_connector *connector; struct device *dev; struct drm_device *drm_dev; @@ -205,59 +205,35 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, static int dp_test_data_show(struct seq_file *m, void *data) { - struct drm_device *dev; - struct dp_debug_private *debug; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; + const struct dp_debug_private *debug = m->private; + const struct drm_connector *connector = debug->connector; u32 bpc; - debug = m->private; - dev = debug->drm_dev; - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - - if (connector->connector_type != - DRM_MODE_CONNECTOR_DisplayPort) - continue; - - if (connector->status == connector_status_connected) { - bpc = debug->link->test_video.test_bit_depth; - seq_printf(m, "hdisplay: %d\n", - debug->link->test_video.test_h_width); - seq_printf(m, "vdisplay: %d\n", - debug->link->test_video.test_v_height); - seq_printf(m, "bpc: %u\n", - dp_link_bit_depth_to_bpc(bpc)); - } else - seq_puts(m, "0"); + if (connector->status == connector_status_connected) { + bpc = debug->link->test_video.test_bit_depth; + seq_printf(m, "hdisplay: %d\n", + debug->link->test_video.test_h_width); + seq_printf(m, "vdisplay: %d\n", + debug->link->test_video.test_v_height); + seq_printf(m, "bpc: %u\n", + dp_link_bit_depth_to_bpc(bpc)); + } else { + seq_puts(m, "0"); } - drm_connector_list_iter_end(&conn_iter); - return 0; } DEFINE_SHOW_ATTRIBUTE(dp_test_data); static int dp_test_type_show(struct seq_file *m, void *data) { - struct dp_debug_private *debug = m->private; - struct drm_device *dev = debug->drm_dev; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; + const struct dp_debug_private *debug = m->private; + const struct drm_connector *connector = debug->connector; - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - - if (connector->connector_type != - DRM_MODE_CONNECTOR_DisplayPort) - continue; - - if (connector->status == connector_status_connected) - seq_printf(m, "%02x", DP_TEST_LINK_VIDEO_PATTERN); - else - seq_puts(m, "0"); - } - drm_connector_list_iter_end(&conn_iter); + if (connector->status == connector_status_connected) + seq_printf(m, "%02x", DP_TEST_LINK_VIDEO_PATTERN); + else + seq_puts(m, "0"); return 0; } @@ -269,14 +245,12 @@ static ssize_t dp_test_active_write(struct file *file, { char *input_buffer; int status = 0; - struct dp_debug_private *debug; - struct drm_device *dev; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; + const struct dp_debug_private *debug; + const struct drm_connector *connector; int val = 0; debug = ((struct seq_file *)file->private_data)->private; - dev = debug->drm_dev; + connector = debug->connector; if (len == 0) return 0; @@ -287,30 +261,22 @@ static ssize_t dp_test_active_write(struct file *file, DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len); - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->connector_type != - DRM_MODE_CONNECTOR_DisplayPort) - continue; - - if (connector->status == connector_status_connected) { - status = kstrtoint(input_buffer, 10, &val); - if (status < 0) - break; - DRM_DEBUG_DRIVER("Got %d for test active\n", val); - /* To prevent erroneous activation of the compliance - * testing code, only accept an actual value of 1 here - */ - if (val == 1) - debug->panel->video_test = true; - else - debug->panel->video_test = false; + if (connector->status == connector_status_connected) { + status = kstrtoint(input_buffer, 10, &val); + if (status < 0) { + kfree(input_buffer); + return status; } + DRM_DEBUG_DRIVER("Got %d for test active\n", val); + /* To prevent erroneous activation of the compliance + * testing code, only accept an actual value of 1 here + */ + if (val == 1) + debug->panel->video_test = true; + else + debug->panel->video_test = false; } - drm_connector_list_iter_end(&conn_iter); kfree(input_buffer); - if (status < 0) - return status; *offp += len; return len; @@ -319,25 +285,16 @@ static ssize_t dp_test_active_write(struct file *file, static int dp_test_active_show(struct seq_file *m, void *data) { struct dp_debug_private *debug = m->private; - struct drm_device *dev = debug->drm_dev; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; + struct drm_connector *connector = debug->connector; - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->connector_type != - DRM_MODE_CONNECTOR_DisplayPort) - continue; - - if (connector->status == connector_status_connected) { - if (debug->panel->video_test) - seq_puts(m, "1"); - else - seq_puts(m, "0"); - } else + if (connector->status == connector_status_connected) { + if (debug->panel->video_test) + seq_puts(m, "1"); + else seq_puts(m, "0"); + } else { + seq_puts(m, "0"); } - drm_connector_list_iter_end(&conn_iter); return 0; } @@ -391,7 +348,7 @@ static int dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor) struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_usbpd *usbpd, struct dp_link *link, - struct drm_connector **connector, struct drm_minor *minor) + struct drm_connector *connector, struct drm_minor *minor) { int rc = 0; struct dp_debug_private *debug; diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 7eaedfbb149c..8c0d0b5178fd 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -43,7 +43,7 @@ struct dp_debug { */ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_usbpd *usbpd, struct dp_link *link, - struct drm_connector **connector, + struct drm_connector *connector, struct drm_minor *minor); /** @@ -60,7 +60,7 @@ void dp_debug_put(struct dp_debug *dp_debug); static inline struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_usbpd *usbpd, struct dp_link *link, - struct drm_connector **connector, struct drm_minor *minor) + struct drm_connector *connector, struct drm_minor *minor) { return ERR_PTR(-EINVAL); } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a0392e4d8134..e2064cf446c7 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1429,7 +1429,7 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) dev = &dp->pdev->dev; dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, - dp->link, &dp->dp_display.connector, + dp->link, dp->dp_display.connector, minor); if (IS_ERR(dp->debug)) { rc = PTR_ERR(dp->debug); From eea8f024dd5320256f7bbaa573ab92eb2aa5078e Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 7 Oct 2021 12:02:11 -0700 Subject: [PATCH 398/554] drm/msm/dp: Simplify the dp_debug debugfs show function The "dp_debug" show function allocates a buffer and piecemeal appends line by line, checking for buffer overflows etc. Migrate the function to seq_file, to remove all the extra book keeping and simplify the function. Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211007190211.3158868-1-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_debug.c | 163 +++++------------------------- 1 file changed, 25 insertions(+), 138 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 4963d21fcdd9..da4323556ef3 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -31,177 +31,69 @@ struct dp_debug_private { struct dp_debug dp_debug; }; -static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len) +static int dp_debug_show(struct seq_file *seq, void *p) { - if (rc >= *max_size) { - DRM_ERROR("buffer overflow\n"); - return -EINVAL; - } - *len += rc; - *max_size = SZ_4K - *len; - - return 0; -} - -static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, - size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char *buf; - u32 len = 0, rc = 0; + struct dp_debug_private *debug = seq->private; u64 lclk = 0; - u32 max_size = SZ_4K; u32 link_params_rate; - struct drm_display_mode *drm_mode; + const struct drm_display_mode *drm_mode; if (!debug) return -ENODEV; - if (*ppos) - return 0; - - buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) - return -ENOMEM; - drm_mode = &debug->panel->dp_mode.drm_mode; - rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdp_panel\n\t\tmax_pclk_khz = %d\n", + seq_printf(seq, "\tname = %s\n", DEBUG_NAME); + seq_printf(seq, "\tdp_panel\n\t\tmax_pclk_khz = %d\n", debug->panel->max_pclk_khz); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdrm_dp_link\n\t\trate = %u\n", + seq_printf(seq, "\tdrm_dp_link\n\t\trate = %u\n", debug->panel->link_info.rate); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tnum_lanes = %u\n", + seq_printf(seq, "\t\tnum_lanes = %u\n", debug->panel->link_info.num_lanes); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tcapabilities = %lu\n", + seq_printf(seq, "\t\tcapabilities = %lu\n", debug->panel->link_info.capabilities); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdp_panel_info:\n\t\tactive = %dx%d\n", + seq_printf(seq, "\tdp_panel_info:\n\t\tactive = %dx%d\n", drm_mode->hdisplay, drm_mode->vdisplay); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tback_porch = %dx%d\n", + seq_printf(seq, "\t\tback_porch = %dx%d\n", drm_mode->htotal - drm_mode->hsync_end, drm_mode->vtotal - drm_mode->vsync_end); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tfront_porch = %dx%d\n", + seq_printf(seq, "\t\tfront_porch = %dx%d\n", drm_mode->hsync_start - drm_mode->hdisplay, drm_mode->vsync_start - drm_mode->vdisplay); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tsync_width = %dx%d\n", + seq_printf(seq, "\t\tsync_width = %dx%d\n", drm_mode->hsync_end - drm_mode->hsync_start, drm_mode->vsync_end - drm_mode->vsync_start); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tactive_low = %dx%d\n", + seq_printf(seq, "\t\tactive_low = %dx%d\n", debug->panel->dp_mode.h_active_low, debug->panel->dp_mode.v_active_low); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\th_skew = %d\n", + seq_printf(seq, "\t\th_skew = %d\n", drm_mode->hskew); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\trefresh rate = %d\n", + seq_printf(seq, "\t\trefresh rate = %d\n", drm_mode_vrefresh(drm_mode)); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tpixel clock khz = %d\n", + seq_printf(seq, "\t\tpixel clock khz = %d\n", drm_mode->clock); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tbpp = %d\n", + seq_printf(seq, "\t\tbpp = %d\n", debug->panel->dp_mode.bpp); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; /* Link Information */ - rc = snprintf(buf + len, max_size, - "\tdp_link:\n\t\ttest_requested = %d\n", + seq_printf(seq, "\tdp_link:\n\t\ttest_requested = %d\n", debug->link->sink_request); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tnum_lanes = %d\n", + seq_printf(seq, "\t\tnum_lanes = %d\n", debug->link->link_params.num_lanes); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - link_params_rate = debug->link->link_params.rate; - rc = snprintf(buf + len, max_size, - "\t\tbw_code = %d\n", + seq_printf(seq, "\t\tbw_code = %d\n", drm_dp_link_rate_to_bw_code(link_params_rate)); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - lclk = debug->link->link_params.rate * 1000; - rc = snprintf(buf + len, max_size, - "\t\tlclk = %lld\n", lclk); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tv_level = %d\n", + seq_printf(seq, "\t\tlclk = %lld\n", lclk); + seq_printf(seq, "\t\tv_level = %d\n", debug->link->phy_params.v_level); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tp_level = %d\n", + seq_printf(seq, "\t\tp_level = %d\n", debug->link->phy_params.p_level); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - if (copy_to_user(user_buff, buf, len)) - goto error; - - *ppos += len; - - kfree(buf); - return len; - error: - kfree(buf); - return -EINVAL; + return 0; } +DEFINE_SHOW_ATTRIBUTE(dp_debug); static int dp_test_data_show(struct seq_file *m, void *data) { @@ -306,11 +198,6 @@ static int dp_test_active_open(struct inode *inode, inode->i_private); } -static const struct file_operations dp_debug_fops = { - .open = simple_open, - .read = dp_debug_read_info, -}; - static const struct file_operations test_active_fops = { .owner = THIS_MODULE, .open = dp_test_active_open, From f8e7bce3a661408377366515118485a2c07f4860 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 10 Oct 2021 15:59:40 +0200 Subject: [PATCH 399/554] drm: Remove redundant 'flush_workqueue()' calls 'destroy_workqueue()' already drains the queue before destroying it, so there is no need to flush it explicitly. Remove the redundant 'flush_workqueue()' calls. This was generated with coccinelle: @@ expression E; @@ - flush_workqueue(E); destroy_workqueue(E); Signed-off-by: Christophe JAILLET Acked-by: Jyri Sarha Reviewed-by: Rob Clark Link: https://lore.kernel.org/r/75e8ba40076ad707d47e3a3670e6b23c1b8b11bc.1633874223.git.christophe.jaillet@wanadoo.fr Signed-off-by: Rob Clark --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 1 - drivers/gpu/drm/msm/dsi/dsi_host.c | 1 - drivers/gpu/drm/msm/edp/edp_ctrl.c | 1 - drivers/gpu/drm/msm/hdmi/hdmi.c | 4 +--- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 4 +--- drivers/gpu/drm/vmwgfx/ttm_memory.c | 1 - 6 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index cc5b07f86346..242a5fd8b932 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1733,7 +1733,6 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, DBG("%s", dev_name(gpu->dev)); - flush_workqueue(gpu->wq); destroy_workqueue(gpu->wq); etnaviv_sched_fini(gpu); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 734a209071d9..4b030a00fa79 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1904,7 +1904,6 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host) DBG(""); dsi_tx_buf_free(msm_host); if (msm_host->workqueue) { - flush_workqueue(msm_host->workqueue); destroy_workqueue(msm_host->workqueue); msm_host->workqueue = NULL; } diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 6ef4bee8fa86..a68a4a1867c1 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -1190,7 +1190,6 @@ void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl) return; if (ctrl->workqueue) { - flush_workqueue(ctrl->workqueue); destroy_workqueue(ctrl->workqueue); ctrl->workqueue = NULL; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 737453b6e596..5ba7c8f28419 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -61,10 +61,8 @@ static void msm_hdmi_destroy(struct hdmi *hdmi) * at this point, hpd has been disabled, * after flush workq, it's safe to deinit hdcp */ - if (hdmi->workq) { - flush_workqueue(hdmi->workq); + if (hdmi->workq) destroy_workqueue(hdmi->workq); - } msm_hdmi_hdcp_destroy(hdmi); if (hdmi->phy_dev) { diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 6b03f89a98d4..3ddb7c710a3d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -186,10 +186,8 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->mmio) iounmap(priv->mmio); - if (priv->wq) { - flush_workqueue(priv->wq); + if (priv->wq) destroy_workqueue(priv->wq); - } dev->dev_private = NULL; diff --git a/drivers/gpu/drm/vmwgfx/ttm_memory.c b/drivers/gpu/drm/vmwgfx/ttm_memory.c index edd17c30d5a5..7f7fe35fc21d 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_memory.c +++ b/drivers/gpu/drm/vmwgfx/ttm_memory.c @@ -468,7 +468,6 @@ void ttm_mem_global_release(struct ttm_mem_global *glob) struct ttm_mem_zone *zone; unsigned int i; - flush_workqueue(glob->swap_queue); destroy_workqueue(glob->swap_queue); glob->swap_queue = NULL; for (i = 0; i < glob->num_zones; ++i) { From 7425e8167507fe512d8ac0825acda4aebf0a7ca0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 11 Oct 2021 15:40:05 +0300 Subject: [PATCH 400/554] drm/msm: unlock on error in get_sched_entity() Add a missing unlock on the error path if drm_sched_entity_init() fails. Fixes: 68002469e571 ("drm/msm: One sched entity per process per priority") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211011124005.GE15188@kili Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_submitqueue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c index b8621c6e0554..7cb158bcbcf6 100644 --- a/drivers/gpu/drm/msm/msm_submitqueue.c +++ b/drivers/gpu/drm/msm/msm_submitqueue.c @@ -101,6 +101,7 @@ get_sched_entity(struct msm_file_private *ctx, struct msm_ringbuffer *ring, ret = drm_sched_entity_init(entity, sched_prio, &sched, 1, NULL); if (ret) { + mutex_unlock(&entity_lock); kfree(entity); return ERR_PTR(ret); } From 027d052a36e56789a2134772bacb4fd0860f03a3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Oct 2021 11:11:33 +0300 Subject: [PATCH 401/554] drm/msm: fix potential NULL dereference in cleanup The "msm_obj->node" list needs to be initialized earlier so that the list_del() in msm_gem_free_object() doesn't experience a NULL pointer dereference. Fixes: 6ed0897cd800 ("drm/msm: Fix debugfs deadlock") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211013081133.GF6010@kili Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 22308a1b66fc..fd398a4eaf46 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1132,6 +1132,7 @@ static int msm_gem_new_impl(struct drm_device *dev, msm_obj->flags = flags; msm_obj->madv = MSM_MADV_WILLNEED; + INIT_LIST_HEAD(&msm_obj->node); INIT_LIST_HEAD(&msm_obj->vmas); *obj = &msm_obj->base; From 2203bd0e5c12ffc53ffdd4fbd7b12d6ba27e0424 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Oct 2021 11:13:15 +0300 Subject: [PATCH 402/554] drm/msm: uninitialized variable in msm_gem_import() The msm_gem_new_impl() function cleans up after itself so there is no need to call drm_gem_object_put(). Conceptually, it does not make sense to call a kref_put() function until after the reference counting has been initialized which happens immediately after this call in the drm_gem_(private_)object_init() functions. In the msm_gem_import() function the "obj" pointer is uninitialized, so it will lead to a crash. Fixes: 05b849111c07 ("drm/msm: prime support") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211013081315.GG6010@kili Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index fd398a4eaf46..bd6ec04f345e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1167,7 +1167,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32 ret = msm_gem_new_impl(dev, size, flags, &obj); if (ret) - goto fail; + return ERR_PTR(ret); msm_obj = to_msm_bo(obj); @@ -1251,7 +1251,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); if (ret) - goto fail; + return ERR_PTR(ret); drm_gem_private_object_init(dev, obj, size); From ef7ec41f17cbc0861891ccc0634d06a0c8dcbf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Oct 2021 12:09:38 +0300 Subject: [PATCH 403/554] drm/i915: Replace the unconditional clflush with drm_clflush_virt_range() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all machines have clflush, so don't go assuming they do. Not really sure why the clflush is even here since hwsp is supposed to get snooped I thought. Although in my case we're talking about a i830 machine where render/blitter snooping is definitely busted. But it might work for the hswp perhaps. Haven't really reverse engineered that one fully. Cc: stable@vger.kernel.org Cc: Chris Wilson Cc: Mika Kuoppala Fixes: b436a5f8b6c8 ("drm/i915/gt: Track all timelines created using the HWSP") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-2-ville.syrjala@linux.intel.com Reviewed-by: Dave Airlie --- drivers/gpu/drm/i915/gt/intel_ring_submission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index 593524195707..586dca1731ce 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -292,7 +292,7 @@ static void xcs_sanitize(struct intel_engine_cs *engine) sanitize_hwsp(engine); /* And scrub the dirty cachelines for the HWSP */ - clflush_cache_range(engine->status_page.addr, PAGE_SIZE); + drm_clflush_virt_range(engine->status_page.addr, PAGE_SIZE); intel_engine_reset_pinned_contexts(engine); } From af7b6d234eefa30c461cc16912bafb32b9e6141c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Oct 2021 12:09:39 +0300 Subject: [PATCH 404/554] drm/i915: Convert unconditional clflush to drm_clflush_virt_range() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This one is apparently a "clflush for good measure", so bit more justification (if you can call it that) than some of the others. Convert to drm_clflush_virt_range() again so that machines without clflush will survive the ordeal. Cc: stable@vger.kernel.org Cc: Maarten Lankhorst Cc: Thomas Hellström #v1 Fixes: 12ca695d2c1e ("drm/i915: Do not share hwsp across contexts any more, v8.") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-3-ville.syrjala@linux.intel.com Reviewed-by: Dave Airlie --- drivers/gpu/drm/i915/gt/intel_timeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.c b/drivers/gpu/drm/i915/gt/intel_timeline.c index 1257f4f11e66..23d7328892ed 100644 --- a/drivers/gpu/drm/i915/gt/intel_timeline.c +++ b/drivers/gpu/drm/i915/gt/intel_timeline.c @@ -225,7 +225,7 @@ void intel_timeline_reset_seqno(const struct intel_timeline *tl) memset(hwsp_seqno + 1, 0, TIMELINE_SEQNO_BYTES - sizeof(*hwsp_seqno)); WRITE_ONCE(*hwsp_seqno, tl->seqno); - clflush(hwsp_seqno); + drm_clflush_virt_range(hwsp_seqno, TIMELINE_SEQNO_BYTES); } void intel_timeline_enter(struct intel_timeline *tl) From 9ced12182d0d8401d821e9602e56e276459900fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Oct 2021 12:09:40 +0300 Subject: [PATCH 405/554] drm/i915: Catch yet another unconditioal clflush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the unconditional clflush() with drm_clflush_virt_range() which does the wbinvd() fallback when clflush is not available. This time no justification is given for the clflush in the offending commit. Cc: stable@vger.kernel.org Cc: Maarten Lankhorst Cc: Thomas Hellström Fixes: 2c8ab3339e39 ("drm/i915: Pin timeline map after first timeline pin, v4.") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-4-ville.syrjala@linux.intel.com Reviewed-by: Dave Airlie --- drivers/gpu/drm/i915/gt/intel_timeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.c b/drivers/gpu/drm/i915/gt/intel_timeline.c index 23d7328892ed..438bbc7b8147 100644 --- a/drivers/gpu/drm/i915/gt/intel_timeline.c +++ b/drivers/gpu/drm/i915/gt/intel_timeline.c @@ -64,7 +64,7 @@ intel_timeline_pin_map(struct intel_timeline *timeline) timeline->hwsp_map = vaddr; timeline->hwsp_seqno = memset(vaddr + ofs, 0, TIMELINE_SEQNO_BYTES); - clflush(vaddr + ofs); + drm_clflush_virt_range(vaddr + ofs, TIMELINE_SEQNO_BYTES); return 0; } From d624e50aa3c16283e2ee9f6644d9155697347ab5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:37 -0700 Subject: [PATCH 406/554] drm/msm/dp: Remove global g_dp_display variable As the Qualcomm DisplayPort driver only supports a single instance of the driver the commonly used struct dp_display is kept in a global variable. As we introduce additional instances this obviously doesn't work. Replace this with a combination of existing references to adjacent objects and drvdata. Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211016221843.2167329-2-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_display.c | 79 ++++++++--------------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index e2064cf446c7..f8926f63c6bf 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -27,7 +27,6 @@ #include "dp_audio.h" #include "dp_debug.h" -static struct msm_dp *g_dp_display; #define HPD_STRING_SIZE 30 enum { @@ -121,6 +120,13 @@ static const struct of_device_id dp_dt_match[] = { {} }; +static struct dp_display_private *dev_get_dp_display_private(struct device *dev) +{ + struct msm_dp *dp = dev_get_drvdata(dev); + + return container_of(dp, struct dp_display_private, dp_display); +} + static int dp_add_event(struct dp_display_private *dp_priv, u32 event, u32 data, u32 delay) { @@ -197,15 +203,12 @@ static int dp_display_bind(struct device *dev, struct device *master, void *data) { int rc = 0; - struct dp_display_private *dp; - struct drm_device *drm; + struct dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv; + struct drm_device *drm; drm = dev_get_drvdata(master); - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); - dp->dp_display.drm_dev = drm; priv = drm->dev_private; priv->dp = &(dp->dp_display); @@ -240,13 +243,10 @@ end: static void dp_display_unbind(struct device *dev, struct device *master, void *data) { - struct dp_display_private *dp; + struct dp_display_private *dp = dev_get_dp_display_private(dev); struct drm_device *drm = dev_get_drvdata(master); struct msm_drm_private *priv = drm->dev_private; - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); - dp_power_client_deinit(dp->power); dp_aux_unregister(dp->aux); priv->dp = NULL; @@ -379,38 +379,17 @@ static void dp_display_host_deinit(struct dp_display_private *dp) static int dp_display_usbpd_configure_cb(struct device *dev) { - int rc = 0; - struct dp_display_private *dp; - - if (!dev) { - DRM_ERROR("invalid dev\n"); - rc = -EINVAL; - goto end; - } - - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); + struct dp_display_private *dp = dev_get_dp_display_private(dev); dp_display_host_init(dp, false); - rc = dp_display_process_hpd_high(dp); -end: - return rc; + return dp_display_process_hpd_high(dp); } static int dp_display_usbpd_disconnect_cb(struct device *dev) { int rc = 0; - struct dp_display_private *dp; - - if (!dev) { - DRM_ERROR("invalid dev\n"); - rc = -EINVAL; - return rc; - } - - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); + struct dp_display_private *dp = dev_get_dp_display_private(dev); dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); @@ -472,15 +451,7 @@ static int dp_display_usbpd_attention_cb(struct device *dev) { int rc = 0; u32 sink_request; - struct dp_display_private *dp; - - if (!dev) { - DRM_ERROR("invalid dev\n"); - return -EINVAL; - } - - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); + struct dp_display_private *dp = dev_get_dp_display_private(dev); /* check for any test request issued by sink */ rc = dp_link_process_request(dp->link); @@ -647,7 +618,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) DRM_DEBUG_DP("hpd_state=%d\n", state); /* signal the disconnect event early to ensure proper teardown */ - dp_display_handle_plugged_change(g_dp_display, false); + dp_display_handle_plugged_change(&dp->dp_display, false); /* enable HDP plug interrupt to prepare for next plugin */ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true); @@ -842,9 +813,7 @@ static int dp_display_prepare(struct msm_dp *dp) static int dp_display_enable(struct dp_display_private *dp, u32 data) { int rc = 0; - struct msm_dp *dp_display; - - dp_display = g_dp_display; + struct msm_dp *dp_display = &dp->dp_display; DRM_DEBUG_DP("sink_count=%d\n", dp->link->sink_count); if (dp_display->power_on) { @@ -880,9 +849,7 @@ static int dp_display_post_enable(struct msm_dp *dp_display) static int dp_display_disable(struct dp_display_private *dp, u32 data) { - struct msm_dp *dp_display; - - dp_display = g_dp_display; + struct msm_dp *dp_display = &dp->dp_display; if (!dp_display->power_on) return 0; @@ -1237,14 +1204,13 @@ static int dp_display_probe(struct platform_device *pdev) } mutex_init(&dp->event_mutex); - g_dp_display = &dp->dp_display; /* Store DP audio handle inside DP display */ - g_dp_display->dp_audio = dp->audio; + dp->dp_display.dp_audio = dp->audio; init_completion(&dp->audio_comp); - platform_set_drvdata(pdev, g_dp_display); + platform_set_drvdata(pdev, &dp->dp_display); rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { @@ -1257,10 +1223,7 @@ static int dp_display_probe(struct platform_device *pdev) static int dp_display_remove(struct platform_device *pdev) { - struct dp_display_private *dp; - - dp = container_of(g_dp_display, - struct dp_display_private, dp_display); + struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); dp_display_deinit_sub_modules(dp); @@ -1315,7 +1278,7 @@ static int dp_pm_resume(struct device *dev) dp->dp_display.is_connected = true; } else { dp->dp_display.is_connected = false; - dp_display_handle_plugged_change(g_dp_display, false); + dp_display_handle_plugged_change(dp_display, false); } DRM_DEBUG_DP("After, sink_count=%d is_connected=%d core_inited=%d power_on=%d\n", From 167dac97eb46c7b8a15b2195080e191bb0c9ce35 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:38 -0700 Subject: [PATCH 407/554] drm/msm/dp: Modify prototype of encoder based API Functions in the DisplayPort code that relates to individual instances (encoders) are passed both the struct msm_dp and the struct drm_encoder. But in a situation where multiple DP instances would exist this means that the caller need to resolve which struct msm_dp relates to the struct drm_encoder at hand. Store a reference to the struct msm_dp associated with each dpu_encoder_virt to allow the particular instance to be associate with the encoder in the following patch. Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211016221843.2167329-3-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index f564cef948f0..05db937b92fb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -168,6 +168,7 @@ enum dpu_enc_rc_states { * @vsync_event_work: worker to handle vsync event for autorefresh * @topology: topology of the display * @idle_timeout: idle timeout duration in milliseconds + * @dp: msm_dp pointer, for DP encoders */ struct dpu_encoder_virt { struct drm_encoder base; @@ -206,6 +207,8 @@ struct dpu_encoder_virt { struct msm_display_topology topology; u32 idle_timeout; + + struct msm_dp *dp; }; #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base) @@ -992,8 +995,8 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, trace_dpu_enc_mode_set(DRMID(drm_enc)); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) - msm_dp_display_mode_set(priv->dp, drm_enc, mode, adj_mode); + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) + msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode); list_for_each_entry(conn_iter, connector_list, head) if (conn_iter->encoder == drm_enc) @@ -1174,9 +1177,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) _dpu_encoder_virt_enable_helper(drm_enc); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { - ret = msm_dp_display_enable(priv->dp, - drm_enc); + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { + ret = msm_dp_display_enable(dpu_enc->dp, drm_enc); if (ret) { DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", ret); @@ -1216,8 +1218,8 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) /* wait for idle */ dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { - if (msm_dp_display_pre_disable(priv->dp, drm_enc)) + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { + if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc)) DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); } @@ -1245,8 +1247,8 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { - if (msm_dp_display_disable(priv->dp, drm_enc)) + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { + if (msm_dp_display_disable(dpu_enc->dp, drm_enc)) DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); } @@ -2162,7 +2164,8 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, timer_setup(&dpu_enc->vsync_event_timer, dpu_encoder_vsync_event_handler, 0); - + else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS) + dpu_enc->dp = priv->dp; INIT_DELAYED_WORK(&dpu_enc->delayed_off_work, dpu_encoder_off_work); From 269e92d84cd223b3bc32b752a0bcf639c2cb3bd9 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:39 -0700 Subject: [PATCH 408/554] drm/msm/dp: Allow specifying connector_type per controller As the following patches introduced support for multiple DP blocks in a platform and some of those block might be eDP it becomes useful to be able to specify the connector type per block. Although there's only a single block at this point, the array of descs and the search in dp_display_get_desc() are introduced here to simplify the next patch, that does introduce support for multiple DP blocks. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211016221843.2167329-4-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_display.c | 43 ++++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_drm.c | 2 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index f8926f63c6bf..c2ec59184390 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -115,8 +115,25 @@ struct dp_display_private { struct dp_audio *audio; }; +struct msm_dp_desc { + phys_addr_t io_start; + unsigned int connector_type; +}; + +struct msm_dp_config { + const struct msm_dp_desc *descs; + size_t num_descs; +}; + +static const struct msm_dp_config sc7180_dp_cfg = { + .descs = (const struct msm_dp_desc[]) { + { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + }, + .num_descs = 1, +}; + static const struct of_device_id dp_dt_match[] = { - {.compatible = "qcom,sc7180-dp"}, + { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg }, {} }; @@ -1180,10 +1197,29 @@ int dp_display_request_irq(struct msm_dp *dp_display) return 0; } +static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev) +{ + const struct msm_dp_config *cfg = of_device_get_match_data(&pdev->dev); + struct resource *res; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return NULL; + + for (i = 0; i < cfg->num_descs; i++) + if (cfg->descs[i].io_start == res->start) + return &cfg->descs[i]; + + dev_err(&pdev->dev, "unknown displayport instance\n"); + return NULL; +} + static int dp_display_probe(struct platform_device *pdev) { int rc = 0; struct dp_display_private *dp; + const struct msm_dp_desc *desc; if (!pdev || !pdev->dev.of_node) { DRM_ERROR("pdev not found\n"); @@ -1194,8 +1230,13 @@ static int dp_display_probe(struct platform_device *pdev) if (!dp) return -ENOMEM; + desc = dp_display_get_desc(pdev); + if (!desc) + return -EINVAL; + dp->pdev = pdev; dp->name = "drm_dp"; + dp->dp_display.connector_type = desc->connector_type; rc = dp_init_sub_modules(dp); if (rc) { diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 8b47cdabb67e..75fcabcfbbdd 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -18,6 +18,7 @@ struct msm_dp { bool is_connected; bool audio_enabled; bool power_on; + unsigned int connector_type; hdmi_codec_plugged_cb plugged_cb; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 764f4b81017e..f33e31523f56 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -147,7 +147,7 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display) ret = drm_connector_init(dp_display->drm_dev, connector, &dp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); + dp_display->connector_type); if (ret) return ERR_PTR(ret); From 4b296d15b355a866504e60af85ebb72b47873206 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:40 -0700 Subject: [PATCH 409/554] drm/msm/dp: Allow attaching a drm_panel eDP panels might need some power sequencing and backlight management, so make it possible to associate a drm_panel with an eDP instance and prepare and enable the panel accordingly. Now that we know which hardware instance is DP and which is eDP, parser->parse() is passed the connector_type and the parser is limited to only search for a panel in the eDP case. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211016221843.2167329-5-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_display.c | 9 ++++++--- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_drm.c | 11 +++++++++++ drivers/gpu/drm/msm/dp/dp_parser.c | 30 ++++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_parser.h | 3 ++- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index c2ec59184390..2e6367f03c9f 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "msm_drv.h" #include "msm_kms.h" @@ -230,12 +231,14 @@ static int dp_display_bind(struct device *dev, struct device *master, priv = drm->dev_private; priv->dp = &(dp->dp_display); - rc = dp->parser->parse(dp->parser); + rc = dp->parser->parse(dp->parser, dp->dp_display.connector_type); if (rc) { DRM_ERROR("device tree parsing failed\n"); goto end; } + dp->dp_display.panel_bridge = dp->parser->panel_bridge; + dp->aux->drm_dev = drm; rc = dp_aux_register(dp->aux); if (rc) { @@ -822,7 +825,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display, return 0; } -static int dp_display_prepare(struct msm_dp *dp) +static int dp_display_prepare(struct msm_dp *dp_display) { return 0; } @@ -896,7 +899,7 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data) return 0; } -static int dp_display_unprepare(struct msm_dp *dp) +static int dp_display_unprepare(struct msm_dp *dp_display) { return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 75fcabcfbbdd..8e80e3bac394 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -15,6 +15,7 @@ struct msm_dp { struct device *codec_dev; struct drm_connector *connector; struct drm_encoder *encoder; + struct drm_bridge *panel_bridge; bool is_connected; bool audio_enabled; bool power_on; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index f33e31523f56..76856c4ee1d6 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "msm_drv.h" @@ -160,5 +161,15 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display) drm_connector_attach_encoder(connector, dp_display->encoder); + if (dp_display->panel_bridge) { + ret = drm_bridge_attach(dp_display->encoder, + dp_display->panel_bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + DRM_ERROR("failed to attach panel bridge: %d\n", ret); + return ERR_PTR(ret); + } + } + return connector; } diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index a431b4e7f385..81dbcc86d08a 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "dp_parser.h" @@ -263,7 +264,28 @@ static int dp_parser_clock(struct dp_parser *parser) return 0; } -static int dp_parser_parse(struct dp_parser *parser) +static int dp_parser_find_panel(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + struct drm_panel *panel; + int rc; + + rc = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); + if (rc) { + DRM_ERROR("failed to acquire DRM panel: %d\n", rc); + return rc; + } + + parser->panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(parser->panel_bridge)) { + DRM_ERROR("failed to create panel bridge\n"); + return PTR_ERR(parser->panel_bridge); + } + + return 0; +} + +static int dp_parser_parse(struct dp_parser *parser, int connector_type) { int rc = 0; @@ -284,6 +306,12 @@ static int dp_parser_parse(struct dp_parser *parser) if (rc) return rc; + if (connector_type == DRM_MODE_CONNECTOR_eDP) { + rc = dp_parser_find_panel(parser); + if (rc) + return rc; + } + /* Map the corresponding regulator information according to * version. Currently, since we only have one supported platform, * mapping the regulator directly. diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index dac10923abde..3172da089421 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -123,8 +123,9 @@ struct dp_parser { struct dp_display_data disp_data; const struct dp_regulator_cfg *regulator_cfg; u32 max_dp_lanes; + struct drm_bridge *panel_bridge; - int (*parse)(struct dp_parser *parser); + int (*parse)(struct dp_parser *parser, int connector_type); }; /** From bb3de286d9921c168f5dfd4097aca691662a3def Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:41 -0700 Subject: [PATCH 410/554] drm/msm/dp: Support up to 3 DP controllers Based on the removal of the g_dp_display and the movement of the priv->dp lookup into the DP code it's now possible to have multiple DP instances. In line with the other controllers in the MSM driver, introduce a per-compatible list of base addresses which is used to resolve the "instance id" for the given DP controller. This instance id is used as index in the priv->dp[] array. Then extend the initialization code to initialize struct drm_encoder for each of the registered priv->dp[] and update the logic for associating each struct msm_dp with the struct dpu_encoder_virt. A new enum is introduced to document the connection between the instances referenced in the dpu_intf_cfg array and the controllers in the DP driver and sc7180 is updated. Lastly, bump the number of struct msm_dp instances carries by priv->dp to 3, the currently known maximum number of controllers found in a Qualcomm SoC. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211016221843.2167329-6-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 68 +++++++++++-------- .../gpu/drm/msm/disp/msm_disp_snapshot_util.c | 8 ++- drivers/gpu/drm/msm/dp/dp_display.c | 20 ++++-- drivers/gpu/drm/msm/msm_drv.h | 9 ++- 6 files changed, 69 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 05db937b92fb..e7ee4cfb8461 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2165,7 +2165,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, dpu_encoder_vsync_event_handler, 0); else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS) - dpu_enc->dp = priv->dp; + dpu_enc->dp = priv->dp[disp_info->h_tile_instance[0]]; INIT_DELAYED_WORK(&dpu_enc->delayed_off_work, dpu_encoder_off_work); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index e0bf12df3611..ce6f32a919e5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -844,7 +844,7 @@ static const struct dpu_intf_cfg sdm845_intf[] = { }; static const struct dpu_intf_cfg sc7180_intf[] = { - INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 24, 25), INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 26, 27), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index ad247c06e198..a15b26428280 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -188,6 +188,7 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) struct dentry *entry; struct drm_device *dev; struct msm_drm_private *priv; + int i; if (!p) return -EINVAL; @@ -203,8 +204,10 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) dpu_debugfs_vbif_init(dpu_kms, entry); dpu_debugfs_core_irq_init(dpu_kms, entry); - if (priv->dp) - msm_dp_debugfs_init(priv->dp, minor); + for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { + if (priv->dp[i]) + msm_dp_debugfs_init(priv->dp[i], minor); + } return dpu_core_perf_debugfs_init(dpu_kms, entry); } @@ -544,35 +547,42 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, { struct drm_encoder *encoder = NULL; struct msm_display_info info; - int rc = 0; + int rc; + int i; - if (!priv->dp) - return rc; + for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { + if (!priv->dp[i]) + continue; - encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS); - if (IS_ERR(encoder)) { - DPU_ERROR("encoder init failed for dsi display\n"); - return PTR_ERR(encoder); + encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS); + if (IS_ERR(encoder)) { + DPU_ERROR("encoder init failed for dsi display\n"); + return PTR_ERR(encoder); + } + + memset(&info, 0, sizeof(info)); + rc = msm_dp_modeset_init(priv->dp[i], dev, encoder); + if (rc) { + DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); + drm_encoder_cleanup(encoder); + return rc; + } + + priv->encoders[priv->num_encoders++] = encoder; + + info.num_of_h_tiles = 1; + info.h_tile_instance[0] = i; + info.capabilities = MSM_DISPLAY_CAP_VID_MODE; + info.intf_type = encoder->encoder_type; + rc = dpu_encoder_setup(dev, encoder, &info); + if (rc) { + DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n", + encoder->base.id, rc); + return rc; + } } - memset(&info, 0, sizeof(info)); - rc = msm_dp_modeset_init(priv->dp, dev, encoder); - if (rc) { - DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); - drm_encoder_cleanup(encoder); - return rc; - } - - priv->encoders[priv->num_encoders++] = encoder; - - info.num_of_h_tiles = 1; - info.capabilities = MSM_DISPLAY_CAP_VID_MODE; - info.intf_type = encoder->encoder_type; - rc = dpu_encoder_setup(dev, encoder, &info); - if (rc) - DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n", - encoder->base.id, rc); - return rc; + return 0; } /** @@ -792,6 +802,7 @@ static int dpu_irq_postinstall(struct msm_kms *kms) { struct msm_drm_private *priv; struct dpu_kms *dpu_kms = to_dpu_kms(kms); + int i; if (!dpu_kms || !dpu_kms->dev) return -EINVAL; @@ -800,7 +811,8 @@ static int dpu_irq_postinstall(struct msm_kms *kms) if (!priv) return -EINVAL; - msm_dp_irq_postinstall(priv->dp); + for (i = 0; i < ARRAY_SIZE(priv->dp); i++) + msm_dp_irq_postinstall(priv->dp[i]); return 0; } diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index cabe15190ec1..2e1acb1bc390 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -126,8 +126,12 @@ void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state) priv = drm_dev->dev_private; kms = priv->kms; - if (priv->dp) - msm_dp_snapshot(disp_state, priv->dp); + for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { + if (!priv->dp[i]) + continue; + + msm_dp_snapshot(disp_state, priv->dp[i]); + } for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { if (!priv->dsi[i]) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 2e6367f03c9f..aba8aa47ed76 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -79,6 +79,8 @@ struct dp_display_private { char *name; int irq; + unsigned int id; + /* state variables */ bool core_initialized; bool hpd_irq_on; @@ -128,7 +130,7 @@ struct msm_dp_config { static const struct msm_dp_config sc7180_dp_cfg = { .descs = (const struct msm_dp_desc[]) { - { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, }, .num_descs = 1, }; @@ -229,7 +231,7 @@ static int dp_display_bind(struct device *dev, struct device *master, dp->dp_display.drm_dev = drm; priv = drm->dev_private; - priv->dp = &(dp->dp_display); + priv->dp[dp->id] = &dp->dp_display; rc = dp->parser->parse(dp->parser, dp->dp_display.connector_type); if (rc) { @@ -269,7 +271,7 @@ static void dp_display_unbind(struct device *dev, struct device *master, dp_power_client_deinit(dp->power); dp_aux_unregister(dp->aux); - priv->dp = NULL; + priv->dp[dp->id] = NULL; } static const struct component_ops dp_display_comp_ops = { @@ -1200,7 +1202,8 @@ int dp_display_request_irq(struct msm_dp *dp_display) return 0; } -static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev) +static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev, + unsigned int *id) { const struct msm_dp_config *cfg = of_device_get_match_data(&pdev->dev); struct resource *res; @@ -1210,9 +1213,12 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde if (!res) return NULL; - for (i = 0; i < cfg->num_descs; i++) - if (cfg->descs[i].io_start == res->start) + for (i = 0; i < cfg->num_descs; i++) { + if (cfg->descs[i].io_start == res->start) { + *id = i; return &cfg->descs[i]; + } + } dev_err(&pdev->dev, "unknown displayport instance\n"); return NULL; @@ -1233,7 +1239,7 @@ static int dp_display_probe(struct platform_device *pdev) if (!dp) return -ENOMEM; - desc = dp_display_get_desc(pdev); + desc = dp_display_get_desc(pdev, &dp->id); if (!desc) return -EINVAL; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 205cc937dafa..69952b239384 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -60,6 +60,13 @@ enum msm_mdp_plane_property { PLANE_PROP_MAX_NUM }; +enum msm_dp_controller { + MSM_DP_CONTROLLER_0, + MSM_DP_CONTROLLER_1, + MSM_DP_CONTROLLER_2, + MSM_DP_CONTROLLER_COUNT, +}; + #define MSM_GPU_MAX_RINGS 4 #define MAX_H_TILES_PER_DISPLAY 2 @@ -153,7 +160,7 @@ struct msm_drm_private { /* DSI is shared by mdp4 and mdp5 */ struct msm_dsi *dsi[2]; - struct msm_dp *dp; + struct msm_dp *dp[MSM_DP_CONTROLLER_COUNT]; /* when we have more than one 'msm_gpu' these need to be an array: */ struct msm_gpu *gpu; From e60af4f8550f4400263e6a28e01f285ddf71b8c3 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 16 Oct 2021 15:18:42 -0700 Subject: [PATCH 411/554] dt-bindings: msm/dp: Add SC8180x compatibles The Qualcomm SC8180x has 2 DP controllers and 1 eDP controller, add compatibles for these to the msm/dp binding. Reviewed-by: Abhinav Kumar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211016221843.2167329-7-bjorn.andersson@linaro.org Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/dp-controller.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index f915dc080cbc..b36d74c1da7c 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -17,6 +17,8 @@ properties: compatible: enum: - qcom,sc7180-dp + - qcom,sc8180x-dp + - qcom,sc8180x-edp reg: items: From 5aeeac6fa38fca450faed9770f75b1470c0e2073 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Mon, 11 Oct 2021 13:57:25 +0800 Subject: [PATCH 412/554] drm/amdkfd: Fix an inappropriate error handling in allloc memory of gpu We should unreference a gem object instead of an amdgpu bo here. Fixes: fd9a9f8801de ("drm/amdgpu: Use GEM obj reference for KFD BOs") Signed-off-by: Lang Yu Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 054c1a224def..cdf46bd0d8d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1503,7 +1503,7 @@ allocate_init_user_pages_failed: remove_kgd_mem_from_kfd_bo_list(*mem, avm->process_info); drm_vma_node_revoke(&gobj->vma_node, drm_priv); err_node_allow: - amdgpu_bo_unref(&bo); + drm_gem_object_put(gobj); /* Don't unreserve system mem limit twice */ goto err_reserve_limit; err_bo_create: From c72942c167c1329f0aaa348e764f52e0aac09459 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Fri, 15 Oct 2021 14:29:38 +0800 Subject: [PATCH 413/554] drm/amdgpu: load PSP RL in resume path Some registers' access will fail without PSP RL after resume. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 2bfe0682e0e6..88274c254c76 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -2623,6 +2623,12 @@ static int psp_resume(void *handle) goto failed; } + ret = psp_rl_load(adev); + if (ret) { + dev_err(adev->dev, "PSP load RL failed!\n"); + goto failed; + } + if (adev->gmc.xgmi.num_physical_nodes > 1) { ret = psp_xgmi_initialize(psp, false, true); /* Warning the XGMI seesion initialize failure From d5edb56fbc59f06324c2d625ab3e7ea0cc4e8b6e Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 14 Oct 2021 12:34:27 -0400 Subject: [PATCH 414/554] drm/amdkfd: map gpu hive id to xgmi connected cpu ROCr needs to be able to identify all devices that have direct access to fine grain memory, which should include CPUs that are connected to GPUs over xGMI. The GPU hive ID can be mapped onto the CPU hive ID since the CPU is part of the hive. Signed-off-by: Jonathan Kim Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 98cca5f2b27f..dd593ad0614a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1296,6 +1296,24 @@ int kfd_topology_add_device(struct kfd_dev *gpu) proximity_domain = atomic_inc_return(&topology_crat_proximity_domain); + adev = (struct amdgpu_device *)(gpu->kgd); + + /* Include the CPU in xGMI hive if xGMI connected by assigning it the hive ID. */ + if (gpu->hive_id && adev->gmc.xgmi.connected_to_cpu) { + struct kfd_topology_device *top_dev; + + down_read(&topology_lock); + + list_for_each_entry(top_dev, &topology_device_list, list) { + if (top_dev->gpu) + break; + + top_dev->node_props.hive_id = gpu->hive_id; + } + + up_read(&topology_lock); + } + /* Check to see if this gpu device exists in the topology_device_list. * If so, assign the gpu to that device, * else create a Virtual CRAT for this gpu device and then parse that @@ -1457,7 +1475,6 @@ int kfd_topology_add_device(struct kfd_dev *gpu) dev->node_props.max_waves_per_simd = 10; } - adev = (struct amdgpu_device *)(dev->gpu->kgd); /* kfd only concerns sram ecc on GFX and HBM ecc on UMC */ dev->node_props.capability |= ((adev->ras_enabled & BIT(AMDGPU_RAS_BLOCK__GFX)) != 0) ? From a3848df60b0606da8a12f34d34eef5183b07fc38 Mon Sep 17 00:00:00 2001 From: YuBiao Wang Date: Tue, 19 Oct 2021 17:16:23 -0400 Subject: [PATCH 415/554] drm/amd/amdgpu: Do irq_fini_hw after ip_fini_early [Why] drm_irq_uninstall is called in irq_fini_hw so that irq is disabled in sw stage. SMU (and maybe other IP blocks) fini_hw will call irq_put for cleanup and the whole cleanup process will be skipped because of drm->irq_enable = false. [How] Move ip_fini_early before irq_fini_hw. Signed-off-by: YuBiao Wang Reviewed-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 7798276c8c49..69e0eccc00fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3835,10 +3835,10 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_fbdev_fini(adev); - amdgpu_irq_fini_hw(adev); - amdgpu_device_ip_fini_early(adev); + amdgpu_irq_fini_hw(adev); + ttm_device_clear_dma_mappings(&adev->mman.bdev); amdgpu_gart_dummy_page_fini(adev); From 652de07addd2c40684fbf3a91c5b335709a585ca Mon Sep 17 00:00:00 2001 From: Roman Li Date: Fri, 15 Oct 2021 13:16:31 -0400 Subject: [PATCH 416/554] drm/amd/display: Fully switch to dmub for all dcn21 asics [Why] On renoir usb-c port stops functioning on resume after f/w update. New dmub firmware caused regression due to conflict with dmcu. With new dmub f/w dmcu is superseded and should be disabled. [How] - Disable dmcu for all dcn21. Check dmesg for dmub f/w version. The old firmware (before regression): [drm] DMUB hardware initialized: version=0x00000001 All other versions require this patch for renoir. Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1735 Acked-by: Alex Deucher Reviewed-by: Harry Wentland Tested-by: Mario Limonciello Signed-off-by: Roman Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 20065a145851..a0fd497515d0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1356,8 +1356,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) switch (adev->ip_versions[DCE_HWIP][0]) { case IP_VERSION(2, 1, 0): init_data.flags.gpu_vm_support = true; - if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) - init_data.flags.disable_dmcu = true; + init_data.flags.disable_dmcu = true; break; case IP_VERSION(1, 0, 0): case IP_VERSION(1, 0, 1): From 7a28bee067d524c1b8770aa72a82263eb9fc53f0 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Wed, 22 Sep 2021 14:22:59 -0400 Subject: [PATCH 417/554] drm/amd/display: Disable dpp root clock when not being used [Why & How] Disable root clock for dpp when not being used. Reviewed-by: Eric Yang Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 5 ++- .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 41 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index d7bf9283dc90..3fae1f1f028d 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -219,14 +219,17 @@ static void dcn31_update_clocks(struct clk_mgr *clk_mgr_base, update_dispclk = true; } - /* TODO: add back DTO programming when DPPCLK restore is fixed in FSDL*/ if (dpp_clock_lowered) { // increase per DPP DTO before lowering global dppclk + dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); dcn31_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); } else { // increase global DPPCLK before lowering per DPP DTO if (update_dppclk || update_dispclk) dcn31_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); + // always update dtos unless clock is lowered and not safe to lower + if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz) + dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); } // notify DMCUB of latest clocks diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 9896adf67425..582c500ecb49 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -42,6 +42,45 @@ #define DC_LOGGER \ dccg->ctx->logger +static void dccg31_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (dccg->ref_dppclk && req_dppclk) { + int ref_dppclk = dccg->ref_dppclk; + int modulo, phase; + + // phase / modulo = dpp pipe clk / dpp global clk + modulo = 0xff; // use FF at the end + phase = ((modulo * req_dppclk) + ref_dppclk - 1) / ref_dppclk; + + if (phase > 0xff) { + ASSERT(false); + phase = 0xff; + } + + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, phase, + DPPCLK0_DTO_MODULO, modulo); + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 1); + } else { + //DTO must be enabled to generate a 0Hz clock output + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) { + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 1); + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, 0, + DPPCLK0_DTO_MODULO, 1); + } else { + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 0); + } + } + dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk; +} + + void dccg31_set_dpstreamclk( struct dccg *dccg, enum hdmistreamclk_source src, @@ -401,7 +440,7 @@ void dccg31_init(struct dccg *dccg) } static const struct dccg_funcs dccg31_funcs = { - .update_dpp_dto = dccg2_update_dpp_dto, + .update_dpp_dto = dccg31_update_dpp_dto, .get_dccg_ref_freq = dccg31_get_dccg_ref_freq, .dccg_init = dccg31_init, .set_dpstreamclk = dccg31_set_dpstreamclk, From 4a0dc87fca19c51421a8ef5ca086f57898447c70 Mon Sep 17 00:00:00 2001 From: Jimmy Kizito Date: Tue, 21 Sep 2021 10:03:05 -0400 Subject: [PATCH 418/554] drm/amd/display: Clear encoder assignment for copied streams [Why] When copying a stream, the encoder assigned to it is copied too. Encoder assignment should only happen when executing the encoder assignment function link_encs_assign(). [How] Clear the link encoder pointer for copied stream. Reviewed-by: Meenakshikumar Somasundaram Reviewed-by: Jun Lei Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jimmy Kizito Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index f0f54f4d3d9b..57cf4cb82370 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -202,6 +202,10 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) new_stream->stream_id = new_stream->ctx->dc_stream_id_count; new_stream->ctx->dc_stream_id_count++; + /* If using dynamic encoder assignment, wait till stream committed to assign encoder. */ + if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign) + new_stream->link_enc = NULL; + kref_init(&new_stream->refcount); return new_stream; From d5ce4313cca480308ee0b41a1a0e223e4ba8a0ff Mon Sep 17 00:00:00 2001 From: Jimmy Kizito Date: Wed, 22 Sep 2021 09:50:38 -0400 Subject: [PATCH 419/554] drm/amd/display: Do not skip link training on DP quick hot plug [Why] When rapidly plugging and unplugging a DP sink, detection link training can be mistakenly skipped. This is due to the hotplug processing occurring before the encoder assignment logic has had a chance to process the removal of a stream. The encoder that would be used for detection link training is then erroneously reported as already in use and detection link training is skipped. [How] During hot plug processing, only determine a link encoder to be unavailable for a particular link if it has been assigned to a different link. Reviewed-by: Meenakshikumar Somasundaram Reviewed-by: Jun Lei Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jimmy Kizito Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c | 9 ++++++--- drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 54662d74c65a..8e0b40c7a1ee 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2863,7 +2863,7 @@ bool dp_verify_link_cap( link->verified_link_cap = *known_limit_link_setting; return true; } else if (link->link_enc && link->dc->res_pool->funcs->link_encs_assign && - !link_enc_cfg_is_link_enc_avail(link->ctx->dc, link->link_enc->preferred_engine)) { + !link_enc_cfg_is_link_enc_avail(link->ctx->dc, link->link_enc->preferred_engine, link)) { link->verified_link_cap = initial_link_settings; return true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c index 1cab4bf06abe..72b0f8594b4a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c @@ -488,16 +488,19 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream( return link_enc; } -bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id) +bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link) { bool is_avail = true; int i; - /* Add assigned encoders to list. */ + /* An encoder is not available if it has already been assigned to a different endpoint. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = get_assignment(dc, i); + struct display_endpoint_id ep_id = (struct display_endpoint_id) { + .link_id = link->link_id, + .ep_type = link->ep_type}; - if (assignment.valid && assignment.eng_id == eng_id) { + if (assignment.valid && assignment.eng_id == eng_id && !are_ep_ids_equal(&ep_id, &assignment.ep_id)) { is_avail = false; break; } diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h index 83b2199b2c83..10dcf6a5e9b1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h @@ -97,7 +97,7 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream( const struct dc_stream_state *stream); /* Return true if encoder available to use. */ -bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id); +bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link); /* Returns true if encoder assignments in supplied state pass validity checks. */ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state); From 05692bb02abd63959fde2108dbe80dd5082e4f89 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 24 Sep 2021 16:12:34 -0400 Subject: [PATCH 420/554] drm/amd/display: add DP2.0 debug option to set MST_EN for SST stream [why] Some DP2.0 RX requires us to set MST_EN even for SST configuration. We added this debug option so we can configure this temporary workaround for the RX. Reviewed-by: George Shen Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 7 ++++++- drivers/gpu/drm/amd/display/dc/dc.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index ca5dc3c168ec..fa11a2b094ba 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1869,8 +1869,13 @@ static enum dc_status enable_link_dp(struct dc_state *state, do_fallback = true; #if defined(CONFIG_DRM_AMD_DC_DCN) + /* + * Temporary w/a to get DP2.0 link rates to work with SST. + * TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved. + */ if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING && - pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) { + pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && + link->dc->debug.set_mst_en_for_sst) { dp_enable_mst_on_sink(link, true); } #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index dd995905b0cb..254b760ae91f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -664,6 +664,7 @@ struct dc_debug_options { #if defined(CONFIG_DRM_AMD_DC_DCN) /* TODO - remove once tested */ bool legacy_dp2_lt; + bool set_mst_en_for_sst; #endif union mem_low_power_enable_options enable_mem_low_power; union root_clock_optimization_options root_clock_optimization; From fd8811e60db45e423b0227373fdf79447826f0ca Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Tue, 21 Sep 2021 13:35:19 -0400 Subject: [PATCH 421/554] drm/amd/display: Clean Up VPG Low Mem Power [WHAT] One of the current VPG power on calls is unnecessary Reviewed-by: Eric Yang Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Michael Strauss Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 10 ---------- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 13 +++++++++++++ .../gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 4 ---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index f9876e429f26..8be04be19124 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -71,8 +71,6 @@ #include "dmub/dmub_srv.h" -#include "dcn30/dcn30_vpg.h" - #include "i2caux_interface.h" #include "dce/dmub_hw_lock_mgr.h" @@ -2674,9 +2672,6 @@ static void commit_planes_do_stream_update(struct dc *dc, enum surface_update_type update_type, struct dc_state *context) { -#if defined(CONFIG_DRM_AMD_DC_DCN) - struct vpg *vpg; -#endif int j; // Stream updates @@ -2697,11 +2692,6 @@ static void commit_planes_do_stream_update(struct dc *dc, stream_update->vrr_infopacket || stream_update->vsc_infopacket || stream_update->vsp_infopacket) { -#if defined(CONFIG_DRM_AMD_DC_DCN) - vpg = pipe_ctx->stream_res.stream_enc->vpg; - if (vpg && vpg->funcs->vpg_poweron) - vpg->funcs->vpg_poweron(vpg); -#endif resource_build_info_frame(pipe_ctx); dc->hwss.update_info_frame(pipe_ctx); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 18e33ef3d217..968b8825dec7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -49,6 +49,7 @@ #include "inc/link_dpcd.h" #include "dcn10/dcn10_hw_sequencer.h" #include "inc/link_enc_cfg.h" +#include "dcn30/dcn30_vpg.h" #define DC_LOGGER_INIT(logger) @@ -126,6 +127,18 @@ void dcn31_init_hw(struct dc *dc) REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); } +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { + // Power down VPGs + for (i = 0; i < dc->res_pool->stream_enc_count; i++) + dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); +#if defined(CONFIG_DRM_AMD_DC_DP2_0) + for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) + dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); +#endif + } +#endif + if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 7cb7604a35eb..20b4202bda13 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1312,10 +1312,6 @@ static struct vpg *dcn31_vpg_create( &vpg_shift, &vpg_mask); - // Will re-enable hw block when we enable stream - // Check for enabled stream before powering down? - vpg31_powerdown(&vpg31->base); - return &vpg31->base; } From 2fcb26979d5b2e5a07ee3ceda8e7a10e52cc8a4c Mon Sep 17 00:00:00 2001 From: Josip Pavic Date: Mon, 27 Sep 2021 17:38:10 -0400 Subject: [PATCH 422/554] drm/amd/display: do not compare integers of different widths [Why & How] Increase width of some variables to avoid comparing integers of different widths Reviewed-by: Aric Cyr Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Josip Pavic Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index fa11a2b094ba..d54592b573e9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3439,7 +3439,7 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp; struct fixed31_32 pbn; struct fixed31_32 pbn_per_slot; - uint8_t i; + int i; enum act_return_status ret; DC_LOGGER_INIT(link->ctx->logger); @@ -3531,7 +3531,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; struct dp_mst_stream_allocation_table proposed_table = {0}; struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0); - uint8_t i; + int i; bool mst_mode = (link->type == dc_connection_mst_branch); DC_LOGGER_INIT(link->ctx->logger); From b78f26d3efef70cc6dbaea1172059696e08f3465 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Tue, 28 Sep 2021 13:09:14 -0400 Subject: [PATCH 423/554] drm/amd/display: correct apg audio channel enable golden value Hardware team has recommended to generically hard code this register to 0xFF as part of the effort to eventually remove this control. However we set it to 0xF instead. This causes 4 of audio 8ch to be muted. Reviewed-by: Ariel Bernstein Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c index 6bd7a0626665..de5e18c2a3ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c @@ -129,7 +129,7 @@ static void apg31_se_audio_setup( /* When running in "pair mode", pairs of audio channels have their own enable * this is for really old audio drivers */ - REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xF); + REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xFF); // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels); /* Disable forced mem power off */ From 94e587b8d1bbfb9fbce5b158c2b63d1af6a73af1 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Tue, 28 Sep 2021 16:05:27 -0400 Subject: [PATCH 424/554] drm/amd/display: Validate plane rects before use [Why] Calculation of scaling ratio can result in a crash due to zero'd src or dst plane rects. [How] Validate that src and dst rects are valid before using for scaling calculations. Reviewed-by: Josip Pavic Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Aric Cyr Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 561c10a92bb5..9e83fd54e2ca 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -3009,6 +3009,11 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla { enum dc_status res = DC_OK; + /* check if surface has invalid dimensions */ + if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 || + plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0) + return DC_FAIL_SURFACE_VALIDATE; + /* TODO For now validates pixel format only */ if (dc->res_pool->funcs->validate_plane) return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps); From 4a86858d3993b64bc435434855cca57a67866fed Mon Sep 17 00:00:00 2001 From: "Lai, Derek" Date: Tue, 28 Sep 2021 13:58:56 +0800 Subject: [PATCH 425/554] drm/amd/display: Removed power down on boot from DCN31 [Why] Error message on Linux when booting. [How] Removed power down on boot from DCN31 HW init to match DCN10 HW init. Reviewed-by: Anthony Koo Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Derek Lai Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dcn31/dcn31_hwseq.c | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 968b8825dec7..52947c03be31 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -73,7 +73,6 @@ void dcn31_init_hw(struct dc *dc) struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; int i; - int edp_num; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -209,48 +208,6 @@ void dcn31_init_hw(struct dc *dc) !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); } - /* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on and seamless boot not enabled - */ - if (dc->config.power_down_display_on_boot) { - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link; - bool power_down = false; - - get_edp_links(dc, edp_links, &edp_num); - if (edp_num) { - for (i = 0; i < edp_num; i++) { - edp_link = edp_links[i]; - if (edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwss.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwss.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - power_down = true; - } - } - } - if (!power_down) { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->ep_type == DISPLAY_ENDPOINT_PHY && - link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - } - for (i = 0; i < res_pool->audio_count; i++) { struct audio *audio = res_pool->audios[i]; From 8048af26034f899f1dead814c5161e93b434026d Mon Sep 17 00:00:00 2001 From: Nikola Cornij Date: Tue, 28 Sep 2021 22:43:52 -0400 Subject: [PATCH 426/554] drm/amd/display: Limit display scaling to up to true 4k for DCN 3.1 [why] The requirement is that image width up to 4096 shall be supported Reviewed-by: Aric Cyr Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Nikola Cornij Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 20b4202bda13..a2e40405c97d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -998,7 +998,7 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_dcc = DCC_ENABLE, .vsr_support = true, .performance_trace = false, - .max_downscale_src_width = 3840,/*upto 4K*/ + .max_downscale_src_width = 4096,/*upto true 4K*/ .disable_pplib_wm_range = false, .scl_reset_length10 = true, .sanity_checks = false, From 3cf79bb772a4f95770a3b3670474058addb7d14f Mon Sep 17 00:00:00 2001 From: Hansen Date: Tue, 28 Sep 2021 16:09:47 -0400 Subject: [PATCH 427/554] drm/amd/display: Fix DP2 SE and LE SYMCLK selection for B0 PHY Remap phyd32clk to PHYF and PHYG for B0, PHYC and PHYD are unused Reviewed-by: Nicholas Kazlauskas Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Hansen Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 582c500ecb49..152adb597d48 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -26,6 +26,7 @@ #include "reg_helper.h" #include "core_types.h" #include "dcn31_dccg.h" +#include "dal_asic_id.h" #define TO_DCN_DCCG(dccg)\ container_of(dccg, struct dcn_dccg, base) @@ -80,6 +81,18 @@ static void dccg31_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk; } +static enum phyd32clk_clock_source get_phy_mux_symclk( + struct dcn_dccg *dccg_dcn, + enum phyd32clk_clock_source src) +{ + if (dccg_dcn->base.ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + if (src == PHYD32CLKC) + src = PHYD32CLKF; + if (src == PHYD32CLKD) + src = PHYD32CLKG; + } + return src; +} void dccg31_set_dpstreamclk( struct dccg *dccg, @@ -119,6 +132,8 @@ void dccg31_enable_symclk32_se( { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + phyd32clk = get_phy_mux_symclk(dccg_dcn, phyd32clk); + /* select one of the PHYD32CLKs as the source for symclk32_se */ switch (hpo_se_inst) { case 0: @@ -188,6 +203,8 @@ void dccg31_enable_symclk32_le( { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + phyd32clk = get_phy_mux_symclk(dccg_dcn, phyd32clk); + /* select one of the PHYD32CLKs as the source for symclk32_le */ switch (hpo_le_inst) { case 0: From 641e0e1f5d7f9793a5785ae8aac4d5dc5b4aa9d6 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 29 Sep 2021 11:37:33 -0400 Subject: [PATCH 428/554] drm/amd/display: Fix prefetch bandwidth calculation for DCN3.1 [Why] Prefetch BW calculated is lower than the DML reference because of a porting error that's excluding cursor and row bandwidth from the pixel data bandwidth. [How] Change the dml_max4 to dml_max3 and include cursor and row bandwidth in the same calculation as the rest of the pixel data during vactive. Reviewed-by: Dmytro Laktyushkin Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index ce55c9caf9a2..d58925cff420 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -5398,9 +5398,9 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->MaximumReadBandwidthWithPrefetch = v->MaximumReadBandwidthWithPrefetch - + dml_max4( - v->VActivePixelBandwidth[i][j][k], - v->VActiveCursorBandwidth[i][j][k] + + dml_max3( + v->VActivePixelBandwidth[i][j][k] + + v->VActiveCursorBandwidth[i][j][k] + v->NoOfDPP[i][j][k] * (v->meta_row_bandwidth[i][j][k] + v->dpte_row_bandwidth[i][j][k]), From a35e5c5b758709ac66a40b2aa90bbd82f3735d3e Mon Sep 17 00:00:00 2001 From: Mikita Lipski Date: Wed, 29 Sep 2021 08:39:21 -0400 Subject: [PATCH 429/554] drm/amd/display: Add missing PSR state [why] PSR_STATE2b was introduced on DMCUB side, but not on the driver side, which caused convert_psr_state helper function to return PSR_STATE_INVALID. That caused visual lagging during state transition. [how] Add PSR_STATE2b to dc_psr_state and convert_psr_state Reviewed-by: Wyatt Wood Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Mikita Lipski Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 15c353c389d8..388457ffc0a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -653,6 +653,7 @@ enum dc_psr_state { PSR_STATE1a, PSR_STATE2, PSR_STATE2a, + PSR_STATE2b, PSR_STATE3, PSR_STATE3Init, PSR_STATE4, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index aa8403bc4c83..05d96ca80512 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -50,6 +50,8 @@ static enum dc_psr_state convert_psr_state(uint32_t raw_state) state = PSR_STATE2; else if (raw_state == 0x21) state = PSR_STATE2a; + else if (raw_state == 0x22) + state = PSR_STATE2b; else if (raw_state == 0x30) state = PSR_STATE3; else if (raw_state == 0x31) From e22ad7e338230889e6bbb5e3ca599b5219aac700 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Wed, 22 Sep 2021 16:25:36 -0400 Subject: [PATCH 430/554] drm/amd/display: Disable dsc root clock when not being used [Why & How] Disable root clock for dsc when not being used. Reviewed-by: Nikola Cornij Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 16 ++++- .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 72 +++++++++++++++++++ .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h | 18 ++++- .../drm/amd/display/dc/dcn31/dcn31_hwseq.c | 17 +++++ drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 9 +++ 5 files changed, 129 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index ede65100a050..f6f2d48a70c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -169,7 +169,17 @@ type DTBCLK_DTO_DIV[MAX_PIPES];\ type DCCG_AUDIO_DTO_SEL;\ type DCCG_AUDIO_DTO0_SOURCE_SEL;\ - type DENTIST_DISPCLK_CHG_MODE; + type DENTIST_DISPCLK_CHG_MODE;\ + type DSCCLK0_DTO_PHASE;\ + type DSCCLK0_DTO_MODULO;\ + type DSCCLK1_DTO_PHASE;\ + type DSCCLK1_DTO_MODULO;\ + type DSCCLK2_DTO_PHASE;\ + type DSCCLK2_DTO_MODULO;\ + type DSCCLK0_DTO_ENABLE;\ + type DSCCLK1_DTO_ENABLE;\ + type DSCCLK2_DTO_ENABLE; + struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) @@ -205,6 +215,10 @@ struct dccg_registers { uint32_t SYMCLK32_SE_CNTL; uint32_t SYMCLK32_LE_CNTL; uint32_t DENTIST_DISPCLK_CNTL; + uint32_t DSCCLK_DTO_CTRL; + uint32_t DSCCLK0_DTO_PARAM; + uint32_t DSCCLK1_DTO_PARAM; + uint32_t DSCCLK2_DTO_PARAM; }; struct dcn_dccg { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 152adb597d48..3a325e4afe2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -247,6 +247,76 @@ void dccg31_disable_symclk32_le( } } +static void dccg31_disable_dscclk(struct dccg *dccg, int inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) + return; + //DTO must be enabled to generate a 0 Hz clock output + switch (inst) { + case 0: + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK0_DTO_ENABLE, 1); + REG_UPDATE_2(DSCCLK0_DTO_PARAM, + DSCCLK0_DTO_PHASE, 0, + DSCCLK0_DTO_MODULO, 1); + break; + case 1: + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK1_DTO_ENABLE, 1); + REG_UPDATE_2(DSCCLK1_DTO_PARAM, + DSCCLK1_DTO_PHASE, 0, + DSCCLK1_DTO_MODULO, 1); + break; + case 2: + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK2_DTO_ENABLE, 1); + REG_UPDATE_2(DSCCLK2_DTO_PARAM, + DSCCLK2_DTO_PHASE, 0, + DSCCLK2_DTO_MODULO, 1); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + +static void dccg31_enable_dscclk(struct dccg *dccg, int inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) + return; + //Disable DTO + switch (inst) { + case 0: + REG_UPDATE_2(DSCCLK0_DTO_PARAM, + DSCCLK0_DTO_PHASE, 0, + DSCCLK0_DTO_MODULO, 0); + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK0_DTO_ENABLE, 0); + break; + case 1: + REG_UPDATE_2(DSCCLK1_DTO_PARAM, + DSCCLK1_DTO_PHASE, 0, + DSCCLK1_DTO_MODULO, 0); + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK1_DTO_ENABLE, 0); + break; + case 2: + REG_UPDATE_2(DSCCLK2_DTO_PARAM, + DSCCLK2_DTO_PHASE, 0, + DSCCLK2_DTO_MODULO, 0); + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK2_DTO_ENABLE, 0); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + void dccg31_set_physymclk( struct dccg *dccg, int phy_inst, @@ -469,6 +539,8 @@ static const struct dccg_funcs dccg31_funcs = { .set_dtbclk_dto = dccg31_set_dtbclk_dto, .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto, .set_dispclk_change_mode = dccg31_set_dispclk_change_mode, + .disable_dsc = dccg31_disable_dscclk, + .enable_dsc = dccg31_enable_dscclk, }; struct dccg *dccg31_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h index 1e5aabcb7799..61b457ab790d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h @@ -61,7 +61,11 @@ SR(DCCG_AUDIO_DTBCLK_DTO_MODULO),\ SR(DCCG_AUDIO_DTBCLK_DTO_PHASE),\ SR(DCCG_AUDIO_DTO_SOURCE),\ - SR(DENTIST_DISPCLK_CNTL) + SR(DENTIST_DISPCLK_CNTL),\ + SR(DSCCLK0_DTO_PARAM),\ + SR(DSCCLK1_DTO_PARAM),\ + SR(DSCCLK2_DTO_PARAM),\ + SR(DSCCLK_DTO_CTRL) #define DCCG_MASK_SH_LIST_DCN31(mask_sh) \ @@ -119,7 +123,17 @@ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DTBCLK_DTO, DIV, 3, mask_sh),\ DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\ DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\ - DCCG_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE, mask_sh) + DCCG_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE, mask_sh), \ + DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_ENABLE, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_ENABLE, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh) + struct dccg *dccg31_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 52947c03be31..fee385e37c9b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -270,6 +270,12 @@ void dcn31_dsc_pg_control( if (hws->ctx->dc->debug.disable_dsc_power_gate) return; + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc && + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc && + power_on) + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -306,6 +312,17 @@ void dcn31_dsc_pg_control( if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); + + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) { + if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) + hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_save_init(hws->ctx->dc); +#endif + } + } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 09237d5819f4..c940fdfda144 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -123,6 +123,15 @@ struct dccg_funcs { void (*set_dispclk_change_mode)( struct dccg *dccg, enum dentist_dispclk_change_mode change_mode); + + void (*disable_dsc)( + struct dccg *dccg, + int inst); + + void (*enable_dsc)( + struct dccg *dccg, + int inst); + }; #endif //__DAL_DCCG_H__ From 5595e962bd22024d7dc1eee22ba22d76cab76b20 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 29 Sep 2021 16:22:53 -0400 Subject: [PATCH 431/554] drm/amd/display: Require immediate flip support for DCN3.1 planes [Why] Immediate flip can be enabled dynamically and has higher BW requirements when validating which voltage mode to use. If we validate when it's not set then potentially DCFCLK will be too low and we will underflow. [How] DM always requires support so always require it as part of DML input parameters. This can't be enabled unconditionally on older ASIC because it blocks some expected modes so only target DCN3.1 for now. Reviewed-by: Dmytro Laktyushkin Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index a2e40405c97d..c9d3d691f4c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1778,6 +1778,13 @@ static int dcn31_populate_dml_pipes_from_context( pipe = &res_ctx->pipe_ctx[i]; timing = &pipe->stream->timing; + /* + * Immediate flip can be set dynamically after enabling the plane. + * We need to require support for immediate flip or underflow can be + * intermittently experienced depending on peak b/w requirements. + */ + pipes[pipe_cnt].pipe.src.immediate_flip = true; + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; pipes[pipe_cnt].pipe.src.gpuvm = true; pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; From 22006ad23b4f614ea0d5a1f57f6b1570c2a4688b Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Thu, 30 Sep 2021 13:46:45 -0400 Subject: [PATCH 432/554] drm/amd/display: increase Z9 latency to workaround underflow in Z9 [Why] Z9 latency is higher than when we originally tuned the watermark parameters, causing underflow. Increasing the value until the latency issues is resolved. Reviewed-by: Nicholas Kazlauskas Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Eric Yang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index c9d3d691f4c6..12ebd9f8912f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -222,8 +222,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = { .num_states = 5, .sr_exit_time_us = 9.0, .sr_enter_plus_exit_time_us = 11.0, - .sr_exit_z8_time_us = 402.0, - .sr_enter_plus_exit_z8_time_us = 520.0, + .sr_exit_z8_time_us = 442.0, + .sr_enter_plus_exit_z8_time_us = 560.0, .writeback_latency_us = 12.0, .dram_channel_width_bytes = 4, .round_trip_ping_latency_dcfclk_cycles = 106, From aacdc9d07ecd2d119229dbd59784c7aea4f3aed3 Mon Sep 17 00:00:00 2001 From: Nikola Cornij Date: Fri, 1 Oct 2021 13:26:05 -0400 Subject: [PATCH 433/554] drm/amd/display: Increase watermark latencies for DCN3.1 [why] The original latencies were causing underflow in some modes [how] Replace with the up-to-date watermark values based on new measurments Reviewed-by: Ahmad Othman Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Nikola Cornij Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 3fae1f1f028d..0088dff441da 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -371,32 +371,32 @@ static struct wm_table lpddr5_wm_table = { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 5.32, - .sr_enter_plus_exit_time_us = 6.38, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, .valid = true, }, { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 9.82, - .sr_enter_plus_exit_time_us = 11.196, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, .valid = true, }, { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 9.89, - .sr_enter_plus_exit_time_us = 11.24, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, .valid = true, }, { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 9.748, - .sr_enter_plus_exit_time_us = 11.102, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, .valid = true, }, } From bda24462578ca2b0538d9257509070708ce41acc Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Thu, 23 Sep 2021 00:52:43 -0400 Subject: [PATCH 434/554] drm/amd/display: Disable dpstreamclk, symclk32_se, and symclk32_le [Why & How] Disable dpstreamclk, symclk32_se, and symclk32_le when not in use. Reviewed-by: Ariel Bernstein Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 15 ++- .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 107 ++++++++++++++++-- .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h | 19 +++- 3 files changed, 130 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index f6f2d48a70c1..4098669a0c1f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -178,7 +178,16 @@ type DSCCLK2_DTO_MODULO;\ type DSCCLK0_DTO_ENABLE;\ type DSCCLK1_DTO_ENABLE;\ - type DSCCLK2_DTO_ENABLE; + type DSCCLK2_DTO_ENABLE;\ + type SYMCLK32_ROOT_SE0_GATE_DISABLE;\ + type SYMCLK32_ROOT_SE1_GATE_DISABLE;\ + type SYMCLK32_ROOT_SE2_GATE_DISABLE;\ + type SYMCLK32_ROOT_SE3_GATE_DISABLE;\ + type SYMCLK32_ROOT_LE0_GATE_DISABLE;\ + type SYMCLK32_ROOT_LE1_GATE_DISABLE;\ + type DPSTREAMCLK_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK_GATE_DISABLE; + struct dccg_shift { @@ -219,6 +228,10 @@ struct dccg_registers { uint32_t DSCCLK0_DTO_PARAM; uint32_t DSCCLK1_DTO_PARAM; uint32_t DSCCLK2_DTO_PARAM; + uint32_t DPSTREAMCLK_ROOT_GATE_DISABLE; + uint32_t DPSTREAMCLK_GATE_DISABLE; + uint32_t DCCG_GATE_DISABLE_CNTL3; + }; struct dcn_dccg { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 3a325e4afe2f..815481a3ef54 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -94,10 +94,7 @@ static enum phyd32clk_clock_source get_phy_mux_symclk( return src; } -void dccg31_set_dpstreamclk( - struct dccg *dccg, - enum hdmistreamclk_source src, - int otg_inst) +static void dccg31_enable_dpstreamclk(struct dccg *dccg, int otg_inst) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -105,24 +102,69 @@ void dccg31_set_dpstreamclk( switch (otg_inst) { case 0: REG_UPDATE(DPSTREAMCLK_CNTL, - DPSTREAMCLK_PIPE0_EN, (src == REFCLK) ? 0 : 1); + DPSTREAMCLK_PIPE0_EN, 1); break; case 1: REG_UPDATE(DPSTREAMCLK_CNTL, - DPSTREAMCLK_PIPE1_EN, (src == REFCLK) ? 0 : 1); + DPSTREAMCLK_PIPE1_EN, 1); break; case 2: REG_UPDATE(DPSTREAMCLK_CNTL, - DPSTREAMCLK_PIPE2_EN, (src == REFCLK) ? 0 : 1); + DPSTREAMCLK_PIPE2_EN, 1); break; case 3: REG_UPDATE(DPSTREAMCLK_CNTL, - DPSTREAMCLK_PIPE3_EN, (src == REFCLK) ? 0 : 1); + DPSTREAMCLK_PIPE3_EN, 1); break; default: BREAK_TO_DEBUGGER(); return; } + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + DPSTREAMCLK_ROOT_GATE_DISABLE, 1); +} + +static void dccg31_disable_dpstreamclk(struct dccg *dccg, int otg_inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + DPSTREAMCLK_ROOT_GATE_DISABLE, 0); + + switch (otg_inst) { + case 0: + REG_UPDATE(DPSTREAMCLK_CNTL, + DPSTREAMCLK_PIPE0_EN, 0); + break; + case 1: + REG_UPDATE(DPSTREAMCLK_CNTL, + DPSTREAMCLK_PIPE1_EN, 0); + break; + case 2: + REG_UPDATE(DPSTREAMCLK_CNTL, + DPSTREAMCLK_PIPE2_EN, 0); + break; + case 3: + REG_UPDATE(DPSTREAMCLK_CNTL, + DPSTREAMCLK_PIPE3_EN, 0); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + +void dccg31_set_dpstreamclk( + struct dccg *dccg, + enum hdmistreamclk_source src, + int otg_inst) +{ + if (src == REFCLK) + dccg31_disable_dpstreamclk(dccg, otg_inst); + else + dccg31_enable_dpstreamclk(dccg, otg_inst); } void dccg31_enable_symclk32_se( @@ -137,21 +179,33 @@ void dccg31_enable_symclk32_se( /* select one of the PHYD32CLKs as the source for symclk32_se */ switch (hpo_se_inst) { case 0: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE0_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, phyd32clk, SYMCLK32_SE0_EN, 1); break; case 1: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE1_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, phyd32clk, SYMCLK32_SE1_EN, 1); break; case 2: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE2_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, phyd32clk, SYMCLK32_SE2_EN, 1); break; case 3: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE3_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, phyd32clk, SYMCLK32_SE3_EN, 1); @@ -174,21 +228,33 @@ void dccg31_disable_symclk32_se( REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, 0, SYMCLK32_SE0_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE0_GATE_DISABLE, 0); break; case 1: REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, 0, SYMCLK32_SE1_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE1_GATE_DISABLE, 0); break; case 2: REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, 0, SYMCLK32_SE2_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE2_GATE_DISABLE, 0); break; case 3: REG_UPDATE_2(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, 0, SYMCLK32_SE3_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_SE3_GATE_DISABLE, 0); break; default: BREAK_TO_DEBUGGER(); @@ -208,11 +274,17 @@ void dccg31_enable_symclk32_le( /* select one of the PHYD32CLKs as the source for symclk32_le */ switch (hpo_le_inst) { case 0: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_LE0_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, phyd32clk, SYMCLK32_LE0_EN, 1); break; case 1: + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_LE1_GATE_DISABLE, 1); REG_UPDATE_2(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, phyd32clk, SYMCLK32_LE1_EN, 1); @@ -235,11 +307,17 @@ void dccg31_disable_symclk32_le( REG_UPDATE_2(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, 0, SYMCLK32_LE0_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_LE0_GATE_DISABLE, 0); break; case 1: REG_UPDATE_2(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, 0, SYMCLK32_LE1_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_ROOT_LE1_GATE_DISABLE, 0); break; default: BREAK_TO_DEBUGGER(); @@ -524,6 +602,19 @@ void dccg31_init(struct dccg *dccg) dccg31_disable_symclk32_se(dccg, 1); dccg31_disable_symclk32_se(dccg, 2); dccg31_disable_symclk32_se(dccg, 3); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) { + dccg31_disable_symclk32_le(dccg, 0); + dccg31_disable_symclk32_le(dccg, 1); + } + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) { + dccg31_disable_dpstreamclk(dccg, 0); + dccg31_disable_dpstreamclk(dccg, 1); + dccg31_disable_dpstreamclk(dccg, 2); + dccg31_disable_dpstreamclk(dccg, 3); + } + } static const struct dccg_funcs dccg31_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h index 61b457ab790d..602bf461298b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h @@ -65,7 +65,8 @@ SR(DSCCLK0_DTO_PARAM),\ SR(DSCCLK1_DTO_PARAM),\ SR(DSCCLK2_DTO_PARAM),\ - SR(DSCCLK_DTO_CTRL) + SR(DSCCLK_DTO_CTRL),\ + SR(DCCG_GATE_DISABLE_CNTL3) #define DCCG_MASK_SH_LIST_DCN31(mask_sh) \ @@ -132,7 +133,16 @@ DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_ENABLE, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_ENABLE, mask_sh),\ - DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh) + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, DPSTREAMCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, DPSTREAMCLK_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh) + @@ -144,6 +154,11 @@ struct dccg *dccg31_create( void dccg31_init(struct dccg *dccg); +void dccg31_set_dpstreamclk( + struct dccg *dccg, + enum hdmistreamclk_source src, + int otg_inst); + void dccg31_enable_symclk32_se( struct dccg *dccg, int hpo_se_inst, From dd706b20934f8890ab3f2567a589d99df0503868 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Fri, 1 Oct 2021 16:46:49 -0400 Subject: [PATCH 435/554] drm/amd/display: Removed z10 save after dsc disable [Why & How] Z10 save is done during PSR and bootup. DSC disable does not need to save for Z10. Reviewed-by: Eric Yang Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index fee385e37c9b..65f66687af4c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -317,10 +317,6 @@ void dcn31_dsc_pg_control( if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( hws->ctx->dc->res_pool->dccg, dsc_inst); - -#if defined(CONFIG_DRM_AMD_DC_DCN) - dc_z10_save_init(hws->ctx->dc); -#endif } } From f2949a513a8cb2fecf0f403e660369515d68ac90 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Fri, 1 Oct 2021 17:14:21 -0400 Subject: [PATCH 436/554] drm/amd/display: Moved dccg init to after bios golden init [Why] bios_golden_init will override dccg_init during init_hw. [How] Move dccg_init to after bios_golden_init. Reviewed-by: Aric Cyr Reviewed-by: Eric Yang Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 65f66687af4c..186d08aec812 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -77,10 +77,6 @@ void dcn31_init_hw(struct dc *dc) if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { REG_WRITE(REFCLK_CNTL, 0); @@ -107,6 +103,9 @@ void dcn31_init_hw(struct dc *dc) hws->funcs.bios_golden_init(dc); hws->funcs.disable_vga(dc->hwseq); } + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); if (dc->debug.enable_mem_low_power.bits.dmcu) { // Force ERAM to shutdown if DMCU is not enabled From e7414a1a185ead49e8b7e0fa6952e74cfe4a76f4 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Wed, 22 Sep 2021 23:37:52 -0400 Subject: [PATCH 437/554] drm/amd/display: Disable hdmistream and hdmichar clocks [Why & How] Disable hdmistream and hdmichar root clocks when not being used. Reviewed-by: Aric Cyr Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Jake Wang Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 9 +++++++-- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h | 9 +++++---- .../gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_offset.h | 2 ++ .../gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_sh_mask.h | 8 ++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 4098669a0c1f..f98aba308028 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -186,8 +186,11 @@ type SYMCLK32_ROOT_LE0_GATE_DISABLE;\ type SYMCLK32_ROOT_LE1_GATE_DISABLE;\ type DPSTREAMCLK_ROOT_GATE_DISABLE;\ - type DPSTREAMCLK_GATE_DISABLE; - + type DPSTREAMCLK_GATE_DISABLE;\ + type HDMISTREAMCLK0_DTO_PHASE;\ + type HDMISTREAMCLK0_DTO_MODULO;\ + type HDMICHARCLK0_GATE_DISABLE;\ + type HDMICHARCLK0_ROOT_GATE_DISABLE; struct dccg_shift { @@ -231,6 +234,8 @@ struct dccg_registers { uint32_t DPSTREAMCLK_ROOT_GATE_DISABLE; uint32_t DPSTREAMCLK_GATE_DISABLE; uint32_t DCCG_GATE_DISABLE_CNTL3; + uint32_t HDMISTREAMCLK0_DTO_PARAM; + uint32_t DCCG_GATE_DISABLE_CNTL4; }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h index 602bf461298b..a013a32bbaf7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h @@ -66,7 +66,8 @@ SR(DSCCLK1_DTO_PARAM),\ SR(DSCCLK2_DTO_PARAM),\ SR(DSCCLK_DTO_CTRL),\ - SR(DCCG_GATE_DISABLE_CNTL3) + SR(DCCG_GATE_DISABLE_CNTL3),\ + SR(HDMISTREAMCLK0_DTO_PARAM) #define DCCG_MASK_SH_LIST_DCN31(mask_sh) \ @@ -141,9 +142,9 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh) - - + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh) struct dccg *dccg31_create( diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_offset.h index 312c50ea30f3..f268d33c4744 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_offset.h @@ -436,6 +436,8 @@ #define regPHYESYMCLK_CLOCK_CNTL_BASE_IDX 2 #define regDCCG_GATE_DISABLE_CNTL3 0x005a #define regDCCG_GATE_DISABLE_CNTL3_BASE_IDX 2 +#define regHDMISTREAMCLK0_DTO_PARAM 0x005b +#define regHDMISTREAMCLK0_DTO_PARAM_BASE_IDX 2 #define regDCCG_AUDIO_DTBCLK_DTO_PHASE 0x0061 #define regDCCG_AUDIO_DTBCLK_DTO_PHASE_BASE_IDX 2 #define regDCCG_AUDIO_DTBCLK_DTO_MODULO 0x0062 diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_sh_mask.h index a9d553ef26c0..1f21f313bd1d 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_2_sh_mask.h @@ -1438,6 +1438,14 @@ #define DCCG_GATE_DISABLE_CNTL3__SYMCLK32_LE0_GATE_DISABLE_MASK 0x00200000L #define DCCG_GATE_DISABLE_CNTL3__SYMCLK32_ROOT_LE1_GATE_DISABLE_MASK 0x00400000L #define DCCG_GATE_DISABLE_CNTL3__SYMCLK32_LE1_GATE_DISABLE_MASK 0x00800000L +//HDMISTREAMCLK0_DTO_PARAM +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_PHASE__SHIFT 0x0 +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_MODULO__SHIFT 0x8 +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_EN__SHIFT 0x10 +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_PHASE_MASK 0x000000FFL +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_MODULO_MASK 0x0000FF00L +#define HDMISTREAMCLK0_DTO_PARAM__HDMISTREAMCLK0_DTO_EN_MASK 0x00010000L + //DCCG_AUDIO_DTBCLK_DTO_PHASE #define DCCG_AUDIO_DTBCLK_DTO_PHASE__DCCG_AUDIO_DTBCLK_DTO_PHASE__SHIFT 0x0 #define DCCG_AUDIO_DTBCLK_DTO_PHASE__DCCG_AUDIO_DTBCLK_DTO_PHASE_MASK 0xFFFFFFFFL From c78abac92190512b31b5557740f61a23fb005f7b Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 2 Oct 2021 21:06:38 -0400 Subject: [PATCH 438/554] drm/amd/display: Change initializer to single brace Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Aric Cyr Tested-by: Daniel Wheeler Signed-off-by: Anthony Koo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 7 ++--- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 2 +- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 30 +++++++++---------- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 8 ++--- .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 4 +-- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index d54592b573e9..6db611f9f554 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -674,13 +674,13 @@ static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) static void read_current_link_settings_on_detect(struct dc_link *link) { - union lane_count_set lane_count_set = { {0} }; + union lane_count_set lane_count_set = {0}; uint8_t link_bw_set; uint8_t link_rate_set; uint32_t read_dpcd_retry_cnt = 10; enum dc_status status = DC_ERROR_UNEXPECTED; int i; - union max_down_spread max_down_spread = { {0} }; + union max_down_spread max_down_spread = {0}; // Read DPCD 00101h to find out the number of lanes currently set for (i = 0; i < read_dpcd_retry_cnt; i++) { @@ -3279,8 +3279,7 @@ static void update_mst_stream_alloc_table( struct stream_encoder *stream_enc, const struct dp_mst_stream_allocation_table *proposed_table) { - struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { - { 0 } }; + struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { 0 }; struct link_mst_stream_allocation *dc_alloc; int i; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index b0f1cd7268c8..471a67a64299 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -763,7 +763,7 @@ void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service) dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &tmds_config, sizeof(tmds_config)); if (tmds_config & 0x1) { - union hdmi_scdc_status_flags_data status_data = { {0} }; + union hdmi_scdc_status_flags_data status_data = {0}; uint8_t scramble_status = 0; offset = HDMI_SCDC_SCRAMBLER_STATUS; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 8e0b40c7a1ee..296b0defcd1c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -259,7 +259,7 @@ static void dpcd_set_training_pattern( struct dc_link *link, enum dc_dp_training_pattern training_pattern) { - union dpcd_training_pattern dpcd_pattern = { {0} }; + union dpcd_training_pattern dpcd_pattern = {0}; dpcd_pattern.v1_4.TRAINING_PATTERN_SET = dc_dp_training_pattern_to_dpcd_training_pattern( @@ -401,8 +401,8 @@ enum dc_status dpcd_set_link_settings( uint8_t rate; enum dc_status status; - union down_spread_ctrl downspread = { {0} }; - union lane_count_set lane_count_set = { {0} }; + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; downspread.raw = (uint8_t) (lt_settings->link_settings.link_spread); @@ -520,7 +520,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( uint32_t dpcd_base_lt_offset; uint8_t dpcd_lt_buffer[5] = {0}; - union dpcd_training_pattern dpcd_pattern = { {0} }; + union dpcd_training_pattern dpcd_pattern = { 0 }; uint32_t size_in_bytes; bool edp_workaround = false; /* TODO link_prop.INTERNAL */ dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; @@ -1266,8 +1266,8 @@ static enum link_training_result perform_channel_equalization_sequence( uint32_t retries_ch_eq; uint32_t wait_time_microsec; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_align_status_updated dpcd_lane_status_updated = { {0} }; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; /* Note: also check that TPS4 is a supported feature*/ @@ -1487,7 +1487,7 @@ static inline enum link_training_result dp_transition_to_video_idle( struct link_training_settings *lt_settings, enum link_training_result status) { - union lane_count_set lane_count_set = { {0} }; + union lane_count_set lane_count_set = {0}; /* 4. mainlink output idle pattern*/ dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); @@ -1800,7 +1800,7 @@ static enum dc_status configure_lttpr_mode_non_transparent( static void repeater_training_done(struct dc_link *link, uint32_t offset) { - union dpcd_training_pattern dpcd_pattern = { {0} }; + union dpcd_training_pattern dpcd_pattern = {0}; const uint32_t dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + @@ -2078,8 +2078,8 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( uint32_t aux_rd_interval = 0; uint32_t wait_time = 0; struct link_training_settings req_settings; - union lane_align_status_updated dpcd_lane_status_updated = { {0} }; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; enum link_training_result status = LINK_TRAINING_SUCCESS; /* Transmit 128b/132b_TPS1 over Main-Link and Set TRAINING_PATTERN_SET to 01h */ @@ -2149,8 +2149,8 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( /* Assumption: assume hardware has transmitted eq pattern */ enum link_training_result status = LINK_TRAINING_SUCCESS; struct link_training_settings req_settings; - union lane_align_status_updated dpcd_lane_status_updated = { {0} }; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; uint32_t wait_time = 0; /* initiate CDS done sequence */ @@ -4065,8 +4065,8 @@ void dc_link_dp_handle_link_loss(struct dc_link *link) bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss, bool defer_handling, bool *has_left_work) { - union hpd_irq_data hpd_irq_dpcd_data = { { { {0} } } }; - union device_service_irq device_service_clear = { { 0 } }; + union hpd_irq_data hpd_irq_dpcd_data = {0}; + union device_service_irq device_service_clear = {0}; enum dc_status result; bool status = false; @@ -5939,7 +5939,7 @@ bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timin uint8_t link_bw_set; uint8_t link_rate_set; uint32_t req_bw; - union lane_count_set lane_count_set = { {0} }; + union lane_count_set lane_count_set = {0}; ASSERT(link || crtc_timing); // invalid input diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index bc3ec05bf34b..aa2d430f2a1a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2304,8 +2304,8 @@ static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - struct vm_system_aperture_param apt = { {{ 0 } } }; - struct vm_context0_param vm0 = { { { 0 } } }; + struct vm_system_aperture_param apt = {0}; + struct vm_context0_param vm0 = {0}; mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); mmhub_read_vm_context0_settings(hubp1, &vm0, hws); @@ -2478,7 +2478,7 @@ void dcn10_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg = {{0}}; + struct mpcc_blnd_cfg blnd_cfg = {0}; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; int mpcc_id; struct mpcc *new_mpcc; @@ -3635,7 +3635,7 @@ void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings) { - struct encoder_unblank_param params = { { 0 } }; + struct encoder_unblank_param params = {0}; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; struct dce_hwseq *hws = link->dc->hwseq; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index fc83744149d9..cfee456c6c9a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2123,7 +2123,7 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings) { - struct encoder_unblank_param params = { { 0 } }; + struct encoder_unblank_param params = {0}; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; struct dce_hwseq *hws = link->dc->hwseq; @@ -2298,7 +2298,7 @@ void dcn20_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg = { {0} }; + struct mpcc_blnd_cfg blnd_cfg = {0}; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; int mpcc_id; struct mpcc *new_mpcc; From c57d7da77b48fbe345cbaab55b2f3e0814d9708c Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Sun, 3 Oct 2021 23:42:48 -0400 Subject: [PATCH 439/554] drm/amd/display: 3.2.157 This DC patchset brings improvements in multiple areas. In summary, we highlight: * Fix some issues such as DP2 problem, prefetch bandwidth calculation for DCN3.1 and others. * Increased Z9 latency and removed z10 save after dsc disable. * Revert a couple of bad changes. * Added missing PSR state patch. Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Aric Cyr Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 254b760ae91f..fc3f0fd1f068 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.156" +#define DC_VER "3.2.157" #define MAX_SURFACES 3 #define MAX_PLANES 6 From 69c86e6be3224f831d80e458ba7aedaee3407b73 Mon Sep 17 00:00:00 2001 From: Nevenko Stupar Date: Wed, 29 Sep 2021 18:00:28 -0400 Subject: [PATCH 440/554] drm/amd/display: Add bios parser support for latest firmware_info [Why] V3_4 is latest in use. [How] Add bios parser support for firmware_info_v3_4 along with some relevant fields it is also retrieving from dce_info and smu_info. Reviewed-by: Jun Lei Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Nevenko Stupar Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/bios/bios_parser2.c | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index cdb5c027411a..c17732fba039 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -99,6 +99,10 @@ static enum bp_result get_firmware_info_v3_2( struct bios_parser *bp, struct dc_firmware_info *info); +static enum bp_result get_firmware_info_v3_4( + struct bios_parser *bp, + struct dc_firmware_info *info); + static struct atom_hpd_int_record *get_hpd_record(struct bios_parser *bp, struct atom_display_object_path_v2 *object); @@ -1426,8 +1430,10 @@ static enum bp_result bios_parser_get_firmware_info( break; case 2: case 3: - case 4: result = get_firmware_info_v3_2(bp, info); + break; + case 4: + result = get_firmware_info_v3_4(bp, info); break; default: break; @@ -1575,6 +1581,88 @@ static enum bp_result get_firmware_info_v3_2( return BP_RESULT_OK; } +static enum bp_result get_firmware_info_v3_4( + struct bios_parser *bp, + struct dc_firmware_info *info) +{ + struct atom_firmware_info_v3_4 *firmware_info; + struct atom_common_table_header *header; + struct atom_data_revision revision; + struct atom_display_controller_info_v4_1 *dce_info_v4_1 = NULL; + struct atom_display_controller_info_v4_4 *dce_info_v4_4 = NULL; + if (!info) + return BP_RESULT_BADINPUT; + + firmware_info = GET_IMAGE(struct atom_firmware_info_v3_4, + DATA_TABLES(firmwareinfo)); + + if (!firmware_info) + return BP_RESULT_BADBIOSTABLE; + + memset(info, 0, sizeof(*info)); + + header = GET_IMAGE(struct atom_common_table_header, + DATA_TABLES(dce_info)); + + get_atom_data_table_revision(header, &revision); + + switch (revision.major) { + case 4: + switch (revision.minor) { + case 4: + dce_info_v4_4 = GET_IMAGE(struct atom_display_controller_info_v4_4, + DATA_TABLES(dce_info)); + + if (!dce_info_v4_4) + return BP_RESULT_BADBIOSTABLE; + + /* 100MHz expected */ + info->pll_info.crystal_frequency = dce_info_v4_4->dce_refclk_10khz * 10; + info->dp_phy_ref_clk = dce_info_v4_4->dpphy_refclk_10khz * 10; + /* 50MHz expected */ + info->i2c_engine_ref_clk = dce_info_v4_4->i2c_engine_refclk_10khz * 10; + + /* Get SMU Display PLL VCO Frequency in KHz*/ + info->smu_gpu_pll_output_freq = dce_info_v4_4->dispclk_pll_vco_freq * 10; + break; + + default: + /* should not come here, keep as backup, as was before */ + dce_info_v4_1 = GET_IMAGE(struct atom_display_controller_info_v4_1, + DATA_TABLES(dce_info)); + + if (!dce_info_v4_1) + return BP_RESULT_BADBIOSTABLE; + + info->pll_info.crystal_frequency = dce_info_v4_1->dce_refclk_10khz * 10; + info->dp_phy_ref_clk = dce_info_v4_1->dpphy_refclk_10khz * 10; + info->i2c_engine_ref_clk = dce_info_v4_1->i2c_engine_refclk_10khz * 10; + break; + } + break; + + default: + ASSERT(0); + break; + } + + header = GET_IMAGE(struct atom_common_table_header, + DATA_TABLES(smu_info)); + get_atom_data_table_revision(header, &revision); + + // We need to convert from 10KHz units into KHz units. + info->default_memory_clk = firmware_info->bootup_mclk_in10khz * 10; + + if (firmware_info->board_i2c_feature_id == 0x2) { + info->oem_i2c_present = true; + info->oem_i2c_obj_id = firmware_info->board_i2c_feature_gpio_id; + } else { + info->oem_i2c_present = false; + } + + return BP_RESULT_OK; +} + static enum bp_result bios_parser_get_encoder_cap_info( struct dc_bios *dcb, struct graphics_object_id object_id, From 8098acd3dc827d9e2498352c89ba987eb0ee8764 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 2 Oct 2021 21:06:38 -0400 Subject: [PATCH 441/554] drm/amd/display: [FW Promotion] Release 0.0.88 Acked-by: Agustin Gutierrez Sanchez Signed-off-by: Anthony Koo Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 0b9d6bf4886d..4c436fb4624b 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -46,10 +46,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xf0c64c97 +#define DMUB_FW_VERSION_GIT_HASH 0xd146258f #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 87 +#define DMUB_FW_VERSION_REVISION 88 #define DMUB_FW_VERSION_TEST 0 #define DMUB_FW_VERSION_VBIOS 0 #define DMUB_FW_VERSION_HOTFIX 0 From e848c714dbda4d6f0ad17a4d374af0ce9fcd1615 Mon Sep 17 00:00:00 2001 From: Agustin Gutierrez Date: Fri, 15 Oct 2021 13:42:15 -0400 Subject: [PATCH 442/554] Revert "drm/amd/display: Fix error in dmesg at boot" This reverts commit 4874ecf5fd1de008756a76796bf255d3b19715c1. Signed-off-by: Agustin Gutierrez Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 6db611f9f554..c01309a1cbf2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1999,7 +1999,7 @@ void blank_all_dp_displays(struct dc *dc, bool hw_init) if ((signal == SIGNAL_TYPE_EDP) || (signal == SIGNAL_TYPE_DISPLAY_PORT)) { - if (hw_init && signal != SIGNAL_TYPE_EDP && dc->links[i]->priv != NULL) { + if (hw_init && signal != SIGNAL_TYPE_EDP) { /* DP 2.0 spec requires that we read LTTPR caps first */ dp_retrieve_lttpr_cap(dc->links[i]); /* if any of the displays are lit up turn them off */ @@ -2025,7 +2025,7 @@ void blank_all_dp_displays(struct dc *dc, bool hw_init) } if (!dc->links[i]->wa_flags.dp_keep_receiver_powered || - (hw_init && signal != SIGNAL_TYPE_EDP && dc->links[i]->priv != NULL)) + (hw_init && signal != SIGNAL_TYPE_EDP)) dp_receiver_power_ctrl(dc->links[i], false); } } From c494e57992f9b85e72fac3003358387249b359b6 Mon Sep 17 00:00:00 2001 From: Agustin Gutierrez Date: Fri, 15 Oct 2021 14:05:19 -0400 Subject: [PATCH 443/554] Revert "drm/amd/display: Add helper for blanking all dp displays" This reverts commit 1445d967fb915156aed0e79ca80c239cb2d414ce. This patch introduced a couple of dmesg warnings, this is not a valid approach anymore. For this reason, we are reverting this patch, and we need to revert the workaround patch. v2: squash in unused variable removal (Alex) Cc: Hanghong Ma Cc: Mark Broadworth Signed-off-by: Agustin Gutierrez Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 45 ------------------- drivers/gpu/drm/amd/display/dc/dc_link.h | 1 - .../display/dc/dce110/dce110_hw_sequencer.c | 24 ++++++++-- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 41 +++++++++++++++-- .../drm/amd/display/dc/dcn30/dcn30_hwseq.c | 39 ++++++++++++++-- .../drm/amd/display/dc/dcn31/dcn31_hwseq.c | 37 +++++++++++++-- 6 files changed, 129 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index c01309a1cbf2..e5d6cbd7ea78 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1988,51 +1988,6 @@ static enum dc_status enable_link_dp_mst( return enable_link_dp(state, pipe_ctx); } -void blank_all_dp_displays(struct dc *dc, bool hw_init) -{ - unsigned int i, j, fe; - uint8_t dpcd_power_state = '\0'; - enum dc_status status = DC_ERROR_UNEXPECTED; - - for (i = 0; i < dc->link_count; i++) { - enum signal_type signal = dc->links[i]->connector_signal; - - if ((signal == SIGNAL_TYPE_EDP) || - (signal == SIGNAL_TYPE_DISPLAY_PORT)) { - if (hw_init && signal != SIGNAL_TYPE_EDP) { - /* DP 2.0 spec requires that we read LTTPR caps first */ - dp_retrieve_lttpr_cap(dc->links[i]); - /* if any of the displays are lit up turn them off */ - status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, - &dpcd_power_state, sizeof(dpcd_power_state)); - } - - if ((signal != SIGNAL_TYPE_EDP && status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) || - (!hw_init && dc->links[i]->link_enc && - dc->links[i]->link_enc->funcs->is_dig_enabled(dc->links[i]->link_enc))) { - if (dc->links[i]->link_enc->funcs->get_dig_frontend) { - fe = dc->links[i]->link_enc->funcs->get_dig_frontend(dc->links[i]->link_enc); - if (fe == ENGINE_ID_UNKNOWN) - continue; - - for (j = 0; j < dc->res_pool->stream_enc_count; j++) { - if (fe == dc->res_pool->stream_enc[j]->id) { - dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i], - dc->res_pool->stream_enc[j]); - break; - } - } - } - - if (!dc->links[i]->wa_flags.dp_keep_receiver_powered || - (hw_init && signal != SIGNAL_TYPE_EDP)) - dp_receiver_power_ctrl(dc->links[i], false); - } - } - } - -} - static bool get_ext_hdmi_settings(struct pipe_ctx *pipe_ctx, enum engine_id eng_id, struct ext_hdmi_settings *settings) diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 69b008bafbbc..a73d64b1fd33 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -277,7 +277,6 @@ bool dc_link_setup_psr(struct dc_link *dc_link, struct psr_context *psr_context); void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency); -void blank_all_dp_displays(struct dc *dc, bool hw_init); /* Request DC to detect if there is a Panel connected. * boot - If this call is during initial boot. diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 8108f9ae2638..af3e68d3e747 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1649,13 +1649,31 @@ static enum dc_status apply_single_controller_ctx_to_hw( static void power_down_encoders(struct dc *dc) { - int i; - - blank_all_dp_displays(dc, false); + int i, j; for (i = 0; i < dc->link_count; i++) { enum signal_type signal = dc->links[i]->connector_signal; + if ((signal == SIGNAL_TYPE_EDP) || + (signal == SIGNAL_TYPE_DISPLAY_PORT)) { + if (dc->links[i]->link_enc->funcs->get_dig_frontend && + dc->links[i]->link_enc->funcs->is_dig_enabled(dc->links[i]->link_enc)) { + unsigned int fe = dc->links[i]->link_enc->funcs->get_dig_frontend( + dc->links[i]->link_enc); + + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { + if (fe == dc->res_pool->stream_enc[j]->id) { + dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i], + dc->res_pool->stream_enc[j]); + break; + } + } + } + + if (!dc->links[i]->wa_flags.dp_keep_receiver_powered) + dp_receiver_power_ctrl(dc->links[i], false); + } + if (signal != SIGNAL_TYPE_EDP) signal = SIGNAL_TYPE_NONE; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index aa2d430f2a1a..44d27579d898 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1366,7 +1366,7 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context) void dcn10_init_hw(struct dc *dc) { - int i; + int i, j; struct abm *abm = dc->res_pool->abm; struct dmcu *dmcu = dc->res_pool->dmcu; struct dce_hwseq *hws = dc->hwseq; @@ -1462,8 +1462,43 @@ void dcn10_init_hw(struct dc *dc) dmub_enable_outbox_notification(dc); /* we want to turn off all dp displays before doing detection */ - if (dc->config.power_down_display_on_boot) - blank_all_dp_displays(dc, true); + if (dc->config.power_down_display_on_boot) { + uint8_t dpcd_power_state = '\0'; + enum dc_status status = DC_ERROR_UNEXPECTED; + + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) + continue; + + /* DP 2.0 requires that LTTPR Caps be read first */ + dp_retrieve_lttpr_cap(dc->links[i]); + + /* + * If any of the displays are lit up turn them off. + * The reason is that some MST hubs cannot be turned off + * completely until we tell them to do so. + * If not turned off, then displays connected to MST hub + * won't light up. + */ + status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) { + /* blank dp stream before power off receiver*/ + if (dc->links[i]->link_enc->funcs->get_dig_frontend) { + unsigned int fe = dc->links[i]->link_enc->funcs->get_dig_frontend(dc->links[i]->link_enc); + + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { + if (fe == dc->res_pool->stream_enc[j]->id) { + dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i], + dc->res_pool->stream_enc[j]); + break; + } + } + } + dp_receiver_power_ctrl(dc->links[i], false); + } + } + } /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 2936a334cd64..df2717116604 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -437,7 +437,7 @@ void dcn30_init_hw(struct dc *dc) struct dce_hwseq *hws = dc->hwseq; struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; - int i; + int i, j; int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; @@ -534,8 +534,41 @@ void dcn30_init_hw(struct dc *dc) hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); /* we want to turn off all dp displays before doing detection */ - if (dc->config.power_down_display_on_boot) - blank_all_dp_displays(dc, true); + if (dc->config.power_down_display_on_boot) { + uint8_t dpcd_power_state = '\0'; + enum dc_status status = DC_ERROR_UNEXPECTED; + + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) + continue; + /* DP 2.0 states that LTTPR regs must be read first */ + dp_retrieve_lttpr_cap(dc->links[i]); + + /* if any of the displays are lit up turn them off */ + status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) { + /* blank dp stream before power off receiver*/ + if (dc->links[i]->link_enc->funcs->get_dig_frontend) { + unsigned int fe; + + fe = dc->links[i]->link_enc->funcs->get_dig_frontend( + dc->links[i]->link_enc); + if (fe == ENGINE_ID_UNKNOWN) + continue; + + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { + if (fe == dc->res_pool->stream_enc[j]->id) { + dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i], + dc->res_pool->stream_enc[j]); + break; + } + } + } + dp_receiver_power_ctrl(dc->links[i], false); + } + } + } /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 186d08aec812..9a6ad1cebc85 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -72,7 +72,7 @@ void dcn31_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; - int i; + int i, j; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -190,9 +190,40 @@ void dcn31_init_hw(struct dc *dc) dmub_enable_outbox_notification(dc); /* we want to turn off all dp displays before doing detection */ - if (dc->config.power_down_display_on_boot) - blank_all_dp_displays(dc, true); + if (dc->config.power_down_display_on_boot) { + uint8_t dpcd_power_state = '\0'; + enum dc_status status = DC_ERROR_UNEXPECTED; + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) + continue; + + /* if any of the displays are lit up turn them off */ + status = core_link_read_dpcd(dc->links[i], DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) { + /* blank dp stream before power off receiver*/ + if (dc->links[i]->ep_type == DISPLAY_ENDPOINT_PHY && + dc->links[i]->link_enc->funcs->get_dig_frontend) { + unsigned int fe; + + fe = dc->links[i]->link_enc->funcs->get_dig_frontend( + dc->links[i]->link_enc); + if (fe == ENGINE_ID_UNKNOWN) + continue; + + for (j = 0; j < dc->res_pool->stream_enc_count; j++) { + if (fe == dc->res_pool->stream_enc[j]->id) { + dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i], + dc->res_pool->stream_enc[j]); + break; + } + } + } + dp_receiver_power_ctrl(dc->links[i], false); + } + } + } /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which From 1b5254e8d9322d34909cc452d76117e743432549 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Fri, 15 Oct 2021 16:57:43 +0800 Subject: [PATCH 444/554] drm/amdgpu: centralize checking for RAS TA status Create new function to check status returned by RAS TA. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 88274c254c76..bcf95982f6fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1292,6 +1292,25 @@ static int psp_ras_unload(struct psp_context *psp) return psp_ta_unload(psp, &psp->ras_context.context); } +static void psp_ras_ta_check_status(struct psp_context *psp) +{ + struct ta_ras_shared_memory *ras_cmd = + (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf; + + switch (ras_cmd->ras_status) { + case TA_RAS_STATUS__ERROR_UNSUPPORTED_IP: + dev_warn(psp->adev->dev, + "RAS WARNING: cmd failed due to unsupported ip\n"); + break; + case TA_RAS_STATUS__SUCCESS: + break; + default: + dev_warn(psp->adev->dev, + "RAS WARNING: ras status = 0x%X\n", ras_cmd->ras_status); + break; + } +} + int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) { struct ta_ras_shared_memory *ras_cmd; @@ -1326,10 +1345,7 @@ int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) dev_warn(psp->adev->dev, "RAS internal register access blocked\n"); - if (ras_cmd->ras_status == TA_RAS_STATUS__ERROR_UNSUPPORTED_IP) - dev_warn(psp->adev->dev, "RAS WARNING: cmd failed due to unsupported ip\n"); - else if (ras_cmd->ras_status) - dev_warn(psp->adev->dev, "RAS WARNING: ras status = 0x%X\n", ras_cmd->ras_status); + psp_ras_ta_check_status(psp); } return ret; From 42f88ab772a3be6e94cca559e2270f04164dc3ac Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Mon, 18 Oct 2021 17:02:16 +0800 Subject: [PATCH 445/554] drm/amdgpu: output warning for unsupported ras error inject (v2) Output a warning message if RAS TA returns UNSUPPORTED_ERROR_INJ status. v2: implement it in psp_ras_ta_check_status function. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 4 ++++ drivers/gpu/drm/amd/amdgpu/ta_ras_if.h | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index bcf95982f6fa..fd04e83031d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1302,6 +1302,10 @@ static void psp_ras_ta_check_status(struct psp_context *psp) dev_warn(psp->adev->dev, "RAS WARNING: cmd failed due to unsupported ip\n"); break; + case TA_RAS_STATUS__ERROR_UNSUPPORTED_ERROR_INJ: + dev_warn(psp->adev->dev, + "RAS WARNING: cmd failed due to unsupported error injection\n"); + break; case TA_RAS_STATUS__SUCCESS: break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h index de24a0a97d5e..5093826a43d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h @@ -59,7 +59,12 @@ enum ta_ras_status { TA_RAS_STATUS__ERROR_SYS_DRV_REG_ACCESS = 0xA011, TA_RAS_STATUS__ERROR_RAS_READ_WRITE = 0xA012, TA_RAS_STATUS__ERROR_NULL_PTR = 0xA013, - TA_RAS_STATUS__ERROR_UNSUPPORTED_IP = 0xA014 + TA_RAS_STATUS__ERROR_UNSUPPORTED_IP = 0xA014, + TA_RAS_STATUS__ERROR_PCS_STATE_QUIET = 0xA015, + TA_RAS_STATUS__ERROR_PCS_STATE_ERROR = 0xA016, + TA_RAS_STATUS__ERROR_PCS_STATE_HANG = 0xA017, + TA_RAS_STATUS__ERROR_PCS_STATE_UNKNOWN = 0xA018, + TA_RAS_STATUS__ERROR_UNSUPPORTED_ERROR_INJ = 0xA019 }; enum ta_ras_block { From dac35c423984a22cfc91d9a520fc203ba0c19744 Mon Sep 17 00:00:00 2001 From: Guchun Chen Date: Mon, 18 Oct 2021 22:26:01 +0800 Subject: [PATCH 446/554] drm/amdgpu/discovery: parse hw_id_name for SDMA instance 2 and 3 Otherwise, hw_id_name string is NULL for SDMA 2 and 3 when dumping ip version from VBIOS. Signed-off-by: Guchun Chen Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 9645b95b9c42..dfb92f229748 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -108,6 +108,8 @@ static const char *hw_id_names[HW_ID_MAX] = { [HDP_HWID] = "HDP", [SDMA0_HWID] = "SDMA0", [SDMA1_HWID] = "SDMA1", + [SDMA2_HWID] = "SDMA2", + [SDMA3_HWID] = "SDMA3", [ISP_HWID] = "ISP", [DBGU_IO_HWID] = "DBGU_IO", [DF_HWID] = "DF", From c654dc379379b9fa5323a8b859e05c1ef3c3ff28 Mon Sep 17 00:00:00 2001 From: Ran Jianping Date: Tue, 19 Oct 2021 09:02:05 +0000 Subject: [PATCH 447/554] drm/i915/selftests: remove duplicate include in mock_region.c 'drm/ttm/ttm_placement.h' included in 'drivers/gpu/drm/i915/selftests/mock_region.c' is duplicated. It is also included on the 9 line. Reported-by: Zeal Robot Signed-off-by: Ran Jianping Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20211019090205.1003458-1-ran.jianping@zte.com.cn --- drivers/gpu/drm/i915/selftests/mock_region.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c index efa86dffe3c6..75793008c4ef 100644 --- a/drivers/gpu/drm/i915/selftests/mock_region.c +++ b/drivers/gpu/drm/i915/selftests/mock_region.c @@ -6,8 +6,6 @@ #include #include -#include - #include "gem/i915_gem_region.h" #include "intel_memory_region.h" #include "intel_region_ttm.h" From 5efacdf072d19d5321354fa4d8a4df0cc4e1d0cc Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Tue, 19 Oct 2021 11:13:25 +0800 Subject: [PATCH 448/554] drm/amdgpu: support B0&B1 external revision id for yellow carp B0 internal rev_id is 0x01, B1 internal rev_id is 0x02. The external rev_id for B0 and B1 is 0x20. The original expression is not suitable for B1. v2: squash in fix for display code (Alex) Signed-off-by: Aaron Liu Reviewed-by: Huang Rui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nv.c | 2 +- drivers/gpu/drm/amd/display/include/dal_asic_id.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 898e688be63c..5166a1573e7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -1248,7 +1248,7 @@ static int nv_common_early_init(void *handle) AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_JPEG; if (adev->pdev->device == 0x1681) - adev->external_rev_id = adev->rev_id + 0x19; + adev->external_rev_id = 0x20; else adev->external_rev_id = adev->rev_id + 0x01; break; diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index a9974f12f7fb..e4a2dfacab4c 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -228,7 +228,7 @@ enum { #define FAMILY_YELLOW_CARP 146 #define YELLOW_CARP_A0 0x01 -#define YELLOW_CARP_B0 0x1A +#define YELLOW_CARP_B0 0x20 #define YELLOW_CARP_UNKNOWN 0xFF #ifndef ASICREV_IS_YELLOW_CARP From 40320159f066a8172234b044b4a37abaee175581 Mon Sep 17 00:00:00 2001 From: Qing Wang Date: Thu, 14 Oct 2021 23:47:20 -0700 Subject: [PATCH 449/554] drm/amdgpu: replace snprintf in show functions with sysfs_emit show() must not use snprintf() when formatting the value to be returned to user space. Fix the following coccicheck warning: drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c:427: WARNING: use scnprintf or sprintf. Signed-off-by: Qing Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 0c3127f37686..920c4f6ac914 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -509,7 +509,7 @@ static ssize_t show_##name(struct device *dev, \ struct drm_device *ddev = dev_get_drvdata(dev); \ struct amdgpu_device *adev = drm_to_adev(ddev); \ \ - return snprintf(buf, PAGE_SIZE, "0x%08x\n", adev->field); \ + return sysfs_emit(buf, "0x%08x\n", adev->field); \ } \ static DEVICE_ATTR(name, mode, show_##name, NULL) From 68e3871dcd6e547f6c47454492bc452356cb9eac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 4 Oct 2021 11:33:00 -0400 Subject: [PATCH 450/554] drm/amdgpu/pm: properly handle sclk for profiling modes on vangogh When selecting between levels in the force performance levels interface sclk (gfxclk) was not set correctly for all levels. Select the proper sclk settings for all levels. Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1726 Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 91 ++++++------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index eba516428f1b..421f38e8dada 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1386,52 +1386,38 @@ static int vangogh_set_performance_level(struct smu_context *smu, uint32_t soc_mask, mclk_mask, fclk_mask; uint32_t vclk_mask = 0, dclk_mask = 0; + smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; + smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; + switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: - smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; + smu->gfx_actual_hard_min_freq = smu->gfx_default_soft_max_freq; smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; ret = vangogh_force_dpm_limit_value(smu, true); + if (ret) + return ret; break; case AMD_DPM_FORCED_LEVEL_LOW: smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; - smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; + smu->gfx_actual_soft_max_freq = smu->gfx_default_hard_min_freq; ret = vangogh_force_dpm_limit_value(smu, false); + if (ret) + return ret; break; case AMD_DPM_FORCED_LEVEL_AUTO: smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - ret = vangogh_unforce_dpm_levels(smu); + if (ret) + return ret; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: - smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; - smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetHardMinGfxClk, - VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL); - if (ret) - return ret; - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetSoftMaxGfxClk, - VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL); - if (ret) - return ret; + smu->gfx_actual_hard_min_freq = VANGOGH_UMD_PSTATE_STANDARD_GFXCLK; + smu->gfx_actual_soft_max_freq = VANGOGH_UMD_PSTATE_STANDARD_GFXCLK; ret = vangogh_get_profiling_clk_mask(smu, level, &vclk_mask, @@ -1446,32 +1432,15 @@ static int vangogh_set_performance_level(struct smu_context *smu, vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask); vangogh_force_clk_levels(smu, SMU_VCLK, 1 << vclk_mask); vangogh_force_clk_levels(smu, SMU_DCLK, 1 << dclk_mask); - break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; - smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, - VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL); - if (ret) - return ret; - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, - VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL); - if (ret) - return ret; + smu->gfx_actual_soft_max_freq = smu->gfx_default_hard_min_freq; break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - ret = vangogh_get_profiling_clk_mask(smu, level, NULL, NULL, @@ -1484,29 +1453,29 @@ static int vangogh_set_performance_level(struct smu_context *smu, vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask); break; case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; - smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - - smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; - smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, - VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL); - if (ret) - return ret; - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, - VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL); - if (ret) - return ret; + smu->gfx_actual_hard_min_freq = VANGOGH_UMD_PSTATE_PEAK_GFXCLK; + smu->gfx_actual_soft_max_freq = VANGOGH_UMD_PSTATE_PEAK_GFXCLK; ret = vangogh_set_peak_clock_by_device(smu); + if (ret) + return ret; break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: - break; + return 0; } + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, + smu->gfx_actual_hard_min_freq, NULL); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, + smu->gfx_actual_soft_max_freq, NULL); + if (ret) + return ret; + return ret; } From c9c7d180459267dc4a1033c4765f6ac29ad839b1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Oct 2021 12:22:59 -0400 Subject: [PATCH 451/554] drm/amdgpu/gfx10: fix typo in gfx_v10_0_update_gfx_clock_gating() Check was incorrectly converted to IP version checking. Fixes: 4b0ad8425498ba ("drm/amdgpu/gfx10: convert to IP version checking") Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 71bb3c0dc1da..8cec03949835 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -8238,8 +8238,9 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev, /* === CGCG + CGLS === */ gfx_v10_0_update_coarse_grain_clock_gating(adev, enable); - if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 1, 10)) && - (adev->ip_versions[GC_HWIP][0] <= IP_VERSION(10, 1, 2))) + if ((adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 10)) || + (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 1)) || + (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 2))) gfx_v10_0_apply_medium_grain_clock_gating_workaround(adev); } else { /* CGCG/CGLS should be disabled before MGCG/MGLS From 18f12604f5eec0484c531712fce9690d78731ccb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Oct 2021 09:36:33 -0400 Subject: [PATCH 452/554] drm/amdkfd: protect hawaii_device_info with CONFIG_DRM_AMDGPU_CIK hawaii_device_info is not used when CONFIG_DRM_AMDGPU_CIK is not set. Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 99d2b9c875ea..5137132250c5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -114,6 +114,7 @@ static const struct kfd_device_info raven_device_info = { .num_sdma_queues_per_engine = 2, }; +#ifdef CONFIG_DRM_AMDGPU_CIK static const struct kfd_device_info hawaii_device_info = { .asic_family = CHIP_HAWAII, .asic_name = "hawaii", @@ -133,6 +134,7 @@ static const struct kfd_device_info hawaii_device_info = { .num_xgmi_sdma_engines = 0, .num_sdma_queues_per_engine = 2, }; +#endif static const struct kfd_device_info tonga_device_info = { .asic_family = CHIP_TONGA, From 0f3d2b680444d5697650b5529c9e749acbf7371f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Oct 2021 09:39:37 -0400 Subject: [PATCH 453/554] drm/amdkfd: protect raven_device_info with KFD_SUPPORT_IOMMU_V2 raven_device_info is not used when KFD_SUPPORT_IOMMU_V2 is not set. Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 5137132250c5..0fffaf859c59 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -93,7 +93,6 @@ static const struct kfd_device_info carrizo_device_info = { .num_xgmi_sdma_engines = 0, .num_sdma_queues_per_engine = 2, }; -#endif static const struct kfd_device_info raven_device_info = { .asic_family = CHIP_RAVEN, @@ -113,6 +112,7 @@ static const struct kfd_device_info raven_device_info = { .num_xgmi_sdma_engines = 0, .num_sdma_queues_per_engine = 2, }; +#endif #ifdef CONFIG_DRM_AMDGPU_CIK static const struct kfd_device_info hawaii_device_info = { From 7092432e3cb1a47f1ba7fe59ceb23f85bd8e09a4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Oct 2021 09:44:47 -0400 Subject: [PATCH 454/554] drm/amdgpu: drop soc15_set_ip_blocks() No longer used since IP enumeration is now driven by amdgpu IP discovery code. Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc15.c | 179 ----------------------------- drivers/gpu/drm/amd/amdgpu/soc15.h | 1 - 2 files changed, 180 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 0640e143e7a5..0c316a2d42ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -780,185 +780,6 @@ void soc15_set_virt_ops(struct amdgpu_device *adev) soc15_reg_base_init(adev); } -int soc15_set_ip_blocks(struct amdgpu_device *adev) -{ - /* for bare metal case */ - if (!amdgpu_sriov_vf(adev)) - soc15_reg_base_init(adev); - - if (adev->flags & AMD_IS_APU) { - adev->nbio.funcs = &nbio_v7_0_funcs; - adev->nbio.hdp_flush_reg = &nbio_v7_0_hdp_flush_reg; - } else if (adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_ARCTURUS || - adev->asic_type == CHIP_ALDEBARAN) { - adev->nbio.funcs = &nbio_v7_4_funcs; - adev->nbio.hdp_flush_reg = &nbio_v7_4_hdp_flush_reg; - } else { - adev->nbio.funcs = &nbio_v6_1_funcs; - adev->nbio.hdp_flush_reg = &nbio_v6_1_hdp_flush_reg; - } - adev->hdp.funcs = &hdp_v4_0_funcs; - - if (adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_ARCTURUS || - adev->asic_type == CHIP_ALDEBARAN) - adev->df.funcs = &df_v3_6_funcs; - else - adev->df.funcs = &df_v1_7_funcs; - - if (adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_ARCTURUS) - adev->smuio.funcs = &smuio_v11_0_funcs; - else if (adev->asic_type == CHIP_ALDEBARAN) - adev->smuio.funcs = &smuio_v13_0_funcs; - else - adev->smuio.funcs = &smuio_v9_0_funcs; - - adev->rev_id = soc15_get_rev_id(adev); - - switch (adev->asic_type) { - case CHIP_VEGA10: - case CHIP_VEGA12: - case CHIP_VEGA20: - amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); - - /* For Vega10 SR-IOV, PSP need to be initialized before IH */ - if (amdgpu_sriov_vf(adev)) { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) { - if (adev->asic_type == CHIP_VEGA20) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - else - amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); - } - if (adev->asic_type == CHIP_VEGA20) - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - else - amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); - } else { - if (adev->asic_type == CHIP_VEGA20) - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - else - amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) { - if (adev->asic_type == CHIP_VEGA20) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - else - amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); - } - } - amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - if (is_support_sw_smu(adev)) { - if (!amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - } else { - amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); - } - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - if (!(adev->asic_type == CHIP_VEGA20 && amdgpu_sriov_vf(adev))) { - amdgpu_device_ip_block_add(adev, &uvd_v7_0_ip_block); - amdgpu_device_ip_block_add(adev, &vce_v4_0_ip_block); - } - break; - case CHIP_RAVEN: - amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &vcn_v1_0_ip_block); - break; - case CHIP_ARCTURUS: - amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); - - if (amdgpu_sriov_vf(adev)) { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - } else { - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - } - - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); - amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - - if (amdgpu_sriov_vf(adev)) { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block); - } else { - amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block); - } - if (!amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block); - break; - case CHIP_RENOIR: - amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v12_0_ip_block); - amdgpu_device_ip_block_add(adev, &smu_v12_0_ip_block); - amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); - break; - case CHIP_ALDEBARAN: - amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block); - - if (amdgpu_sriov_vf(adev)) { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v13_0_ip_block); - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - } else { - amdgpu_device_ip_block_add(adev, &vega20_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v13_0_ip_block); - } - - amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - - amdgpu_device_ip_block_add(adev, &smu_v13_0_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v2_6_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v2_6_ip_block); - break; - default: - return -EINVAL; - } - - return 0; -} - static bool soc15_need_full_reset(struct amdgpu_device *adev) { /* change this when we implement soft reset */ diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.h b/drivers/gpu/drm/amd/amdgpu/soc15.h index f9359003385d..efc2a253e8db 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15.h @@ -102,7 +102,6 @@ struct soc15_ras_field_entry { void soc15_grbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); void soc15_set_virt_ops(struct amdgpu_device *adev); -int soc15_set_ip_blocks(struct amdgpu_device *adev); void soc15_program_register_sequence(struct amdgpu_device *adev, const struct soc15_reg_golden *registers, From bf99b9b03265b28f08591ea08661f2fd644ea45f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Oct 2021 09:46:18 -0400 Subject: [PATCH 455/554] drm/amdgpu: drop nv_set_ip_blocks() No longer used since IP enumeration is now driven by amdgpu IP discovery code. Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/nv.c | 293 -------------------------------- drivers/gpu/drm/amd/amdgpu/nv.h | 1 - 2 files changed, 294 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 5166a1573e7e..febc903adf58 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -607,304 +607,11 @@ const struct amdgpu_ip_block_version nv_common_ip_block = .funcs = &nv_common_ip_funcs, }; -static int nv_reg_base_init(struct amdgpu_device *adev) -{ - int r; - - if (amdgpu_discovery) { - r = amdgpu_discovery_reg_base_init(adev); - if (r) { - DRM_WARN("failed to init reg base from ip discovery table, " - "fallback to legacy init method\n"); - goto legacy_init; - } - - amdgpu_discovery_harvest_ip(adev); - - return 0; - } - -legacy_init: - switch (adev->asic_type) { - case CHIP_NAVI10: - navi10_reg_base_init(adev); - break; - case CHIP_NAVI14: - navi14_reg_base_init(adev); - break; - case CHIP_NAVI12: - navi12_reg_base_init(adev); - break; - case CHIP_SIENNA_CICHLID: - case CHIP_NAVY_FLOUNDER: - sienna_cichlid_reg_base_init(adev); - break; - case CHIP_VANGOGH: - vangogh_reg_base_init(adev); - break; - case CHIP_DIMGREY_CAVEFISH: - dimgrey_cavefish_reg_base_init(adev); - break; - case CHIP_BEIGE_GOBY: - beige_goby_reg_base_init(adev); - break; - case CHIP_YELLOW_CARP: - yellow_carp_reg_base_init(adev); - break; - case CHIP_CYAN_SKILLFISH: - cyan_skillfish_reg_base_init(adev); - break; - default: - return -EINVAL; - } - - return 0; -} - void nv_set_virt_ops(struct amdgpu_device *adev) { adev->virt.ops = &xgpu_nv_virt_ops; } -int nv_set_ip_blocks(struct amdgpu_device *adev) -{ - int r; - - if (adev->asic_type == CHIP_CYAN_SKILLFISH) { - adev->nbio.funcs = &nbio_v2_3_funcs; - adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg; - } else if (adev->flags & AMD_IS_APU) { - adev->nbio.funcs = &nbio_v7_2_funcs; - adev->nbio.hdp_flush_reg = &nbio_v7_2_hdp_flush_reg; - } else { - adev->nbio.funcs = &nbio_v2_3_funcs; - adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg; - } - adev->hdp.funcs = &hdp_v5_0_funcs; - - if (adev->asic_type >= CHIP_SIENNA_CICHLID) - adev->smuio.funcs = &smuio_v11_0_6_funcs; - else - adev->smuio.funcs = &smuio_v11_0_funcs; - - if (adev->asic_type == CHIP_SIENNA_CICHLID) - adev->gmc.xgmi.supported = true; - - /* Set IP register base before any HW register access */ - r = nv_reg_base_init(adev); - if (r) - return r; - - switch (adev->asic_type) { - case CHIP_NAVI10: - case CHIP_NAVI14: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP && - !amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT && - !amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); - if (adev->enable_mes) - amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block); - break; - case CHIP_NAVI12: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - if (!amdgpu_sriov_vf(adev)) { - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - } else { - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - } - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT && - !amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); - if (!amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); - break; - case CHIP_SIENNA_CICHLID: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - if (!amdgpu_sriov_vf(adev)) { - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - } else { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - } - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - if (!amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block); - if (adev->enable_mes) - amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block); - break; - case CHIP_NAVY_FLOUNDER: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - break; - case CHIP_VANGOGH: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block); - break; - case CHIP_DIMGREY_CAVEFISH: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block); - break; - case CHIP_BEIGE_GOBY: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT && - is_support_sw_smu(adev)) - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - break; - case CHIP_YELLOW_CARP: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v13_0_ip_block); - amdgpu_device_ip_block_add(adev, &smu_v13_0_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block); - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block); - amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block); - break; - case CHIP_CYAN_SKILLFISH: - amdgpu_device_ip_block_add(adev, &nv_common_ip_block); - amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block); - if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2) { - if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) - amdgpu_device_ip_block_add(adev, &psp_v11_0_8_ip_block); - amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - } - if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) - amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block); -#if defined(CONFIG_DRM_AMD_DC) - else if (amdgpu_device_has_dc_support(adev)) - amdgpu_device_ip_block_add(adev, &dm_ip_block); -#endif - amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block); - amdgpu_device_ip_block_add(adev, &sdma_v5_0_ip_block); - break; - default: - return -EINVAL; - } - - return 0; -} - static uint32_t nv_get_rev_id(struct amdgpu_device *adev) { return adev->nbio.funcs->get_rev_id(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/nv.h b/drivers/gpu/drm/amd/amdgpu/nv.h index 7df2f85bbcd0..c6e9233afd17 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.h +++ b/drivers/gpu/drm/amd/amdgpu/nv.h @@ -31,7 +31,6 @@ extern const struct amdgpu_ip_block_version nv_common_ip_block; void nv_grbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); void nv_set_virt_ops(struct amdgpu_device *adev); -int nv_set_ip_blocks(struct amdgpu_device *adev); int navi10_reg_base_init(struct amdgpu_device *adev); int navi14_reg_base_init(struct amdgpu_device *adev); int navi12_reg_base_init(struct amdgpu_device *adev); From 0d055f09e12104e08398a27ba38bd7e2cef2a92b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Oct 2021 09:55:54 -0400 Subject: [PATCH 456/554] drm/amdgpu: drop navi reg init functions No longer used since IP enumeration is driven by the IP discovery table now. Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/Makefile | 6 +- .../gpu/drm/amd/amdgpu/beige_goby_reg_init.c | 54 ------------------ .../drm/amd/amdgpu/cyan_skillfish_reg_init.c | 51 ----------------- drivers/gpu/drm/amd/amdgpu/navi10_reg_init.c | 55 ------------------- drivers/gpu/drm/amd/amdgpu/navi12_reg_init.c | 52 ------------------ drivers/gpu/drm/amd/amdgpu/navi14_reg_init.c | 53 ------------------ drivers/gpu/drm/amd/amdgpu/nv.h | 9 --- .../drm/amd/amdgpu/sienna_cichlid_reg_init.c | 54 ------------------ drivers/gpu/drm/amd/amdgpu/vangogh_reg_init.c | 50 ----------------- .../gpu/drm/amd/amdgpu/yellow_carp_reg_init.c | 51 ----------------- 10 files changed, 2 insertions(+), 433 deletions(-) delete mode 100644 drivers/gpu/drm/amd/amdgpu/beige_goby_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/cyan_skillfish_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/navi10_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/navi12_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/navi14_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/sienna_cichlid_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/vangogh_reg_init.c delete mode 100644 drivers/gpu/drm/amd/amdgpu/yellow_carp_reg_init.c diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 8d0748184a14..653726588956 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -73,10 +73,8 @@ amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce amdgpu-y += \ vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \ - vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \ - arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \ - nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o \ - beige_goby_reg_init.o yellow_carp_reg_init.o cyan_skillfish_reg_init.o + vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o arct_reg_init.o mxgpu_nv.o \ + nbio_v7_2.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o # add DF block amdgpu-y += \ diff --git a/drivers/gpu/drm/amd/amdgpu/beige_goby_reg_init.c b/drivers/gpu/drm/amd/amdgpu/beige_goby_reg_init.c deleted file mode 100644 index 608a113ce354..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/beige_goby_reg_init.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "soc15_hw_ip.h" -#include "beige_goby_ip_offset.h" - -int beige_goby_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialize the block needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN0_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DCN_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA2_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA3_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - } - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/cyan_skillfish_reg_init.c b/drivers/gpu/drm/amd/amdgpu/cyan_skillfish_reg_init.c deleted file mode 100644 index 58808814d8fb..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/cyan_skillfish_reg_init.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "soc15_hw_ip.h" -#include "cyan_skillfish_ip_offset.h" - -int cyan_skillfish_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialized the blocke needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(UVD0_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DMU_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - } - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_reg_init.c b/drivers/gpu/drm/amd/amdgpu/navi10_reg_init.c deleted file mode 100644 index 88efaecf9f70..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/navi10_reg_init.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "navi10_ip_offset.h" - -int navi10_reg_base_init(struct amdgpu_device *adev) -{ - int i; - - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DCN_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i])); - } - - return 0; -} - - diff --git a/drivers/gpu/drm/amd/amdgpu/navi12_reg_init.c b/drivers/gpu/drm/amd/amdgpu/navi12_reg_init.c deleted file mode 100644 index a786d159e5e9..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/navi12_reg_init.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "navi12_ip_offset.h" - -int navi12_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialized the blocks needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIF0_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(UVD0_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DMU_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i])); - } - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/navi14_reg_init.c b/drivers/gpu/drm/amd/amdgpu/navi14_reg_init.c deleted file mode 100644 index 4ea1e8fbb601..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/navi14_reg_init.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "navi14_ip_offset.h" - -int navi14_reg_base_init(struct amdgpu_device *adev) -{ - int i; - - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIF0_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(UVD0_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DMU_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i])); - } - - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/nv.h b/drivers/gpu/drm/amd/amdgpu/nv.h index c6e9233afd17..83e9782aef39 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.h +++ b/drivers/gpu/drm/amd/amdgpu/nv.h @@ -31,14 +31,5 @@ extern const struct amdgpu_ip_block_version nv_common_ip_block; void nv_grbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); void nv_set_virt_ops(struct amdgpu_device *adev); -int navi10_reg_base_init(struct amdgpu_device *adev); -int navi14_reg_base_init(struct amdgpu_device *adev); -int navi12_reg_base_init(struct amdgpu_device *adev); -int sienna_cichlid_reg_base_init(struct amdgpu_device *adev); -void vangogh_reg_base_init(struct amdgpu_device *adev); -int dimgrey_cavefish_reg_base_init(struct amdgpu_device *adev); -int beige_goby_reg_base_init(struct amdgpu_device *adev); -int yellow_carp_reg_base_init(struct amdgpu_device *adev); -int cyan_skillfish_reg_base_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid_reg_init.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid_reg_init.c deleted file mode 100644 index 5ee69f70c49b..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid_reg_init.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2019 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "soc15_hw_ip.h" -#include "sienna_cichlid_ip_offset.h" - -int sienna_cichlid_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialized the blocke needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DCN_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA2_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SDMA3_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - } - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/vangogh_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vangogh_reg_init.c deleted file mode 100644 index d64d681a05dc..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/vangogh_reg_init.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2019 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "soc15_hw_ip.h" -#include "vangogh_ip_offset.h" - -void vangogh_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialized the blocke needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DCN_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - } -} diff --git a/drivers/gpu/drm/amd/amdgpu/yellow_carp_reg_init.c b/drivers/gpu/drm/amd/amdgpu/yellow_carp_reg_init.c deleted file mode 100644 index 3d89421275ed..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/yellow_carp_reg_init.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2019 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "amdgpu.h" -#include "nv.h" - -#include "soc15_common.h" -#include "soc15_hw_ip.h" -#include "yellow_carp_offset.h" - -int yellow_carp_reg_base_init(struct amdgpu_device *adev) -{ - /* HW has more IP blocks, only initialized the block needed by driver */ - uint32_t i; - for (i = 0 ; i < MAX_INSTANCE ; ++i) { - adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i])); - adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i])); - adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i])); - adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); - adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); - adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); - adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); - adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN_BASE.instance[i])); - adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); - adev->reg_offset[DCE_HWIP][i] = (uint32_t *)(&(DCN_BASE.instance[i])); - adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i])); - adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(SDMA0_BASE.instance[i])); - adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); - adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); - } - return 0; -} From dcd5ea9f9428d1c95b59416cf1d7af92fd5d0b45 Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Tue, 19 Oct 2021 09:53:17 -0400 Subject: [PATCH 457/554] drm/amdgpu: Clarify error when hitting bad page threshold Change the error message when the bad_page_threshold is reached, explicitly stating that the GPU will not be initialized. Cc: Luben Tuikov Cc: Mukul Joshi Signed-off-by: Kent Russell Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 98732518543e..f4c05ff4b26c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1101,7 +1101,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, *exceed_err_limit = true; dev_err(adev->dev, "RAS records:%d exceed threshold:%d, " - "maybe retire this GPU?", + "GPU will not be initialized. Replace this GPU or increase the threshold", control->ras_num_recs, ras->bad_page_cnt_threshold); } } else { From e1f17ea4c36fb1bbd866a71fe07ab42e9a49f5e7 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:00 +0100 Subject: [PATCH 458/554] drm/i915: mark dmabuf objects as ALLOC_USER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are userspace objects, so mark them as such. In a later patch it's useful to determine how paranoid we need to be when managing cache flushes. In theory no functional changes. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index afa34111de02..5be505ebbb7b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -301,7 +301,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, } drm_gem_private_object_init(dev, &obj->base, dma_buf->size); - i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class, 0); + i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class, + I915_BO_ALLOC_USER); obj->base.import_attach = attach; obj->base.resv = dma_buf->resv; From f7858cb48bf8ee70e71933f1a354a666bb802e54 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:01 +0100 Subject: [PATCH 459/554] drm/i915: mark userptr objects as ALLOC_USER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are userspace objects, so mark them as such. In a later patch it's useful to determine how paranoid we need to be when managing cache flushes. In theory no functional changes. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-2-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 8ea0fa665e53..887aca9e8dd2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -546,7 +546,8 @@ i915_gem_userptr_ioctl(struct drm_device *dev, return -ENOMEM; drm_gem_private_object_init(dev, &obj->base, args->user_size); - i915_gem_object_init(obj, &i915_gem_userptr_ops, &lock_class, 0); + i915_gem_object_init(obj, &i915_gem_userptr_ops, &lock_class, + I915_BO_ALLOC_USER); obj->mem_flags = I915_BO_FLAG_STRUCT_PAGE; obj->read_domains = I915_GEM_DOMAIN_CPU; obj->write_domain = I915_GEM_DOMAIN_CPU; From 30f1dccd295b6865fad9e41873dce2f76998cbae Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:02 +0100 Subject: [PATCH 460/554] drm/i915: extract bypass-llc check into helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like we will need this in some more places, so extract as a helper. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-3-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 26 ++++++++++++++++++++++ drivers/gpu/drm/i915/gem/i915_gem_object.h | 1 + drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 17 +------------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 76ce6a1500bc..1e426a42a36c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -128,6 +128,32 @@ void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj, !(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE); } +bool i915_gem_object_can_bypass_llc(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + + /* + * This is purely from a security perspective, so we simply don't care + * about non-userspace objects being able to bypass the LLC. + */ + if (!(obj->flags & I915_BO_ALLOC_USER)) + return false; + + /* + * EHL and JSL add the 'Bypass LLC' MOCS entry, which should make it + * possible for userspace to bypass the GTT caching bits set by the + * kernel, as per the given object cache_level. This is troublesome + * since the heavy flush we apply when first gathering the pages is + * skipped if the kernel thinks the object is coherent with the GPU. As + * a result it might be possible to bypass the cache and read the + * contents of the page directly, which could be stale data. If it's + * just a case of userspace shooting themselves in the foot then so be + * it, but since i915 takes the stance of always zeroing memory before + * handing it to userspace, we need to prevent this. + */ + return IS_JSL_EHL(i915); +} + static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file) { struct drm_i915_gem_object *obj = to_intel_bo(gem); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 9df3ee60604e..59201801cec5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -514,6 +514,7 @@ i915_gem_object_finish_access(struct drm_i915_gem_object *obj) void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj, unsigned int cache_level); +bool i915_gem_object_can_bypass_llc(struct drm_i915_gem_object *obj); void i915_gem_object_flush_if_display(struct drm_i915_gem_object *obj); void i915_gem_object_flush_if_display_locked(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 11f072193f3b..cf11aa7e08a0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -182,22 +182,7 @@ rebuild_st: if (i915_gem_object_needs_bit17_swizzle(obj)) i915_gem_object_do_bit_17_swizzle(obj, st); - /* - * EHL and JSL add the 'Bypass LLC' MOCS entry, which should make it - * possible for userspace to bypass the GTT caching bits set by the - * kernel, as per the given object cache_level. This is troublesome - * since the heavy flush we apply when first gathering the pages is - * skipped if the kernel thinks the object is coherent with the GPU. As - * a result it might be possible to bypass the cache and read the - * contents of the page directly, which could be stale data. If it's - * just a case of userspace shooting themselves in the foot then so be - * it, but since i915 takes the stance of always zeroing memory before - * handing it to userspace, we need to prevent this. - * - * By setting cache_dirty here we make the clflush in set_pages - * unconditional on such platforms. - */ - if (IS_JSL_EHL(i915) && obj->flags & I915_BO_ALLOC_USER) + if (i915_gem_object_can_bypass_llc(obj)) obj->cache_dirty = true; __i915_gem_object_set_pages(obj, st, sg_page_sizes); From a035154da45d19e09dc68454673ff257a660aece Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:03 +0100 Subject: [PATCH 461/554] drm/i915/dmabuf: add paranoid flush-on-acquire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As pointed out by Thomas, we likely need to flush the pages here if the GPU can read the page contents directly from main memory. Underneath we don't know what the sg_table is pointing to, so just add a wbinvd_on_all_cpus() here, for now. Reported-by: Thomas Hellström Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-4-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 5be505ebbb7b..1adcd8e02d29 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -232,6 +232,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags) static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) { + struct drm_i915_private *i915 = to_i915(obj->base.dev); struct sg_table *pages; unsigned int sg_page_sizes; @@ -242,8 +243,11 @@ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) if (IS_ERR(pages)) return PTR_ERR(pages); - sg_page_sizes = i915_sg_dma_sizes(pages->sgl); + /* XXX: consider doing a vmap flush or something */ + if (!HAS_LLC(i915) || i915_gem_object_can_bypass_llc(obj)) + wbinvd_on_all_cpus(); + sg_page_sizes = i915_sg_dma_sizes(pages->sgl); __i915_gem_object_set_pages(obj, pages, sg_page_sizes); return 0; From 63430347713a5ba48617687cc8b2aa1f01514432 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:04 +0100 Subject: [PATCH 462/554] drm/i915/userptr: add paranoid flush-on-acquire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though userptr objects are always coherent with the GPU, with no way for userspace to change this with the set_caching ioctl, even on non-LLC platforms, there is still the 'Bypass LCC' mocs setting, which might permit reading the contents of main memory directly. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-5-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 887aca9e8dd2..3173c9f9a040 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -165,8 +165,11 @@ alloc_table: goto err; } - sg_page_sizes = i915_sg_dma_sizes(st->sgl); + WARN_ON_ONCE(!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE)); + if (i915_gem_object_can_bypass_llc(obj)) + obj->cache_dirty = true; + sg_page_sizes = i915_sg_dma_sizes(st->sgl); __i915_gem_object_set_pages(obj, st, sg_page_sizes); return 0; From d70af57944a1593f2cd6f94b7eb29fae97929953 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:05 +0100 Subject: [PATCH 463/554] drm/i915/shmem: ensure flush during swap-in on non-LLC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On non-LLC platforms, force the flush-on-acquire if this is ever swapped-in. Our async flush path is not trust worthy enough yet(and happens in the wrong order), and with some tricks it's conceivable for userspace to change the cache-level to I915_CACHE_NONE after the pages are swapped-in, and since execbuf binds the object before doing the async flush, there is a potential race window. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-6-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index cf11aa7e08a0..d77da59fae04 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -286,6 +286,8 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, struct sg_table *pages, bool needs_clflush) { + struct drm_i915_private *i915 = to_i915(obj->base.dev); + GEM_BUG_ON(obj->mm.madv == __I915_MADV_PURGED); if (obj->mm.madv == I915_MADV_DONTNEED) @@ -297,6 +299,16 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, drm_clflush_sg(pages); __start_cpu_write(obj); + /* + * On non-LLC platforms, force the flush-on-acquire if this is ever + * swapped-in. Our async flush path is not trust worthy enough yet(and + * happens in the wrong order), and with some tricks it's conceivable + * for userspace to change the cache-level to I915_CACHE_NONE after the + * pages are swapped-in, and since execbuf binds the object before doing + * the async flush, we have a race window. + */ + if (!HAS_LLC(i915)) + obj->cache_dirty = true; } void i915_gem_object_put_pages_shmem(struct drm_i915_gem_object *obj, struct sg_table *pages) From df94fd05e69e25dd72a7574405b896540803f8b8 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:06 +0100 Subject: [PATCH 464/554] drm/i915: expand on the kernel-doc for cache_dirty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some details around non-LLC platforms and cflushing, when dealing with the flush-on-acquire, which is potentially security sensitive. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Daniel Vetter Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-7-matthew.auld@intel.com --- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 11 ++++++++ .../gpu/drm/i915/gem/i915_gem_object_types.h | 27 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index f20a3a5b3c84..4d7da07442f2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -1922,6 +1922,17 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) * !(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ) * but gcc's optimiser doesn't handle that as well and emits * two jumps instead of one. Maybe one day... + * + * FIXME: There is also sync flushing in set_pages(), which + * serves a different purpose(some of the time at least). + * + * We should consider: + * + * 1. Rip out the async flush code. + * + * 2. Or make the sync flushing use the async clflush path + * using mandatory fences underneath. Currently the below + * async flush happens after we bind the object. */ if (unlikely(obj->cache_dirty & ~obj->cache_coherent)) { if (i915_gem_clflush_object(obj, 0)) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 7c3da4e3e737..da85169006d4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -427,6 +427,33 @@ struct drm_i915_gem_object { * can freely bypass the CPU cache when touching the pages with the GPU, * where the kernel is completely unaware. On such platform we need * apply the sledgehammer-on-acquire regardless of the @cache_coherent. + * + * Special care is taken on non-LLC platforms, to prevent potential + * information leak. The driver currently ensures: + * + * 1. All userspace objects, by default, have @cache_level set as + * I915_CACHE_NONE. The only exception is userptr objects, where we + * instead force I915_CACHE_LLC, but we also don't allow userspace to + * ever change the @cache_level for such objects. Another special case + * is dma-buf, which doesn't rely on @cache_dirty, but there we + * always do a forced flush when acquiring the pages, if there is a + * chance that the pages can be read directly from main memory with + * the GPU. + * + * 2. All I915_CACHE_NONE objects have @cache_dirty initially true. + * + * 3. All swapped-out objects(i.e shmem) have @cache_dirty set to + * true. + * + * 4. The @cache_dirty is never freely reset before the initial + * flush, even if userspace adjusts the @cache_level through the + * i915_gem_set_caching_ioctl. + * + * 5. All @cache_dirty objects(including swapped-in) are initially + * flushed with a synchronous call to drm_clflush_sg in + * __i915_gem_object_set_pages. The @cache_dirty can be freely reset + * at this point. All further asynchronous clfushes are never security + * critical, i.e userspace is free to race against itself. */ unsigned int cache_dirty:1; From 3884d8af9b3fcc0c41f04fbd4131be61101d4a4d Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:07 +0100 Subject: [PATCH 465/554] drm/i915: mark up internal objects with start_cpu_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the pages can't be swapped out, they can be discarded by the shrinker. Normally such objects are marked with __I915_MADV_PURGED, which can't be unset, and therefore requires a new object. For kernel internal objects this is not true, since the madv hint is reset for our special volatile objects, such that we can re-acquire new pages, if so desired, without needing a new object. As a result we should probably be paranoid here and put the object back into the CPU domain when discarding the pages, and also correctly set cache_dirty, if required. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-8-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index e5ae9c06510c..a57a6b7013c2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -134,6 +134,8 @@ static void i915_gem_object_put_pages_internal(struct drm_i915_gem_object *obj, internal_free_pages(pages); obj->mm.dirty = false; + + __start_cpu_write(obj); } static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = { From ab5d964c001b9efffcbfa4d67a30186b67d79771 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 18 Oct 2021 18:45:08 +0100 Subject: [PATCH 466/554] drm/i915/selftests: mark up hugepages object with start_cpu_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like we do for internal objects. Also just use i915_gem_object_set_cache_coherency() here. No need for over-flushing on LLC platforms. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20211018174508.2137279-9-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/selftests/huge_pages.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 41d0680f3bd7..b2003133deaf 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -136,6 +136,8 @@ static void put_huge_pages(struct drm_i915_gem_object *obj, huge_pages_free_pages(pages); obj->mm.dirty = false; + + __start_cpu_write(obj); } static const struct drm_i915_gem_object_ops huge_page_ops = { @@ -152,6 +154,7 @@ huge_pages_object(struct drm_i915_private *i915, { static struct lock_class_key lock_class; struct drm_i915_gem_object *obj; + unsigned int cache_level; GEM_BUG_ON(!size); GEM_BUG_ON(!IS_ALIGNED(size, BIT(__ffs(page_mask)))); @@ -173,7 +176,9 @@ huge_pages_object(struct drm_i915_private *i915, obj->write_domain = I915_GEM_DOMAIN_CPU; obj->read_domains = I915_GEM_DOMAIN_CPU; - obj->cache_level = I915_CACHE_NONE; + + cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE; + i915_gem_object_set_cache_coherency(obj, cache_level); obj->mm.page_mask = page_mask; From f8546caa41ddab1c7c2c23b47331c40e93b1bf60 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Thu, 14 Oct 2021 16:51:33 +0800 Subject: [PATCH 467/554] drm/msm: Fix missing include files in msm_gem.c Include linux/vmalloc.h to fix below errors: error: implicit declaration of function 'vmap' Signed-off-by: Yanteng Si Link: https://lore.kernel.org/r/15f30165e94574e4cd7c4da9f9c6fd1e320d4d8e.1634200323.git.siyanteng@loongson.cn Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index bd6ec04f345e..6b03e00cc5f2 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include From 89e56d5ed1f729b7b80e74ea972f1d89d26f41c4 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Thu, 14 Oct 2021 16:51:34 +0800 Subject: [PATCH 468/554] drm/msm: Fix missing include files in msm_gem_shrinker.c Include linux/vmalloc.h to fix below errors: error: implicit declaration of function 'register_vmap_purge_notifier' error: implicit declaration of function 'unregister_vmap_purge_notifier' Signed-off-by: Yanteng Si Link: https://lore.kernel.org/r/f270502946fa411cc85c18fc252e5ddbeaf9c2f5.1634200323.git.siyanteng@loongson.cn Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_shrinker.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 0f1b29ee04a9..4a1420b05e97 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -4,6 +4,8 @@ * Author: Rob Clark */ +#include + #include "msm_drv.h" #include "msm_gem.h" #include "msm_gpu.h" From 31b3b1f5e35252b255f2a0d6a3883b09b5c4af97 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 15 Oct 2021 03:10:59 +0300 Subject: [PATCH 469/554] drm/msm/hdmi: use bulk regulator API Switch to using bulk regulator API instead of hand coding loops. Signed-off-by: Dmitry Baryshkov Reviewed-by: Stephen Boyd Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20211015001100.4193241-1-dmitry.baryshkov@linaro.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi.c | 34 +++++++---------------- drivers/gpu/drm/msm/hdmi/hdmi.h | 6 ++-- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 20 ++++--------- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 24 ++++++---------- drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 33 ++++++++-------------- 5 files changed, 40 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 5ba7c8f28419..75b64e6ae035 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -152,19 +152,13 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) ret = -ENOMEM; goto fail; } - for (i = 0; i < config->hpd_reg_cnt; i++) { - struct regulator *reg; + for (i = 0; i < config->hpd_reg_cnt; i++) + hdmi->hpd_regs[i].supply = config->hpd_reg_names[i]; - reg = devm_regulator_get(&pdev->dev, - config->hpd_reg_names[i]); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } - - hdmi->hpd_regs[i] = reg; + ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs); + if (ret) { + DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %d\n", ret); + goto fail; } hdmi->pwr_regs = devm_kcalloc(&pdev->dev, @@ -175,19 +169,11 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) ret = -ENOMEM; goto fail; } - for (i = 0; i < config->pwr_reg_cnt; i++) { - struct regulator *reg; - reg = devm_regulator_get(&pdev->dev, - config->pwr_reg_names[i]); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %s (%d)\n", - config->pwr_reg_names[i], ret); - goto fail; - } - - hdmi->pwr_regs[i] = reg; + ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); + if (ret) { + DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret); + goto fail; } hdmi->hpd_clks = devm_kcalloc(&pdev->dev, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index d0b84f0abee1..82261078c6b1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -56,8 +56,8 @@ struct hdmi { void __iomem *qfprom_mmio; phys_addr_t mmio_phy_addr; - struct regulator **hpd_regs; - struct regulator **pwr_regs; + struct regulator_bulk_data *hpd_regs; + struct regulator_bulk_data *pwr_regs; struct clk **hpd_clks; struct clk **pwr_clks; @@ -163,7 +163,7 @@ struct hdmi_phy { void __iomem *mmio; struct hdmi_phy_cfg *cfg; const struct hdmi_phy_funcs *funcs; - struct regulator **regs; + struct regulator_bulk_data *regs; struct clk **clks; }; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 6e380db9287b..f04eb4a70f0d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -28,13 +28,9 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge) pm_runtime_get_sync(&hdmi->pdev->dev); - for (i = 0; i < config->pwr_reg_cnt; i++) { - ret = regulator_enable(hdmi->pwr_regs[i]); - if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %s (%d)\n", - config->pwr_reg_names[i], ret); - } - } + ret = regulator_bulk_enable(config->pwr_reg_cnt, hdmi->pwr_regs); + if (ret) + DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %d\n", ret); if (config->pwr_clk_cnt > 0) { DBG("pixclock: %lu", hdmi->pixclock); @@ -70,13 +66,9 @@ static void power_off(struct drm_bridge *bridge) for (i = 0; i < config->pwr_clk_cnt; i++) clk_disable_unprepare(hdmi->pwr_clks[i]); - for (i = 0; i < config->pwr_reg_cnt; i++) { - ret = regulator_disable(hdmi->pwr_regs[i]); - if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %s (%d)\n", - config->pwr_reg_names[i], ret); - } - } + ret = regulator_bulk_disable(config->pwr_reg_cnt, hdmi->pwr_regs); + if (ret) + DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %d\n", ret); pm_runtime_put_autosuspend(&hdmi->pdev->dev); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 58707a1f3878..a7f729cdec7b 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -146,16 +146,13 @@ int msm_hdmi_hpd_enable(struct drm_connector *connector) const struct hdmi_platform_config *config = hdmi->config; struct device *dev = &hdmi->pdev->dev; uint32_t hpd_ctrl; - int i, ret; + int ret; unsigned long flags; - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_enable(hdmi->hpd_regs[i]); - if (ret) { - DRM_DEV_ERROR(dev, "failed to enable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } + ret = regulator_bulk_enable(config->hpd_reg_cnt, hdmi->hpd_regs); + if (ret) { + DRM_DEV_ERROR(dev, "failed to enable hpd regulators: %d\n", ret); + goto fail; } ret = pinctrl_pm_select_default_state(dev); @@ -207,7 +204,7 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) struct hdmi *hdmi = hdmi_connector->hdmi; const struct hdmi_platform_config *config = hdmi->config; struct device *dev = &hdmi->pdev->dev; - int i, ret = 0; + int ret; /* Disable HPD interrupt */ hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); @@ -225,12 +222,9 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) if (ret) dev_warn(dev, "pinctrl state chg failed: %d\n", ret); - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_disable(hdmi->hpd_regs[i]); - if (ret) - dev_warn(dev, "failed to disable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - } + ret = regulator_bulk_disable(config->hpd_reg_cnt, hdmi->hpd_regs); + if (ret) + dev_warn(dev, "failed to disable hpd regulator: %d\n", ret); } static void diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 8a38d4b95102..16b0e8836d27 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -23,22 +23,15 @@ static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy) if (!phy->clks) return -ENOMEM; - for (i = 0; i < cfg->num_regs; i++) { - struct regulator *reg; + for (i = 0; i < cfg->num_regs; i++) + phy->regs[i].supply = cfg->reg_names[i]; - reg = devm_regulator_get(dev, cfg->reg_names[i]); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - if (ret != -EPROBE_DEFER) { - DRM_DEV_ERROR(dev, - "failed to get phy regulator: %s (%d)\n", - cfg->reg_names[i], ret); - } + ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs); + if (ret) { + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret); - return ret; - } - - phy->regs[i] = reg; + return ret; } for (i = 0; i < cfg->num_clks; i++) { @@ -66,11 +59,10 @@ int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy) pm_runtime_get_sync(dev); - for (i = 0; i < cfg->num_regs; i++) { - ret = regulator_enable(phy->regs[i]); - if (ret) - DRM_DEV_ERROR(dev, "failed to enable regulator: %s (%d)\n", - cfg->reg_names[i], ret); + ret = regulator_bulk_enable(cfg->num_regs, phy->regs); + if (ret) { + DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret); + return ret; } for (i = 0; i < cfg->num_clks; i++) { @@ -92,8 +84,7 @@ void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy) for (i = cfg->num_clks - 1; i >= 0; i--) clk_disable_unprepare(phy->clks[i]); - for (i = cfg->num_regs - 1; i >= 0; i--) - regulator_disable(phy->regs[i]); + regulator_bulk_disable(cfg->num_regs, phy->regs); pm_runtime_put_sync(dev); } From 78d9b458cc211fefb656beaebf938cb143a75bb7 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Tue, 19 Oct 2021 15:48:22 -0700 Subject: [PATCH 470/554] drm/msm/dpu: Add CRC support for DPU Add CRC support to DPU, which is currently not supported by this driver. Only supports CRC for CRTC for now, but will extend support to other blocks later on. Changes in v2: - Added kfree() calls for return paths in dpu_crtc_get_crc() - Propogated error code for dpu_crtc_get_crc() - Renamed skip_count - Removed dpu_crtc_is_valid_crc_source() - Removed wait for commit in dpu_crtc_set_crc_source() - Moved crc_source from struct dpu_crtc to struct dpu_crtc_state - Moved CRC register constants from dpu_hw_util.h to dpu_hw_lm.c Validated with IGT kms_pipe_crc_basic, and kms_cursor_crc Test: kms_pipe_crc_basic Subtests Passed: - bad-source - read-crc-pipe-A - read-crc-pipe-A-frame-sequence - nonblocking-crc-pipe-A - nonblocking-crc-pipe-A-frame-sequence - disable-crc-after-crtc-pipe-A[1] - compare-crc-sanitycheck-pipe-A[1] Rest skipped Test: kms_cursor_crc Subtests Passed: - pipe-A-cursor-size-change - pipe-A-cursor-alpha-opaque - pipe-A-cursor-alpha-transparent Subtests Failed: - pipe-A-cursor-dpms - pipe-A-cursor-*-onscreen - pipe-A-cursor-*-offscreen Rest skipped Tested on Qualcomm RB3 (debian, sdm845), Qualcomm RB5 (debian, qrb5165) Reported-by: kernel test robot Signed-off-by: Jessica Zhang [1] Skipped on RB5 due to issue related to DPMS. Planning to upload a fix for this in the future. Link: https://lore.kernel.org/r/20211019224822.25940-1-jesszhan@codeaurora.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 153 +++++++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 19 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c | 56 ++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h | 13 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 3 +- 5 files changed, 239 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index eecfa88517e0..e91568d4f09a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark */ @@ -70,6 +70,102 @@ static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) return NULL; } +static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) +{ + if (!src_name || + !strcmp(src_name, "none")) + return DPU_CRTC_CRC_SOURCE_NONE; + if (!strcmp(src_name, "auto") || + !strcmp(src_name, "lm")) + return DPU_CRTC_CRC_SOURCE_LAYER_MIXER; + + return DPU_CRTC_CRC_SOURCE_INVALID; +} + +static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, + const char *src_name, size_t *values_cnt) +{ + enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); + struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); + + if (source < 0) { + DRM_DEBUG_DRIVER("Invalid source %s for CRTC%d\n", src_name, crtc->index); + return -EINVAL; + } + + if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) + *values_cnt = crtc_state->num_mixers; + + return 0; +} + +static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) +{ + enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); + enum dpu_crtc_crc_source current_source; + struct drm_crtc_commit *commit; + struct dpu_crtc_state *crtc_state; + struct drm_device *drm_dev = crtc->dev; + struct dpu_crtc_mixer *m; + + bool was_enabled; + bool enable = false; + int i, ret = 0; + + if (source < 0) { + DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index); + return -EINVAL; + } + + ret = drm_modeset_lock(&crtc->mutex, NULL); + + if (ret) + return ret; + + enable = (source != DPU_CRTC_CRC_SOURCE_NONE); + crtc_state = to_dpu_crtc_state(crtc->state); + + spin_lock_irq(&drm_dev->event_lock); + current_source = crtc_state->crc_source; + spin_unlock_irq(&drm_dev->event_lock); + + was_enabled = (current_source != DPU_CRTC_CRC_SOURCE_NONE); + + if (!was_enabled && enable) { + ret = drm_crtc_vblank_get(crtc); + + if (ret) + goto cleanup; + + } else if (was_enabled && !enable) { + drm_crtc_vblank_put(crtc); + } + + spin_lock_irq(&drm_dev->event_lock); + crtc_state->crc_source = source; + spin_unlock_irq(&drm_dev->event_lock); + + crtc_state->crc_frame_skip_count = 0; + + for (i = 0; i < crtc_state->num_mixers; ++i) { + m = &crtc_state->mixers[i]; + + if (!m->hw_lm || !m->hw_lm->ops.setup_misr) + continue; + + /* Calculate MISR over 1 frame */ + m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); + } + + +cleanup: + if (commit) + drm_crtc_commit_put(commit); + drm_modeset_unlock(&crtc->mutex); + + return ret; +} + static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) { struct drm_encoder *encoder = get_encoder_from_crtc(crtc); @@ -81,6 +177,56 @@ static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) return dpu_encoder_get_vsync_count(encoder); } + +static int dpu_crtc_get_crc(struct drm_crtc *crtc) +{ + struct dpu_crtc_state *crtc_state; + struct dpu_crtc_mixer *m; + u32 *crcs; + + int i = 0; + int rc = 0; + + if (!crtc) { + DPU_ERROR("Invalid crtc\n"); + return -EINVAL; + } + + crtc_state = to_dpu_crtc_state(crtc->state); + crcs = kcalloc(crtc_state->num_mixers, sizeof(*crcs), GFP_KERNEL); + + if (!crcs) + return -ENOMEM; + + /* Skip first 2 frames in case of "uncooked" CRCs */ + if (crtc_state->crc_frame_skip_count < 2) { + crtc_state->crc_frame_skip_count++; + goto cleanup; + } + + for (i = 0; i < crtc_state->num_mixers; ++i) { + + m = &crtc_state->mixers[i]; + + if (!m->hw_lm || !m->hw_lm->ops.collect_misr) + continue; + + rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]); + + if (rc) { + DRM_DEBUG_DRIVER("MISR read failed\n"); + goto cleanup; + } + } + + rc = drm_crtc_add_crc_entry(crtc, true, + drm_crtc_accurate_vblank_count(crtc), crcs); + +cleanup: + kfree(crcs); + return rc; +} + static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos, @@ -387,6 +533,9 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc) dpu_crtc->vblank_cb_time = ktime_get(); else dpu_crtc->vblank_cb_count++; + + dpu_crtc_get_crc(crtc); + drm_crtc_handle_vblank(crtc); trace_dpu_crtc_vblank_cb(DRMID(crtc)); } @@ -1330,6 +1479,8 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = { .atomic_destroy_state = dpu_crtc_destroy_state, .late_register = dpu_crtc_late_register, .early_unregister = dpu_crtc_early_unregister, + .verify_crc_source = dpu_crtc_verify_crc_source, + .set_crc_source = dpu_crtc_set_crc_source, .enable_vblank = msm_crtc_enable_vblank, .disable_vblank = msm_crtc_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index cec3474340e8..ae9546ca1359 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark */ @@ -69,6 +69,19 @@ struct dpu_crtc_smmu_state_data { uint32_t transition_error; }; +/** + * enum dpu_crtc_crc_source: CRC source + * @DPU_CRTC_CRC_SOURCE_NONE: no source set + * @DPU_CRTC_CRC_SOURCE_LAYER_MIXER: CRC in layer mixer + * @DPU_CRTC_CRC_SOURCE_INVALID: Invalid source + */ +enum dpu_crtc_crc_source { + DPU_CRTC_CRC_SOURCE_NONE = 0, + DPU_CRTC_CRC_SOURCE_LAYER_MIXER, + DPU_CRTC_CRC_SOURCE_MAX, + DPU_CRTC_CRC_SOURCE_INVALID = -1 +}; + /** * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC * @hw_lm: LM HW Driver context @@ -139,6 +152,7 @@ struct dpu_crtc_frame_event { * @event_lock : Spinlock around event handling code * @phandle: Pointer to power handler * @cur_perf : current performance committed to clock/bandwidth driver + * @crc_source : CRC source */ struct dpu_crtc { struct drm_crtc base; @@ -210,6 +224,9 @@ struct dpu_crtc_state { u32 num_ctls; struct dpu_hw_ctl *hw_ctls[CRTC_DUAL_MIXERS]; + + enum dpu_crtc_crc_source crc_source; + int crc_frame_skip_count; }; #define to_dpu_crtc_state(x) \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index cb6bb7a22c15..86363c0ec834 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #include "dpu_kms.h" @@ -24,6 +25,15 @@ #define LM_BLEND0_FG_ALPHA 0x04 #define LM_BLEND0_BG_ALPHA 0x08 +#define LM_MISR_CTRL 0x310 +#define LM_MISR_SIGNATURE 0x314 +#define LM_MISR_FRAME_COUNT_MASK 0xFF +#define LM_MISR_CTRL_ENABLE BIT(8) +#define LM_MISR_CTRL_STATUS BIT(9) +#define LM_MISR_CTRL_STATUS_CLEAR BIT(10) +#define LM_MISR_CTRL_FREE_RUN_MASK BIT(31) + + static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer, const struct dpu_mdss_cfg *m, void __iomem *addr, @@ -96,6 +106,48 @@ static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx, } } +static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 config = 0; + + DPU_REG_WRITE(c, LM_MISR_CTRL, LM_MISR_CTRL_STATUS_CLEAR); + + /* Clear old MISR value (in case it's read before a new value is calculated)*/ + wmb(); + + if (enable) { + config = (frame_count & LM_MISR_FRAME_COUNT_MASK) | + LM_MISR_CTRL_ENABLE | LM_MISR_CTRL_FREE_RUN_MASK; + + DPU_REG_WRITE(c, LM_MISR_CTRL, config); + } else { + DPU_REG_WRITE(c, LM_MISR_CTRL, 0); + } + +} + +static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 ctrl = 0; + + if (!misr_value) + return -EINVAL; + + ctrl = DPU_REG_READ(c, LM_MISR_CTRL); + + if (!(ctrl & LM_MISR_CTRL_ENABLE)) + return -EINVAL; + + if (!(ctrl & LM_MISR_CTRL_STATUS)) + return -EINVAL; + + *misr_value = DPU_REG_READ(c, LM_MISR_SIGNATURE); + + return 0; +} + static void dpu_hw_lm_setup_blend_config_sdm845(struct dpu_hw_mixer *ctx, u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) { @@ -158,6 +210,8 @@ static void _setup_mixer_ops(const struct dpu_mdss_cfg *m, ops->setup_blend_config = dpu_hw_lm_setup_blend_config; ops->setup_alpha_out = dpu_hw_lm_setup_color3; ops->setup_border_color = dpu_hw_lm_setup_border_color; + ops->setup_misr = dpu_hw_lm_setup_misr; + ops->collect_misr = dpu_hw_lm_collect_misr; } struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 4a6b2de19ef6..d8052fb2d5da 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _DPU_HW_LM_H @@ -53,6 +54,16 @@ struct dpu_hw_lm_ops { void (*setup_border_color)(struct dpu_hw_mixer *ctx, struct dpu_mdss_color *color, u8 border_en); + + /** + * setup_misr: Enable/disable MISR + */ + void (*setup_misr)(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count); + + /** + * collect_misr: Read MISR signature + */ + int (*collect_misr)(struct dpu_hw_mixer *ctx, u32 *misr_value); }; struct dpu_hw_mixer { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index ff3cffde84cd..6d4911957e33 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _DPU_HW_UTIL_H From 6427f5d05e7f82945a26a3ccfb4d4340daeb2d4d Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Sun, 17 Oct 2021 16:43:50 +0200 Subject: [PATCH 471/554] dt-bindings: drm/msm/gpu: convert to YAML Conversion of text binding for Adreno GPU to the YAML format. Signed-off-by: David Heidelberg Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211017144350.70295-1-david@ixit.cz Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/gpu.txt | 157 ---------- .../devicetree/bindings/display/msm/gpu.yaml | 288 ++++++++++++++++++ 2 files changed, 288 insertions(+), 157 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/gpu.txt create mode 100644 Documentation/devicetree/bindings/display/msm/gpu.yaml diff --git a/Documentation/devicetree/bindings/display/msm/gpu.txt b/Documentation/devicetree/bindings/display/msm/gpu.txt deleted file mode 100644 index 090dcb3fc34d..000000000000 --- a/Documentation/devicetree/bindings/display/msm/gpu.txt +++ /dev/null @@ -1,157 +0,0 @@ -Qualcomm adreno/snapdragon GPU - -Required properties: -- compatible: "qcom,adreno-XYZ.W", "qcom,adreno" or - "amd,imageon-XYZ.W", "amd,imageon" - for example: "qcom,adreno-306.0", "qcom,adreno" - Note that you need to list the less specific "qcom,adreno" (since this - is what the device is matched on), in addition to the more specific - with the chip-id. - If "amd,imageon" is used, there should be no top level msm device. -- reg: Physical base address and length of the controller's registers. -- interrupts: The interrupt signal from the gpu. -- clocks: device clocks (if applicable) - See ../clocks/clock-bindings.txt for details. -- clock-names: the following clocks are required by a3xx, a4xx and a5xx - cores: - * "core" - * "iface" - * "mem_iface" - For GMU attached devices the GPU clocks are not used and are not required. The - following devices should not list clocks: - - qcom,adreno-630.2 -- iommus: optional phandle to an adreno iommu instance -- operating-points-v2: optional phandle to the OPP operating points -- interconnects: optional phandle to an interconnect provider. See - ../interconnect/interconnect.txt for details. Some A3xx and all A4xx platforms - will have two paths; all others will have one path. -- interconnect-names: The names of the interconnect paths that correspond to the - interconnects property. Values must be gfx-mem and ocmem. -- qcom,gmu: For GMU attached devices a phandle to the GMU device that will - control the power for the GPU. Applicable targets: - - qcom,adreno-630.2 -- zap-shader: For a5xx and a6xx devices this node contains a memory-region that - points to reserved memory to store the zap shader that can be used to help - bring the GPU out of secure mode. -- firmware-name: optional property of the 'zap-shader' node, listing the - relative path of the device specific zap firmware. -- sram: phandle to the On Chip Memory (OCMEM) that's present on some a3xx and - a4xx Snapdragon SoCs. See - Documentation/devicetree/bindings/sram/qcom,ocmem.yaml. - -Optional properties: -- #cooling-cells: The value must be 2. For details, please refer - Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml. - -Example 3xx/4xx: - -/ { - ... - - gpu: adreno@fdb00000 { - compatible = "qcom,adreno-330.2", - "qcom,adreno"; - reg = <0xfdb00000 0x10000>; - reg-names = "kgsl_3d0_reg_memory"; - interrupts = ; - interrupt-names = "kgsl_3d0_irq"; - clock-names = "core", - "iface", - "mem_iface"; - clocks = <&mmcc OXILI_GFX3D_CLK>, - <&mmcc OXILICX_AHB_CLK>, - <&mmcc OXILICX_AXI_CLK>; - sram = <&gpu_sram>; - power-domains = <&mmcc OXILICX_GDSC>; - operating-points-v2 = <&gpu_opp_table>; - iommus = <&gpu_iommu 0>; - #cooling-cells = <2>; - }; - - gpu_sram: ocmem@fdd00000 { - compatible = "qcom,msm8974-ocmem"; - - reg = <0xfdd00000 0x2000>, - <0xfec00000 0x180000>; - reg-names = "ctrl", - "mem"; - - clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>, - <&mmcc OCMEMCX_OCMEMNOC_CLK>; - clock-names = "core", - "iface"; - - #address-cells = <1>; - #size-cells = <1>; - - gpu_sram: gpu-sram@0 { - reg = <0x0 0x100000>; - ranges = <0 0 0xfec00000 0x100000>; - }; - }; -}; - -Example a6xx (with GMU): - -/ { - ... - - gpu@5000000 { - compatible = "qcom,adreno-630.2", "qcom,adreno"; - #stream-id-cells = <16>; - - reg = <0x5000000 0x40000>, <0x509e000 0x10>; - reg-names = "kgsl_3d0_reg_memory", "cx_mem"; - - #cooling-cells = <2>; - - /* - * Look ma, no clocks! The GPU clocks and power are - * controlled entirely by the GMU - */ - - interrupts = ; - - iommus = <&adreno_smmu 0>; - - operating-points-v2 = <&gpu_opp_table>; - - interconnects = <&rsc_hlos MASTER_GFX3D &rsc_hlos SLAVE_EBI1>; - interconnect-names = "gfx-mem"; - - gpu_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-430000000 { - opp-hz = /bits/ 64 <430000000>; - opp-level = ; - opp-peak-kBps = <5412000>; - }; - - opp-355000000 { - opp-hz = /bits/ 64 <355000000>; - opp-level = ; - opp-peak-kBps = <3072000>; - }; - - opp-267000000 { - opp-hz = /bits/ 64 <267000000>; - opp-level = ; - opp-peak-kBps = <3072000>; - }; - - opp-180000000 { - opp-hz = /bits/ 64 <180000000>; - opp-level = ; - opp-peak-kBps = <1804000>; - }; - }; - - qcom,gmu = <&gmu>; - - zap-shader { - memory-region = <&zap_shader_region>; - firmware-name = "qcom/LENOVO/81JL/qcdxkmsuc850.mbn" - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml new file mode 100644 index 000000000000..99a1ba3ada56 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -0,0 +1,288 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: "http://devicetree.org/schemas/display/msm/gpu.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Devicetree bindings for the Adreno or Snapdragon GPUs + +maintainers: + - Rob Clark + +properties: + compatible: + oneOf: + - description: | + The driver is parsing the compat string for Adreno to + figure out the gpu-id and patch level. + items: + - pattern: '^qcom,adreno-[3-6][0-9][0-9]\.[0-9]$' + - const: qcom,adreno + - description: | + The driver is parsing the compat string for Imageon to + figure out the gpu-id and patch level. + items: + - pattern: '^amd,imageon-200\.[0-1]$' + - const: amd,imageon + + clocks: true + + clock-names: true + + reg: + minItems: 1 + maxItems: 3 + + reg-names: + minItems: 1 + items: + - const: kgsl_3d0_reg_memory + - const: cx_mem + - const: cx_dbgc + + interrupts: + maxItems: 1 + + interrupt-names: + maxItems: 1 + + interconnects: + minItems: 1 + maxItems: 2 + + interconnect-names: + minItems: 1 + items: + - const: gfx-mem + - const: ocmem + + iommus: + maxItems: 1 + + sram: + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + maxItems: 4 + description: | + phandles to one or more reserved on-chip SRAM regions. + phandle to the On Chip Memory (OCMEM) that's present on some a3xx and + a4xx Snapdragon SoCs. See + Documentation/devicetree/bindings/sram/qcom,ocmem.yaml + + operating-points-v2: true + opp-table: + type: object + + power-domains: + maxItems: 1 + + zap-shader: + type: object + description: | + For a5xx and a6xx devices this node contains a memory-region that + points to reserved memory to store the zap shader that can be used to + help bring the GPU out of secure mode. + properties: + memory-region: + $ref: /schemas/types.yaml#/definitions/phandle + + firmware-name: + description: | + Default name of the firmware to load to the remote processor. + + "#cooling-cells": + const: 2 + + nvmem-cell-names: + maxItems: 1 + + nvmem-cells: + description: efuse registers + maxItems: 1 + + qcom,gmu: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + For GMU attached devices a phandle to the GMU device that will + control the power for the GPU. + + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + pattern: '^qcom,adreno-[3-5][0-9][0-9]\.[0-9]$' + + then: + properties: + clocks: + minItems: 2 + maxItems: 7 + + clock-names: + items: + anyOf: + - const: core + description: GPU Core clock + - const: iface + description: GPU Interface clock + - const: mem + description: GPU Memory clock + - const: mem_iface + description: GPU Memory Interface clock + - const: alt_mem_iface + description: GPU Alternative Memory Interface clock + - const: gfx3d + description: GPU 3D engine clock + - const: rbbmtimer + description: GPU RBBM Timer for Adreno 5xx series + minItems: 2 + maxItems: 7 + + required: + - clocks + - clock-names + - if: + properties: + compatible: + contains: + pattern: '^qcom,adreno-6[0-9][0-9]\.[0-9]$' + + then: # Since Adreno 6xx series clocks should be defined in GMU + properties: + clocks: false + clock-names: false + +examples: + - | + + // Example a3xx/4xx: + + #include + #include + #include + #include + + gpu: gpu@fdb00000 { + compatible = "qcom,adreno-330.2", "qcom,adreno"; + + reg = <0xfdb00000 0x10000>; + reg-names = "kgsl_3d0_reg_memory"; + + clock-names = "core", "iface", "mem_iface"; + clocks = <&mmcc OXILI_GFX3D_CLK>, + <&mmcc OXILICX_AHB_CLK>, + <&mmcc OXILICX_AXI_CLK>; + + interrupts = ; + interrupt-names = "kgsl_3d0_irq"; + + sram = <&gpu_sram>; + power-domains = <&mmcc OXILICX_GDSC>; + operating-points-v2 = <&gpu_opp_table>; + iommus = <&gpu_iommu 0>; + #cooling-cells = <2>; + }; + + ocmem@fdd00000 { + compatible = "qcom,msm8974-ocmem"; + + reg = <0xfdd00000 0x2000>, + <0xfec00000 0x180000>; + reg-names = "ctrl", "mem"; + + clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>, + <&mmcc OCMEMCX_OCMEMNOC_CLK>; + clock-names = "core", "iface"; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xfec00000 0x100000>; + + gpu_sram: gpu-sram@0 { + reg = <0x0 0x100000>; + }; + }; + - | + + // Example a6xx (with GMU): + + #include + #include + #include + #include + #include + #include + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + + zap_shader_region: gpu@8f200000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x90b00000 0x0 0xa00000>; + no-map; + }; + }; + + gpu@5000000 { + compatible = "qcom,adreno-630.2", "qcom,adreno"; + + reg = <0x5000000 0x40000>, <0x509e000 0x10>; + reg-names = "kgsl_3d0_reg_memory", "cx_mem"; + + #cooling-cells = <2>; + + interrupts = ; + + iommus = <&adreno_smmu 0>; + + operating-points-v2 = <&gpu_opp_table>; + + interconnects = <&rsc_hlos MASTER_GFX3D &rsc_hlos SLAVE_EBI1>; + interconnect-names = "gfx-mem"; + + qcom,gmu = <&gmu>; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-430000000 { + opp-hz = /bits/ 64 <430000000>; + opp-level = ; + opp-peak-kBps = <5412000>; + }; + + opp-355000000 { + opp-hz = /bits/ 64 <355000000>; + opp-level = ; + opp-peak-kBps = <3072000>; + }; + + opp-267000000 { + opp-hz = /bits/ 64 <267000000>; + opp-level = ; + opp-peak-kBps = <3072000>; + }; + + opp-180000000 { + opp-hz = /bits/ 64 <180000000>; + opp-level = ; + opp-peak-kBps = <1804000>; + }; + }; + + zap-shader { + memory-region = <&zap_shader_region>; + firmware-name = "qcom/LENOVO/81JL/qcdxkmsuc850.mbn"; + }; + }; From 57fd4f34ddac61c9ef5ec7a3d91d58f590626c87 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Wed, 20 Oct 2021 19:28:50 +0530 Subject: [PATCH 472/554] dt-bindings: msm: add DT bindings for sc7280 MSM Mobile Display Subsystem (MDSS) encapsulates sub-blocks like DPU display controller, DSI, EDP etc. Add required DPU device tree bindings for SC7280. Signed-off-by: Krishna Manikandan Changes in v2: - Drop target from description (Stephen Boyd) - Drop items from compatible (Stephen Boyd) - Add clock names one per line for readability (Stephen Boyd) - Use correct indendation (Stephen Boyd) Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1634738333-3916-1-git-send-email-quic_mkrishn@quicinc.com Signed-off-by: Rob Clark --- .../bindings/display/msm/dpu-sc7280.yaml | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml new file mode 100644 index 000000000000..fbeb931a026e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml @@ -0,0 +1,232 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/dpu-sc7280.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for SC7280 + +maintainers: + - Krishna Manikandan + +description: | + Device tree bindings for MSM Mobile Display Subsystem (MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS and DPU are mentioned for SC7280. + +properties: + compatible: + const: qcom,sc7280-mdss + + reg: + maxItems: 1 + + reg-names: + const: mdss + + power-domains: + maxItems: 1 + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display AHB clock from dispcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: ahb + - const: core + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#address-cells": true + + "#size-cells": true + + "#interrupt-cells": + const: 1 + + iommus: + items: + - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 + + ranges: true + + interconnects: + items: + - description: Interconnect path specifying the port ids for data bus + + interconnect-names: + const: mdp0-mem + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + description: Node containing the properties of DPU. + + properties: + compatible: + const: qcom,sc7280-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display hf axi clock + - description: Display sf axi clock + - description: Display ahb clock + - description: Display lut clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: bus + - const: nrt_bus + - const: iface + - const: lut + - const: core + - const: vsync + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + operating-points-v2: true + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + Contains the list of output ports from DPU device. These ports + connect to interfaces that are external to the DPU hardware, + such as DSI, DP etc. Each output port contains an endpoint that + describes how it is connected to an external interface. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: DPU_INTF1 (DSI) + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: DPU_INTF5 (EDP) + + required: + - port@0 + + required: + - compatible + - reg + - reg-names + - clocks + - interrupts + - power-domains + - operating-points-v2 + - ports + +required: + - compatible + - reg + - reg-names + - power-domains + - clocks + - interrupts + - interrupt-controller + - iommus + - ranges + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,sc7280-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>; + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", + "ahb", + "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; + interconnect-names = "mdp0-mem"; + + iommus = <&apps_smmu 0x900 0x402>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sc7280-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", + "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SC7280_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf5_out: endpoint { + remote-endpoint = <&edp_in>; + }; + }; + }; + }; + }; +... From 8bf71a5719b6cc5b6ba358096081e5d50ea23ab6 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Wed, 20 Oct 2021 10:57:33 -0700 Subject: [PATCH 473/554] drm/msm: Fix potential NULL dereference in DPU SSPP Move initialization of sblk in _sspp_subblk_offset() after NULL check to avoid potential NULL pointer dereference. Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support") Reported-by: Dan Carpenter Signed-off-by: Jessica Zhang Link: https://lore.kernel.org/r/20211020175733.3379-1-jesszhan@codeaurora.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 69eed7932486..f9460672176a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -138,11 +138,13 @@ static int _sspp_subblk_offset(struct dpu_hw_pipe *ctx, u32 *idx) { int rc = 0; - const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk; + const struct dpu_sspp_sub_blks *sblk; - if (!ctx) + if (!ctx || !ctx->cap || !ctx->cap->sblk) return -EINVAL; + sblk = ctx->cap->sblk; + switch (s_id) { case DPU_SSPP_SRC: *idx = sblk->src_blk.base; @@ -419,7 +421,7 @@ static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe *ctx, (void)pe; if (_sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx) || !sspp - || !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk) + || !scaler3_cfg) return; dpu_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx, From 409af447c2a0a6e08ba190993a1153c91d3b11bd Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Wed, 20 Oct 2021 11:34:38 -0700 Subject: [PATCH 474/554] drm/msm/dsi: fix wrong type in msm_dsi_host Change byte_clk_rate, pixel_clk_rate, esc_clk_rate, and src_clk_rate from u32 to unsigned long, since clk_get_rate() returns an unsigned long. Fixes: a6bcddbc2ee1 ("drm/msm: dsi: Handle dual-channel for 6G as well") Reported-by: Dan Carpenter Signed-off-by: Jessica Zhang Link: https://lore.kernel.org/r/20211020183438.32263-1-jesszhan@codeaurora.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4b030a00fa79..f69a125f9559 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -116,16 +116,16 @@ struct msm_dsi_host { struct clk *pixel_clk_src; struct clk *byte_intf_clk; - u32 byte_clk_rate; - u32 pixel_clk_rate; - u32 esc_clk_rate; + unsigned long byte_clk_rate; + unsigned long pixel_clk_rate; + unsigned long esc_clk_rate; /* DSI v2 specific clocks */ struct clk *src_clk; struct clk *esc_clk_src; struct clk *dsi_clk_src; - u32 src_clk_rate; + unsigned long src_clk_rate; struct gpio_desc *disp_en_gpio; struct gpio_desc *te_gpio; @@ -463,10 +463,10 @@ int msm_dsi_runtime_resume(struct device *dev) int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) { - u32 byte_intf_rate; + unsigned long byte_intf_rate; int ret; - DBG("Set clk rates: pclk=%d, byteclk=%d", + DBG("Set clk rates: pclk=%d, byteclk=%lu", msm_host->mode->clock, msm_host->byte_clk_rate); ret = dev_pm_opp_set_rate(&msm_host->pdev->dev, @@ -546,7 +546,7 @@ int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) { int ret; - DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d", + DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", msm_host->mode->clock, msm_host->byte_clk_rate, msm_host->esc_clk_rate, msm_host->src_clk_rate); @@ -635,10 +635,10 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } -static u32 dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi) +static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi) { struct drm_display_mode *mode = msm_host->mode; - u32 pclk_rate; + unsigned long pclk_rate; pclk_rate = mode->clock * 1000; @@ -658,7 +658,7 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) { u8 lanes = msm_host->lanes; u32 bpp = dsi_get_bpp(msm_host->format); - u32 pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi); + unsigned long pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi); u64 pclk_bpp = (u64)pclk_rate * bpp; if (lanes == 0) { @@ -675,7 +675,7 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) msm_host->pixel_clk_rate = pclk_rate; msm_host->byte_clk_rate = pclk_bpp; - DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate, + DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate, msm_host->byte_clk_rate); } @@ -734,7 +734,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi) msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; - DBG("esc=%d, src=%d", msm_host->esc_clk_rate, + DBG("esc=%lu, src=%lu", msm_host->esc_clk_rate, msm_host->src_clk_rate); return 0; From ac82902df9cf448a9400ec5bb1416100b157a6c4 Mon Sep 17 00:00:00 2001 From: Vignesh Chander Date: Tue, 12 Oct 2021 22:07:17 -0400 Subject: [PATCH 475/554] drm/amd/pm: Enable GPU metrics for One VF mode Enable GPU metrics feature in one VF mode. These are only possible in one VF mode because the VF is dedicated in that case. Signed-off-by: Vignesh Chander Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index c255b4b8e685..01cca08a774f 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2019,15 +2019,15 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RW(pp_dpm_pcie, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(pp_sclk_od, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(pp_mclk_od, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RW(pp_power_profile_mode, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RW(pp_power_profile_mode, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RW(pp_od_clk_voltage, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RO(gpu_busy_percent, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RO(mem_busy_percent, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RO(gpu_busy_percent, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), + AMDGPU_DEVICE_ATTR_RO(mem_busy_percent, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RO(pcie_bw, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RW(pp_features, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RO(unique_id, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RW(thermal_throttling_logging, ATTR_FLAG_BASIC), - AMDGPU_DEVICE_ATTR_RO(gpu_metrics, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RW(pp_features, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), + AMDGPU_DEVICE_ATTR_RO(unique_id, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), + AMDGPU_DEVICE_ATTR_RW(thermal_throttling_logging, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), + AMDGPU_DEVICE_ATTR_RO(gpu_metrics, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RO(smartshift_apu_power, ATTR_FLAG_BASIC, .attr_update = ss_power_attr_update), AMDGPU_DEVICE_ATTR_RO(smartshift_dgpu_power, ATTR_FLAG_BASIC, From a61794bd2f657702fcafa26e14097beb17e6f9a6 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 19 Oct 2021 14:26:39 +0800 Subject: [PATCH 476/554] drm/amdgpu: remove grbm cam index/data operations for gfx v10 PSP firmware will be responsible for applying the GRBM CAM remapping in the production. And the GRBM_CAM_INDEX / GRBM_CAM_DATA registers will be protected by PSP under security policy. So remove it according to the new security policy. Signed-off-by: Huang Rui Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 8cec03949835..90a834dc4008 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -270,25 +270,6 @@ MODULE_FIRMWARE("amdgpu/cyan_skillfish2_mec.bin"); MODULE_FIRMWARE("amdgpu/cyan_skillfish2_mec2.bin"); MODULE_FIRMWARE("amdgpu/cyan_skillfish2_rlc.bin"); -static const struct soc15_reg_golden golden_settings_gc_10_0[] = -{ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_INDEX, 0xffffffff, 0x00000000), - /* TA_GRAD_ADJ_UCONFIG -> TA_GRAD_ADJ */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x2544c382), - /* VGT_TF_RING_SIZE_UMD -> VGT_TF_RING_SIZE */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x2262c24e), - /* VGT_HS_OFFCHIP_PARAM_UMD -> VGT_HS_OFFCHIP_PARAM */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x226cc24f), - /* VGT_TF_MEMORY_BASE_UMD -> VGT_TF_MEMORY_BASE */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x226ec250), - /* VGT_TF_MEMORY_BASE_HI_UMD -> VGT_TF_MEMORY_BASE_HI */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x2278c261), - /* VGT_ESGS_RING_SIZE_UMD -> VGT_ESGS_RING_SIZE */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x2232c240), - /* VGT_GSVS_RING_SIZE_UMD -> VGT_GSVS_RING_SIZE */ - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGRBM_CAM_DATA, 0xffffffff, 0x2233c241), -}; - static const struct soc15_reg_golden golden_settings_gc_10_1[] = { SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_4, 0xffffffff, 0x00400014), @@ -3809,9 +3790,6 @@ static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) (const u32)ARRAY_SIZE(golden_settings_gc_10_3_5)); break; case IP_VERSION(10, 1, 3): - soc15_program_register_sequence(adev, - golden_settings_gc_10_0, - (const u32)ARRAY_SIZE(golden_settings_gc_10_0)); soc15_program_register_sequence(adev, golden_settings_gc_10_0_cyan_skillfish, (const u32)ARRAY_SIZE(golden_settings_gc_10_0_cyan_skillfish)); From e77f0f5c6a66298b034c8e2021c5a0ece07235ac Mon Sep 17 00:00:00 2001 From: Jingwen Chen Date: Thu, 21 Oct 2021 16:46:14 +0800 Subject: [PATCH 477/554] drm/amd/amdgpu: add dummy_page_addr to sriov msg Add dummy_page_addr to sriov msg for host driver to set GCVM_L2_PROTECTION_DEFAULT_ADDR* registers correctly. v2: should update vf2pf msg instead Signed-off-by: Jingwen Chen Reviewed-by: Horace Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 88c4177b708a..99c149397aae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -584,6 +584,7 @@ static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev) vf2pf_info->encode_usage = 0; vf2pf_info->decode_usage = 0; + vf2pf_info->dummy_page_addr = (uint64_t)adev->dummy_page_addr; vf2pf_info->checksum = amd_sriov_msg_checksum( vf2pf_info, vf2pf_info->header.size, 0, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index 995899191288..7326b6c1b71c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -261,9 +261,10 @@ struct amd_sriov_msg_vf2pf_info { uint8_t id; uint32_t version; } ucode_info[AMD_SRIOV_MSG_RESERVE_UCODE]; + uint64_t dummy_page_addr; /* reserved */ - uint32_t reserved[256-68]; + uint32_t reserved[256-70]; }; /* mailbox message send from guest to host */ From 75fa98d6e458d0fb723c9c968c872cd4aa153049 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Fri, 15 Oct 2021 15:57:52 -0400 Subject: [PATCH 478/554] drm/amdkfd: clarify the origin of cpages returned by migration functions cpages is only updated by migrate_vma_setup. So capture its value at that point to clarify the significance of the number. The next patch will add counting of actually migrated pages after migrate_vma_pages for debug purposes. Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 43 ++++++++++++------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 147300a161d0..a14d0077e262 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -385,6 +385,7 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; struct migrate_vma migrate; + unsigned long cpages = 0; dma_addr_t *scratch; size_t size; void *buf; @@ -414,17 +415,17 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, goto out_free; } - if (migrate.cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", - migrate.cpages, npages); - else - pr_debug("0x%lx pages migrated\n", migrate.cpages); - - if (!migrate.cpages) { + cpages = migrate.cpages; + if (!cpages) { pr_debug("failed collect migrate sys pages [0x%lx 0x%lx]\n", prange->start, prange->last); goto out_free; } + if (cpages != npages) + pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + cpages, npages); + else + pr_debug("0x%lx pages migrated\n", cpages); r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, scratch); migrate_vma_pages(&migrate); @@ -437,12 +438,12 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, out_free: kvfree(buf); out: - if (!r && migrate.cpages) { + if (!r && cpages) { pdd = svm_range_get_pdd_by_adev(prange, adev); if (pdd) - WRITE_ONCE(pdd->page_in, pdd->page_in + migrate.cpages); + WRITE_ONCE(pdd->page_in, pdd->page_in + cpages); - return migrate.cpages; + return cpages; } return r; } @@ -619,6 +620,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; struct migrate_vma migrate; + unsigned long cpages = 0; dma_addr_t *scratch; size_t size; void *buf; @@ -648,17 +650,17 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, goto out_free; } - if (migrate.cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", - migrate.cpages, npages); - else - pr_debug("0x%lx pages migrated\n", migrate.cpages); - - if (!migrate.cpages) { + cpages = migrate.cpages; + if (!cpages) { pr_debug("failed collect migrate device pages [0x%lx 0x%lx]\n", prange->start, prange->last); goto out_free; } + if (cpages != npages) + pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + cpages, npages); + else + pr_debug("0x%lx pages migrated\n", cpages); r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, scratch, npages); @@ -670,13 +672,12 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, out_free: kvfree(buf); out: - if (!r && migrate.cpages) { + if (!r && cpages) { pdd = svm_range_get_pdd_by_adev(prange, adev); if (pdd) - WRITE_ONCE(pdd->page_out, - pdd->page_out + migrate.cpages); + WRITE_ONCE(pdd->page_out, pdd->page_out + cpages); - return migrate.cpages; + return cpages; } return r; } From 33c6bd989d5e483b6197f5b6a53c81f8a8f6a215 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Wed, 20 Oct 2021 17:26:49 -0400 Subject: [PATCH 479/554] drm/amdkfd: debug message to count successfully migrated pages Not all migrate.cpages returned from migrate_vma_setup can be migrated, for example non anonymous page, or out of device memory. So after migrate_vma_pages returns, add debug message to count pages are successfully migrated which has MIGRATE_PFN_VALID and MIGRATE_PFN_MIGRATE flag set. Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index a14d0077e262..6d8634e40b3b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -268,6 +268,19 @@ static void svm_migrate_put_sys_page(unsigned long addr) put_page(page); } +static unsigned long svm_migrate_successful_pages(struct migrate_vma *migrate) +{ + unsigned long cpages = 0; + unsigned long i; + + for (i = 0; i < migrate->npages; i++) { + if (migrate->src[i] & MIGRATE_PFN_VALID && + migrate->src[i] & MIGRATE_PFN_MIGRATE) + cpages++; + } + return cpages; +} + static int svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, struct migrate_vma *migrate, struct dma_fence **mfence, @@ -429,6 +442,10 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, scratch); migrate_vma_pages(&migrate); + + pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n", + svm_migrate_successful_pages(&migrate), cpages, migrate.npages); + svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(&migrate); @@ -665,6 +682,10 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, scratch, npages); migrate_vma_pages(&migrate); + + pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n", + svm_migrate_successful_pages(&migrate), cpages, migrate.npages); + svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(&migrate); svm_range_dma_unmap(adev->dev, scratch, 0, npages); From e8ac9e93b492e281e6051aac65024b580017f850 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Oct 2021 11:08:05 -0400 Subject: [PATCH 480/554] drm/amdgpu/vcn3.0: handle harvesting in firmware setup Only enable firmware for the instance that is enabled. v2: use AMDGPU_UCODE_ID_VCN + i Fixes: 1b592d00b4ac83 ("drm/amdgpu/vcn: remove manual instance setting") Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1743 Reviewed-by: James Zhu Reviewed-by: Leo Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index dbfd92984655..49752574a13c 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -123,6 +123,7 @@ static int vcn_v3_0_sw_init(void *handle) { struct amdgpu_ring *ring; int i, j, r; + unsigned int idx; int vcn_doorbell_index = 0; struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -133,14 +134,13 @@ static int vcn_v3_0_sw_init(void *handle) if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { const struct common_firmware_header *hdr; hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].ucode_id = AMDGPU_UCODE_ID_VCN; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - if (adev->vcn.num_vcn_inst == VCN_INSTANCES_SIENNA_CICHLID) { - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN1].ucode_id = AMDGPU_UCODE_ID_VCN1; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN1].fw = adev->vcn.fw; + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + idx = AMDGPU_UCODE_ID_VCN + i; + adev->firmware.ucode[idx].ucode_id = idx; + adev->firmware.ucode[idx].fw = adev->vcn.fw; adev->firmware.fw_size += ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); } From c5dd5667f4196b5b3b4bc2a83ad795850c08197f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Oct 2021 13:20:37 -0400 Subject: [PATCH 481/554] drm/amdgpu: Consolidate VCN firmware setup code Roughly the same code was present in all VCN versions. Consolidate it into a single function. v2: use AMDGPU_UCODE_ID_VCN + i, check if num_inst >= 2 Signed-off-by: Alex Deucher Reviewed-by: Leo Liu Reviewed-by: James Zhu --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 27 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 2 ++ drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 10 +-------- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 10 +-------- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 17 +--------------- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 17 +--------------- 6 files changed, 33 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index c7d316850570..2658414c503d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -949,3 +949,30 @@ enum amdgpu_ring_priority_level amdgpu_vcn_get_enc_ring_prio(int ring) return AMDGPU_RING_PRIO_0; } } + +void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev) +{ + int i; + unsigned int idx; + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + const struct common_firmware_header *hdr; + hdr = (const struct common_firmware_header *)adev->vcn.fw->data; + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + /* currently only support 2 FW instances */ + if (i >= 2) { + dev_info(adev->dev, "More then 2 VCN FW instances!\n"); + break; + } + idx = AMDGPU_UCODE_ID_VCN + i; + adev->firmware.ucode[idx].ucode_id = idx; + adev->firmware.ucode[idx].fw = adev->vcn.fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); + } + dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 795cbaa02ff8..bfa27ea94804 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -310,4 +310,6 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); enum amdgpu_ring_priority_level amdgpu_vcn_get_enc_ring_prio(int ring); +void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index ad0d2564087c..d54d720b3cf6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -111,15 +111,7 @@ static int vcn_v1_0_sw_init(void *handle) /* Override the work func */ adev->vcn.idle_work.work.func = vcn_v1_0_idle_work_handler; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - const struct common_firmware_header *hdr; - hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].ucode_id = AMDGPU_UCODE_ID_VCN; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); - } + amdgpu_vcn_setup_ucode(adev); r = amdgpu_vcn_resume(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 091d8c0f6801..3883df5b31ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -115,15 +115,7 @@ static int vcn_v2_0_sw_init(void *handle) if (r) return r; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - const struct common_firmware_header *hdr; - hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].ucode_id = AMDGPU_UCODE_ID_VCN; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); - } + amdgpu_vcn_setup_ucode(adev); r = amdgpu_vcn_resume(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 59f469bab005..44fc4c218433 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -139,22 +139,7 @@ static int vcn_v2_5_sw_init(void *handle) if (r) return r; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - const struct common_firmware_header *hdr; - hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].ucode_id = AMDGPU_UCODE_ID_VCN; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - - if (adev->vcn.num_vcn_inst == VCN25_MAX_HW_INSTANCES_ARCTURUS) { - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN1].ucode_id = AMDGPU_UCODE_ID_VCN1; - adev->firmware.ucode[AMDGPU_UCODE_ID_VCN1].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - } - dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); - } + amdgpu_vcn_setup_ucode(adev); r = amdgpu_vcn_resume(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 49752574a13c..57b62fb04750 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -123,7 +123,6 @@ static int vcn_v3_0_sw_init(void *handle) { struct amdgpu_ring *ring; int i, j, r; - unsigned int idx; int vcn_doorbell_index = 0; struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -131,21 +130,7 @@ static int vcn_v3_0_sw_init(void *handle) if (r) return r; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - const struct common_firmware_header *hdr; - hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - - for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - if (adev->vcn.harvest_config & (1 << i)) - continue; - idx = AMDGPU_UCODE_ID_VCN + i; - adev->firmware.ucode[idx].ucode_id = idx; - adev->firmware.ucode[idx].fw = adev->vcn.fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); - } - dev_info(adev->dev, "Will use PSP to load VCN firmware\n"); - } + amdgpu_vcn_setup_ucode(adev); r = amdgpu_vcn_resume(adev); if (r) From 7876c7ea14af692cecedb451c3601a20c19fe430 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Oct 2021 12:48:22 -0400 Subject: [PATCH 482/554] drm/amdgpu/vcn2.0: remove intermediate variable No need to use the tmp variable, just use the constant directly. Reviewed-by: Leo Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 3883df5b31ab..313fc1b53999 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -1876,15 +1876,14 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) /* mc resume*/ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - tmp = AMDGPU_UCODE_ID_VCN; MMSCH_V2_0_INSERT_DIRECT_WT( SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), - adev->firmware.ucode[tmp].tmr_mc_addr_lo); + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); MMSCH_V2_0_INSERT_DIRECT_WT( SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), - adev->firmware.ucode[tmp].tmr_mc_addr_hi); + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); offset = 0; } else { MMSCH_V2_0_INSERT_DIRECT_WT( From 47be978be0e6010479c13e30c80124d47f8b97a3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Oct 2021 12:51:33 -0400 Subject: [PATCH 483/554] drm/amdgpu/vcn3.0: remove intermediate variable No need to use the id variable, just use the constant plus instance offset directly. Reviewed-by: Leo Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 57b62fb04750..da11ceba0698 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -60,11 +60,6 @@ static int amdgpu_ih_clientid_vcns[] = { SOC15_IH_CLIENTID_VCN1 }; -static int amdgpu_ucode_id_vcns[] = { - AMDGPU_UCODE_ID_VCN, - AMDGPU_UCODE_ID_VCN1 -}; - static int vcn_v3_0_start_sriov(struct amdgpu_device *adev); static void vcn_v3_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v3_0_set_enc_ring_funcs(struct amdgpu_device *adev); @@ -1278,7 +1273,6 @@ static int vcn_v3_0_start_sriov(struct amdgpu_device *adev) uint32_t param, resp, expected; uint32_t offset, cache_size; uint32_t tmp, timeout; - uint32_t id; struct amdgpu_mm_table *table = &adev->virt.mm_table; uint32_t *table_loc; @@ -1322,13 +1316,12 @@ static int vcn_v3_0_start_sriov(struct amdgpu_device *adev) cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - id = amdgpu_ucode_id_vcns[i]; MMSCH_V3_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), - adev->firmware.ucode[id].tmr_mc_addr_lo); + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + i].tmr_mc_addr_lo); MMSCH_V3_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), - adev->firmware.ucode[id].tmr_mc_addr_hi); + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + i].tmr_mc_addr_hi); offset = 0; MMSCH_V3_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CACHE_OFFSET0), From 8cbc52c20793de8fd75b93ce1872182071282b7b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Oct 2021 09:50:00 -0400 Subject: [PATCH 484/554] drm/amdgpu: Workaround harvesting info for some navy flounder boards Some navy flounder boards do not properly mark harvested VCN instances. Fix that here. v2: use IP versions Fixes: 1b592d00b4ac83 ("drm/amdgpu/vcn: remove manual instance setting") Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1743 Reviewed-and-tested-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index dfb92f229748..814e9620fac5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -507,6 +507,10 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev) break; } } + /* some IP discovery tables on Navy Flounder don't have this set correctly */ + if ((adev->ip_versions[UVD_HWIP][1] == IP_VERSION(3, 0, 1)) && + (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 2))) + adev->vcn.harvest_config |= AMDGPU_VCN_HARVEST_VCN1; if (vcn_harvest_count == adev->vcn.num_vcn_inst) { adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK; adev->harvest_ip_mask |= AMD_HARVEST_IP_JPEG_MASK; From 0b54122ca1da24902aaaaa8726674a0a4c1a0de8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Oct 2021 09:52:30 -0400 Subject: [PATCH 485/554] drm/amdgpu/swsmu: handle VCN harvesting for VCN SMU setup Check if VCN instances are harvested when controlling VCN power gating and setting up VCN clocks. Fixes: 1b592d00b4ac83 ("drm/amdgpu/vcn: remove manual instance setting") Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1743 Reviewed-and-tested-by: Guchun Chen Signed-off-by: Alex Deucher --- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 95 +++++-------------- 1 file changed, 24 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 15e66e1912de..a4108025fe29 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -670,7 +670,7 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; struct smu_11_0_dpm_table *dpm_table; struct amdgpu_device *adev = smu->adev; - int ret = 0; + int i, ret = 0; DpmDescriptor_t *table_member; /* socclk dpm table setup */ @@ -746,78 +746,45 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) dpm_table->max = dpm_table->dpm_levels[0].value; } - /* vclk0 dpm table setup */ - dpm_table = &dpm_context->dpm_tables.vclk_table; - if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { - ret = smu_v11_0_set_single_dpm_table(smu, - SMU_VCLK, - dpm_table); - if (ret) - return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_VCLK_0].SnapToDiscrete; - } else { - dpm_table->count = 1; - dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; - dpm_table->dpm_levels[0].enabled = true; - dpm_table->min = dpm_table->dpm_levels[0].value; - dpm_table->max = dpm_table->dpm_levels[0].value; - } + /* vclk0/1 dpm table setup */ + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; - /* vclk1 dpm table setup */ - if (adev->vcn.num_vcn_inst > 1) { - dpm_table = &dpm_context->dpm_tables.vclk1_table; + dpm_table = &dpm_context->dpm_tables.vclk_table; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, - SMU_VCLK1, + i ? SMU_VCLK1 : SMU_VCLK, dpm_table); if (ret) return ret; dpm_table->is_fine_grained = - !table_member[PPCLK_VCLK_1].SnapToDiscrete; + !table_member[i ? PPCLK_VCLK_1 : PPCLK_VCLK_0].SnapToDiscrete; } else { dpm_table->count = 1; - dpm_table->dpm_levels[0].value = - smu->smu_table.boot_values.vclk / 100; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; dpm_table->dpm_levels[0].enabled = true; dpm_table->min = dpm_table->dpm_levels[0].value; dpm_table->max = dpm_table->dpm_levels[0].value; } } - /* dclk0 dpm table setup */ - dpm_table = &dpm_context->dpm_tables.dclk_table; - if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { - ret = smu_v11_0_set_single_dpm_table(smu, - SMU_DCLK, - dpm_table); - if (ret) - return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_DCLK_0].SnapToDiscrete; - } else { - dpm_table->count = 1; - dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; - dpm_table->dpm_levels[0].enabled = true; - dpm_table->min = dpm_table->dpm_levels[0].value; - dpm_table->max = dpm_table->dpm_levels[0].value; - } - - /* dclk1 dpm table setup */ - if (adev->vcn.num_vcn_inst > 1) { - dpm_table = &dpm_context->dpm_tables.dclk1_table; + /* dclk0/1 dpm table setup */ + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + dpm_table = &dpm_context->dpm_tables.dclk_table; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, - SMU_DCLK1, + i ? SMU_DCLK1 : SMU_DCLK, dpm_table); if (ret) return ret; dpm_table->is_fine_grained = - !table_member[PPCLK_DCLK_1].SnapToDiscrete; + !table_member[i ? PPCLK_DCLK_1 : PPCLK_DCLK_0].SnapToDiscrete; } else { dpm_table->count = 1; - dpm_table->dpm_levels[0].value = - smu->smu_table.boot_values.dclk / 100; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; dpm_table->dpm_levels[0].enabled = true; dpm_table->min = dpm_table->dpm_levels[0].value; dpm_table->max = dpm_table->dpm_levels[0].value; @@ -902,32 +869,18 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enable) { struct amdgpu_device *adev = smu->adev; - int ret = 0; + int i, ret = 0; - if (enable) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; /* vcn dpm on is a prerequisite for vcn power gate messages */ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn, + 0x10000 * i, NULL); if (ret) return ret; - if (adev->vcn.num_vcn_inst > 1) { - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, - 0x10000, NULL); - if (ret) - return ret; - } - } - } else { - if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL); - if (ret) - return ret; - if (adev->vcn.num_vcn_inst > 1) { - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, - 0x10000, NULL); - if (ret) - return ret; - } } } From 4df5585776fad6bc1179ea004622e9c694f2f7df Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Oct 2021 11:28:18 -0400 Subject: [PATCH 486/554] drm/amdgpu/smu11.0: add missing IP version check Add missing check in smu_v11_0_init_display_count(), Fixes: af3b89d3a639d5 ("drm/amdgpu/smu11.0: convert to IP version checking") Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 5c1703cc25fd..28b7c0562b99 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -755,6 +755,7 @@ int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) */ if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 11) || adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 5, 0) || + adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 12) || adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 13)) return 0; From df9feb1a6972af994dce8a5aae9e770181e5d065 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 22 Oct 2021 00:14:11 -0400 Subject: [PATCH 487/554] drm/amdgpu/nbio7.4: use original HDP_FLUSH bits The extended bits were not available for use on vega20 and presumably arcturus as well. Fixes: a0f9f854666834 ("drm/amdgpu/nbio7.4: don't use GPU_HDP_FLUSH bit 12") Reviewed-and-tested-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 5 ++++- drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c | 15 +++++++++++++++ drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 814e9620fac5..208a784475bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1125,10 +1125,13 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) break; case IP_VERSION(7, 4, 0): case IP_VERSION(7, 4, 1): - case IP_VERSION(7, 4, 4): adev->nbio.funcs = &nbio_v7_4_funcs; adev->nbio.hdp_flush_reg = &nbio_v7_4_hdp_flush_reg; break; + case IP_VERSION(7, 4, 4): + adev->nbio.funcs = &nbio_v7_4_funcs; + adev->nbio.hdp_flush_reg = &nbio_v7_4_hdp_flush_reg_ald; + break; case IP_VERSION(7, 2, 0): case IP_VERSION(7, 2, 1): case IP_VERSION(7, 5, 0): diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 3b7775d74bb2..b8bd03d16dba 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -325,6 +325,21 @@ static u32 nbio_v7_4_get_pcie_data_offset(struct amdgpu_device *adev) } const struct nbio_hdp_flush_reg nbio_v7_4_hdp_flush_reg = { + .ref_and_mask_cp0 = GPU_HDP_FLUSH_DONE__CP0_MASK, + .ref_and_mask_cp1 = GPU_HDP_FLUSH_DONE__CP1_MASK, + .ref_and_mask_cp2 = GPU_HDP_FLUSH_DONE__CP2_MASK, + .ref_and_mask_cp3 = GPU_HDP_FLUSH_DONE__CP3_MASK, + .ref_and_mask_cp4 = GPU_HDP_FLUSH_DONE__CP4_MASK, + .ref_and_mask_cp5 = GPU_HDP_FLUSH_DONE__CP5_MASK, + .ref_and_mask_cp6 = GPU_HDP_FLUSH_DONE__CP6_MASK, + .ref_and_mask_cp7 = GPU_HDP_FLUSH_DONE__CP7_MASK, + .ref_and_mask_cp8 = GPU_HDP_FLUSH_DONE__CP8_MASK, + .ref_and_mask_cp9 = GPU_HDP_FLUSH_DONE__CP9_MASK, + .ref_and_mask_sdma0 = GPU_HDP_FLUSH_DONE__SDMA0_MASK, + .ref_and_mask_sdma1 = GPU_HDP_FLUSH_DONE__SDMA1_MASK, +}; + +const struct nbio_hdp_flush_reg nbio_v7_4_hdp_flush_reg_ald = { .ref_and_mask_cp0 = GPU_HDP_FLUSH_DONE__CP0_MASK, .ref_and_mask_cp1 = GPU_HDP_FLUSH_DONE__CP1_MASK, .ref_and_mask_cp2 = GPU_HDP_FLUSH_DONE__CP2_MASK, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h index b8216581ec8d..cc5692db6f98 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.h @@ -27,6 +27,7 @@ #include "soc15_common.h" extern const struct nbio_hdp_flush_reg nbio_v7_4_hdp_flush_reg; +extern const struct nbio_hdp_flush_reg nbio_v7_4_hdp_flush_reg_ald; extern const struct amdgpu_nbio_funcs nbio_v7_4_funcs; extern const struct amdgpu_nbio_ras_funcs nbio_v7_4_ras_funcs; From 47b67c9900db0db41e7a678bc0b2fc54983b6cb9 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 22 Oct 2021 15:35:25 +0800 Subject: [PATCH 488/554] drm/amd/pm: Disable fan control if not supported On arcturus, not all platforms use PMFW based fan control. On such ASICs fan control by PMFW will be disabled in PPTable. Disable hwmon knobs for fan control also as it is not possible to report or control fan speed on such platforms through driver. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 082f01893f3d..fd1d30a93db5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -436,6 +436,19 @@ static void arcturus_check_bxco_support(struct smu_context *smu) } } +static void arcturus_check_fan_support(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + + /* No sort of fan control possible if PPTable has it disabled */ + smu->adev->pm.no_fan = + !(pptable->FeaturesToRun[0] & FEATURE_FAN_CONTROL_MASK); + if (smu->adev->pm.no_fan) + dev_info_once(smu->adev->dev, + "PMFW based fan control disabled"); +} + static int arcturus_check_powerplay_table(struct smu_context *smu) { struct smu_table_context *table_context = &smu->smu_table; @@ -443,6 +456,7 @@ static int arcturus_check_powerplay_table(struct smu_context *smu) table_context->power_play_table; arcturus_check_bxco_support(smu); + arcturus_check_fan_support(smu); table_context->thermal_controller_type = powerplay_table->thermal_controller_type; From 41ad36623fabe7d02c9f89aff077dd4c8ba5d602 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 14 Oct 2021 15:35:13 +0000 Subject: [PATCH 489/554] amd/display: remove ChromeOS workaround This reverts commits ddab8bd788f5 ("drm/amd/display: Fix two cursor duplication when using overlay") and e7d9560aeae5 ("Revert "drm/amd/display: Fix overlay validation by considering cursors""). tl;dr ChromeOS uses the atomic interface for everything except the cursor. This is incorrect and forces amdgpu to disable some hardware features. Let's revert the ChromeOS-specific workaround in mainline and allow the Chrome team to keep it internally in their own tree. See [1] for more details. This patch is an alternative to [2], which added ChromeOS detection. [1]: https://lore.kernel.org/amd-gfx/JIQ_93_cHcshiIDsrMU1huBzx9P9LVQxucx8hQArpQu7Wk5DrCl_vTXj_Q20m_L-8C8A5dSpNcSJ8ehfcCrsQpfB5QG_Spn14EYkH9chtg0=@emersion.fr/ [2]: https://lore.kernel.org/amd-gfx/20211011151609.452132-1-contact@emersion.fr/ Signed-off-by: Simon Ser Cc: Alex Deucher Cc: Harry Wentland Cc: Nicholas Kazlauskas Cc: Bas Nieuwenhuizen Cc: Rodrigo Siqueira Cc: Sean Paul Fixes: ddab8bd788f5 ("drm/amd/display: Fix two cursor duplication when using overlay") Fixes: e7d9560aeae5 ("Revert "drm/amd/display: Fix overlay validation by considering cursors"") Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a0fd497515d0..5b8d1635da5c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10627,53 +10627,6 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm } #endif -static int validate_overlay(struct drm_atomic_state *state) -{ - int i; - struct drm_plane *plane; - struct drm_plane_state *new_plane_state; - struct drm_plane_state *primary_state, *overlay_state = NULL; - - /* Check if primary plane is contained inside overlay */ - for_each_new_plane_in_state_reverse(state, plane, new_plane_state, i) { - if (plane->type == DRM_PLANE_TYPE_OVERLAY) { - if (drm_atomic_plane_disabling(plane->state, new_plane_state)) - return 0; - - overlay_state = new_plane_state; - continue; - } - } - - /* check if we're making changes to the overlay plane */ - if (!overlay_state) - return 0; - - /* check if overlay plane is enabled */ - if (!overlay_state->crtc) - return 0; - - /* find the primary plane for the CRTC that the overlay is enabled on */ - primary_state = drm_atomic_get_plane_state(state, overlay_state->crtc->primary); - if (IS_ERR(primary_state)) - return PTR_ERR(primary_state); - - /* check if primary plane is enabled */ - if (!primary_state->crtc) - return 0; - - /* Perform the bounds check to ensure the overlay plane covers the primary */ - if (primary_state->crtc_x < overlay_state->crtc_x || - primary_state->crtc_y < overlay_state->crtc_y || - primary_state->crtc_x + primary_state->crtc_w > overlay_state->crtc_x + overlay_state->crtc_w || - primary_state->crtc_y + primary_state->crtc_h > overlay_state->crtc_y + overlay_state->crtc_h) { - DRM_DEBUG_ATOMIC("Overlay plane is enabled with hardware cursor but does not fully cover primary plane\n"); - return -EINVAL; - } - - return 0; -} - /** * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM. * @dev: The DRM device @@ -10855,10 +10808,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } - ret = validate_overlay(state); - if (ret) - goto fail; - /* Add new/modified planes */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ret = dm_update_plane_state(dc, state, plane, From c6c2fb596b29bb5b667f1c5e7d9400a3456b23b2 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 23 Oct 2021 09:00:12 -0700 Subject: [PATCH 490/554] drm/msm/dpu: Remove impossible NULL check Signed-off-by: Rob Clark Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20211023160016.3322052-1-robdclark@gmail.com Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e91568d4f09a..0ae397044310 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -187,11 +187,6 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) int i = 0; int rc = 0; - if (!crtc) { - DPU_ERROR("Invalid crtc\n"); - return -EINVAL; - } - crtc_state = to_dpu_crtc_state(crtc->state); crcs = kcalloc(crtc_state->num_mixers, sizeof(*crcs), GFP_KERNEL); From 00326bfa4e6363e4b0b8b019ecd2556fdda5ad1c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 23 Oct 2021 09:00:13 -0700 Subject: [PATCH 491/554] drm/msm/dpu: Remove dynamic allocation from atomic context We know the upper bound on # of mixers (ie. two), so lets just allocate this on the stack. Fixes: BUG: sleeping function called from invalid context at include/linux/sched/mm.h:201 in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 0, name: swapper/0 INFO: lockdep is turned off. irq event stamp: 43642 hardirqs last enabled at (43641): [] cpuidle_enter_state+0x158/0x25c hardirqs last disabled at (43642): [] enter_el1_irq_or_nmi+0x10/0x1c softirqs last enabled at (43620): [] __do_softirq+0x1e4/0x464 softirqs last disabled at (43615): [] __irq_exit_rcu+0x104/0x150 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 5.15.0-rc3-debug+ #105 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) Call trace: dump_backtrace+0x0/0x18c show_stack+0x24/0x30 dump_stack_lvl+0xa0/0xd4 dump_stack+0x18/0x34 ___might_sleep+0x1e0/0x1f0 __might_sleep+0x78/0x8c slab_pre_alloc_hook.constprop.0+0x48/0x6c __kmalloc+0xc8/0x21c dpu_crtc_vblank_callback+0x158/0x1f8 dpu_encoder_vblank_callback+0x70/0xc4 dpu_encoder_phys_vid_vblank_irq+0x50/0x12c dpu_core_irq+0x1bc/0x1d0 dpu_irq+0x1c/0x28 msm_irq+0x34/0x40 __handle_irq_event_percpu+0x15c/0x308 handle_irq_event_percpu+0x3c/0x90 handle_irq_event+0x54/0x98 handle_level_irq+0xa0/0xd0 handle_irq_desc+0x2c/0x44 generic_handle_domain_irq+0x28/0x34 dpu_mdss_irq+0x90/0xe8 handle_irq_desc+0x2c/0x44 handle_domain_irq+0x54/0x80 gic_handle_irq+0xd4/0x148 call_on_irq_stack+0x2c/0x54 do_interrupt_handler+0x4c/0x64 el1_interrupt+0x30/0xd0 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x78/0x7c arch_local_irq_enable+0xc/0x14 cpuidle_enter+0x44/0x5c do_idle+0x248/0x268 cpu_startup_entry+0x30/0x48 rest_init+0x188/0x19c arch_call_rest_init+0x1c/0x28 start_kernel+0x704/0x744 __primary_switched+0xc0/0xc8 Fixes: 78d9b458cc21 ("drm/msm/dpu: Add CRC support for DPU") Signed-off-by: Rob Clark Link: https://lore.kernel.org/r/20211023160016.3322052-2-robdclark@gmail.com Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 0ae397044310..2523e829f485 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -182,21 +182,19 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) { struct dpu_crtc_state *crtc_state; struct dpu_crtc_mixer *m; - u32 *crcs; + u32 crcs[CRTC_DUAL_MIXERS]; int i = 0; int rc = 0; crtc_state = to_dpu_crtc_state(crtc->state); - crcs = kcalloc(crtc_state->num_mixers, sizeof(*crcs), GFP_KERNEL); - if (!crcs) - return -ENOMEM; + BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers)); /* Skip first 2 frames in case of "uncooked" CRCs */ if (crtc_state->crc_frame_skip_count < 2) { crtc_state->crc_frame_skip_count++; - goto cleanup; + return 0; } for (i = 0; i < crtc_state->num_mixers; ++i) { @@ -210,16 +208,12 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) if (rc) { DRM_DEBUG_DRIVER("MISR read failed\n"); - goto cleanup; + return rc; } } - rc = drm_crtc_add_crc_entry(crtc, true, + return drm_crtc_add_crc_entry(crtc, true, drm_crtc_accurate_vblank_count(crtc), crcs); - -cleanup: - kfree(crcs); - return rc; } static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, From 0332078398d0a3d99a59347c3a896896ccac2cc1 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Mon, 25 Oct 2021 18:38:21 -0400 Subject: [PATCH 492/554] drm: Remove slot checks in dp mst topology during commit This code path is used during commit, and we dont expect things to fail during the commit stage, so remove this. Signed-off-by: Bhawanpreet Lakha Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211025223825.301703-2-lyude@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 86d13d6bc463..04ed34a7f71c 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -4334,10 +4334,6 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, { int ret; - /* max. time slots - one slot for MTP header */ - if (slots > 63) - return -ENOSPC; - vcpi->pbn = pbn; vcpi->aligned_pbn = slots * mgr->pbn_div; vcpi->num_slots = slots; @@ -4540,7 +4536,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); if (ret) { - drm_dbg_kms(mgr->dev, "failed to init vcpi slots=%d max=63 ret=%d\n", + drm_dbg_kms(mgr->dev, "failed to init vcpi slots=%d ret=%d\n", DIV_ROUND_UP(pbn, mgr->pbn_div), ret); drm_dp_mst_topology_put_port(port); goto out; From d6c6a76f80a1c91dceacef3630a7465ece630615 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Mon, 25 Oct 2021 18:38:22 -0400 Subject: [PATCH 493/554] drm: Update MST First Link Slot Information Based on Encoding Format 8b/10b encoding format requires to reserve the first slot for recording metadata. Real data transmission starts from the second slot, with a total of available 63 slots available. In 128b/132b encoding format, metadata is transmitted separately in LLCP packet before MTP. Real data transmission starts from the first slot, with a total of 64 slots available. v2: * Move total/start slots to mst_state, and copy it to mst_mgr in atomic_check v3: * Only keep the slot info on the mst_state * add a start_slot parameter to the payload function, to facilitate non atomic drivers (this is a temporary workaround and should be removed when we are moving out the non atomic driver helpers) v4: *fixed typo and formatting v5: (no functional changes) * Fixed formatting in drm_dp_mst_update_slots() * Reference mst_state instead of mst_state->mgr for debugging info Signed-off-by: Bhawanpreet Lakha Signed-off-by: Fangzhi Zuo [v5 nitpicks] Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211025223825.301703-3-lyude@redhat.com --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 +- drivers/gpu/drm/drm_dp_mst_topology.c | 36 ++++++++++++++++--- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 +-- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/radeon/radeon_dp_mst.c | 4 +-- include/drm/drm_dp_mst_helper.h | 5 ++- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index ff0f91c93ba4..6169488e2011 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -251,7 +251,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( } /* It's OK for this to fail */ - drm_dp_update_payload_part1(mst_mgr); + drm_dp_update_payload_part1(mst_mgr, 1); /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or * AUX message. The sequence is slot 1-63 allocated sequence for each diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 04ed34a7f71c..571da0c2f39f 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3355,6 +3355,10 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr, /** * drm_dp_update_payload_part1() - Execute payload update part 1 * @mgr: manager to use. + * @start_slot: this is the cur slot + * + * NOTE: start_slot is a temporary workaround for non-atomic drivers, + * this will be removed when non-atomic mst helpers are moved out of the helper * * This iterates over all proposed virtual channels, and tries to * allocate space in the link for them. For 0->slots transitions, @@ -3365,12 +3369,12 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr, * after calling this the driver should generate ACT and payload * packets. */ -int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) +int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int start_slot) { struct drm_dp_payload req_payload; struct drm_dp_mst_port *port; int i, j; - int cur_slots = 1; + int cur_slots = start_slot; bool skip; mutex_lock(&mgr->payload_lock); @@ -4505,6 +4509,27 @@ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_dp_atomic_release_vcpi_slots); +/** + * drm_dp_mst_update_slots() - updates the slot info depending on the DP ecoding format + * @mst_state: mst_state to update + * @link_encoding_cap: the ecoding format on the link + */ +void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_t link_encoding_cap) +{ + if (link_encoding_cap == DP_CAP_ANSI_128B132B) { + mst_state->total_avail_slots = 64; + mst_state->start_slot = 0; + } else { + mst_state->total_avail_slots = 63; + mst_state->start_slot = 1; + } + + DRM_DEBUG_KMS("%s encoding format on mst_state 0x%p\n", + (link_encoding_cap == DP_CAP_ANSI_128B132B) ? "128b/132b":"8b/10b", + mst_state); +} +EXPORT_SYMBOL(drm_dp_mst_update_slots); + /** * drm_dp_mst_allocate_vcpi() - Allocate a virtual channel * @mgr: manager for this port @@ -5224,7 +5249,7 @@ drm_dp_mst_atomic_check_vcpi_alloc_limit(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_state *mst_state) { struct drm_dp_vcpi_allocation *vcpi; - int avail_slots = 63, payload_count = 0; + int avail_slots = mst_state->total_avail_slots, payload_count = 0; list_for_each_entry(vcpi, &mst_state->vcpis, next) { /* Releasing VCPI is always OK-even if the port is gone */ @@ -5253,7 +5278,7 @@ drm_dp_mst_atomic_check_vcpi_alloc_limit(struct drm_dp_mst_topology_mgr *mgr, } } drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", - mgr, mst_state, avail_slots, 63 - avail_slots); + mgr, mst_state, avail_slots, mst_state->total_avail_slots - avail_slots); return 0; } @@ -5530,6 +5555,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, if (mst_state == NULL) return -ENOMEM; + mst_state->total_avail_slots = 63; + mst_state->start_slot = 1; + mst_state->mgr = mgr; INIT_LIST_HEAD(&mst_state->vcpis); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0de0b4ff4d73..89d701e8ae9d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -378,7 +378,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port); - ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); + ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr, 1); if (ret) { drm_dbg_kms(&i915->drm, "failed to update payload %d\n", ret); } @@ -518,7 +518,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, intel_dp->active_mst_links++; - ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); + ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr, 1); /* * Before Gen 12 this is not done as part of diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index d7b9f7f8c9e3..8e28403ea9b1 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1414,7 +1414,7 @@ nv50_mstm_prepare(struct nv50_mstm *mstm) int ret; NV_ATOMIC(drm, "%s: mstm prepare\n", mstm->outp->base.base.name); - ret = drm_dp_update_payload_part1(&mstm->mgr); + ret = drm_dp_update_payload_part1(&mstm->mgr, 1); drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index ec867fa880a4..751c2c075e09 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -423,7 +423,7 @@ radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr, radeon_connector->port, mst_enc->pbn, slots); - drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); + drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr, 1); radeon_dp_mst_set_be_cntl(primary, mst_enc, radeon_connector->mst_port->hpd.hpd, true); @@ -452,7 +452,7 @@ radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) return; drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port); - drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); + drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr, 1); drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr); /* and this can also fail */ diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index ddb9231d0309..78044ac5b59b 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -554,6 +554,8 @@ struct drm_dp_mst_topology_state { struct drm_private_state base; struct list_head vcpis; struct drm_dp_mst_topology_mgr *mgr; + u8 total_avail_slots; + u8 start_slot; }; #define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base) @@ -806,6 +808,7 @@ int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); +void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_t link_encoding_cap); void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); @@ -815,7 +818,7 @@ int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, int pbn); -int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr); +int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int start_slot); int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr); From d740e0bf8ed4c14ac6a616e2b31626bdcf417135 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Mon, 25 Oct 2021 18:38:23 -0400 Subject: [PATCH 494/554] drm/amd/display: Add DP 2.0 MST DC Support [Why] configure/call DC interface for DP2 mst support. This is needed to make DP2 mst work. [How] - add encoding type, logging, mst update/reduce payload functions Use the link encoding to determine the DP type (1.4 or 2.0) and add a flag to dc_stream_update to determine whether to increase/reduce payloads. v2: * add DP_UNKNOWN_ENCODING handling Signed-off-by: Fangzhi Zuo Reviewed-by: "Lin, Wayne" Signed-off-by: Bhawanpreet Lakha Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211025223825.301703-4-lyude@redhat.com --- drivers/gpu/drm/amd/display/dc/core/dc.c | 14 + drivers/gpu/drm/amd/display/dc/core/dc_link.c | 292 ++++++++++++++++++ .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 19 ++ drivers/gpu/drm/amd/display/dc/dc_link.h | 7 + drivers/gpu/drm/amd/display/dc/dc_stream.h | 13 + 5 files changed, 345 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index da942e9f5142..782141ba8ac5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2356,6 +2356,11 @@ static enum surface_update_type check_update_surfaces_for_stream( if (stream_update->dsc_config) su_flags->bits.dsc_changed = 1; +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (stream_update->mst_bw_update) + su_flags->bits.mst_bw = 1; +#endif + if (su_flags->raw != 0) overall_type = UPDATE_TYPE_FULL; @@ -2741,6 +2746,15 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->dsc_config) dp_update_dsc_config(pipe_ctx); +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (stream_update->mst_bw_update) { + if (stream_update->mst_bw_update->is_increase) + dc_link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw); + else + dc_link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw); + } +#endif + if (stream_update->pending_test_pattern) { dc_link_dp_set_test_pattern(stream->link, stream->test_pattern.type, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index ca5dc3c168ec..fd12561b70cc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3272,6 +3272,9 @@ static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx) static void update_mst_stream_alloc_table( struct dc_link *link, struct stream_encoder *stream_enc, +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc? +#endif const struct dp_mst_stream_allocation_table *proposed_table) { struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { @@ -3308,6 +3311,9 @@ static void update_mst_stream_alloc_table( work_table[i].slot_count = proposed_table->stream_allocations[i].slot_count; work_table[i].stream_enc = stream_enc; +#if defined(CONFIG_DRM_AMD_DC_DCN) + work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc; +#endif } } @@ -3430,6 +3436,10 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct dc_link *link = stream->link; struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; +#endif struct dp_mst_stream_allocation_table proposed_table = {0}; struct fixed31_32 avg_time_slots_per_mtp; struct fixed31_32 pbn; @@ -3457,7 +3467,14 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) &proposed_table, true)) { update_mst_stream_alloc_table( +#if defined(CONFIG_DRM_AMD_DC_DCN) + link, + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc, + &proposed_table); +#else link, pipe_ctx->stream_res.stream_enc, &proposed_table); +#endif } else DC_LOG_WARNING("Failed to update" @@ -3471,6 +3488,20 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { +#if defined(CONFIG_DRM_AMD_DC_DCN) + DC_LOG_MST("stream_enc[%d]: %p " + "stream[%d].hpo_dp_stream_enc: %p " + "stream[%d].vcp_id: %d " + "stream[%d].slot_count: %d\n", + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc, + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc, + i, + link->mst_stream_alloc_table.stream_allocations[i].vcp_id, + i, + link->mst_stream_alloc_table.stream_allocations[i].slot_count); +#else DC_LOG_MST("stream_enc[%d]: %p " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", @@ -3480,14 +3511,33 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) link->mst_stream_alloc_table.stream_allocations[i].vcp_id, i, link->mst_stream_alloc_table.stream_allocations[i].slot_count); +#endif } ASSERT(proposed_table.stream_count > 0); /* program DP source TX for payload */ +#if defined(CONFIG_DRM_AMD_DC_DCN) + switch (dp_get_link_encoding_format(&link->cur_link_settings)) { + case DP_8b_10b_ENCODING: + link_encoder->funcs->update_mst_stream_allocation_table( + link_encoder, + &link->mst_stream_alloc_table); + break; + case DP_128b_132b_ENCODING: + hpo_dp_link_encoder->funcs->update_stream_allocation_table( + hpo_dp_link_encoder, + &link->mst_stream_alloc_table); + break; + case DP_UNKNOWN_ENCODING: + DC_LOG_ERROR("Failure: unknown encoding format\n"); + return DC_ERROR_UNEXPECTED; + } +#else link_encoder->funcs->update_mst_stream_allocation_table( link_encoder, &link->mst_stream_alloc_table); +#endif /* send down message */ ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger( @@ -3510,20 +3560,202 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) pbn = get_pbn_from_timing(pipe_ctx); avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot); +#if defined(CONFIG_DRM_AMD_DC_DCN) + switch (dp_get_link_encoding_format(&link->cur_link_settings)) { + case DP_8b_10b_ENCODING: + stream_encoder->funcs->set_throttled_vcp_size( + stream_encoder, + avg_time_slots_per_mtp); + break; + case DP_128b_132b_ENCODING: + hpo_dp_link_encoder->funcs->set_throttled_vcp_size( + hpo_dp_link_encoder, + hpo_dp_stream_encoder->inst, + avg_time_slots_per_mtp); + break; + case DP_UNKNOWN_ENCODING: + DC_LOG_ERROR("Failure: unknown encoding format\n"); + return DC_ERROR_UNEXPECTED; + } +#else stream_encoder->funcs->set_throttled_vcp_size( stream_encoder, avg_time_slots_per_mtp); +#endif return DC_OK; } +#if defined(CONFIG_DRM_AMD_DC_DCN) +enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct fixed31_32 avg_time_slots_per_mtp; + struct fixed31_32 pbn; + struct fixed31_32 pbn_per_slot; + struct link_encoder *link_encoder = link->link_enc; + struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; + struct dp_mst_stream_allocation_table proposed_table = {0}; + uint8_t i; + enum act_return_status ret; + DC_LOGGER_INIT(link->ctx->logger); + + /* decrease throttled vcp size */ + pbn_per_slot = get_pbn_per_slot(stream); + pbn = get_pbn_from_bw_in_kbps(bw_in_kbps); + avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot); + + stream_encoder->funcs->set_throttled_vcp_size( + stream_encoder, + avg_time_slots_per_mtp); + + /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ + dm_helpers_dp_mst_send_payload_allocation( + stream->ctx, + stream, + true); + + /* notify immediate branch device table update */ + if (dm_helpers_dp_mst_write_payload_allocation_table( + stream->ctx, + stream, + &proposed_table, + true)) { + /* update mst stream allocation table software state */ + update_mst_stream_alloc_table( + link, + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc, + &proposed_table); + } else { + DC_LOG_WARNING("Failed to update" + "MST allocation table for" + "pipe idx:%d\n", + pipe_ctx->pipe_idx); + } + + DC_LOG_MST("%s " + "stream_count: %d: \n ", + __func__, + link->mst_stream_alloc_table.stream_count); + + for (i = 0; i < MAX_CONTROLLER_NUM; i++) { + DC_LOG_MST("stream_enc[%d]: %p " + "stream[%d].vcp_id: %d " + "stream[%d].slot_count: %d\n", + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc, + i, + link->mst_stream_alloc_table.stream_allocations[i].vcp_id, + i, + link->mst_stream_alloc_table.stream_allocations[i].slot_count); + } + + ASSERT(proposed_table.stream_count > 0); + + /* update mst stream allocation table hardware state */ + link_encoder->funcs->update_mst_stream_allocation_table( + link_encoder, + &link->mst_stream_alloc_table); + + /* poll for immediate branch device ACT handled */ + ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger( + stream->ctx, + stream); + + return DC_OK; +} + +enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct fixed31_32 avg_time_slots_per_mtp; + struct fixed31_32 pbn; + struct fixed31_32 pbn_per_slot; + struct link_encoder *link_encoder = link->link_enc; + struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; + struct dp_mst_stream_allocation_table proposed_table = {0}; + uint8_t i; + enum act_return_status ret; + DC_LOGGER_INIT(link->ctx->logger); + + /* notify immediate branch device table update */ + if (dm_helpers_dp_mst_write_payload_allocation_table( + stream->ctx, + stream, + &proposed_table, + true)) { + /* update mst stream allocation table software state */ + update_mst_stream_alloc_table( + link, + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc, + &proposed_table); + } + + DC_LOG_MST("%s " + "stream_count: %d: \n ", + __func__, + link->mst_stream_alloc_table.stream_count); + + for (i = 0; i < MAX_CONTROLLER_NUM; i++) { + DC_LOG_MST("stream_enc[%d]: %p " + "stream[%d].vcp_id: %d " + "stream[%d].slot_count: %d\n", + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc, + i, + link->mst_stream_alloc_table.stream_allocations[i].vcp_id, + i, + link->mst_stream_alloc_table.stream_allocations[i].slot_count); + } + + ASSERT(proposed_table.stream_count > 0); + + /* update mst stream allocation table hardware state */ + link_encoder->funcs->update_mst_stream_allocation_table( + link_encoder, + &link->mst_stream_alloc_table); + + /* poll for immediate branch device ACT handled */ + ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger( + stream->ctx, + stream); + + if (ret != ACT_LINK_LOST) { + /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ + dm_helpers_dp_mst_send_payload_allocation( + stream->ctx, + stream, + true); + } + + /* increase throttled vcp size */ + pbn = get_pbn_from_bw_in_kbps(bw_in_kbps); + pbn_per_slot = get_pbn_per_slot(stream); + avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot); + + stream_encoder->funcs->set_throttled_vcp_size( + stream_encoder, + avg_time_slots_per_mtp); + + return DC_OK; +} +#endif + static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; +#endif struct dp_mst_stream_allocation_table proposed_table = {0}; struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0); uint8_t i; @@ -3545,9 +3777,28 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) */ /* slot X.Y */ +#if defined(CONFIG_DRM_AMD_DC_DCN) + switch (dp_get_link_encoding_format(&link->cur_link_settings)) { + case DP_8b_10b_ENCODING: + stream_encoder->funcs->set_throttled_vcp_size( + stream_encoder, + avg_time_slots_per_mtp); + break; + case DP_128b_132b_ENCODING: + hpo_dp_link_encoder->funcs->set_throttled_vcp_size( + hpo_dp_link_encoder, + hpo_dp_stream_encoder->inst, + avg_time_slots_per_mtp); + break; + case DP_UNKNOWN_ENCODING: + DC_LOG_ERROR("Failure: unknown encoding format\n"); + return DC_ERROR_UNEXPECTED; + } +#else stream_encoder->funcs->set_throttled_vcp_size( stream_encoder, avg_time_slots_per_mtp); +#endif /* TODO: which component is responsible for remove payload table? */ if (mst_mode) { @@ -3557,8 +3808,16 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) &proposed_table, false)) { +#if defined(CONFIG_DRM_AMD_DC_DCN) + update_mst_stream_alloc_table( + link, + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.hpo_dp_stream_enc, + &proposed_table); +#else update_mst_stream_alloc_table( link, pipe_ctx->stream_res.stream_enc, &proposed_table); +#endif } else { DC_LOG_WARNING("Failed to update" @@ -3574,6 +3833,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { +#if defined(CONFIG_DRM_AMD_DC_DCN) + DC_LOG_MST("stream_enc[%d]: %p " + "stream[%d].hpo_dp_stream_enc: %p " + "stream[%d].vcp_id: %d " + "stream[%d].slot_count: %d\n", + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc, + i, + (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc, + i, + link->mst_stream_alloc_table.stream_allocations[i].vcp_id, + i, + link->mst_stream_alloc_table.stream_allocations[i].slot_count); +#else DC_LOG_MST("stream_enc[%d]: %p " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", @@ -3583,11 +3856,30 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link->mst_stream_alloc_table.stream_allocations[i].vcp_id, i, link->mst_stream_alloc_table.stream_allocations[i].slot_count); +#endif } +#if defined(CONFIG_DRM_AMD_DC_DCN) + switch (dp_get_link_encoding_format(&link->cur_link_settings)) { + case DP_8b_10b_ENCODING: + link_encoder->funcs->update_mst_stream_allocation_table( + link_encoder, + &link->mst_stream_alloc_table); + break; + case DP_128b_132b_ENCODING: + hpo_dp_link_encoder->funcs->update_stream_allocation_table( + hpo_dp_link_encoder, + &link->mst_stream_alloc_table); + break; + case DP_UNKNOWN_ENCODING: + DC_LOG_ERROR("Failure: unknown encoding format\n"); + return DC_ERROR_UNEXPECTED; + } +#else link_encoder->funcs->update_mst_stream_allocation_table( link_encoder, &link->mst_stream_alloc_table); +#endif if (mst_mode) { dm_helpers_dp_mst_poll_for_allocation_change_trigger( diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 54662d74c65a..ab13d2304f3e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -5993,6 +5993,25 @@ enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings } #if defined(CONFIG_DRM_AMD_DC_DCN) +enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link) +{ + struct dc_link_settings link_settings = {0}; + + if (!dc_is_dp_signal(link->connector_signal)) + return DP_UNKNOWN_ENCODING; + + if (link->preferred_link_setting.lane_count != + LANE_COUNT_UNKNOWN && + link->preferred_link_setting.link_rate != + LINK_RATE_UNKNOWN) { + link_settings = link->preferred_link_setting; + } else { + decide_mst_link_settings(link, &link_settings); + } + + return dp_get_link_encoding_format(&link_settings); +} + // TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST) static void get_lane_status( struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 69b008bafbbc..d9fb43d99dc0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -296,6 +296,10 @@ enum dc_detect_reason { bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason); bool dc_link_get_hpd_state(struct dc_link *dc_link); enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx); +#if defined(CONFIG_DRM_AMD_DC_DCN) +enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn); +enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn); +#endif /* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt). * Return: @@ -425,4 +429,7 @@ uint32_t dc_bandwidth_in_kbps_from_timing( bool dc_link_is_fec_supported(const struct dc_link *link); bool dc_link_should_enable_fec(const struct dc_link *link); +#if defined(CONFIG_DRM_AMD_DC_DCN) +enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link); +#endif #endif /* DC_LINK_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index b8ebc1f09538..e37c4a10bfd5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -115,6 +115,13 @@ struct periodic_interrupt_config { int lines_offset; }; +#if defined(CONFIG_DRM_AMD_DC_DCN) +struct dc_mst_stream_bw_update { + bool is_increase; // is bandwidth reduced or increased + uint32_t mst_stream_bw; // new mst bandwidth in kbps +}; +#endif + union stream_update_flags { struct { uint32_t scaling:1; @@ -125,6 +132,9 @@ union stream_update_flags { uint32_t gamut_remap:1; uint32_t wb_update:1; uint32_t dsc_changed : 1; +#if defined(CONFIG_DRM_AMD_DC_DCN) + uint32_t mst_bw : 1; +#endif } bits; uint32_t raw; @@ -278,6 +288,9 @@ struct dc_stream_update { struct dc_writeback_update *wb_update; struct dc_dsc_config *dsc_config; +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct dc_mst_stream_bw_update *mst_bw_update; +#endif struct dc_transfer_func *func_shaper; struct dc_3dlut *lut3d_func; From 41724ea273cdda5261db4fabd6bfb1375fbc96b2 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Mon, 25 Oct 2021 18:38:24 -0400 Subject: [PATCH 495/554] drm/amd/display: Add DP 2.0 MST DM Support [Why] Add DP2 MST and debugfs support [How] Update the slot info based on the link encoding format Reviewed-by: "Lin, Wayne" Signed-off-by: Bhawanpreet Lakha Signed-off-by: Fangzhi Zuo Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211025223825.301703-5-lyude@redhat.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 29 +++++++++++++++++++ .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 3 ++ .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 +++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f35561b5a465..ecdeeedb1cde 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10684,6 +10684,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_mst_fairness_vars vars[MAX_PIPES]; #endif + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_topology_mgr *mgr; trace_amdgpu_dm_atomic_check_begin(state); @@ -10891,6 +10893,33 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, lock_and_validation_needed = true; } +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* set the slot info for each mst_state based on the link encoding format */ + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_list_iter iter; + u8 link_coding_cap; + + if (!mgr->mst_state ) + continue; + + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(connector, &iter) { + int id = connector->index; + + if (id == mst_state->mgr->conn_base_id) { + aconnector = to_amdgpu_dm_connector(connector); + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); + drm_dp_mst_update_slots(mst_state, link_coding_cap); + + break; + } + } + drm_connector_list_iter_end(&iter); + + } +#endif /** * Streams and planes are reset when there are changes that affect * bandwidth. Anything that affects bandwidth needs to go through diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 814f67d86a3c..3d44896149a2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -294,6 +294,9 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, case LINK_RATE_RBR2: case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: +#if defined(CONFIG_DRM_AMD_DC_DCN) + case LINK_RATE_UHBR10: +#endif break; default: valid_input = false; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 6169488e2011..53b5cc7b0679 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -219,6 +219,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( struct drm_dp_mst_topology_mgr *mst_mgr; struct drm_dp_mst_port *mst_port; bool ret; + u8 link_coding_cap; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; /* Accessing the connector state is required for vcpi_slots allocation @@ -238,6 +239,8 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_port = aconnector->port; + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); + if (enable) { ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, @@ -251,7 +254,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( } /* It's OK for this to fail */ - drm_dp_update_payload_part1(mst_mgr, 1); + drm_dp_update_payload_part1(mst_mgr, (link_coding_cap == DP_CAP_ANSI_128B132B) ? 0:1); /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or * AUX message. The sequence is slot 1-63 allocated sequence for each From e9afd45788d223bfd562dd062e43208e958683e7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 26 Oct 2021 07:24:36 -0700 Subject: [PATCH 496/554] drm/msm/dpu: Remove commit and its uses in dpu_crtc_set_crc_source() Clang warns: drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c:162:6: error: variable 'commit' is uninitialized when used here [-Werror,-Wuninitialized] if (commit) ^~~~~~ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c:106:32: note: initialize the variable 'commit' to silence this warning struct drm_crtc_commit *commit; ^ = NULL 1 error generated. The assignment and use of commit in the main body of dpu_crtc_set_crc_source() were removed from v1 to v2 but the call to drm_crtc_commit_put() at the end was not. Do that now so there is no more warning. Fixes: 78d9b458cc21 ("drm/msm/dpu: Add CRC support for DPU") Link: https://github.com/ClangBuiltLinux/linux/issues/1493 Reported-by: "kernelci.org bot" Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20211026142435.3606413-1-nathan@kernel.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 2523e829f485..967245b8cc02 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -103,7 +103,6 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); enum dpu_crtc_crc_source current_source; - struct drm_crtc_commit *commit; struct dpu_crtc_state *crtc_state; struct drm_device *drm_dev = crtc->dev; struct dpu_crtc_mixer *m; @@ -159,8 +158,6 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) cleanup: - if (commit) - drm_crtc_commit_put(commit); drm_modeset_unlock(&crtc->mutex); return ret; From 02d44fde976a8e9330f855fc535180727c779b9b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Oct 2021 10:32:41 +0200 Subject: [PATCH 497/554] drm/msm/dp: fix missing #include Some randconfig builds fail when drm/drm_bridge.h is not included implicitly in this file: drivers/gpu/drm/msm/dp/dp_parser.c:279:25: error: implicit declaration of function 'devm_drm_panel_bridge_add' [-Werror,-Wimplicit-function-declaration] parser->panel_bridge = devm_drm_panel_bridge_add(dev, panel); Fixes: 4b296d15b355 ("drm/msm/dp: Allow attaching a drm_panel") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20211026083254.3396322-1-arnd@kernel.org Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index 81dbcc86d08a..a7acc23f742b 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -8,6 +8,7 @@ #include #include +#include #include "dp_parser.h" #include "dp_reg.h" From 00f965e700ef5aa2d889e7e65c7458531d2a4bcf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 27 Oct 2021 18:39:14 -0400 Subject: [PATCH 498/554] drm/amdgpu/display: fix build when CONFIG_DRM_AMD_DC_DCN is not set Need to guard some things with CONFIG_DRM_AMD_DC_DCN. Fixes: 41724ea273cdda ("drm/amd/display: Add DP 2.0 MST DM Support") Signed-off-by: Alex Deucher Cc: Lyude Paul Cc: Dave Airlie Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20211027223914.1776061-1-alexander.deucher@amd.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ecdeeedb1cde..ee02776980b6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10683,9 +10683,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, struct dm_crtc_state *dm_old_crtc_state; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_mst_fairness_vars vars[MAX_PIPES]; -#endif struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_mgr *mgr; +#endif trace_amdgpu_dm_atomic_check_begin(state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 53b5cc7b0679..8cbeeb7c986d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -219,7 +219,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( struct drm_dp_mst_topology_mgr *mst_mgr; struct drm_dp_mst_port *mst_port; bool ret; - u8 link_coding_cap; + u8 link_coding_cap = DP_8b_10b_ENCODING; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; /* Accessing the connector state is required for vcpi_slots allocation @@ -239,7 +239,9 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_port = aconnector->port; +#if defined(CONFIG_DRM_AMD_DC_DCN) link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); +#endif if (enable) { From 31fa8cbce4664946a1688898410fee41ad05364d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 28 Oct 2021 02:31:40 +0300 Subject: [PATCH 499/554] drm: Add R10 and R12 FourCC Add FourCCs for 10- and 12-bit red formats with padding to 16 bits. They correspond to the V4L2 10- and 12-bit greyscale (V4L2_PIX_FMT_Y10 and V4L2_PIX_FMT_Y12) formats, as well as the Bayer formats with the same bit depth (V4L2_PIX_FMT_SBGGR{10,12} and all other Bayer pattern permutations). These formats are not used by any kernel driver at this point, but need to be exposed to applications by libcamera, which uses DRM FourCCs for pixel formats. Signed-off-by: Laurent Pinchart Signed-off-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20211027233140.12268-1-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/drm_fourcc.c | 2 ++ include/uapi/drm/drm_fourcc.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 783844bfecc1..25837b1d6639 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -134,6 +134,8 @@ const struct drm_format_info *__drm_format_info(u32 format) static const struct drm_format_info formats[] = { { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_R8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R10, .depth = 10, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R12, .depth = 12, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 45a914850be0..7f652c96845b 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -104,6 +104,12 @@ extern "C" { /* 8 bpp Red */ #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ +/* 10 bpp Red */ +#define DRM_FORMAT_R10 fourcc_code('R', '1', '0', ' ') /* [15:0] x:R 6:10 little endian */ + +/* 12 bpp Red */ +#define DRM_FORMAT_R12 fourcc_code('R', '1', '2', ' ') /* [15:0] x:R 4:12 little endian */ + /* 16 bpp Red */ #define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */ From 8483fdfea778aedded76c74659692dee3756b12b Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Tue, 12 Oct 2021 16:49:24 -0400 Subject: [PATCH 500/554] drm/amdgpu: Warn when bad pages approaches 90% threshold dmesg doesn't warn when the number of bad pages approaches the threshold for page retirement. WARN when the number of bad pages is at 90% or greater for easier checks and planning, instead of waiting until the GPU is full of bad pages. Cc: Luben Tuikov Cc: Mukul Joshi Signed-off-by: Kent Russell Reviewed-by: Felix Kuehling Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index f4c05ff4b26c..3978152e5ccc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1077,6 +1077,13 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, if (res) DRM_ERROR("RAS table incorrect checksum or error:%d\n", res); + + /* Warn if we are at 90% of the threshold or above + */ + if (10 * control->ras_num_recs >= 9 * ras->bad_page_cnt_threshold) + dev_warn(adev->dev, "RAS records:%u exceeds 90%% of threshold:%d", + control->ras_num_recs, + ras->bad_page_cnt_threshold); } else if (hdr->header == RAS_TABLE_HDR_BAD && amdgpu_bad_page_threshold != 0) { res = __verify_ras_table_checksum(control); From 68daadf3d673568bb7122b1683fd8b0e27c55d9b Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Tue, 19 Oct 2021 10:05:07 -0400 Subject: [PATCH 501/554] drm/amdgpu: Add kernel parameter support for ignoring bad page threshold When a GPU hits the bad_page_threshold, it will not be initialized by the amdgpu driver. This means that the table cannot be cleared, nor can information gathering be performed (getting serial number, BDF, etc). If the bad_page_threshold kernel parameter is set to -2, continue to initialize the GPU, while printing a warning to dmesg that this action has been done v2: squash in Luben's fix to restore RAS info reporting Cc: Luben Tuikov Cc: Mukul Joshi Signed-off-by: Kent Russell Acked-by: Felix Kuehling Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 15 +++++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d58e37fd01f4..b85b67a88a3d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -205,6 +205,7 @@ extern struct amdgpu_mgpu_info mgpu_info; extern int amdgpu_ras_enable; extern uint amdgpu_ras_mask; extern int amdgpu_bad_page_threshold; +extern bool amdgpu_ignore_bad_page_threshold; extern struct amdgpu_watchdog_timer amdgpu_watchdog_timer; extern int amdgpu_async_gfx_ring; extern int amdgpu_mcbp; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index c718fb5f3f8a..4cefe867ccf2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -877,7 +877,7 @@ module_param_named(reset_method, amdgpu_reset_method, int, 0444); * result in the GPU entering bad status when the number of total * faulty pages by ECC exceeds the threshold value. */ -MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = auto(default value), 0 = disable bad page retirement)"); +MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = auto(default value), 0 = disable bad page retirement, -2 = ignore bad page threshold)"); module_param_named(bad_page_threshold, amdgpu_bad_page_threshold, int, 0444); MODULE_PARM_DESC(num_kcq, "number of kernel compute queue user want to setup (8 if set to greater than 8 or less than 0, only affect gfx 8+)"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 3978152e5ccc..05117eda105b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1105,11 +1105,18 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, res = amdgpu_ras_eeprom_correct_header_tag(control, RAS_TABLE_HDR_VAL); } else { - *exceed_err_limit = true; - dev_err(adev->dev, - "RAS records:%d exceed threshold:%d, " - "GPU will not be initialized. Replace this GPU or increase the threshold", + dev_err(adev->dev, "RAS records:%d exceed threshold:%d", control->ras_num_recs, ras->bad_page_cnt_threshold); + if (amdgpu_bad_page_threshold == -2) { + dev_warn(adev->dev, "GPU will be initialized due to bad_page_threshold = -2."); + res = 0; + } else { + *exceed_err_limit = true; + dev_err(adev->dev, + "RAS records:%d exceed threshold:%d, " + "GPU will not be initialized. Replace this GPU or increase the threshold", + control->ras_num_recs, ras->bad_page_cnt_threshold); + } } } else { DRM_INFO("Creating a new EEPROM table"); From 3b8a23ae52dfbf785ea6f7c81358b1225a6bd339 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Tue, 26 Oct 2021 11:59:28 -0400 Subject: [PATCH 502/554] drm/amdkfd: restore userptr ignore bad address error The userptr can be unmapped by application and still registered to driver, restore userptr work return user pages will get -EFAULT bad address error. Pretend this error as succeed. GPU access this userptr will have VM fault later, it is better than application soft hangs with stalled user mode queues. v2: squash in warning fix (Alex) Signed-off-by: Philip Yang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 27 ++++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index cdf46bd0d8d5..6f01c6145a87 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2041,19 +2041,26 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info, /* Get updated user pages */ ret = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages); if (ret) { - pr_debug("%s: Failed to get user pages: %d\n", - __func__, ret); + pr_debug("Failed %d to get user pages\n", ret); - /* Return error -EBUSY or -ENOMEM, retry restore */ - return ret; + /* Return -EFAULT bad address error as success. It will + * fail later with a VM fault if the GPU tries to access + * it. Better than hanging indefinitely with stalled + * user mode queues. + * + * Return other error -EBUSY or -ENOMEM to retry restore + */ + if (ret != -EFAULT) + return ret; + } else { + + /* + * FIXME: Cannot ignore the return code, must hold + * notifier_lock + */ + amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm); } - /* - * FIXME: Cannot ignore the return code, must hold - * notifier_lock - */ - amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm); - /* Mark the BO as valid unless it was invalidated * again concurrently. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 590537b62a0a..17b5dd6adf8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -696,6 +696,9 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages) true, NULL); out_unlock: mmap_read_unlock(mm); + if (r) + pr_debug("failed %d to get user pages 0x%lx\n", r, start); + mmput(mm); return r; From 68df0f195a689bbb0f92bfeadee6edd90c79c31f Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Mon, 11 Oct 2021 14:41:57 +0800 Subject: [PATCH 503/554] drm/amdkfd: Separate pinned BOs destruction from general routine Currently, all kfd BOs use same destruction routine. But pinned BOs are not unpinned properly. Separate them from general routine. v2 (Felix): Add safeguard to prevent user space from freeing signal BO. Kunmap signal BO in the event of setting event page error. Just kunmap signal BO to avoid duplicating the code. Signed-off-by: Lang Yu Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 + .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 10 ++ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 31 +++-- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 109 +++++++++++++----- 5 files changed, 118 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 69de31754907..751557af09bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -279,6 +279,8 @@ int amdgpu_amdkfd_gpuvm_sync_memory( struct kgd_dev *kgd, struct kgd_mem *mem, bool intr); int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, struct kgd_mem *mem, void **kptr, uint64_t *size); +void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_dev *kgd, struct kgd_mem *mem); + int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info, struct dma_fence **ef); int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 6f01c6145a87..0e9cfe99ae9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1871,6 +1871,16 @@ bo_reserve_failed: return ret; } +void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_dev *kgd, struct kgd_mem *mem) +{ + struct amdgpu_bo *bo = mem->bo; + + amdgpu_bo_reserve(bo, true); + amdgpu_bo_kunmap(bo); + amdgpu_bo_unpin(bo); + amdgpu_bo_unreserve(bo); +} + int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, struct kfd_vm_fault_info *mem) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index f1e7edeb4e6b..9317a2e238d0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1011,11 +1011,6 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p, void *mem, *kern_addr; uint64_t size; - if (p->signal_page) { - pr_err("Event page is already set\n"); - return -EINVAL; - } - kfd = kfd_device_by_id(GET_GPU_ID(args->event_page_offset)); if (!kfd) { pr_err("Getting device by id failed in %s\n", __func__); @@ -1023,6 +1018,13 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p, } mutex_lock(&p->mutex); + + if (p->signal_page) { + pr_err("Event page is already set\n"); + err = -EINVAL; + goto out_unlock; + } + pdd = kfd_bind_process_to_device(kfd, p); if (IS_ERR(pdd)) { err = PTR_ERR(pdd); @@ -1037,20 +1039,24 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p, err = -EINVAL; goto out_unlock; } - mutex_unlock(&p->mutex); err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kfd->kgd, mem, &kern_addr, &size); if (err) { pr_err("Failed to map event page to kernel\n"); - return err; + goto out_unlock; } err = kfd_event_page_set(p, kern_addr, size); if (err) { pr_err("Failed to set event page\n"); - return err; + amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(kfd->kgd, mem); + goto out_unlock; } + + p->signal_handle = args->event_page_offset; + + mutex_unlock(&p->mutex); } err = kfd_event_create(filp, p, args->event_type, @@ -1368,6 +1374,15 @@ static int kfd_ioctl_free_memory_of_gpu(struct file *filep, return -EINVAL; mutex_lock(&p->mutex); + /* + * Safeguard to prevent user space from freeing signal BO. + * It will be freed at process termination. + */ + if (p->signal_handle && (p->signal_handle == args->handle)) { + pr_err("Free signal BO is not allowed\n"); + ret = -EPERM; + goto err_unlock; + } pdd = kfd_get_process_device_data(dev, p); if (!pdd) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 6d8f9bb2d905..30f08f1606bb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -608,12 +608,14 @@ struct qcm_process_device { uint32_t sh_hidden_private_base; /* CWSR memory */ + struct kgd_mem *cwsr_mem; void *cwsr_kaddr; uint64_t cwsr_base; uint64_t tba_addr; uint64_t tma_addr; /* IB memory */ + struct kgd_mem *ib_mem; uint64_t ib_base; void *ib_kaddr; @@ -808,6 +810,7 @@ struct kfd_process { /* Event ID allocator and lookup */ struct idr event_idr; /* Event page */ + u64 signal_handle; struct kfd_signal_page *signal_page; size_t signal_mapped_size; size_t signal_event_count; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 21ec8a18cad2..457863861d6f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -72,6 +72,8 @@ static int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep); static void evict_process_worker(struct work_struct *work); static void restore_process_worker(struct work_struct *work); +static void kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device *pdd); + struct kfd_procfs_tree { struct kobject *kobj; }; @@ -685,10 +687,15 @@ void kfd_process_destroy_wq(void) } static void kfd_process_free_gpuvm(struct kgd_mem *mem, - struct kfd_process_device *pdd) + struct kfd_process_device *pdd, void *kptr) { struct kfd_dev *dev = pdd->dev; + if (kptr) { + amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(dev->kgd, mem); + kptr = NULL; + } + amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->kgd, mem, pdd->drm_priv); amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, mem, pdd->drm_priv, NULL); @@ -702,63 +709,46 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem, */ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd, uint64_t gpu_va, uint32_t size, - uint32_t flags, void **kptr) + uint32_t flags, struct kgd_mem **mem, void **kptr) { struct kfd_dev *kdev = pdd->dev; - struct kgd_mem *mem = NULL; - int handle; int err; err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(kdev->kgd, gpu_va, size, - pdd->drm_priv, &mem, NULL, flags); + pdd->drm_priv, mem, NULL, flags); if (err) goto err_alloc_mem; - err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, mem, + err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, *mem, pdd->drm_priv, NULL); if (err) goto err_map_mem; - err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, mem, true); + err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, *mem, true); if (err) { pr_debug("Sync memory failed, wait interrupted by user signal\n"); goto sync_memory_failed; } - /* Create an obj handle so kfd_process_device_remove_obj_handle - * will take care of the bo removal when the process finishes. - * We do not need to take p->mutex, because the process is just - * created and the ioctls have not had the chance to run. - */ - handle = kfd_process_device_create_obj_handle(pdd, mem); - - if (handle < 0) { - err = handle; - goto free_gpuvm; - } - if (kptr) { err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kdev->kgd, - (struct kgd_mem *)mem, kptr, NULL); + (struct kgd_mem *)*mem, kptr, NULL); if (err) { pr_debug("Map GTT BO to kernel failed\n"); - goto free_obj_handle; + goto sync_memory_failed; } } return err; -free_obj_handle: - kfd_process_device_remove_obj_handle(pdd, handle); -free_gpuvm: sync_memory_failed: - kfd_process_free_gpuvm(mem, pdd); - return err; + amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(kdev->kgd, *mem, pdd->drm_priv); err_map_mem: - amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, mem, pdd->drm_priv, + amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, *mem, pdd->drm_priv, NULL); err_alloc_mem: + *mem = NULL; *kptr = NULL; return err; } @@ -776,6 +766,7 @@ static int kfd_process_device_reserve_ib_mem(struct kfd_process_device *pdd) KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE | KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE | KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE; + struct kgd_mem *mem; void *kaddr; int ret; @@ -784,15 +775,26 @@ static int kfd_process_device_reserve_ib_mem(struct kfd_process_device *pdd) /* ib_base is only set for dGPU */ ret = kfd_process_alloc_gpuvm(pdd, qpd->ib_base, PAGE_SIZE, flags, - &kaddr); + &mem, &kaddr); if (ret) return ret; + qpd->ib_mem = mem; qpd->ib_kaddr = kaddr; return 0; } +static void kfd_process_device_destroy_ib_mem(struct kfd_process_device *pdd) +{ + struct qcm_process_device *qpd = &pdd->qpd; + + if (!qpd->ib_kaddr || !qpd->ib_base) + return; + + kfd_process_free_gpuvm(qpd->ib_mem, pdd, qpd->ib_kaddr); +} + struct kfd_process *kfd_create_process(struct file *filep) { struct kfd_process *process; @@ -947,6 +949,37 @@ static void kfd_process_device_free_bos(struct kfd_process_device *pdd) } } +/* + * Just kunmap and unpin signal BO here. It will be freed in + * kfd_process_free_outstanding_kfd_bos() + */ +static void kfd_process_kunmap_signal_bo(struct kfd_process *p) +{ + struct kfd_process_device *pdd; + struct kfd_dev *kdev; + void *mem; + + kdev = kfd_device_by_id(GET_GPU_ID(p->signal_handle)); + if (!kdev) + return; + + mutex_lock(&p->mutex); + + pdd = kfd_get_process_device_data(kdev, p); + if (!pdd) + goto out; + + mem = kfd_process_device_translate_handle( + pdd, GET_IDR_HANDLE(p->signal_handle)); + if (!mem) + goto out; + + amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(kdev->kgd, mem); + +out: + mutex_unlock(&p->mutex); +} + static void kfd_process_free_outstanding_kfd_bos(struct kfd_process *p) { int i; @@ -965,6 +998,9 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) pr_debug("Releasing pdd (topology id %d) for process (pasid 0x%x)\n", pdd->dev->id, p->pasid); + kfd_process_device_destroy_cwsr_dgpu(pdd); + kfd_process_device_destroy_ib_mem(pdd); + if (pdd->drm_file) { amdgpu_amdkfd_gpuvm_release_process_vm( pdd->dev->kgd, pdd->drm_priv); @@ -1049,9 +1085,11 @@ static void kfd_process_wq_release(struct work_struct *work) { struct kfd_process *p = container_of(work, struct kfd_process, release_work); + kfd_process_remove_sysfs(p); kfd_iommu_unbind_process(p); + kfd_process_kunmap_signal_bo(p); kfd_process_free_outstanding_kfd_bos(p); svm_range_list_fini(p); @@ -1198,6 +1236,7 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT | KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE | KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE; + struct kgd_mem *mem; void *kaddr; int ret; @@ -1206,10 +1245,11 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) /* cwsr_base is only set for dGPU */ ret = kfd_process_alloc_gpuvm(pdd, qpd->cwsr_base, - KFD_CWSR_TBA_TMA_SIZE, flags, &kaddr); + KFD_CWSR_TBA_TMA_SIZE, flags, &mem, &kaddr); if (ret) return ret; + qpd->cwsr_mem = mem; qpd->cwsr_kaddr = kaddr; qpd->tba_addr = qpd->cwsr_base; @@ -1222,6 +1262,17 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) return 0; } +static void kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device *pdd) +{ + struct kfd_dev *dev = pdd->dev; + struct qcm_process_device *qpd = &pdd->qpd; + + if (!dev->cwsr_enabled || !qpd->cwsr_kaddr || !qpd->cwsr_base) + return; + + kfd_process_free_gpuvm(qpd->cwsr_mem, pdd, qpd->cwsr_kaddr); +} + void kfd_process_set_trap_handler(struct qcm_process_device *qpd, uint64_t tba_addr, uint64_t tma_addr) From a5c5d8d50ecf5874be90a76e1557279ff8a30c9e Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Thu, 21 Oct 2021 14:36:36 +0800 Subject: [PATCH 504/554] drm/amdgpu: fix a potential memory leak in amdgpu_device_fini_sw() amdgpu_fence_driver_sw_fini() should be executed before amdgpu_device_ip_fini(), otherwise fence driver resource won't be properly freed as adev->rings have been tore down. Fixes: 72c8c97b1522 ("drm/amdgpu: Split amdgpu_device_fini into early and late") Signed-off-by: Lang Yu Reviewed-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c218d53a031d..6e40cc1bc6dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3852,8 +3852,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) void amdgpu_device_fini_sw(struct amdgpu_device *adev) { - amdgpu_device_ip_fini(adev); amdgpu_fence_driver_sw_fini(adev); + amdgpu_device_ip_fini(adev); release_firmware(adev->firmware.gpu_info_fw); adev->firmware.gpu_info_fw = NULL; adev->accel_working = false; From 4320e6f86d976f86d836441c31e23ef8cfed048e Mon Sep 17 00:00:00 2001 From: Candice Li Date: Thu, 21 Oct 2021 14:52:59 +0800 Subject: [PATCH 505/554] drm/amdgpu: Update TA version output in driver TA version should only be displayed in firmware version column. Signed-off-by: Candice Li Reviewed-by: John Clements Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 12 ++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 14 +++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/psp_v10_0.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/psp_v12_0.c | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index d2955ea4a62b..dfe667ea8b05 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -340,32 +340,32 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, case AMDGPU_INFO_FW_TA: switch (query_fw->index) { case TA_FW_TYPE_PSP_XGMI: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.xgmi_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.xgmi_context.context .bin_desc.feature_version; break; case TA_FW_TYPE_PSP_RAS: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.ras_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.ras_context.context .bin_desc.feature_version; break; case TA_FW_TYPE_PSP_HDCP: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.hdcp_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.hdcp_context.context .bin_desc.feature_version; break; case TA_FW_TYPE_PSP_DTM: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.dtm_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.dtm_context.context .bin_desc.feature_version; break; case TA_FW_TYPE_PSP_RAP: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.rap_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.rap_context.context .bin_desc.feature_version; break; case TA_FW_TYPE_PSP_SECUREDISPLAY: - fw_info->ver = adev->psp.ta_fw_version; + fw_info->ver = adev->psp.securedisplay_context.context.bin_desc.fw_version; fw_info->feature = adev->psp.securedisplay_context.context.bin_desc .feature_version; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index fd04e83031d6..c641f84649d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1115,7 +1115,7 @@ int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id) static bool psp_xgmi_peer_link_info_supported(struct psp_context *psp) { return psp->adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 2) && - psp->xgmi_context.context.bin_desc.feature_version >= 0x2000000b; + psp->xgmi_context.context.bin_desc.fw_version >= 0x2000000b; } /* @@ -3108,32 +3108,32 @@ static int parse_ta_bin_descriptor(struct psp_context *psp, psp->asd_context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_XGMI: - psp->xgmi_context.context.bin_desc.feature_version = le32_to_cpu(desc->fw_version); + psp->xgmi_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->xgmi_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->xgmi_context.context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_RAS: - psp->ras_context.context.bin_desc.feature_version = le32_to_cpu(desc->fw_version); + psp->ras_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->ras_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->ras_context.context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_HDCP: - psp->hdcp_context.context.bin_desc.feature_version = le32_to_cpu(desc->fw_version); + psp->hdcp_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->hdcp_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->hdcp_context.context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_DTM: - psp->dtm_context.context.bin_desc.feature_version = le32_to_cpu(desc->fw_version); + psp->dtm_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->dtm_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->dtm_context.context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_RAP: - psp->rap_context.context.bin_desc.feature_version = le32_to_cpu(desc->fw_version); + psp->rap_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->rap_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->rap_context.context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_SECUREDISPLAY: - psp->securedisplay_context.context.bin_desc.feature_version = + psp->securedisplay_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->securedisplay_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 920c4f6ac914..ca3350502618 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -527,8 +527,8 @@ FW_VERSION_ATTR(mec_fw_version, 0444, gfx.mec_fw_version); FW_VERSION_ATTR(mec2_fw_version, 0444, gfx.mec2_fw_version); FW_VERSION_ATTR(sos_fw_version, 0444, psp.sos.fw_version); FW_VERSION_ATTR(asd_fw_version, 0444, psp.asd_context.bin_desc.fw_version); -FW_VERSION_ATTR(ta_ras_fw_version, 0444, psp.ras_context.context.bin_desc.feature_version); -FW_VERSION_ATTR(ta_xgmi_fw_version, 0444, psp.xgmi_context.context.bin_desc.feature_version); +FW_VERSION_ATTR(ta_ras_fw_version, 0444, psp.ras_context.context.bin_desc.fw_version); +FW_VERSION_ATTR(ta_xgmi_fw_version, 0444, psp.xgmi_context.context.bin_desc.fw_version); FW_VERSION_ATTR(smc_fw_version, 0444, pm.fw_version); FW_VERSION_ATTR(sdma_fw_version, 0444, sdma.instance[0].fw_version); FW_VERSION_ATTR(sdma2_fw_version, 0444, sdma.instance[1].fw_version); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 99c149397aae..04cf9b207e62 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -535,9 +535,9 @@ static void amdgpu_virt_populate_vf2pf_ucode_info(struct amdgpu_device *adev) POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_ASD, adev->psp.asd_context.bin_desc.fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_TA_RAS, - adev->psp.ras_context.context.bin_desc.feature_version); + adev->psp.ras_context.context.bin_desc.fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_TA_XGMI, - adev->psp.xgmi_context.context.bin_desc.feature_version); + adev->psp.xgmi_context.context.bin_desc.fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SMC, adev->pm.fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SDMA, adev->sdma.instance[0].fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SDMA2, adev->sdma.instance[1].fw_version); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index 59644015dfc3..ed2293686f0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -84,7 +84,7 @@ static int psp_v10_0_init_microcode(struct psp_context *psp) ta_hdr = (const struct ta_firmware_header_v1_0 *) adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.feature_version = + adev->psp.hdcp_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->hdcp.fw_version); adev->psp.hdcp_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->hdcp.size_bytes); @@ -92,7 +92,7 @@ static int psp_v10_0_init_microcode(struct psp_context *psp) (uint8_t *)ta_hdr + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); - adev->psp.dtm_context.context.bin_desc.feature_version = + adev->psp.dtm_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->dtm.fw_version); adev->psp.dtm_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->dtm.size_bytes); @@ -100,7 +100,7 @@ static int psp_v10_0_init_microcode(struct psp_context *psp) (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + le32_to_cpu(ta_hdr->dtm.offset_bytes); - adev->psp.securedisplay_context.context.bin_desc.feature_version = + adev->psp.securedisplay_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->securedisplay.fw_version); adev->psp.securedisplay_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->securedisplay.size_bytes); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index 21a325ea49cb..2176ef85f137 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -151,7 +151,7 @@ static int psp_v11_0_init_microcode(struct psp_context *psp) goto out2; ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; - adev->psp.xgmi_context.context.bin_desc.feature_version = + adev->psp.xgmi_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->xgmi.fw_version); adev->psp.xgmi_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->xgmi.size_bytes); @@ -159,7 +159,7 @@ static int psp_v11_0_init_microcode(struct psp_context *psp) (uint8_t *)ta_hdr + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - adev->psp.ras_context.context.bin_desc.feature_version = + adev->psp.ras_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->ras.fw_version); adev->psp.ras_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->ras.size_bytes); @@ -192,7 +192,7 @@ static int psp_v11_0_init_microcode(struct psp_context *psp) goto out2; ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.feature_version = + adev->psp.hdcp_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->hdcp.fw_version); adev->psp.hdcp_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->hdcp.size_bytes); @@ -203,7 +203,7 @@ static int psp_v11_0_init_microcode(struct psp_context *psp) adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - adev->psp.dtm_context.context.bin_desc.feature_version = + adev->psp.dtm_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->dtm.fw_version); adev->psp.dtm_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->dtm.size_bytes); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c index 281bc4d7f0a1..a2588200ea58 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c @@ -84,7 +84,7 @@ static int psp_v12_0_init_microcode(struct psp_context *psp) ta_hdr = (const struct ta_firmware_header_v1_0 *) adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.feature_version = + adev->psp.hdcp_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->hdcp.fw_version); adev->psp.hdcp_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->hdcp.size_bytes); @@ -94,7 +94,7 @@ static int psp_v12_0_init_microcode(struct psp_context *psp) adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - adev->psp.dtm_context.context.bin_desc.feature_version = + adev->psp.dtm_context.context.bin_desc.fw_version = le32_to_cpu(ta_hdr->dtm.fw_version); adev->psp.dtm_context.context.bin_desc.size_bytes = le32_to_cpu(ta_hdr->dtm.size_bytes); From f7e053435c3d9874df7c12f9865d4c746c1b78f2 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Wed, 20 Oct 2021 11:17:25 +0800 Subject: [PATCH 506/554] drm/amdgpu: skip GPRs init for some CU settings on ALDEBARAN Skip GPRs init in specific condition since current GPRs init algorithm only works for some CU settings. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c index 00a2b36a24b3..24852a24cc58 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c @@ -706,6 +706,11 @@ int gfx_v9_4_2_do_edc_gpr_workarounds(struct amdgpu_device *adev) if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) return 0; + /* Workaround for some CU settings, skip GPRs init. + Will remove it once GPRs init algorithm works for all CU settings */ + if (adev->gfx.cu_info.bitmap[1][1] == 0x3f7f) + return 0; + gfx_v9_4_2_do_sgprs_init(adev); gfx_v9_4_2_do_vgprs_init(adev); From c6e559eb3b246c96bfe77e218097c7c5308da5d8 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Fri, 8 Oct 2021 12:47:18 +0800 Subject: [PATCH 507/554] drm/amdkfd: Add an optional argument into update queue operation(v2) Currently, queue is updated with data in queue_properties. And all allocated resource in queue_properties will not be freed until the queue is destroyed. But some properties(e.g., cu mask) bring some memory management headaches(e.g., memory leak) and make code complex. Actually they have been copied to mqd and don't have to persist in queue_properties. Add an argument into update queue to pass such properties, then we can remove them from queue_properties. v2: Don't use void *. Suggested-by: Felix Kuehling Signed-off-by: Lang Yu Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 5 ++-- .../drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 3 ++- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 23 +++++++++------- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c | 10 ++++--- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 10 ++++--- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 26 +++++++++++-------- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 ++ .../amd/amdkfd/kfd_process_queue_manager.c | 6 ++--- 9 files changed, 52 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index f8fce9d05f50..533b27b35fc9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -557,7 +557,8 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, return retval; } -static int update_queue(struct device_queue_manager *dqm, struct queue *q) +static int update_queue(struct device_queue_manager *dqm, struct queue *q, + struct mqd_update_info *minfo) { int retval = 0; struct mqd_manager *mqd_mgr; @@ -605,7 +606,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) } } - mqd_mgr->update_mqd(mqd_mgr, q->mqd, &q->properties); + mqd_mgr->update_mqd(mqd_mgr, q->mqd, &q->properties, minfo); /* * check active state vs. the previous state and modify diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index c8719682c4da..499fc0ea387f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -93,7 +93,7 @@ struct device_queue_manager_ops { struct queue *q); int (*update_queue)(struct device_queue_manager *dqm, - struct queue *q); + struct queue *q, struct mqd_update_info *minfo); int (*register_process)(struct device_queue_manager *dqm, struct qcm_process_device *qpd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 6e6918ccedfd..965e17c5dbb4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -80,7 +80,8 @@ struct mqd_manager { struct mm_struct *mms); void (*update_mqd)(struct mqd_manager *mm, void *mqd, - struct queue_properties *q); + struct queue_properties *q, + struct mqd_update_info *minfo); int (*destroy_mqd)(struct mqd_manager *mm, void *mqd, enum kfd_preempt_type type, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 064914e1e8d6..00bcaa11ff57 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -135,7 +135,7 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, *mqd = m; if (gart_addr) *gart_addr = addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, @@ -152,7 +152,7 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, if (gart_addr) *gart_addr = mqd_mem_obj->gpu_addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static void free_mqd(struct mqd_manager *mm, void *mqd, @@ -185,7 +185,8 @@ static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, } static void __update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q, unsigned int atc_bit) + struct queue_properties *q, struct mqd_update_info *minfo, + unsigned int atc_bit) { struct cik_mqd *m; @@ -221,9 +222,10 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, } static void update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { - __update_mqd(mm, mqd, q, 1); + __update_mqd(mm, mqd, q, minfo, 1); } static uint32_t read_doorbell_id(void *mqd) @@ -234,13 +236,15 @@ static uint32_t read_doorbell_id(void *mqd) } static void update_mqd_hawaii(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { - __update_mqd(mm, mqd, q, 0); + __update_mqd(mm, mqd, q, minfo, 0); } static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct cik_sdma_rlc_registers *m; @@ -318,7 +322,8 @@ static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, } static void update_mqd_hiq(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct cik_mqd *m; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index c7fb59ca597f..7f1101780135 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -136,7 +136,7 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, *mqd = m; if (gart_addr) *gart_addr = addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd(struct mqd_manager *mm, void *mqd, @@ -162,7 +162,8 @@ static int hiq_load_mqd_kiq(struct mqd_manager *mm, void *mqd, } static void update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct v10_compute_mqd *m; @@ -311,7 +312,7 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, if (gart_addr) *gart_addr = mqd_mem_obj->gpu_addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, @@ -326,7 +327,8 @@ static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, #define SDMA_RLC_DUMMY_DEFAULT 0xf static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct v10_sdma_mqd *m; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 7f4e102ff4bd..152f29b28a79 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -188,7 +188,7 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, *mqd = m; if (gart_addr) *gart_addr = addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd(struct mqd_manager *mm, void *mqd, @@ -212,7 +212,8 @@ static int hiq_load_mqd_kiq(struct mqd_manager *mm, void *mqd, } static void update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct v9_mqd *m; @@ -366,7 +367,7 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, if (gart_addr) *gart_addr = mqd_mem_obj->gpu_addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, @@ -381,7 +382,8 @@ static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, #define SDMA_RLC_DUMMY_DEFAULT 0xf static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct v9_sdma_mqd *m; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 33dbd22d290f..4a8f3a06e6df 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -150,7 +150,7 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, *mqd = m; if (gart_addr) *gart_addr = addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd(struct mqd_manager *mm, void *mqd, @@ -167,8 +167,8 @@ static int load_mqd(struct mqd_manager *mm, void *mqd, } static void __update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q, unsigned int mtype, - unsigned int atc_bit) + struct queue_properties *q, struct mqd_update_info *minfo, + unsigned int mtype, unsigned int atc_bit) { struct vi_mqd *m; @@ -238,9 +238,10 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, static void update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { - __update_mqd(mm, mqd, q, MTYPE_CC, 1); + __update_mqd(mm, mqd, q, minfo, MTYPE_CC, 1); } static uint32_t read_doorbell_id(void *mqd) @@ -251,9 +252,10 @@ static uint32_t read_doorbell_id(void *mqd) } static void update_mqd_tonga(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { - __update_mqd(mm, mqd, q, MTYPE_UC, 0); + __update_mqd(mm, mqd, q, minfo, MTYPE_UC, 0); } static int destroy_mqd(struct mqd_manager *mm, void *mqd, @@ -317,9 +319,10 @@ static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, } static void update_mqd_hiq(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { - __update_mqd(mm, mqd, q, MTYPE_UC, 0); + __update_mqd(mm, mqd, q, minfo, MTYPE_UC, 0); } static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, @@ -336,7 +339,7 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, if (gart_addr) *gart_addr = mqd_mem_obj->gpu_addr; - mm->update_mqd(mm, m, q); + mm->update_mqd(mm, m, q, NULL); } static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, @@ -349,7 +352,8 @@ static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, } static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct queue_properties *q, + struct mqd_update_info *minfo) { struct vi_sdma_mqd *m; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 30f08f1606bb..d758a57b17e2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -482,6 +482,8 @@ struct queue_properties { (q).queue_percent > 0 && \ !(q).is_evicted) +struct mqd_update_info; + /** * struct queue * diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 243dd1efcdbf..37529592457d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -121,7 +121,7 @@ int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid, pdd->qpd.num_gws = gws ? amdgpu_amdkfd_get_num_gws(dev->kgd) : 0; return pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, - pqn->q); + pqn->q, NULL); } void kfd_process_dequeue_from_all_devices(struct kfd_process *p) @@ -429,7 +429,7 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, pqn->q->properties.priority = p->priority; retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, - pqn->q); + pqn->q, NULL); if (retval != 0) return retval; @@ -457,7 +457,7 @@ int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, pqn->q->properties.cu_mask = p->cu_mask; retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, - pqn->q); + pqn->q, NULL); if (retval != 0) return retval; From 7c695a2c54b97ac27b20fc0fd17c626af3eee60a Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Fri, 8 Oct 2021 16:46:07 +0800 Subject: [PATCH 508/554] drm/amdkfd: Remove cu mask from struct queue_properties(v2) Actually, cu_mask has been copied to mqd memory and does't have to persist in queue_properties. Remove it from queue_properties. And use struct mqd_update_info to store such properties, then pass it to update queue operation. v2: * Rename pqm_update_queue to pqm_update_queue_properties. * Rename struct queue_update_info to struct mqd_update_info. * Rename pqm_set_cu_mask to pqm_update_mqd. Suggested-by: Felix Kuehling Signed-off-by: Lang Yu Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 31 ++++++++++--------- drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c | 1 - .../gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 9 +++--- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c | 9 +++--- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 9 +++--- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 9 +++--- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 23 +++++++++----- .../amd/amdkfd/kfd_process_queue_manager.c | 20 +++--------- 8 files changed, 57 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 9317a2e238d0..24ebd61395d8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -405,7 +405,7 @@ static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p, mutex_lock(&p->mutex); - retval = pqm_update_queue(&p->pqm, args->queue_id, &properties); + retval = pqm_update_queue_properties(&p->pqm, args->queue_id, &properties); mutex_unlock(&p->mutex); @@ -418,7 +418,7 @@ static int kfd_ioctl_set_cu_mask(struct file *filp, struct kfd_process *p, int retval; const int max_num_cus = 1024; struct kfd_ioctl_set_cu_mask_args *args = data; - struct queue_properties properties; + struct mqd_update_info minfo = {0}; uint32_t __user *cu_mask_ptr = (uint32_t __user *)args->cu_mask_ptr; size_t cu_mask_size = sizeof(uint32_t) * (args->num_cu_mask / 32); @@ -428,8 +428,8 @@ static int kfd_ioctl_set_cu_mask(struct file *filp, struct kfd_process *p, return -EINVAL; } - properties.cu_mask_count = args->num_cu_mask; - if (properties.cu_mask_count == 0) { + minfo.cu_mask.count = args->num_cu_mask; + if (minfo.cu_mask.count == 0) { pr_debug("CU mask cannot be 0"); return -EINVAL; } @@ -438,32 +438,33 @@ static int kfd_ioctl_set_cu_mask(struct file *filp, struct kfd_process *p, * limit of max_num_cus bits. We can then just drop any CU mask bits * past max_num_cus bits and just use the first max_num_cus bits. */ - if (properties.cu_mask_count > max_num_cus) { + if (minfo.cu_mask.count > max_num_cus) { pr_debug("CU mask cannot be greater than 1024 bits"); - properties.cu_mask_count = max_num_cus; + minfo.cu_mask.count = max_num_cus; cu_mask_size = sizeof(uint32_t) * (max_num_cus/32); } - properties.cu_mask = kzalloc(cu_mask_size, GFP_KERNEL); - if (!properties.cu_mask) + minfo.cu_mask.ptr = kzalloc(cu_mask_size, GFP_KERNEL); + if (!minfo.cu_mask.ptr) return -ENOMEM; - retval = copy_from_user(properties.cu_mask, cu_mask_ptr, cu_mask_size); + retval = copy_from_user(minfo.cu_mask.ptr, cu_mask_ptr, cu_mask_size); if (retval) { pr_debug("Could not copy CU mask from userspace"); - kfree(properties.cu_mask); - return -EFAULT; + retval = -EFAULT; + goto out; } + minfo.update_flag = UPDATE_FLAG_CU_MASK; + mutex_lock(&p->mutex); - retval = pqm_set_cu_mask(&p->pqm, args->queue_id, &properties); + retval = pqm_update_mqd(&p->pqm, args->queue_id, &minfo); mutex_unlock(&p->mutex); - if (retval) - kfree(properties.cu_mask); - +out: + kfree(minfo.cu_mask.ptr); return retval; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index a2b77d1df854..64b4ac339904 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -136,7 +136,6 @@ static bool kq_initialize(struct kernel_queue *kq, struct kfd_dev *dev, prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr; prop.eop_ring_buffer_address = kq->eop_gpu_addr; prop.eop_ring_buffer_size = PAGE_SIZE; - prop.cu_mask = NULL; if (init_queue(&kq->queue, &prop) != 0) goto err_init_queue; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 00bcaa11ff57..8128f4d312f1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -42,16 +42,17 @@ static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) } static void update_cu_mask(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct mqd_update_info *minfo) { struct cik_mqd *m; uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ - if (q->cu_mask_count == 0) + if (!minfo || (minfo->update_flag != UPDATE_FLAG_CU_MASK) || + !minfo->cu_mask.ptr) return; mqd_symmetrically_map_cu_mask(mm, - q->cu_mask, q->cu_mask_count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; @@ -215,7 +216,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_pq_control |= NO_UPDATE_RPTR; - update_cu_mask(mm, mqd, q); + update_cu_mask(mm, mqd, minfo); set_priority(m, q); q->is_active = QUEUE_IS_ACTIVE(*q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 7f1101780135..270160fc401b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -42,16 +42,17 @@ static inline struct v10_sdma_mqd *get_sdma_mqd(void *mqd) } static void update_cu_mask(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct mqd_update_info *minfo) { struct v10_compute_mqd *m; uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ - if (q->cu_mask_count == 0) + if (!minfo || (minfo->update_flag != UPDATE_FLAG_CU_MASK) || + !minfo->cu_mask.ptr) return; mqd_symmetrically_map_cu_mask(mm, - q->cu_mask, q->cu_mask_count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; @@ -219,7 +220,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->cwsr_enabled) m->cp_hqd_ctx_save_control = 0; - update_cu_mask(mm, mqd, q); + update_cu_mask(mm, mqd, minfo); set_priority(m, q); q->is_active = QUEUE_IS_ACTIVE(*q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 152f29b28a79..4e5932f54b5a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -43,16 +43,17 @@ static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd) } static void update_cu_mask(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct mqd_update_info *minfo) { struct v9_mqd *m; uint32_t se_mask[KFD_MAX_NUM_SE] = {0}; - if (q->cu_mask_count == 0) + if (!minfo || (minfo->update_flag != UPDATE_FLAG_CU_MASK) || + !minfo->cu_mask.ptr) return; mqd_symmetrically_map_cu_mask(mm, - q->cu_mask, q->cu_mask_count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; @@ -270,7 +271,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->cwsr_enabled && q->ctx_save_restore_area_address) m->cp_hqd_ctx_save_control = 0; - update_cu_mask(mm, mqd, q); + update_cu_mask(mm, mqd, minfo); set_priority(m, q); q->is_active = QUEUE_IS_ACTIVE(*q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 4a8f3a06e6df..cd9220eb8a7a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -45,16 +45,17 @@ static inline struct vi_sdma_mqd *get_sdma_mqd(void *mqd) } static void update_cu_mask(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) + struct mqd_update_info *minfo) { struct vi_mqd *m; uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ - if (q->cu_mask_count == 0) + if (!minfo || (minfo->update_flag != UPDATE_FLAG_CU_MASK) || + !minfo->cu_mask.ptr) return; mqd_symmetrically_map_cu_mask(mm, - q->cu_mask, q->cu_mask_count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; @@ -230,7 +231,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, atc_bit << CP_HQD_CTX_SAVE_CONTROL__ATC__SHIFT | mtype << CP_HQD_CTX_SAVE_CONTROL__MTYPE__SHIFT; - update_cu_mask(mm, mqd, q); + update_cu_mask(mm, mqd, minfo); set_priority(m, q); q->is_active = QUEUE_IS_ACTIVE(*q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d758a57b17e2..4104b167e721 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -472,9 +472,6 @@ struct queue_properties { uint32_t ctl_stack_size; uint64_t tba_addr; uint64_t tma_addr; - /* Relevant for CU */ - uint32_t cu_mask_count; /* Must be a multiple of 32 */ - uint32_t *cu_mask; }; #define QUEUE_IS_ACTIVE(q) ((q).queue_size > 0 && \ @@ -482,7 +479,19 @@ struct queue_properties { (q).queue_percent > 0 && \ !(q).is_evicted) -struct mqd_update_info; +enum mqd_update_flag { + UPDATE_FLAG_CU_MASK = 0, +}; + +struct mqd_update_info { + union { + struct { + uint32_t count; /* Must be a multiple of 32 */ + uint32_t *ptr; + } cu_mask; + }; + enum mqd_update_flag update_flag; +}; /** * struct queue @@ -1036,10 +1045,10 @@ int pqm_create_queue(struct process_queue_manager *pqm, unsigned int *qid, uint32_t *p_doorbell_offset_in_process); int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid); -int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, - struct queue_properties *p); -int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, +int pqm_update_queue_properties(struct process_queue_manager *pqm, unsigned int qid, struct queue_properties *p); +int pqm_update_mqd(struct process_queue_manager *pqm, unsigned int qid, + struct mqd_update_info *minfo); int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid, void *gws); struct kernel_queue *pqm_get_kernel_queue(struct process_queue_manager *pqm, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 37529592457d..3627e7ac161b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -394,8 +394,6 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) pdd->qpd.num_gws = 0; } - kfree(pqn->q->properties.cu_mask); - pqn->q->properties.cu_mask = NULL; uninit_queue(pqn->q); } @@ -411,8 +409,8 @@ err_destroy_queue: return retval; } -int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, - struct queue_properties *p) +int pqm_update_queue_properties(struct process_queue_manager *pqm, + unsigned int qid, struct queue_properties *p) { int retval; struct process_queue_node *pqn; @@ -436,8 +434,8 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, return 0; } -int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, - struct queue_properties *p) +int pqm_update_mqd(struct process_queue_manager *pqm, + unsigned int qid, struct mqd_update_info *minfo) { int retval; struct process_queue_node *pqn; @@ -448,16 +446,8 @@ int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, return -EFAULT; } - /* Free the old CU mask memory if it is already allocated, then - * allocate memory for the new CU mask. - */ - kfree(pqn->q->properties.cu_mask); - - pqn->q->properties.cu_mask_count = p->cu_mask_count; - pqn->q->properties.cu_mask = p->cu_mask; - retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, - pqn->q, NULL); + pqn->q, minfo); if (retval != 0) return retval; From 3d1a8d950da81573de8288be622dacbf40a2f222 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Tue, 26 Oct 2021 17:17:38 +0800 Subject: [PATCH 509/554] drm/amdgpu: remove GPRs init for ALDEBARAN in gpu reset (v3) Remove GPRs init for ALDEBARAN in gpu reset temporarily, will add the init once the algorithm is stable. v2: Only remove GPRs init in gpu reset. v3: Suspend needs it, only skip it in gpu reset. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c index 24852a24cc58..c4f37a161875 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2.c @@ -706,9 +706,9 @@ int gfx_v9_4_2_do_edc_gpr_workarounds(struct amdgpu_device *adev) if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) return 0; - /* Workaround for some CU settings, skip GPRs init. - Will remove it once GPRs init algorithm works for all CU settings */ - if (adev->gfx.cu_info.bitmap[1][1] == 0x3f7f) + /* Workaround for ALDEBARAN, skip GPRs init in GPU reset. + Will remove it once GPRs init algorithm works for all CU settings. */ + if (amdgpu_in_reset(adev)) return 0; gfx_v9_4_2_do_sgprs_init(adev); From 3ce51649cdf23ab463494df2bd6d1e9529ebdc6a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 20 Oct 2021 16:45:00 -0400 Subject: [PATCH 510/554] drm/amdgpu/display: add quirk handling for stutter mode Stutter mode is a power saving feature on GPUs, however at least one early raven system exhibits stability issues with it. Add a quirk to disable it for that system. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=214417 Fixes: 005440066f929b ("drm/amdgpu: enable gfxoff again on raven series (v2)") Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ad571f71ee43..d0f27c300c45 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1295,6 +1295,37 @@ static struct hpd_rx_irq_offload_work_queue *hpd_rx_irq_create_workqueue(struct return hpd_rx_offload_wq; } +struct amdgpu_stutter_quirk { + u16 chip_vendor; + u16 chip_device; + u16 subsys_vendor; + u16 subsys_device; + u8 revision; +}; + +static const struct amdgpu_stutter_quirk amdgpu_stutter_quirk_list[] = { + /* https://bugzilla.kernel.org/show_bug.cgi?id=214417 */ + { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc8 }, + { 0, 0, 0, 0, 0 }, +}; + +static bool dm_should_disable_stutter(struct pci_dev *pdev) +{ + const struct amdgpu_stutter_quirk *p = amdgpu_stutter_quirk_list; + + while (p && p->chip_device != 0) { + if (pdev->vendor == p->chip_vendor && + pdev->device == p->chip_device && + pdev->subsystem_vendor == p->subsys_vendor && + pdev->subsystem_device == p->subsys_device && + pdev->revision == p->revision) { + return true; + } + ++p; + } + return false; +} + static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; @@ -1406,6 +1437,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY) adev->dm.dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; + if (dm_should_disable_stutter(adev->pdev)) + adev->dm.dc->debug.disable_stutter = true; if (amdgpu_dc_debug_mask & DC_DISABLE_STUTTER) adev->dm.dc->debug.disable_stutter = true; From 9fac5799c8985aa0263dbed7f16f99f85c4d6cd7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Oct 2021 15:02:33 -0400 Subject: [PATCH 511/554] drm/amdgpu/pm: look up current_level for asics without pm callback For asics without a callback, use the current level rather than 0xff. This can avoid an unnecesary forced level set on older asics when set by the user. Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 01cca08a774f..49fe4155c374 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -310,7 +310,7 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; enum amd_dpm_forced_level level; - enum amd_dpm_forced_level current_level = 0xff; + enum amd_dpm_forced_level current_level; int ret = 0; if (amdgpu_in_reset(adev)) @@ -350,6 +350,8 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, if (pp_funcs->get_performance_level) current_level = amdgpu_dpm_get_performance_level(adev); + else + current_level = adev->pm.dpm.forced_level; if (current_level == level) { pm_runtime_mark_last_busy(ddev->dev); From cafea7728ca66a16dc45724b8bc13da89f703ee4 Mon Sep 17 00:00:00 2001 From: Lewis Huang Date: Wed, 29 Sep 2021 16:32:15 +0800 Subject: [PATCH 512/554] drm/amd/display: Align bw context with hw config when system resume [Why] When the vbios config and driver config are different, if we update clock to lower before call program_timing and program_pixel_clk, garbage appear. [How] Align bw context with hw config when system resume Reviewed-by: Anthony Koo Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Lewis Huang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 44d27579d898..a25732d07222 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1378,6 +1378,12 @@ void dcn10_init_hw(struct dc *dc) if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + /* Align bw context with hw config when system resume. */ + if (dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) { + dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; + dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; + } + // Initialize the dccg if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); From bc39a69a2ac484e6575a958567c162ef56c9f278 Mon Sep 17 00:00:00 2001 From: Anson Jacob Date: Fri, 17 Sep 2021 18:29:36 -0400 Subject: [PATCH 513/554] drm/amd/display: dcn20_resource_construct reduce scope of FPU enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Limit when FPU is enabled to only functions that does FPU operations for dcn20_resource_construct, which gets called during driver initialization. Enabling FPU operation disables preemption. Sleeping functions(mutex (un)lock, memory allocation using GFP_KERNEL, etc.) should not be called when preemption is disabled. Fixes the following case caught by enabling CONFIG_DEBUG_ATOMIC_SLEEP in kernel config [ 1.338434] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:281 [ 1.347395] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 197, name: systemd-udevd [ 1.356356] CPU: 7 PID: 197 Comm: systemd-udevd Not tainted 5.13.0+ #3 [ 1.356358] Hardware name: System manufacturer System Product Name/PRIME X570-PRO, BIOS 3405 02/01/2021 [ 1.356360] Call Trace: [ 1.356361] dump_stack+0x6b/0x86 [ 1.356366] ___might_sleep.cold+0x87/0x98 [ 1.356370] __might_sleep+0x4b/0x80 [ 1.356372] mutex_lock+0x21/0x50 [ 1.356376] smu_get_uclk_dpm_states+0x3f/0x80 [amdgpu] [ 1.356538] pp_nv_get_uclk_dpm_states+0x35/0x50 [amdgpu] [ 1.356711] init_soc_bounding_box+0xf9/0x210 [amdgpu] [ 1.356892] ? create_object+0x20d/0x340 [ 1.356897] ? dcn20_resource_construct+0x46f/0xd30 [amdgpu] [ 1.357077] dcn20_resource_construct+0x4b1/0xd30 [amdgpu] ... Tested on: 5700XT (NAVI10 0x1002:0x731F 0x1DA2:0xE410 0xC1) Cc: Christian König Cc: Hersen Wu Cc: Anson Jacob Cc: Harry Wentland Reviewed-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Anson Jacob Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dcn20/dcn20_resource.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 756f5d411d9a..001737487800 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -3698,16 +3698,22 @@ static bool init_soc_bounding_box(struct dc *dc, clock_limits_available = (status == PP_SMU_RESULT_OK); } - if (clock_limits_available && uclk_states_available && num_states) + if (clock_limits_available && uclk_states_available && num_states) { + DC_FP_START(); dcn20_update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states); - else if (clock_limits_available) + DC_FP_END(); + } else if (clock_limits_available) { + DC_FP_START(); dcn20_cap_soc_clocks(loaded_bb, max_clocks); + DC_FP_END(); + } } loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; loaded_ip->max_num_dpp = pool->base.pipe_count; + DC_FP_START(); dcn20_patch_bounding_box(dc, loaded_bb); - + DC_FP_END(); return true; } @@ -3727,8 +3733,6 @@ static bool dcn20_resource_construct( enum dml_project dml_project_version = get_dml_project_version(ctx->asic_id.hw_internal_rev); - DC_FP_START(); - ctx->dc_bios->regs = &bios_regs; pool->base.funcs = &dcn20_res_pool_funcs; @@ -4077,12 +4081,10 @@ static bool dcn20_resource_construct( pool->base.oem_device = NULL; } - DC_FP_END(); return true; create_fail: - DC_FP_END(); dcn20_resource_destruct(pool); return false; From 33df94e181f2181e2bd04c3830eb380f2f3ed048 Mon Sep 17 00:00:00 2001 From: "Guo, Bing" Date: Mon, 4 Oct 2021 13:13:57 -0400 Subject: [PATCH 514/554] drm/amd/display: Get ceiling for v_total calc Updating certain variable blanking calculations to use ceiling function. Reviewed-by: Chris Park Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Bing Guo Signed-off-by: Alex Deucher --- .../drm/amd/display/modules/freesync/freesync.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index b99aa232bd8b..bd1d1dc93629 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -155,9 +155,18 @@ static unsigned int calc_v_total_from_duration( if (duration_in_us > vrr->max_duration_in_us) duration_in_us = vrr->max_duration_in_us; - v_total = div64_u64(div64_u64(((unsigned long long)( - duration_in_us) * (stream->timing.pix_clk_100hz / 10)), - stream->timing.h_total), 1000); + if (dc_is_hdmi_signal(stream->signal)) { + uint32_t h_total_up_scaled; + + h_total_up_scaled = stream->timing.h_total * 10000; + v_total = div_u64((unsigned long long)duration_in_us + * stream->timing.pix_clk_100hz + (h_total_up_scaled - 1), + h_total_up_scaled); + } else { + v_total = div64_u64(div64_u64(((unsigned long long)( + duration_in_us) * (stream->timing.pix_clk_100hz / 10)), + stream->timing.h_total), 1000); + } /* v_total cannot be less than nominal */ if (v_total < stream->timing.v_total) { From e5dfcd272722fe3948837e7f1ca7aafb471037b1 Mon Sep 17 00:00:00 2001 From: Robin Chen Date: Wed, 22 Sep 2021 18:17:13 +0800 Subject: [PATCH 515/554] drm/amd/display: dc_link_set_psr_allow_active refactoring [Why] To expose new power optimization flags to PSR interface. It allows the PSR related power features can be enabled separately base on different use scenarios. Reviewed-by: Anthony Koo Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Robin Chen Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 10 +++- .../gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c | 6 ++- drivers/gpu/drm/amd/display/dc/core/dc.c | 7 ++- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 39 ++++++++++------ .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 8 +++- drivers/gpu/drm/amd/display/dc/dc.h | 6 +++ drivers/gpu/drm/amd/display/dc/dc_link.h | 5 +- drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 20 ++++++++ drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h | 1 + .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 46 +++++++++++++++++++ 10 files changed, 125 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index 70a554f1e725..c022e56f9459 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -107,6 +107,8 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) */ // Init fail safe of 2 frames static unsigned int num_frames_static = 2; + unsigned int power_opt = 0; + bool psr_enable = true; DRM_DEBUG_DRIVER("Enabling psr...\n"); @@ -133,7 +135,9 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) &stream, 1, ¶ms); - return dc_link_set_psr_allow_active(link, true, false, false); + power_opt |= psr_power_opt_z10_static_screen; + + return dc_link_set_psr_allow_active(link, &psr_enable, false, false, &power_opt); } /* @@ -144,10 +148,12 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) */ bool amdgpu_dm_psr_disable(struct dc_stream_state *stream) { + unsigned int power_opt = 0; + bool psr_enable = false; DRM_DEBUG_DRIVER("Disabling psr...\n"); - return dc_link_set_psr_allow_active(stream->link, false, true, false); + return dc_link_set_psr_allow_active(stream->link, &psr_enable, true, false, &power_opt); } /* diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index 1548b2a3fe03..acbda3962650 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -100,11 +100,13 @@ void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_m if (edp_num) { for (panel_inst = 0; panel_inst < edp_num; panel_inst++) { + bool allow_active = false; + edp_link = edp_links[panel_inst]; if (!edp_link->psr_settings.psr_feature_enabled) continue; clk_mgr->psr_allow_active_cache = edp_link->psr_settings.psr_allow_active; - dc_link_set_psr_allow_active(edp_link, false, false, false); + dc_link_set_psr_allow_active(edp_link, &allow_active, false, false, NULL); } } @@ -124,7 +126,7 @@ void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr) if (!edp_link->psr_settings.psr_feature_enabled) continue; dc_link_set_psr_allow_active(edp_link, - clk_mgr->psr_allow_active_cache, false, false); + &clk_mgr->psr_allow_active_cache, false, false, NULL); } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 935a50d6e933..7def73b1c262 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3493,6 +3493,7 @@ void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_ bool dc_set_psr_allow_active(struct dc *dc, bool enable) { int i; + bool allow_active; for (i = 0; i < dc->current_state->stream_count ; i++) { struct dc_link *link; @@ -3504,10 +3505,12 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable) if (link->psr_settings.psr_feature_enabled) { if (enable && !link->psr_settings.psr_allow_active) { - if (!dc_link_set_psr_allow_active(link, true, false, false)) + allow_active = true; + if (!dc_link_set_psr_allow_active(link, &allow_active, false, false, NULL)) return false; } else if (!enable && link->psr_settings.psr_allow_active) { - if (!dc_link_set_psr_allow_active(link, false, true, false)) + allow_active = false; + if (!dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL)) return false; } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index ec5f107bc85a..e5ea954e9ec0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2916,8 +2916,8 @@ bool dc_link_set_backlight_level(const struct dc_link *link, return true; } -bool dc_link_set_psr_allow_active(struct dc_link *link, bool allow_active, - bool wait, bool force_static) +bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active, + bool wait, bool force_static, const unsigned int *power_opts) { struct dc *dc = link->ctx->dc; struct dmcu *dmcu = dc->res_pool->dmcu; @@ -2930,20 +2930,33 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, bool allow_active, if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) return false; - link->psr_settings.psr_allow_active = allow_active; + /* Set power optimization flag */ + if (power_opts && link->psr_settings.psr_power_opt != *power_opts) { + link->psr_settings.psr_power_opt = *power_opts; + + if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt) + psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt); + } + + /* Enable or Disable PSR */ + if (allow_active && link->psr_settings.psr_allow_active != *allow_active) { + link->psr_settings.psr_allow_active = *allow_active; + #if defined(CONFIG_DRM_AMD_DC_DCN) - if (!allow_active) - dc_z10_restore(dc); + if (!link->psr_settings.psr_allow_active) + dc_z10_restore(dc); #endif - if (psr != NULL && link->psr_settings.psr_feature_enabled) { - if (force_static && psr->funcs->psr_force_static) - psr->funcs->psr_force_static(psr, panel_inst); - psr->funcs->psr_enable(psr, allow_active, wait, panel_inst); - } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && link->psr_settings.psr_feature_enabled) - dmcu->funcs->set_psr_enable(dmcu, allow_active, wait); - else - return false; + if (psr != NULL && link->psr_settings.psr_feature_enabled) { + if (force_static && psr->funcs->psr_force_static) + psr->funcs->psr_force_static(psr, panel_inst); + psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst); + } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && + link->psr_settings.psr_feature_enabled) + dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait); + else + return false; + } return true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index bb96e4e9ccfc..e514506b1997 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -3523,6 +3523,8 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) if (psr_error_status.bits.LINK_CRC_ERROR || psr_error_status.bits.RFB_STORAGE_ERROR || psr_error_status.bits.VSC_SDP_ERROR) { + bool allow_active; + /* Acknowledge and clear error bits */ dm_helpers_dp_write_dpcd( link->ctx, @@ -3532,8 +3534,10 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) sizeof(psr_error_status.raw)); /* PSR error, disable and re-enable PSR */ - dc_link_set_psr_allow_active(link, false, true, false); - dc_link_set_psr_allow_active(link, true, true, false); + allow_active = false; + dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL); + allow_active = true; + dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL); return true; } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS == diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index fc3f0fd1f068..f0141f27880f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -342,6 +342,12 @@ enum visual_confirm { VISUAL_CONFIRM_SWIZZLE = 9, }; +enum dc_psr_power_opts { + psr_power_opt_invalid = 0x0, + psr_power_opt_smu_opt_static_screen = 0x1, + psr_power_opt_z10_static_screen = 0x10, +}; + enum dcc_option { DCC_ENABLE = 0, DCC_DISABLE = 1, diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 08815310d85b..8902d642e719 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -85,6 +85,7 @@ struct psr_settings { */ bool psr_frame_capture_indication_req; unsigned int psr_sdp_transmit_line_num_deadline; + unsigned int psr_power_opt; }; /* @@ -267,8 +268,8 @@ int dc_link_get_backlight_level(const struct dc_link *dc_link); int dc_link_get_target_backlight_pwm(const struct dc_link *link); -bool dc_link_set_psr_allow_active(struct dc_link *dc_link, bool enable, - bool wait, bool force_static); +bool dc_link_set_psr_allow_active(struct dc_link *dc_link, const bool *enable, + bool wait, bool force_static, const unsigned int *power_opts); bool dc_link_get_psr_state(const struct dc_link *dc_link, enum dc_psr_state *state); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index 05d96ca80512..90eb8eedacf2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -227,6 +227,25 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_ dc_dmub_srv_wait_idle(dc->dmub_srv); } +/** + * Set PSR power optimization flags. + */ +static void dmub_psr_set_power_opt(struct dmub_psr *dmub, unsigned int power_opt) +{ + union dmub_rb_cmd cmd; + struct dc_context *dc = dmub->ctx; + + memset(&cmd, 0, sizeof(cmd)); + cmd.psr_set_power_opt.header.type = DMUB_CMD__PSR; + cmd.psr_set_power_opt.header.sub_type = DMUB_CMD__SET_PSR_POWER_OPT; + cmd.psr_set_power_opt.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_power_opt_data); + cmd.psr_set_power_opt.psr_set_power_opt_data.power_opt = power_opt; + + dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dc->dmub_srv); + dc_dmub_srv_wait_idle(dc->dmub_srv); +} + /* * Setup PSR by programming phy registers and sending psr hw context values to firmware. */ @@ -358,6 +377,7 @@ static const struct dmub_psr_funcs psr_funcs = { .psr_set_level = dmub_psr_set_level, .psr_force_static = dmub_psr_force_static, .psr_get_residency = dmub_psr_get_residency, + .psr_set_power_opt = dmub_psr_set_power_opt, }; /* diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h index 9675c269e649..5dbd479660f1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.h @@ -46,6 +46,7 @@ struct dmub_psr_funcs { void (*psr_force_static)(struct dmub_psr *dmub, uint8_t panel_inst); void (*psr_get_residency)(struct dmub_psr *dmub, uint32_t *residency, uint8_t panel_inst); + void (*psr_set_power_opt)(struct dmub_psr *dmub, unsigned int power_opt); }; struct dmub_psr *dmub_psr_create(struct dc_context *ctx); diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 4c436fb4624b..bc1d6d78d1f9 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -1378,6 +1378,10 @@ enum dmub_cmd_psr_type { * Forces PSR enabled until an explicit PSR disable call. */ DMUB_CMD__PSR_FORCE_STATIC = 5, + /** + * Set PSR power option + */ + DMUB_CMD__SET_PSR_POWER_OPT = 7, }; /** @@ -1675,6 +1679,44 @@ struct dmub_rb_cmd_psr_force_static { struct dmub_cmd_psr_force_static_data psr_force_static_data; }; +/** + * Data passed from driver to FW in a DMUB_CMD__SET_PSR_POWER_OPT command. + */ +struct dmub_cmd_psr_set_power_opt_data { + /** + * PSR control version. + */ + uint8_t cmd_version; + /** + * Panel Instance. + * Panel isntance to identify which psr_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; + /** + * PSR power option + */ + uint32_t power_opt; +}; + +/** + * Definition of a DMUB_CMD__SET_PSR_POWER_OPT command. + */ +struct dmub_rb_cmd_psr_set_power_opt { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of a DMUB_CMD__SET_PSR_POWER_OPT command. + */ + struct dmub_cmd_psr_set_power_opt_data psr_set_power_opt_data; +}; + /** * Set of HW components that can be locked. * @@ -2458,6 +2500,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__PSR_FORCE_STATIC command. */ struct dmub_rb_cmd_psr_force_static psr_force_static; + /** + * Definition of a DMUB_CMD__SET_PSR_POWER_OPT command. + */ + struct dmub_rb_cmd_psr_set_power_opt psr_set_power_opt; /** * Definition of a DMUB_CMD__PLAT_54186_WA command. */ From ffd89aa968d9046ab5fb9f7cdb7f8d3c383a15c1 Mon Sep 17 00:00:00 2001 From: Ahmad Othman Date: Tue, 5 Oct 2021 21:04:03 -0400 Subject: [PATCH 516/554] drm/amd/display: Add support for USB4 on C20 PHY for DCN3.1 [Why] Created new fields that matches new B0 structs On DCN31 the mapping of DIO output to PHY differs from A0 to B0 boards with new PHY C20 & this new mapping needed to be handled. [How] Mapped new structure based on new structs Added logic for mapping over A0 and B0 boards Hooked all new structs together. Reviewed-by: Wenjing Liu Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Ahmad Othman Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 53 ++++++++++++++++++- drivers/gpu/drm/amd/display/dc/dc.h | 13 +++-- drivers/gpu/drm/amd/display/dc/dm_cp_psp.h | 2 + .../drm/amd/display/modules/inc/mod_hdcp.h | 2 + 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index e5ea954e9ec0..67dee4f2f9d9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3874,6 +3874,9 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp; #if defined(CONFIG_DRM_AMD_DC_DCN) struct link_encoder *link_enc = NULL; + struct dc_state *state = pipe_ctx->stream->ctx->dc->current_state; + struct link_enc_assignment link_enc_assign; + int i; #endif if (cp_psp && cp_psp->funcs.update_stream_config) { @@ -3887,9 +3890,57 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst; #if defined(CONFIG_DRM_AMD_DC_DCN) config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; - if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) { + + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY || + pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { link_enc = pipe_ctx->stream->link->link_enc; + config.dio_output_type = pipe_ctx->stream->link->ep_type; + config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + // Initialize PHY ID with ABCDE - 01234 mapping except when it is B0 config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + + //look up the link_enc_assignment for the current pipe_ctx + for (i = 0; i < state->stream_count; i++) { + if (pipe_ctx->stream == state->streams[i]) { + link_enc_assign = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; + } + } + + if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0) + config.dig_be = link_enc_assign.eng_id; + + // Add RegKey to guard B0 implementation + if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 && link_enc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + link_enc = pipe_ctx->stream->link->link_enc; + + // enum ID 1-4 maps to DPIA PHY ID 0-3 + config.phy_idx = link_enc_assign.ep_id.link_id.enum_id - ENUM_ID_1; + } else { // for non DPIA mode over B0, ABCDE maps to 01564 + + switch (link_enc->transmitter) { + case TRANSMITTER_UNIPHY_A: + config.phy_idx = 0; + break; + case TRANSMITTER_UNIPHY_B: + config.phy_idx = 1; + break; + case TRANSMITTER_UNIPHY_C: + config.phy_idx = 5; + break; + case TRANSMITTER_UNIPHY_D: + config.phy_idx = 6; + break; + case TRANSMITTER_UNIPHY_E: + config.phy_idx = 4; + break; + default: + config.phy_idx = 0; + break; + } + + } + } } else if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) { link_enc = link_enc_cfg_get_link_enc_used_by_stream( pipe_ctx->stream->ctx->dc, diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f0141f27880f..23977de4811b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -211,12 +211,12 @@ struct dc_dcc_setting { unsigned int max_uncompressed_blk_size; bool independent_64b_blks; #if defined(CONFIG_DRM_AMD_DC_DCN) - //These bitfields to be used starting with DCN 3.0 + //These bitfields to be used starting with DCN struct { - uint32_t dcc_256_64_64 : 1;//available in ASICs before DCN 3.0 (the worst compression case) - uint32_t dcc_128_128_uncontrained : 1; //available in ASICs before DCN 3.0 - uint32_t dcc_256_128_128 : 1; //available starting with DCN 3.0 - uint32_t dcc_256_256_unconstrained : 1; //available in ASICs before DCN 3.0 (the best compression case) + uint32_t dcc_256_64_64 : 1;//available in ASICs before DCN (the worst compression case) + uint32_t dcc_128_128_uncontrained : 1; //available in ASICs before DCN + uint32_t dcc_256_128_128 : 1; //available starting with DCN + uint32_t dcc_256_256_unconstrained : 1; //available in ASICs before DCN (the best compression case) } dcc_controls; #endif }; @@ -731,6 +731,9 @@ struct dc { #if defined(CONFIG_DRM_AMD_DC_DCN) bool idle_optimizations_allowed; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN) + bool enable_c20_dtm_b0; +#endif /* Require to maintain clocks and bandwidth for UEFI enabled HW */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h index 43f33e186088..511f9e1159c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h +++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h @@ -35,6 +35,8 @@ struct cp_psp_stream_config { uint8_t link_enc_idx; uint8_t stream_enc_idx; uint8_t phy_idx; + uint8_t dio_output_idx; + uint8_t dio_output_type; uint8_t assr_enabled; uint8_t mst_enabled; uint8_t dp2_enabled; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h index f37101f5a777..6d648c889866 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h @@ -249,6 +249,8 @@ struct mod_hdcp_link { uint8_t ddc_line; uint8_t link_enc_idx; uint8_t phy_idx; + uint8_t dio_output_type; + uint8_t dio_output_id; uint8_t hdcp_supported_informational; union { struct mod_hdcp_displayport dp; From d738db6883df3e3c513f9e777c842262693f951b Mon Sep 17 00:00:00 2001 From: Qingqing Zhuo Date: Tue, 31 Aug 2021 07:52:24 -0400 Subject: [PATCH 517/554] drm/amd/display: move FPU associated DSC code to DML folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why & How] As part of the FPU isolation work documented in https://patchwork.freedesktop.org/series/93042/, isolate code that uses FPU in DSC to DML, where all FPU code should locate. This change does not refactor any functions but move code around. Cc: Christian König Cc: Hersen Wu Cc: Anson Jacob Cc: Harry Wentland Reviewed-by: Rodrigo Siqueira Acked-by: Agustin Gutierrez Tested-by: Anson Jacob Tested-by: Daniel Wheeler Signed-off-by: Qingqing Zhuo Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 3 + .../amd/display/dc/{ => dml}/dsc/qp_tables.h | 0 .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.c | 291 ++++++++++++++++++ .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.h | 94 ++++++ drivers/gpu/drm/amd/display/dc/dsc/Makefile | 29 -- drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c | 259 ---------------- drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h | 50 +-- .../gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c | 1 - 8 files changed, 389 insertions(+), 338 deletions(-) rename drivers/gpu/drm/amd/display/dc/{ => dml}/dsc/qp_tables.h (100%) create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 169a4e68f86e..e7bb69ec99b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -70,6 +70,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn2x/dcn2x.o := $(dml_rcflags) @@ -84,6 +85,7 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_rcfla CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_rcflags) endif CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_ccflags) @@ -99,6 +101,7 @@ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o +DML += dsc/rc_calc_fpu.o endif AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h similarity index 100% rename from drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h rename to drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c new file mode 100644 index 000000000000..3ee858f311d1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c @@ -0,0 +1,291 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "rc_calc_fpu.h" + +#include "qp_tables.h" +#include "amdgpu_dm/dc_fpu.h" + +#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min) + +#define MODE_SELECT(val444, val422, val420) \ + (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420)) + + +#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \ + table = qp_table_##mode##_##bpc##bpc_##max; \ + table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \ + break + +static int median3(int a, int b, int c) +{ + if (a > b) + swap(a, b); + if (b > c) + swap(b, c); + if (a > b) + swap(b, c); + + return b; +} + +static double dsc_roundf(double num) +{ + if (num < 0.0) + num = num - 0.5; + else + num = num + 0.5; + + return (int)(num); +} + +static double dsc_ceil(double num) +{ + double retval = (int)num; + + if (retval != num && num > 0) + retval = num + 1; + + return (int)retval; +} + +static void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, + enum max_min max_min, float bpp) +{ + int mode = MODE_SELECT(444, 422, 420); + int sel = table_hash(mode, bpc, max_min); + int table_size = 0; + int index; + const struct qp_entry *table = 0L; + + // alias enum + enum { min = DAL_MM_MIN, max = DAL_MM_MAX }; + switch (sel) { + TABLE_CASE(444, 8, max); + TABLE_CASE(444, 8, min); + TABLE_CASE(444, 10, max); + TABLE_CASE(444, 10, min); + TABLE_CASE(444, 12, max); + TABLE_CASE(444, 12, min); + TABLE_CASE(422, 8, max); + TABLE_CASE(422, 8, min); + TABLE_CASE(422, 10, max); + TABLE_CASE(422, 10, min); + TABLE_CASE(422, 12, max); + TABLE_CASE(422, 12, min); + TABLE_CASE(420, 8, max); + TABLE_CASE(420, 8, min); + TABLE_CASE(420, 10, max); + TABLE_CASE(420, 10, min); + TABLE_CASE(420, 12, max); + TABLE_CASE(420, 12, min); + } + + if (table == 0) + return; + + index = (bpp - table[0].bpp) * 2; + + /* requested size is bigger than the table */ + if (index >= table_size) { + dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n"); + return; + } + + memcpy(qps, table[index].qps, sizeof(qp_set)); +} + +static void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp) +{ + int *p = ofs; + + if (mode == CM_444 || mode == CM_RGB) { + *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); + *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); + *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0)))); + *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0)))); + *p++ = -10; + *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } else if (mode == CM_422) { + *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0)))); + *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0)))); + *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0)))); + *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0)))); + *p++ = -10; + *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } else { + *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0)))); + *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0)))); + *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = -10; + *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } +} + +void _do_calc_rc_params(struct rc_params *rc, + enum colour_mode cm, + enum bits_per_comp bpc, + u16 drm_bpp, + bool is_navite_422_or_420, + int slice_width, + int slice_height, + int minor_version) +{ + float bpp; + float bpp_group; + float initial_xmit_delay_factor; + int padding_pixels; + int i; + + dc_assert_fp_enabled(); + + bpp = ((float)drm_bpp / 16.0); + /* in native_422 or native_420 modes, the bits_per_pixel is double the + * target bpp (the latter is what calc_rc_params expects) + */ + if (is_navite_422_or_420) + bpp /= 2.0; + + rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + + bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0); + + switch (cm) { + case CM_420: + rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584))))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group))); + rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group))); + break; + case CM_422: + rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584)))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group))); + rc->second_line_bpg_offset = 0; + break; + case CM_444: + case CM_RGB: + rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2))))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group))); + rc->second_line_bpg_offset = 0; + break; + } + + initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0; + rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor); + + if (cm == CM_422 || cm == CM_420) + slice_width /= 2; + + padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0; + if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) { + if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1) + rc->initial_xmit_delay++; + } + + rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->flatness_det_thresh = 2 << (bpc - 8); + + get_qp_set(rc->qp_min, cm, bpc, DAL_MM_MIN, bpp); + get_qp_set(rc->qp_max, cm, bpc, DAL_MM_MAX, bpp); + if (cm == CM_444 && minor_version == 1) { + for (i = 0; i < QP_SET_SIZE; ++i) { + rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0; + rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0; + } + } + get_ofs_set(rc->ofs, cm, bpp); + + /* fixed parameters */ + rc->rc_model_size = 8192; + rc->rc_edge_factor = 6; + rc->rc_tgt_offset_hi = 3; + rc->rc_tgt_offset_lo = 3; + + rc->rc_buf_thresh[0] = 896; + rc->rc_buf_thresh[1] = 1792; + rc->rc_buf_thresh[2] = 2688; + rc->rc_buf_thresh[3] = 3584; + rc->rc_buf_thresh[4] = 4480; + rc->rc_buf_thresh[5] = 5376; + rc->rc_buf_thresh[6] = 6272; + rc->rc_buf_thresh[7] = 6720; + rc->rc_buf_thresh[8] = 7168; + rc->rc_buf_thresh[9] = 7616; + rc->rc_buf_thresh[10] = 7744; + rc->rc_buf_thresh[11] = 7872; + rc->rc_buf_thresh[12] = 8000; + rc->rc_buf_thresh[13] = 8064; +} + +u32 _do_bytes_per_pixel_calc(int slice_width, + u16 drm_bpp, + bool is_navite_422_or_420) +{ + float bpp; + u32 bytes_per_pixel; + double d_bytes_per_pixel; + + dc_assert_fp_enabled(); + + bpp = ((float)drm_bpp / 16.0); + d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width; + // TODO: Make sure the formula for calculating this is precise (ceiling + // vs. floor, and at what point they should be applied) + if (is_navite_422_or_420) + d_bytes_per_pixel /= 2; + + bytes_per_pixel = (u32)dsc_ceil(d_bytes_per_pixel * 0x10000000); + + return bytes_per_pixel; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h new file mode 100644 index 000000000000..b93b95409fbe --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h @@ -0,0 +1,94 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __RC_CALC_FPU_H__ +#define __RC_CALC_FPU_H__ + +#include "os_types.h" +#include + +#define QP_SET_SIZE 15 + +typedef int qp_set[QP_SET_SIZE]; + +struct rc_params { + int rc_quant_incr_limit0; + int rc_quant_incr_limit1; + int initial_fullness_offset; + int initial_xmit_delay; + int first_line_bpg_offset; + int second_line_bpg_offset; + int flatness_min_qp; + int flatness_max_qp; + int flatness_det_thresh; + qp_set qp_min; + qp_set qp_max; + qp_set ofs; + int rc_model_size; + int rc_edge_factor; + int rc_tgt_offset_hi; + int rc_tgt_offset_lo; + int rc_buf_thresh[QP_SET_SIZE - 1]; +}; + +enum colour_mode { + CM_RGB, /* 444 RGB */ + CM_444, /* 444 YUV or simple 422 */ + CM_422, /* native 422 */ + CM_420 /* native 420 */ +}; + +enum bits_per_comp { + BPC_8 = 8, + BPC_10 = 10, + BPC_12 = 12 +}; + +enum max_min { + DAL_MM_MIN = 0, + DAL_MM_MAX = 1 +}; + +struct qp_entry { + float bpp; + const qp_set qps; +}; + +typedef struct qp_entry qp_table[]; + +u32 _do_bytes_per_pixel_calc(int slice_width, + u16 drm_bpp, + bool is_navite_422_or_420); + +void _do_calc_rc_params(struct rc_params *rc, + enum colour_mode cm, + enum bits_per_comp bpc, + u16 drm_bpp, + bool is_navite_422_or_420, + int slice_width, + int slice_height, + int minor_version); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index 8d31eb75c6a6..a2537229ee88 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -1,35 +1,6 @@ # SPDX-License-Identifier: MIT # # Makefile for the 'dsc' sub-component of DAL. - -ifdef CONFIG_X86 -dsc_ccflags := -mhard-float -msse -endif - -ifdef CONFIG_PPC64 -dsc_ccflags := -mhard-float -maltivec -endif - -ifdef CONFIG_CC_IS_GCC -ifeq ($(call cc-ifversion, -lt, 0701, y), y) -IS_OLD_GCC = 1 -endif -endif - -ifdef CONFIG_X86 -ifdef IS_OLD_GCC -# Stack alignment mismatch, proceed with caution. -# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 -# (8B stack alignment). -dsc_ccflags += -mpreferred-stack-boundary=4 -else -dsc_ccflags += -msse2 -endif -endif - -CFLAGS_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_ccflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_rcflags) - DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC)) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c index 7b294f637881..b19d3aeb5962 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c @@ -23,266 +23,7 @@ * Authors: AMD * */ -#include - -#include "os_types.h" #include "rc_calc.h" -#include "qp_tables.h" - -#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min) - -#define MODE_SELECT(val444, val422, val420) \ - (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420)) - - -#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \ - table = qp_table_##mode##_##bpc##bpc_##max; \ - table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \ - break - - -static void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, - enum max_min max_min, float bpp) -{ - int mode = MODE_SELECT(444, 422, 420); - int sel = table_hash(mode, bpc, max_min); - int table_size = 0; - int index; - const struct qp_entry *table = 0L; - - // alias enum - enum { min = DAL_MM_MIN, max = DAL_MM_MAX }; - switch (sel) { - TABLE_CASE(444, 8, max); - TABLE_CASE(444, 8, min); - TABLE_CASE(444, 10, max); - TABLE_CASE(444, 10, min); - TABLE_CASE(444, 12, max); - TABLE_CASE(444, 12, min); - TABLE_CASE(422, 8, max); - TABLE_CASE(422, 8, min); - TABLE_CASE(422, 10, max); - TABLE_CASE(422, 10, min); - TABLE_CASE(422, 12, max); - TABLE_CASE(422, 12, min); - TABLE_CASE(420, 8, max); - TABLE_CASE(420, 8, min); - TABLE_CASE(420, 10, max); - TABLE_CASE(420, 10, min); - TABLE_CASE(420, 12, max); - TABLE_CASE(420, 12, min); - } - - if (table == 0) - return; - - index = (bpp - table[0].bpp) * 2; - - /* requested size is bigger than the table */ - if (index >= table_size) { - dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n"); - return; - } - - memcpy(qps, table[index].qps, sizeof(qp_set)); -} - -static double dsc_roundf(double num) -{ - if (num < 0.0) - num = num - 0.5; - else - num = num + 0.5; - - return (int)(num); -} - -static double dsc_ceil(double num) -{ - double retval = (int)num; - - if (retval != num && num > 0) - retval = num + 1; - - return (int)retval; -} - -static void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp) -{ - int *p = ofs; - - if (mode == CM_444 || mode == CM_RGB) { - *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); - *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); - *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); - *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); - *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); - *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0)))); - *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0)))); - *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0)))); - *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0)))); - *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0)))); - *p++ = -10; - *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0)))); - *p++ = -12; - *p++ = -12; - *p++ = -12; - } else if (mode == CM_422) { - *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0)))); - *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0)))); - *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0)))); - *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0)))); - *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0)))); - *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0)))); - *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0)))); - *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0)))); - *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0)))); - *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0)))); - *p++ = -10; - *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1)))); - *p++ = -12; - *p++ = -12; - *p++ = -12; - } else { - *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0)))); - *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0)))); - *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0)))); - *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0)))); - *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0)))); - *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0)))); - *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0)))); - *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0)))); - *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0)))); - *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0)))); - *p++ = -10; - *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0)))); - *p++ = -12; - *p++ = -12; - *p++ = -12; - } -} - -static int median3(int a, int b, int c) -{ - if (a > b) - swap(a, b); - if (b > c) - swap(b, c); - if (a > b) - swap(b, c); - - return b; -} - -static void _do_calc_rc_params(struct rc_params *rc, enum colour_mode cm, - enum bits_per_comp bpc, u16 drm_bpp, - bool is_navite_422_or_420, - int slice_width, int slice_height, - int minor_version) -{ - float bpp; - float bpp_group; - float initial_xmit_delay_factor; - int padding_pixels; - int i; - - bpp = ((float)drm_bpp / 16.0); - /* in native_422 or native_420 modes, the bits_per_pixel is double the - * target bpp (the latter is what calc_rc_params expects) - */ - if (is_navite_422_or_420) - bpp /= 2.0; - - rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); - rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); - - bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0); - - switch (cm) { - case CM_420: - rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584))))); - rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group))); - rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group))); - break; - case CM_422: - rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584)))); - rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group))); - rc->second_line_bpg_offset = 0; - break; - case CM_444: - case CM_RGB: - rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2))))); - rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group))); - rc->second_line_bpg_offset = 0; - break; - } - - initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0; - rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor); - - if (cm == CM_422 || cm == CM_420) - slice_width /= 2; - - padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0; - if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) { - if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1) - rc->initial_xmit_delay++; - } - - rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); - rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); - rc->flatness_det_thresh = 2 << (bpc - 8); - - get_qp_set(rc->qp_min, cm, bpc, DAL_MM_MIN, bpp); - get_qp_set(rc->qp_max, cm, bpc, DAL_MM_MAX, bpp); - if (cm == CM_444 && minor_version == 1) { - for (i = 0; i < QP_SET_SIZE; ++i) { - rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0; - rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0; - } - } - get_ofs_set(rc->ofs, cm, bpp); - - /* fixed parameters */ - rc->rc_model_size = 8192; - rc->rc_edge_factor = 6; - rc->rc_tgt_offset_hi = 3; - rc->rc_tgt_offset_lo = 3; - - rc->rc_buf_thresh[0] = 896; - rc->rc_buf_thresh[1] = 1792; - rc->rc_buf_thresh[2] = 2688; - rc->rc_buf_thresh[3] = 3584; - rc->rc_buf_thresh[4] = 4480; - rc->rc_buf_thresh[5] = 5376; - rc->rc_buf_thresh[6] = 6272; - rc->rc_buf_thresh[7] = 6720; - rc->rc_buf_thresh[8] = 7168; - rc->rc_buf_thresh[9] = 7616; - rc->rc_buf_thresh[10] = 7744; - rc->rc_buf_thresh[11] = 7872; - rc->rc_buf_thresh[12] = 8000; - rc->rc_buf_thresh[13] = 8064; -} - -static u32 _do_bytes_per_pixel_calc(int slice_width, u16 drm_bpp, - bool is_navite_422_or_420) -{ - float bpp; - u32 bytes_per_pixel; - double d_bytes_per_pixel; - - bpp = ((float)drm_bpp / 16.0); - d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width; - // TODO: Make sure the formula for calculating this is precise (ceiling - // vs. floor, and at what point they should be applied) - if (is_navite_422_or_420) - d_bytes_per_pixel /= 2; - - bytes_per_pixel = (u32)dsc_ceil(d_bytes_per_pixel * 0x10000000); - - return bytes_per_pixel; -} /** * calc_rc_params - reads the user's cmdline mode diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h index 262f06afcbf9..c2340e001b57 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h @@ -27,55 +27,7 @@ #ifndef __RC_CALC_H__ #define __RC_CALC_H__ - -#define QP_SET_SIZE 15 - -typedef int qp_set[QP_SET_SIZE]; - -struct rc_params { - int rc_quant_incr_limit0; - int rc_quant_incr_limit1; - int initial_fullness_offset; - int initial_xmit_delay; - int first_line_bpg_offset; - int second_line_bpg_offset; - int flatness_min_qp; - int flatness_max_qp; - int flatness_det_thresh; - qp_set qp_min; - qp_set qp_max; - qp_set ofs; - int rc_model_size; - int rc_edge_factor; - int rc_tgt_offset_hi; - int rc_tgt_offset_lo; - int rc_buf_thresh[QP_SET_SIZE - 1]; -}; - -enum colour_mode { - CM_RGB, /* 444 RGB */ - CM_444, /* 444 YUV or simple 422 */ - CM_422, /* native 422 */ - CM_420 /* native 420 */ -}; - -enum bits_per_comp { - BPC_8 = 8, - BPC_10 = 10, - BPC_12 = 12 -}; - -enum max_min { - DAL_MM_MIN = 0, - DAL_MM_MAX = 1 -}; - -struct qp_entry { - float bpp; - const qp_set qps; -}; - -typedef struct qp_entry qp_table[]; +#include "dml/dsc/rc_calc_fpu.h" void calc_rc_params(struct rc_params *rc, const struct drm_dsc_config *pps); u32 calc_dsc_bytes_per_pixel(const struct drm_dsc_config *pps); diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c index ef830aded5b1..1e19dd674e5a 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c @@ -22,7 +22,6 @@ * Authors: AMD * */ -#include "os_types.h" #include #include "dscc_types.h" #include "rc_calc.h" From 986430446c917ba89de5f2beadfec7a90e6a1b2b Mon Sep 17 00:00:00 2001 From: Ahmad Othman Date: Wed, 6 Oct 2021 22:23:04 -0400 Subject: [PATCH 518/554] drm/amd/display: fix a crash on USB4 over C20 PHY [Why] Crash when USB4 is connected. [How] Added an ASIC specific code guard. Reviewed-by: Nikola Cornij Reviewed-by: Wenjing Liu Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Ahmad Othman Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 67dee4f2f9d9..96d2001ede61 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3896,6 +3896,14 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) link_enc = pipe_ctx->stream->link->link_enc; config.dio_output_type = pipe_ctx->stream->link->ep_type; config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) + link_enc = pipe_ctx->stream->link->link_enc; + else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) { + link_enc = link_enc_cfg_get_link_enc_used_by_stream( + pipe_ctx->stream->ctx->dc, + pipe_ctx->stream); + } // Initialize PHY ID with ABCDE - 01234 mapping except when it is B0 config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; @@ -3905,14 +3913,21 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) link_enc_assign = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; } } - - if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0) + // Add flag to guard new A0 DIG mapping + if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 == true) { config.dig_be = link_enc_assign.eng_id; + config.dio_output_type = pipe_ctx->stream->link->ep_type; + config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + } else { + config.dio_output_type = 0; + config.dio_output_idx = 0; + } - // Add RegKey to guard B0 implementation - if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 && link_enc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + // Add flag to guard B0 implementation + if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 == true && + link_enc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - link_enc = pipe_ctx->stream->link->link_enc; + link_enc = link_enc_assign.stream->link_enc; // enum ID 1-4 maps to DPIA PHY ID 0-3 config.phy_idx = link_enc_assign.ep_id.link_id.enum_id - ENUM_ID_1; From 5ffb5267bdc957de827bdd89ef95730d94579ae6 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Thu, 7 Oct 2021 10:05:44 -0400 Subject: [PATCH 519/554] drm/amd/display: Set i2c memory to light sleep during hw init [WHY] i2c memory doesn't get set to light sleep on hw init as intended [HOW] Set i2c to light sleep after reg gets zeroed, ensuring memory power control doesn't get disabled for any other DIO memory Reviewed-by: Haonan Wang Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Michael Strauss Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 3 ++- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 5 +++++ drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 296b2f80a1ec..989f5b6907e2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -1151,7 +1151,8 @@ struct dce_hwseq_registers { type DOMAIN_POWER_GATE;\ type DOMAIN_PGFSM_PWR_STATUS;\ type HPO_HDMISTREAMCLK_G_GATE_DIS;\ - type DISABLE_HOSTVM_FORCE_ALLOW_PSTATE; + type DISABLE_HOSTVM_FORCE_ALLOW_PSTATE;\ + type I2C_LIGHT_SLEEP_FORCE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 9a6ad1cebc85..d24ad7754d71 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -50,6 +50,7 @@ #include "dcn10/dcn10_hw_sequencer.h" #include "inc/link_enc_cfg.h" #include "dcn30/dcn30_vpg.h" +#include "dce/dce_i2c_hw.h" #define DC_LOGGER_INIT(logger) @@ -259,6 +260,10 @@ void dcn31_init_hw(struct dc *dc) /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ REG_WRITE(DIO_MEM_PWR_CTRL, 0); + // Set i2c to light sleep until engine is setup + if (dc->debug.enable_mem_low_power.bits.i2c) + REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); + if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 2b4459909648..4f60b36000cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -899,7 +899,8 @@ static const struct dce_hwseq_registers hwseq_reg = { HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) static const struct dce_hwseq_shift hwseq_shift = { HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) From 5fdccd5b88410b6be7f19f3c91ef112d174b1564 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Wed, 6 Oct 2021 15:50:10 -0400 Subject: [PATCH 520/554] drm/amd/display: Defer GAMCOR and DSCL power down sequence to vupdate [WHY] Every other CM LUT power down sequence is deferred to next vupdate as memory powerdown updates immediately while selecting LUTs is double buffered. Previous update to defer LUT power down missed GAMCOR and DSCL, causing some visible flicker when entering/exiting fullscreen video playback. [HOW] Update dpp deferred update loop to check for valid DPPs in res_pool instead of referencing dcn_ip which turns out to not be populated during runtime. Move GAMCOR and DSCL powerdown to dpp deferred updates. Reviewed-by: Haonan Wang Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Michael Strauss Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++++-- .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c | 12 ++++++++++-- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c | 14 ++++++++++++++ .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c | 8 ++++++-- .../gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 ++ drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 2 ++ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 7def73b1c262..580aa3f1e4a4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1897,12 +1897,14 @@ static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context) static void process_deferred_updates(struct dc *dc) { #ifdef CONFIG_DRM_AMD_DC_DCN - int i; + int i = 0; - if (dc->debug.enable_mem_low_power.bits.cm) + if (dc->debug.enable_mem_low_power.bits.cm) { + ASSERT(dc->dcn_ip->max_num_dpp); for (i = 0; i < dc->dcn_ip->max_num_dpp; i++) if (dc->res_pool->dpps[i]->funcs->dpp_deferred_update) dc->res_pool->dpps[i]->funcs->dpp_deferred_update(dc->res_pool->dpps[i]); + } #endif } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index cb9767ddf93d..44293d66b46b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -205,9 +205,17 @@ static void dpp1_power_on_dscl( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); if (dpp->tf_regs->DSCL_MEM_PWR_CTRL) { - REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, power_on ? 0 : 3); - if (power_on) + if (power_on) { + REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0); REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 5); + } else { + if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) { + dpp->base.ctx->dc->optimized_required = true; + dpp->base.deferred_reg_writes.bits.disable_dscl = true; + } else { + REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 3); + } + } } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c index ef5f6da5248a..c1d967ed6551 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c @@ -494,6 +494,20 @@ void dpp3_deferred_update( int bypass_state; struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); + if (dpp_base->deferred_reg_writes.bits.disable_dscl) { + REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 3); + dpp_base->deferred_reg_writes.bits.disable_dscl = false; + } + + if (dpp_base->deferred_reg_writes.bits.disable_gamcor) { + REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_MODE_CURRENT, &bypass_state); + if (bypass_state == 0) { // only program if bypass was latched + REG_UPDATE(CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_FORCE, 3); + } else + ASSERT(0); // LUT select was updated again before vupdate + dpp_base->deferred_reg_writes.bits.disable_gamcor = false; + } + if (dpp_base->deferred_reg_writes.bits.disable_blnd_lut) { REG_GET(CM_BLNDGAM_CONTROL, CM_BLNDGAM_MODE_CURRENT, &bypass_state); if (bypass_state == 0) { // only program if bypass was latched diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c index 72c5687adc68..387eec616162 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c @@ -136,9 +136,13 @@ static void dpp3_power_on_gamcor_lut( struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.cm) { - REG_UPDATE(CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_FORCE, power_on ? 0 : 3); - if (power_on) + if (power_on) { + REG_UPDATE(CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_FORCE, 0); REG_WAIT(CM_MEM_PWR_STATUS, GAMCOR_MEM_PWR_STATE, 0, 1, 5); + } else { + dpp_base->ctx->dc->optimized_required = true; + dpp_base->deferred_reg_writes.bits.disable_gamcor = true; + } } else REG_SET(CM_MEM_PWR_CTRL, 0, GAMCOR_MEM_PWR_DIS, power_on == true ? 0:1); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 4f60b36000cb..6d812d5a1368 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -2460,6 +2460,8 @@ static bool dcn31_resource_construct( dc->cap_funcs = cap_funcs; + dc->dcn_ip->max_num_dpp = dcn3_1_ip.max_num_dpp; + DC_FP_END(); return true; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 9f12792b7e59..3ef7faa92052 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -34,6 +34,8 @@ union defer_reg_writes { bool disable_blnd_lut:1; bool disable_3dlut:1; bool disable_shaper:1; + bool disable_gamcor:1; + bool disable_dscl:1; } bits; uint32_t raw; }; From af9775a3e13aeba1e366a21159adcda9ca66ba3a Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Thu, 7 Oct 2021 14:54:01 -0400 Subject: [PATCH 521/554] drm/amd/display: clean up dcn31 revision check This is unnecessary in clk_mgr Reviewed-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Dmytro Laktyushkin Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index acbda3962650..26f96ee32472 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -285,13 +285,8 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p BREAK_TO_DEBUGGER(); return NULL; } - if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev)) { - /* TODO: to add DCN31 clk_mgr support, once CLK IP header files are available, - * for now use DCN3.0 clk mgr. - */ - dcn31_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); - return &clk_mgr->base.base; - } + + dcn31_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); return &clk_mgr->base.base; } #endif @@ -328,7 +323,6 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base) break; case FAMILY_YELLOW_CARP: - if (ASICREV_IS_YELLOW_CARP(clk_mgr_base->ctx->asic_id.hw_internal_rev)) dcn31_clk_mgr_destroy(clk_mgr); break; From 876e835ed733ded22f2ce42db82c6132f7684185 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Thu, 7 Oct 2021 10:34:49 -0400 Subject: [PATCH 522/554] drm/amd/display: restyle dcn31 resource header inline with other asics Style change for better consistency across codebase Reviewed-by: Nicholas Kazlauskas Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Dmytro Laktyushkin Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 6d812d5a1368..3447588d29b4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1834,7 +1834,7 @@ static int dcn31_populate_dml_pipes_from_context( return pipe_cnt; } -static void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) +void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) { if (dc->clk_mgr->bw_params->wm_table.entries[WM_A].valid) { context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.entries[WM_A].pstate_latency_us; @@ -1978,7 +1978,7 @@ static void dcn31_calculate_wm_and_dlg_fp( dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); } -static void dcn31_calculate_wm_and_dlg( +void dcn31_calculate_wm_and_dlg( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, int pipe_cnt, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h index 93571c976996..416fe7a721d8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h @@ -35,6 +35,16 @@ struct dcn31_resource_pool { struct resource_pool base; }; +bool dcn31_validate_bandwidth(struct dc *dc, + struct dc_state *context, + bool fast_validate); +void dcn31_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); +void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context); + struct resource_pool *dcn31_create_resource_pool( const struct dc_init_data *init_data, struct dc *dc); From 54fe00be270dd6fdb9e23c31a4497edec5a3609b Mon Sep 17 00:00:00 2001 From: George Shen Date: Wed, 6 Oct 2021 15:47:37 -0400 Subject: [PATCH 523/554] drm/amd/display: Implement fixed DP drive settings [Why] Currently there are use cases that require DP link to maintain fixed VS and PE in HW regardless of what the sink requests. BIOS integrated info table will specify whether we need to use the fixed drive settings, and the drive settings to use. [How] Implement changes to parse the integrated info table and set the fixed drive settings accordingly. Reviewed-by: Wenjing Liu Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: George Shen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 2 ++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 8 ++++++++ drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 8 +++++++- drivers/gpu/drm/amd/display/dc/dc_link.h | 3 +++ .../gpu/drm/amd/display/include/grph_object_ctrl_defs.h | 1 + drivers/gpu/drm/amd/display/include/link_service_types.h | 6 ++++++ 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index c17732fba039..a4bef4364afd 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -2321,6 +2321,8 @@ static enum bp_result get_integrated_info_v2_2( info->ext_disp_conn_info.checksum = info_v2_2->extdispconninfo.checksum; + info->ext_disp_conn_info.fixdpvoltageswing = + info_v2_2->extdispconninfo.fixdpvoltageswing; info->edp1_info.edp_backlight_pwm_hz = le16_to_cpu(info_v2_2->edp1_info.edp_backlight_pwm_hz); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 96d2001ede61..a1fa50ddf43e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1660,6 +1660,14 @@ static bool dc_link_construct_legacy(struct dc_link *link, DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw); DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps); } + + if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) { + link->bios_forced_drive_settings.VOLTAGE_SWING = + (info->ext_disp_conn_info.fixdpvoltageswing & 0x3); + link->bios_forced_drive_settings.PRE_EMPHASIS = + ((info->ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3); + } + break; } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index e514506b1997..3313f2af139f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1661,7 +1661,13 @@ static void override_training_settings( if (overrides->ffe_preset != NULL) lt_settings->ffe_preset = overrides->ffe_preset; #endif - + /* Override HW lane settings with BIOS forced values if present */ + if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && + link->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; + lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; + lt_settings->always_match_dpcd_with_hw_lane_settings = false; + } for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { lt_settings->lane_settings[lane].VOLTAGE_SWING = lt_settings->voltage_swing != NULL ? diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 8902d642e719..517950674729 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -178,6 +178,9 @@ struct dc_link { struct psr_settings psr_settings; + /* Drive settings read from integrated info table */ + struct dc_lane_settings bios_forced_drive_settings; + /* MST record stream using this link */ struct link_flags { bool dp_keep_receiver_powered; diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 792652236c61..dd974c428d23 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -328,6 +328,7 @@ struct integrated_info { uint8_t gu_id[NUMBER_OF_UCHAR_FOR_GUID]; uint8_t checksum; + uint8_t fixdpvoltageswing; } ext_disp_conn_info; /* exiting long long time */ struct available_s_clk_list { diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 9ffea7b40545..9a16fc855254 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -117,6 +117,12 @@ struct link_training_settings { bool enhanced_framing; bool allow_invalid_msa_timing_param; enum lttpr_mode lttpr_mode; + + /* disallow different lanes to have different lane settings */ + bool disallow_per_lane_settings; + /* dpcd lane settings will always use the same hw lane settings + * even if it doesn't match requested lane adjust */ + bool always_match_dpcd_with_hw_lane_settings; }; /*TODO: Move this enum test harness*/ From 1072461cd7725f3e7957371ffb15abf2b82e2720 Mon Sep 17 00:00:00 2001 From: George Shen Date: Thu, 7 Oct 2021 19:32:17 -0400 Subject: [PATCH 524/554] drm/amd/display: Add comment for preferred_training_settings [Why] Currently the naming of preferred_training_settings is ambiguous and has caused confusion regarding its purpose and usage. [How] Add comment to clarify the intention. Reviewed-by: Wenjing Liu Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: George Shen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_link.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 517950674729..b991ba1d6f9a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -124,6 +124,10 @@ struct dc_link { struct dc_link_settings cur_link_settings; struct dc_lane_settings cur_lane_setting[LANE_COUNT_DP_MAX]; struct dc_link_settings preferred_link_setting; + /* preferred_training_settings are override values that + * come from DM. DM is responsible for the memory + * management of the override pointers. + */ struct dc_link_training_overrides preferred_training_settings; struct dp_audio_test_data audio_test_data; From 8df219bb7d4b14e4e82b3db6da4a73f1b0b767d3 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Thu, 7 Oct 2021 21:34:53 -0400 Subject: [PATCH 525/554] drm/amd/display: Handle I2C-over-AUX write channel status update [Why] When writing long AUX commands some sinks will respond will write status update requiring source to read status. [How] When a write request is replied with data (AUX_ACK_M), retry a read of write status to determine when the write is completed. Reviewed-by: Martin Leung Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 ++ .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 15 ++++---- drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 34 +++++++++++++++++-- .../amd/display/include/i2caux_interface.h | 3 ++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 1a99fcc27078..874a49b605c7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -64,6 +64,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0; payload.write = (msg->request & DP_AUX_I2C_READ) == 0; payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0; + payload.write_status_update = + (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; payload.defer_delay = 0; result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 471a67a64299..60539b1f2a80 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -554,6 +554,7 @@ bool dal_ddc_service_query_ddc_data( payload.address = address; payload.reply = NULL; payload.defer_delay = get_defer_delay(ddc); + payload.write_status_update = false; if (write_size != 0) { payload.write = true; @@ -625,24 +626,24 @@ bool dal_ddc_submit_aux_command(struct ddc_service *ddc, do { struct aux_payload current_payload; bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >= - payload->length; + payload->length ? true : false; + uint32_t payload_length = is_end_of_payload ? + payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; current_payload.address = payload->address; current_payload.data = &payload->data[retrieved]; current_payload.defer_delay = payload->defer_delay; current_payload.i2c_over_aux = payload->i2c_over_aux; - current_payload.length = is_end_of_payload ? - payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; - /* set mot (middle of transaction) to false - * if it is the last payload - */ + current_payload.length = payload_length; + /* set mot (middle of transaction) to false if it is the last payload */ current_payload.mot = is_end_of_payload ? payload->mot:true; + current_payload.write_status_update = false; current_payload.reply = payload->reply; current_payload.write = payload->write; ret = dc_link_aux_transfer_with_retries(ddc, ¤t_payload); - retrieved += current_payload.length; + retrieved += payload_length; } while (retrieved < payload->length && ret == true); return ret; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index 95cb4d7cc76a..6d42a9cc9916 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -534,17 +534,26 @@ struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) { if (payload->i2c_over_aux) { + if (payload->write_status_update) { + if (payload->mot) + return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT; + else + return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; + } if (payload->write) { if (payload->mot) return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; - return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; + else + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; } if (payload->mot) return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; + return I2CAUX_TRANSACTION_ACTION_I2C_READ; } if (payload->write) return I2CAUX_TRANSACTION_ACTION_DP_WRITE; + return I2CAUX_TRANSACTION_ACTION_DP_READ; } @@ -698,7 +707,8 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, aux_defer_retries = 0, aux_i2c_defer_retries = 0, aux_timeout_retries = 0, - aux_invalid_reply_retries = 0; + aux_invalid_reply_retries = 0, + aux_ack_m_retries = 0; if (ddc_pin) { aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; @@ -758,9 +768,27 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, aux_defer_retries, AUX_MAX_RETRIES); goto fail; - } else { + } else udelay(300); + } else if (payload->write && ret > 0) { + /* sink requested more time to complete the write via AUX_ACKM */ + if (++aux_ack_m_retries >= AUX_MAX_RETRIES) { + DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, + LOG_FLAG_Error_I2cAux, + "dce_aux_transfer_with_retries: FAILURE: aux_ack_m_retries=%d >= AUX_MAX_RETRIES=%d", + aux_ack_m_retries, + AUX_MAX_RETRIES); + goto fail; } + + /* retry reading the write status until complete + * NOTE: payload is modified here + */ + payload->write = false; + payload->write_status_update = true; + payload->length = 0; + udelay(300); + } else return true; break; diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/include/i2caux_interface.h index c7fbb9c3ad6b..418fbf8c5c3a 100644 --- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h +++ b/drivers/gpu/drm/amd/display/include/i2caux_interface.h @@ -41,6 +41,8 @@ struct aux_payload { * reset it to read data */ bool write; bool mot; + bool write_status_update; + uint32_t address; uint32_t length; uint8_t *data; @@ -53,6 +55,7 @@ struct aux_payload { * zero means "use default value" */ uint32_t defer_delay; + }; struct aux_command { From b129c94ea39bebf56194ef49d89fa3dc766b587b Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 10 Oct 2021 18:31:04 -0400 Subject: [PATCH 526/554] drm/amd/display: [FW Promotion] Release 0.0.89 - Add flag to control root clock gating in init_hw - Add flag to indicate a diags environment is being used Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Anthony Koo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index bc1d6d78d1f9..ed35b3bd30b9 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -46,10 +46,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xd146258f +#define DMUB_FW_VERSION_GIT_HASH 0xdd808d7b #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 88 +#define DMUB_FW_VERSION_REVISION 89 #define DMUB_FW_VERSION_TEST 0 #define DMUB_FW_VERSION_VBIOS 0 #define DMUB_FW_VERSION_HOTFIX 0 @@ -371,7 +371,10 @@ union dmub_fw_boot_options { uint32_t enable_dpia: 1; /**< 1 if DPIA should be enabled */ uint32_t invalid_vbios_data: 1; /**< 1 if VBIOS data table is invalid */ uint32_t reserved_unreleased2: 1; /**< reserved for an unreleased feature */ - uint32_t reserved : 22; /**< reserved */ + uint32_t root_clock_gating: 1; /**< 1 if all root clock gating is enabled */ + uint32_t diag_env: 1; /* 1 if diagnostic environment */ + + uint32_t reserved : 19; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ }; From 6dd8154bd24e2dc5662cd18b3ad1178a2b245f38 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Mon, 11 Oct 2021 23:26:23 -0400 Subject: [PATCH 527/554] drm/amd/display: 3.2.158 Acked-by: Agustin Gutierrez Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 23977de4811b..4cd04a78f926 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.157" +#define DC_VER "3.2.158" #define MAX_SURFACES 3 #define MAX_PLANES 6 From fbde44bcdffc4e1954b9f6f0c030bca2328cc822 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Tue, 12 Oct 2021 15:09:54 -0400 Subject: [PATCH 528/554] drm/amd/display: Fix 3DLUT skipped programming We found a compilation error that we thought was caused by the 3DLUT patch; later on, we figured out the root cause of the problem, but we already applied the revert in the wrong patch. This commit brings it back the 3DLUT fix. Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dc.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 580aa3f1e4a4..9d33b00b7e27 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2285,6 +2285,9 @@ static enum surface_update_type det_surface_update(const struct dc *dc, update_flags->bits.gamma_change = 1; } + if (u->lut3d_func || u->func_shaper) + update_flags->bits.lut_3d = 1; + if (u->hdr_mult.value) if (u->hdr_mult.value != u->surface->hdr_mult.value) { update_flags->bits.hdr_mult = 1; @@ -2298,6 +2301,7 @@ static enum surface_update_type det_surface_update(const struct dc *dc, if (update_flags->bits.input_csc_change || update_flags->bits.coeff_reduction_change + || update_flags->bits.lut_3d || update_flags->bits.gamma_change || update_flags->bits.gamut_remap_change) { type = UPDATE_TYPE_FULL; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 4cd04a78f926..1225406d3381 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -940,6 +940,7 @@ union surface_update_flags { uint32_t bandwidth_change:1; uint32_t clock_change:1; uint32_t stereo_format_change:1; + uint32_t lut_3d:1; uint32_t full_update:1; } bits; From b8f0208858221d1ab6f9cac4302471e9a563586f Mon Sep 17 00:00:00 2001 From: "Guo, Bing" Date: Thu, 7 Oct 2021 16:10:59 -0400 Subject: [PATCH 529/554] drm/amd/display: set Layout properly for 8ch audio at timing validation Why: For audio packet type 0x02, there are 2 Layouts: Layout = 0 for 2 channels and Layout = 1 for > 2 channels. Layout will affect bandwidth check. Currently, for HDMI FRL, Layout field isn't set and has a default value of 0, so theoretically only 2-channel audio for audio packet type 0x02 is supported now. How: 1. Set Layout properly according to maximum audio channel numbers for audios with audio packet type 0x02. 2. 8ch LPCM audio is not supported for timing modes with v_active <= 576. Reviewed-by: Chris Park Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Bing Guo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_audio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 7866cf2a668f..27218ede150a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -514,13 +514,15 @@ void dce_aud_az_configure( union audio_sample_rates sample_rates = audio_mode->sample_rates; uint8_t byte2 = audio_mode->max_bit_rate; + uint8_t channel_count = audio_mode->channel_count; /* adjust specific properties */ switch (audio_format_code) { case AUDIO_FORMAT_CODE_LINEARPCM: { + check_audio_bandwidth( crtc_info, - audio_mode->channel_count, + channel_count, signal, &sample_rates); @@ -548,7 +550,7 @@ void dce_aud_az_configure( /* fill audio format data */ set_reg_field_value(value, - audio_mode->channel_count - 1, + channel_count - 1, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, MAX_CHANNELS); From 7db581d66184eaad070c1ee3943e9bb6a57af337 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Mon, 19 Jul 2021 11:07:30 -0400 Subject: [PATCH 530/554] drm/amd/display: allow windowed mpo + odm This change adds a config flag to allow non fullscreen MPO during ODM. Scaling calculation will still fail configurations where video is only one one side of the screen. Reviewed-by: Aric Cyr Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Dmytro Laktyushkin Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 14 +++++++-- drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../drm/amd/display/dc/dcn30/dcn30_resource.c | 30 ++++++++++--------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 9e83fd54e2ca..c32fdccd4d92 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1155,9 +1155,17 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; } - if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || - pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) - res = false; + if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) { + if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || + pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) + res = false; + } else { + /* Clamp minimum viewport size */ + if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE) + pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE; + if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) + pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE; + } DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n" "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 1225406d3381..4cd26ca26fe0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -323,6 +323,7 @@ struct dc_config { bool multi_mon_pp_mclk_switch; bool disable_dmcu; bool enable_4to1MPC; + bool enable_windowed_mpo_odm; bool allow_edp_hotplug_detection; #if defined(CONFIG_DRM_AMD_DC_DCN) bool clamp_min_dcfclk; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 3a8a3214f770..6d70ccb108af 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -1929,23 +1929,25 @@ noinline bool dcn30_internal_validate_bw( if (vlevel == context->bw_ctx.dml.soc.num_states) goto validate_fail; - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; + if (!dc->config.enable_windowed_mpo_odm) { + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; - if (!pipe->stream) - continue; + if (!pipe->stream) + continue; - /* We only support full screen mpo with ODM */ - if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled - && pipe->plane_state && mpo_pipe - && memcmp(&mpo_pipe->plane_res.scl_data.recout, - &pipe->plane_res.scl_data.recout, - sizeof(struct rect)) != 0) { - ASSERT(mpo_pipe->plane_state != pipe->plane_state); - goto validate_fail; + /* We only support full screen mpo with ODM */ + if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled + && pipe->plane_state && mpo_pipe + && memcmp(&mpo_pipe->plane_res.scl_data.recout, + &pipe->plane_res.scl_data.recout, + sizeof(struct rect)) != 0) { + ASSERT(mpo_pipe->plane_state != pipe->plane_state); + goto validate_fail; + } + pipe_idx++; } - pipe_idx++; } /* merge pipes if necessary */ From aa46d06bf81ed273cc8739757f611987e9847ef8 Mon Sep 17 00:00:00 2001 From: Anson Jacob Date: Tue, 12 Oct 2021 22:21:15 -0400 Subject: [PATCH 531/554] drm/amd/display: Remove unused macros fixed16_to_double & fixed16_to_double_to_cpu are not used. Reviewed-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Acked-by: Agustin Gutierrez Signed-off-by: Anson Jacob Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c | 3 --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c | 3 --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 -- 3 files changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 001737487800..3883f918b3bb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -3660,9 +3660,6 @@ static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) return DML_PROJECT_NAVI10v2; } -#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) -#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) - static bool init_soc_bounding_box(struct dc *dc, struct dcn20_resource_pool *pool) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 6d70ccb108af..6dda20f3741c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -1707,9 +1707,6 @@ bool dcn30_release_post_bldn_3dlut( return ret; } -#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) -#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) - static bool is_soc_bounding_box_valid(struct dc *dc) { uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 3447588d29b4..87b2c2428842 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -101,8 +101,6 @@ #include "link_enc_cfg.h" #define DC_LOGGER_INIT(logger) -#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) -#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) #define DCN3_1_DEFAULT_DET_SIZE 384 From 5b5e0776ddab26392faac4656f9249dae5354104 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sun, 17 Oct 2021 10:40:31 -0400 Subject: [PATCH 532/554] drm/amd/display: [FW Promotion] Release 0.0.90 Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Anthony Koo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index ed35b3bd30b9..aa27c0d432fb 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -46,10 +46,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xdd808d7b +#define DMUB_FW_VERSION_GIT_HASH 0x9525efb5 #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 89 +#define DMUB_FW_VERSION_REVISION 90 #define DMUB_FW_VERSION_TEST 0 #define DMUB_FW_VERSION_VBIOS 0 #define DMUB_FW_VERSION_HOTFIX 0 From e4e330ef3a93e8727f967382bd014e93e7d355a7 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Sun, 17 Oct 2021 17:39:59 -0400 Subject: [PATCH 533/554] drm/amd/display: 3.2.159 This new DC version brings improvements in the following areas: - Improvements for USB4; - Isolate FPU code for DCN20, DCN301, and DSC; - Fixes on Linking training; - Refactoring some parts of the code, such as PSR; Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 4cd26ca26fe0..33c4f74a0add 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.158" +#define DC_VER "3.2.159" #define MAX_SURFACES 3 #define MAX_PLANES 6 From a9a1ac44074ff8cab7d519277f93341e14557f83 Mon Sep 17 00:00:00 2001 From: Martin Leung Date: Fri, 15 Oct 2021 17:36:51 -0400 Subject: [PATCH 534/554] drm/amd/display: Manually adjust strobe for DCN303 why: DCN303's 4 channel SOC BB causes problems at strobe how: workaround to manually adjust strobe calculation using FCLK restrict. Reviewed-by: Jun Lei Acked-by: Agustin Gutierrez Tested-by: Daniel Wheeler Signed-off-by: Martin Leung Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dcn303/dcn303_resource.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index 2ce6eae7535d..4a9b64023675 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -1344,6 +1344,20 @@ void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param dcn3_03_soc.clock_limits[i].phyclk_d18_mhz = dcn3_03_soc.clock_limits[0].phyclk_d18_mhz; dcn3_03_soc.clock_limits[i].dscclk_mhz = dcn3_03_soc.clock_limits[0].dscclk_mhz; } + + // WA: patch strobe modes to compensate for DCN303 BW issue + if (dcn3_03_soc.num_chans <= 4) { + for (i = 0; i < dcn3_03_soc.num_states; i++) { + if (dcn3_03_soc.clock_limits[i].dram_speed_mts > 1700) + break; + + if (dcn3_03_soc.clock_limits[i].dram_speed_mts >= 1500) { + dcn3_03_soc.clock_limits[i].dcfclk_mhz = 100; + dcn3_03_soc.clock_limits[i].fabricclk_mhz = 100; + } + } + } + /* re-init DML with updated bb */ dml_init_instance(&dc->dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30); if (dc->current_state) From 3137f792c5bd68c799a9c3762fd37e428bbcf152 Mon Sep 17 00:00:00 2001 From: Hansen Date: Thu, 9 Sep 2021 15:12:32 -0400 Subject: [PATCH 535/554] drm/amd/display: Set phy_mux_sel bit in dmub scratch register [Why] B0 has pipe mux for DIGC and DIGD which can be connected to PHYF/PHYG or PHYC/PHY D. [How] Based on chip internal hardware revision id determine it is B0 and set DMUB scratch register so DMUBFW can connect the display pipe is connected correctly to the dig. Cc: Wayne Lin Cc: Nicholas Kazlauskas Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Hansen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 1 + drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 6 ++++-- drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 2 ++ drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d0f27c300c45..4b6c021c02f4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1825,7 +1825,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) break; case IP_VERSION(3, 1, 2): case IP_VERSION(3, 1, 3): - dmub_asic = DMUB_ASIC_DCN31; + dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31; fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; break; diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 365fbc4758e1..6c4f0ada163f 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -97,6 +97,7 @@ enum dmub_asic { DMUB_ASIC_DCN302, DMUB_ASIC_DCN303, DMUB_ASIC_DCN31, + DMUB_ASIC_DCN31B, DMUB_ASIC_MAX, }; diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index aa27c0d432fb..48982bc3e243 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -370,8 +370,10 @@ union dmub_fw_boot_options { uint32_t z10_disable: 1; /**< 1 to disable z10 */ uint32_t enable_dpia: 1; /**< 1 if DPIA should be enabled */ uint32_t invalid_vbios_data: 1; /**< 1 if VBIOS data table is invalid */ - uint32_t reserved_unreleased2: 1; /**< reserved for an unreleased feature */ - uint32_t root_clock_gating: 1; /**< 1 if all root clock gating is enabled */ + uint32_t dpia_supported: 1; /**< 1 if DPIA is supported on this platform */ + uint32_t sel_mux_phy_c_d_phy_f_g: 1; /**< 1 if PHYF/PHYG should be enabled */ + /**< 1 if all root clock gating is enabled and low power memory is enabled*/ + uint32_t power_optimization: 1; uint32_t diag_env: 1; /* 1 if diagnostic environment */ uint32_t reserved : 19; /**< reserved */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 3988f65f1ea4..5df990277dd4 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -340,6 +340,8 @@ void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu boot_options.bits.z10_disable = params->disable_z10; boot_options.bits.enable_dpia = params->disable_dpia ? 0 : 1; + boot_options.bits.sel_mux_phy_c_d_phy_f_g = (dmub->asic == DMUB_ASIC_DCN31B) ? 1 : 0; + REG_WRITE(DMCUB_SCRATCH14, boot_options.all); } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 77c67222cabd..56d400ffa7ac 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -208,6 +208,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) break; case DMUB_ASIC_DCN31: + case DMUB_ASIC_DCN31B: dmub->regs_dcn31 = &dmub_srv_dcn31_regs; funcs->reset = dmub_dcn31_reset; funcs->reset_release = dmub_dcn31_reset_release; From 4b169ca3674919756e76616dc65a79114962ea14 Mon Sep 17 00:00:00 2001 From: Jimmy Kizito Date: Tue, 14 Sep 2021 11:37:04 -0400 Subject: [PATCH 536/554] drm/amd/display: Add workaround flag for EDID read on certain docks [Why] Certain docks appear to NAK I2C writes to the segment pointer with the MOT (middle of transaction) bit clear. This behaviour can cause EDID reads from higher segments to fail. [How] Add workaround flag for links which connect to docks exhibiting this issue. Cc: Wayne Lin Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Jimmy Kizito Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 3 +++ drivers/gpu/drm/amd/display/dc/dc_link.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index a1fa50ddf43e..27b9ff98a569 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1765,6 +1765,9 @@ static bool dc_link_construct_dpia(struct dc_link *link, link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + /* Some docks seem to NAK I2C writes to segment pointer with mot=0. */ + link->wa_flags.dp_mot_reset_segment = true; + return true; ddc_create_fail: diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index b991ba1d6f9a..180ecd860296 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -190,6 +190,7 @@ struct dc_link { bool dp_keep_receiver_powered; bool dp_skip_DID2; bool dp_skip_reset_segment; + bool dp_mot_reset_segment; } wa_flags; struct link_mst_stream_allocation_table mst_stream_alloc_table; From 7fb52632ca7a8c45119064754a446b4be8441c12 Mon Sep 17 00:00:00 2001 From: Meenakshikumar Somasundaram Date: Thu, 16 Sep 2021 15:34:40 -0400 Subject: [PATCH 537/554] drm/amd/display: FEC configuration for dpia links [Why] To fix the check condition for fec enable for dpia links. [How] dc_link_should_enable_fec() to be used to check whether fec should be enabled. Cc: Wayne Lin Reviewed-by: Jimmy Kizito Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Meenakshikumar Somasundaram Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index 8f8eee475144..19b085d84b1f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -431,7 +431,7 @@ void dcn31_link_encoder_enable_dp_output( if (link) { dpia_control.dpia_id = link->ddc_hw_inst; - dpia_control.fec_rdy = link->fec_state == dc_link_fec_ready ? 1 : 0; + dpia_control.fec_rdy = dc_link_should_enable_fec(link); } else { DC_LOG_ERROR("%s: Failed to execute DPIA enable DMUB command.\n", __func__); BREAK_TO_DEBUGGER(); From ed0ffb5dcde95a13bd0208db0b65416e8406699a Mon Sep 17 00:00:00 2001 From: Meenakshikumar Somasundaram Date: Mon, 20 Sep 2021 10:59:30 -0400 Subject: [PATCH 538/554] drm/amd/display: FEC configuration for dpia links in MST mode [Why] To fix the check condition for fec enable for dpia links in MST mode. [How] dc_link_should_enable_fec() to be used to check whether fec should be enabled in MST mode. Cc: Wayne Lin Reviewed-by: Jimmy Kizito Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Meenakshikumar Somasundaram Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index 19b085d84b1f..ee6f13bef377 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -476,7 +476,7 @@ void dcn31_link_encoder_enable_dp_mst_output( if (link) { dpia_control.dpia_id = link->ddc_hw_inst; - dpia_control.fec_rdy = link->fec_state == dc_link_fec_ready ? 1 : 0; + dpia_control.fec_rdy = dc_link_should_enable_fec(link); } else { DC_LOG_ERROR("%s: Failed to execute DPIA enable DMUB command.\n", __func__); BREAK_TO_DEBUGGER(); From 5354b2bd28082032644a644448ce6fa3fb476cbe Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Mon, 14 Jun 2021 18:31:21 -0400 Subject: [PATCH 539/554] drm/amd/display: adopt DP2.0 LT SCR revision 8 [how] revision 8 SCR requires DP Source to write TPS2 and FFE lane adjustment in one 5 byte write aux transaction. It specifies to read aux rd interval value as soon as we turn on TPS1 pattern. Cc: Wayne Lin Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 3313f2af139f..75735c520332 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2080,7 +2080,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( struct dc_link *link, struct link_training_settings *lt_settings) { - uint8_t loop_count = 0; + uint8_t loop_count; uint32_t aux_rd_interval = 0; uint32_t wait_time = 0; struct link_training_settings req_settings; @@ -2088,25 +2088,29 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; enum link_training_result status = LINK_TRAINING_SUCCESS; - /* Transmit 128b/132b_TPS1 over Main-Link and Set TRAINING_PATTERN_SET to 01h */ + /* Transmit 128b/132b_TPS1 over Main-Link */ dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX); + /* Set TRAINING_PATTERN_SET to 01h */ dpcd_set_training_pattern(link, lt_settings->pattern_for_cr); - /* Adjust TX_FFE_PRESET_VALUE as requested */ + /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */ + dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, &req_settings, DPRX); dp_update_drive_settings(lt_settings, req_settings); - dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); dp_set_hw_lane_settings(link, lt_settings, DPRX); - dpcd_set_lane_settings(link, lt_settings, DPRX); - /* Transmit 128b/132b_TPS2 over Main-Link and Set TRAINING_PATTERN_SET to 02h */ dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX); - dpcd_set_training_pattern(link, lt_settings->pattern_for_eq); + + /* Set loop counter to start from 1 */ + loop_count = 1; + + /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */ + dpcd_set_lt_pattern_and_lane_settings(link, lt_settings, + lt_settings->pattern_for_eq, DPRX); /* poll for channel EQ done */ while (status == LINK_TRAINING_SUCCESS) { - loop_count++; dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); wait_time += aux_rd_interval; dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, @@ -2125,6 +2129,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( dp_set_hw_lane_settings(link, lt_settings, DPRX); dpcd_set_lane_settings(link, lt_settings, DPRX); } + loop_count++; } /* poll for EQ interlane align done */ From c224aac87041f93bd7046866edfbc9c34c66c18a Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 10 Sep 2021 19:45:36 -0400 Subject: [PATCH 540/554] drm/amd/display: implement decide lane settings [why] Decouple lane settings decision logic all to its own function. The function takes in lane adjust array and link training settings and decide what hw lane setting and dpcd lane setting should be used. Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 292 ++++++------------ .../drm/amd/display/dc/core/dc_link_dpia.c | 62 ++-- .../gpu/drm/amd/display/dc/inc/dc_link_dp.h | 16 +- .../amd/display/include/link_service_types.h | 17 + 4 files changed, 155 insertions(+), 232 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 75735c520332..d780888d7f7f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -106,7 +106,8 @@ static bool decide_fallback_link_setting( static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_a, struct dc_link_settings link_setting_b); - +static void maximize_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link, const struct dc_link_settings *link_settings) { @@ -711,34 +712,37 @@ void dp_hw_to_dpcd_lane_settings( } } -void dp_update_drive_settings( - struct link_training_settings *dest, - struct link_training_settings src) +void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]) { uint32_t lane; - for (lane = 0; lane < src.link_settings.lane_count; lane++) { - if (dest->voltage_swing == NULL) - dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING; - else - dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing; - - if (dest->pre_emphasis == NULL) - dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS; - else - dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis; - - if (dest->post_cursor2 == NULL) - dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2; - else - dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2; + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + if (dp_get_link_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) { + hw_lane_settings[lane].VOLTAGE_SWING = + (enum dc_voltage_swing)(ln_adjust[lane].bits. + VOLTAGE_SWING_LANE); + hw_lane_settings[lane].PRE_EMPHASIS = + (enum dc_pre_emphasis)(ln_adjust[lane].bits. + PRE_EMPHASIS_LANE); + } #if defined(CONFIG_DRM_AMD_DC_DCN) - if (dest->ffe_preset == NULL) - dest->lane_settings[lane].FFE_PRESET = src.lane_settings[lane].FFE_PRESET; - else - dest->lane_settings[lane].FFE_PRESET = *dest->ffe_preset; + else if (dp_get_link_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) { + hw_lane_settings[lane].FFE_PRESET.raw = + ln_adjust[lane].tx_ffe.PRESET_VALUE; + } #endif } + + /* we find the maximum of the requested settings across all lanes*/ + /* and set this maximum for all lanes*/ + maximize_lane_settings(lt_settings, hw_lane_settings); + dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); } static uint8_t get_nibble_at_index(const uint8_t *buf, @@ -768,55 +772,29 @@ static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing( } -static void find_max_drive_settings( - const struct link_training_settings *link_training_setting, - struct link_training_settings *max_lt_setting) +static void maximize_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) { uint32_t lane; struct dc_lane_settings max_requested; - max_requested.VOLTAGE_SWING = - link_training_setting-> - lane_settings[0].VOLTAGE_SWING; - max_requested.PRE_EMPHASIS = - link_training_setting-> - lane_settings[0].PRE_EMPHASIS; - /*max_requested.postCursor2 = - * link_training_setting->laneSettings[0].postCursor2;*/ + max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING; + max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS; #if defined(CONFIG_DRM_AMD_DC_DCN) - max_requested.FFE_PRESET = - link_training_setting->lane_settings[0].FFE_PRESET; + max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET; #endif /* Determine what the maximum of the requested settings are*/ - for (lane = 1; lane < link_training_setting->link_settings.lane_count; - lane++) { - if (link_training_setting->lane_settings[lane].VOLTAGE_SWING > - max_requested.VOLTAGE_SWING) + for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) { + if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING) + max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING; - max_requested.VOLTAGE_SWING = - link_training_setting-> - lane_settings[lane].VOLTAGE_SWING; - - if (link_training_setting->lane_settings[lane].PRE_EMPHASIS > - max_requested.PRE_EMPHASIS) - max_requested.PRE_EMPHASIS = - link_training_setting-> - lane_settings[lane].PRE_EMPHASIS; - - /* - if (link_training_setting->laneSettings[lane].postCursor2 > - max_requested.postCursor2) - { - max_requested.postCursor2 = - link_training_setting->laneSettings[lane].postCursor2; - } - */ + if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS) + max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS; #if defined(CONFIG_DRM_AMD_DC_DCN) - if (link_training_setting->lane_settings[lane].FFE_PRESET.settings.level > + if (lane_settings[lane].FFE_PRESET.settings.level > max_requested.FFE_PRESET.settings.level) max_requested.FFE_PRESET.settings.level = - link_training_setting-> lane_settings[lane].FFE_PRESET.settings.level; #endif } @@ -828,10 +806,6 @@ static void find_max_drive_settings( if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL) max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL; - /* - if (max_requested.postCursor2 > PostCursor2_MaxLevel) - max_requested.postCursor2 = PostCursor2_MaxLevel; - */ #if defined(CONFIG_DRM_AMD_DC_DCN) if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL) max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL; @@ -845,61 +819,30 @@ static void find_max_drive_settings( get_max_pre_emphasis_for_voltage_swing( max_requested.VOLTAGE_SWING); - /* - * Post Cursor2 levels are completely independent from - * pre-emphasis (Post Cursor1) levels. But Post Cursor2 levels - * can only be applied to each allowable combination of voltage - * swing and pre-emphasis levels */ - /* if ( max_requested.postCursor2 > - * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing)) - * max_requested.postCursor2 = - * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing); - */ - - max_lt_setting->link_settings.link_rate = - link_training_setting->link_settings.link_rate; - max_lt_setting->link_settings.lane_count = - link_training_setting->link_settings.lane_count; - max_lt_setting->link_settings.link_spread = - link_training_setting->link_settings.link_spread; - - for (lane = 0; lane < - link_training_setting->link_settings.lane_count; - lane++) { - max_lt_setting->lane_settings[lane].VOLTAGE_SWING = - max_requested.VOLTAGE_SWING; - max_lt_setting->lane_settings[lane].PRE_EMPHASIS = - max_requested.PRE_EMPHASIS; - /*max_lt_setting->laneSettings[lane].postCursor2 = - * max_requested.postCursor2; - */ + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING; + lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS; #if defined(CONFIG_DRM_AMD_DC_DCN) - max_lt_setting->lane_settings[lane].FFE_PRESET = - max_requested.FFE_PRESET; + lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET; #endif } - } -enum dc_status dp_get_lane_status_and_drive_settings( +enum dc_status dp_get_lane_status_and_lane_adjust( struct dc_link *link, const struct link_training_settings *link_training_setting, - union lane_status *ln_status, - union lane_align_status_updated *ln_status_updated, - struct link_training_settings *req_settings, + union lane_status ln_status[LANE_COUNT_DP_MAX], + union lane_align_status_updated *ln_align, + union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], uint32_t offset) { unsigned int lane01_status_address = DP_LANE0_1_STATUS; uint8_t lane_adjust_offset = 4; unsigned int lane01_adjust_address; uint8_t dpcd_buf[6] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - struct link_training_settings request_settings = { {0} }; uint32_t lane; enum dc_status status; - memset(req_settings, '\0', sizeof(struct link_training_settings)); - if (is_repeater(link, offset)) { lane01_status_address = DP_LANE0_1_STATUS_PHY_REPEATER1 + @@ -919,11 +862,11 @@ enum dc_status dp_get_lane_status_and_drive_settings( ln_status[lane].raw = get_nibble_at_index(&dpcd_buf[0], lane); - dpcd_lane_adjust[lane].raw = + ln_adjust[lane].raw = get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); } - ln_status_updated->raw = dpcd_buf[2]; + ln_align->raw = dpcd_buf[2]; if (is_repeater(link, offset)) { DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" @@ -962,55 +905,6 @@ enum dc_status dp_get_lane_status_and_drive_settings( dpcd_buf[lane_adjust_offset + 1]); } - /*copy to req_settings*/ - request_settings.link_settings.lane_count = - link_training_setting->link_settings.lane_count; - request_settings.link_settings.link_rate = - link_training_setting->link_settings.link_rate; - request_settings.link_settings.link_spread = - link_training_setting->link_settings.link_spread; - - for (lane = 0; lane < - (uint32_t)(link_training_setting->link_settings.lane_count); - lane++) { - -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (dp_get_link_encoding_format(&link_training_setting->link_settings) == - DP_128b_132b_ENCODING) { - request_settings.lane_settings[lane].FFE_PRESET.raw = - dpcd_lane_adjust[lane].tx_ffe.PRESET_VALUE; - } else if (dp_get_link_encoding_format(&link_training_setting->link_settings) == - DP_8b_10b_ENCODING) { - request_settings.lane_settings[lane].VOLTAGE_SWING = - (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits. - VOLTAGE_SWING_LANE); - request_settings.lane_settings[lane].PRE_EMPHASIS = - (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits. - PRE_EMPHASIS_LANE); - } -#else - request_settings.lane_settings[lane].VOLTAGE_SWING = - (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits. - VOLTAGE_SWING_LANE); - request_settings.lane_settings[lane].PRE_EMPHASIS = - (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits. - PRE_EMPHASIS_LANE); -#endif - } - - /*Note: for postcursor2, read adjusted - * postcursor2 settings from*/ - /*DpcdAddress_AdjustRequestPostCursor2 = - *0x020C (not implemented yet)*/ - - /* we find the maximum of the requested settings across all lanes*/ - /* and set this maximum for all lanes*/ - find_max_drive_settings(&request_settings, req_settings); - - /* if post cursor 2 is needed in the future, - * read DpcdAddress_AdjustRequestPostCursor2 = 0x020C - */ - return status; } @@ -1140,17 +1034,18 @@ static bool perform_post_lt_adj_req_sequence( adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT; adj_req_timer++) { - struct link_training_settings req_settings; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; - dp_get_lane_status_and_drive_settings( + dp_get_lane_status_and_lane_adjust( link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, DPRX); if (dpcd_lane_status_updated.bits. @@ -1169,10 +1064,9 @@ static bool perform_post_lt_adj_req_sequence( if (lt_settings-> lane_settings[lane].VOLTAGE_SWING != - req_settings.lane_settings[lane]. - VOLTAGE_SWING || + dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || lt_settings->lane_settings[lane].PRE_EMPHASIS != - req_settings.lane_settings[lane].PRE_EMPHASIS) { + dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { req_drv_setting_changed = true; break; @@ -1180,8 +1074,8 @@ static bool perform_post_lt_adj_req_sequence( } if (req_drv_setting_changed) { - dp_update_drive_settings( - lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); dc_link_dp_set_drive_settings(link, lt_settings); @@ -1261,13 +1155,14 @@ static enum link_training_result perform_channel_equalization_sequence( struct link_training_settings *lt_settings, uint32_t offset) { - struct link_training_settings req_settings; enum dc_dp_training_pattern tr_pattern; uint32_t retries_ch_eq; uint32_t wait_time_microsec; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Note: also check that TPS4 is a supported feature*/ @@ -1316,12 +1211,12 @@ static enum link_training_result perform_channel_equalization_sequence( /* 4. Read lane status and requested * drive settings as set by the sink*/ - dp_get_lane_status_and_drive_settings( + dp_get_lane_status_and_lane_adjust( link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, offset); /* 5. check CR done*/ @@ -1335,7 +1230,8 @@ static enum link_training_result perform_channel_equalization_sequence( return LINK_TRAINING_SUCCESS; /* 7. update VS/PE/PC2 in lt_settings*/ - dp_update_drive_settings(lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); } return LINK_TRAINING_EQ_FAIL_EQ; @@ -1361,10 +1257,10 @@ static enum link_training_result perform_clock_recovery_sequence( uint32_t retries_cr; uint32_t retry_count; uint32_t wait_time_microsec; - struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; retries_cr = 0; retry_count = 0; @@ -1418,12 +1314,12 @@ static enum link_training_result perform_clock_recovery_sequence( /* 4. Read lane status and requested drive * settings as set by the sink */ - dp_get_lane_status_and_drive_settings( + dp_get_lane_status_and_lane_adjust( link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, offset); /* 5. check CR done*/ @@ -1441,33 +1337,25 @@ static enum link_training_result perform_clock_recovery_sequence( break; #endif -#if defined(CONFIG_DRM_AMD_DC_DCN) - if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) && - lt_settings->lane_settings[0].FFE_PRESET.settings.level == - req_settings.lane_settings[0].FFE_PRESET.settings.level) - retries_cr++; - else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) && - lt_settings->lane_settings[0].VOLTAGE_SWING == - req_settings.lane_settings[0].VOLTAGE_SWING) - retries_cr++; - else - retries_cr = 0; -#else /* 7. same lane settings*/ /* Note: settings are the same for all lanes, * so comparing first lane is sufficient*/ - if ((lt_settings->lane_settings[0].VOLTAGE_SWING == - req_settings.lane_settings[0].VOLTAGE_SWING) - && (lt_settings->lane_settings[0].PRE_EMPHASIS == - req_settings.lane_settings[0].PRE_EMPHASIS)) + if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) && + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) retries_cr++; +#if defined(CONFIG_DRM_AMD_DC_DCN) + else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) && + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE == + dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE) + retries_cr++; +#endif else retries_cr = 0; -#endif /* 8. update VS/PE/PC2 in lt_settings*/ - dp_update_drive_settings(lt_settings, req_settings); - + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); retry_count++; } @@ -2083,10 +1971,11 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( uint8_t loop_count; uint32_t aux_rd_interval = 0; uint32_t wait_time = 0; - struct link_training_settings req_settings; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; enum link_training_result status = LINK_TRAINING_SUCCESS; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Transmit 128b/132b_TPS1 over Main-Link */ dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX); @@ -2095,11 +1984,11 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */ dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); - dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, &req_settings, DPRX); - dp_update_drive_settings(lt_settings, req_settings); + dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); dp_set_hw_lane_settings(link, lt_settings, DPRX); - dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX); /* Set loop counter to start from 1 */ @@ -2113,9 +2002,10 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( while (status == LINK_TRAINING_SUCCESS) { dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); wait_time += aux_rd_interval; - dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, &req_settings, DPRX); - dp_update_drive_settings(lt_settings, req_settings); + dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, dpcd_lane_status)) { @@ -2145,8 +2035,8 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( dp_wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time); wait_time += lt_settings->eq_pattern_time; - dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, &req_settings, DPRX); + dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); } } @@ -2159,9 +2049,9 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( { /* Assumption: assume hardware has transmitted eq pattern */ enum link_training_result status = LINK_TRAINING_SUCCESS; - struct link_training_settings req_settings; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; uint32_t wait_time = 0; /* initiate CDS done sequence */ @@ -2172,8 +2062,8 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( dp_wait_for_training_aux_rd_interval(link, lt_settings->cds_pattern_time); wait_time += lt_settings->cds_pattern_time; - dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, &req_settings, DPRX); + dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) { /* pass */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c index e9006d099393..c971f8c761ca 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c @@ -263,10 +263,12 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link uint32_t retry_count = 0; /* From DP spec, CR read interval is always 100us. */ uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; - struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; + uint8_t set_cfg_data; enum dpia_set_config_ts ts; @@ -345,11 +347,12 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link dp_wait_for_training_aux_rd_interval(link, wait_time_microsec); /* Read status and adjustment requests from DPCD. */ - status = dp_get_lane_status_and_drive_settings(link, + status = dp_get_lane_status_and_lane_adjust( + link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, hop); if (status != DC_OK) { result = LINK_TRAINING_ABORT; @@ -371,16 +374,18 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link * Note: settings are the same for all lanes, * so comparing first lane is sufficient. */ - if (lt_settings->lane_settings[0].VOLTAGE_SWING == - req_settings.lane_settings[0].VOLTAGE_SWING && - lt_settings->lane_settings[0].PRE_EMPHASIS == - req_settings.lane_settings[0].PRE_EMPHASIS) + if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET == + dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE)) retries_cr++; else retries_cr = 0; /* Update VS/PE. */ - dp_update_drive_settings(lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, + dpcd_lane_settings); retry_count++; } @@ -416,10 +421,11 @@ static enum link_training_result dpia_training_cr_transparent(struct dc_link *li uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */ uint32_t retry_count = 0; uint32_t wait_time_microsec = lt_settings->cr_pattern_time; - struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery. * Fix inherited from perform_clock_recovery_sequence() - @@ -445,11 +451,12 @@ static enum link_training_result dpia_training_cr_transparent(struct dc_link *li dp_wait_for_training_aux_rd_interval(link, wait_time_microsec); /* Read status and adjustment requests from DPCD. */ - status = dp_get_lane_status_and_drive_settings(link, + status = dp_get_lane_status_and_lane_adjust( + link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, DPRX); if (status != DC_OK) { result = LINK_TRAINING_ABORT; @@ -471,16 +478,17 @@ static enum link_training_result dpia_training_cr_transparent(struct dc_link *li * Note: settings are the same for all lanes, * so comparing first lane is sufficient. */ - if (lt_settings->lane_settings[0].VOLTAGE_SWING == - req_settings.lane_settings[0].VOLTAGE_SWING && - lt_settings->lane_settings[0].PRE_EMPHASIS == - req_settings.lane_settings[0].PRE_EMPHASIS) + if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET == + dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE)) retries_cr++; else retries_cr = 0; /* Update VS/PE. */ - dp_update_drive_settings(lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); retry_count++; } @@ -566,10 +574,11 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link enum dc_status status; enum dc_dp_training_pattern tr_pattern; uint32_t wait_time_microsec; - struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; uint8_t set_cfg_data; enum dpia_set_config_ts ts; @@ -639,11 +648,12 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link dp_wait_for_training_aux_rd_interval(link, wait_time_microsec); /* Read status and adjustment requests from DPCD. */ - status = dp_get_lane_status_and_drive_settings(link, + status = dp_get_lane_status_and_lane_adjust( + link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, hop); if (status != DC_OK) { result = LINK_TRAINING_ABORT; @@ -664,7 +674,8 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link } /* Update VS/PE. */ - dp_update_drive_settings(lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); } /* Abort link training if equalization failed due to HPD unplug. */ @@ -701,10 +712,11 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li enum dc_status status; enum dc_dp_training_pattern tr_pattern = lt_settings->pattern_for_eq; uint32_t wait_time_microsec; - struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX); @@ -720,11 +732,12 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li dp_wait_for_training_aux_rd_interval(link, wait_time_microsec); /* Read status and adjustment requests from DPCD. */ - status = dp_get_lane_status_and_drive_settings(link, + status = dp_get_lane_status_and_lane_adjust( + link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings, + dpcd_lane_adjust, DPRX); if (status != DC_OK) { result = LINK_TRAINING_ABORT; @@ -745,7 +758,8 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li } /* Update VS/PE. */ - dp_update_drive_settings(lt_settings, req_settings); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->lane_settings, dpcd_lane_settings); } /* Abort link training if equalization failed due to HPD unplug. */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index c70375117519..a6d3d859754a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -121,12 +121,12 @@ enum dc_status dpcd_set_lane_settings( const struct link_training_settings *link_training_setting, uint32_t offset); /* Read training status and adjustment requests from DPCD. */ -enum dc_status dp_get_lane_status_and_drive_settings( +enum dc_status dp_get_lane_status_and_lane_adjust( struct dc_link *link, const struct link_training_settings *link_training_setting, - union lane_status *ln_status, - union lane_align_status_updated *ln_status_updated, - struct link_training_settings *req_settings, + union lane_status ln_status[LANE_COUNT_DP_MAX], + union lane_align_status_updated *ln_align, + union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], uint32_t offset); void dp_wait_for_training_aux_rd_interval( @@ -151,9 +151,11 @@ void dp_hw_to_dpcd_lane_settings( const struct link_training_settings *lt_settings, const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]); -void dp_update_drive_settings( - struct link_training_settings *dest, - struct link_training_settings src); +void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]); uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval); diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 9a16fc855254..dc30dcd918bb 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -123,6 +123,23 @@ struct link_training_settings { /* dpcd lane settings will always use the same hw lane settings * even if it doesn't match requested lane adjust */ bool always_match_dpcd_with_hw_lane_settings; + + /***************************************************************** + * training states - parameters that can change in link training + *****************************************************************/ + /* TODO: Move hw_lane_settings and dpcd_lane_settings + * along with lane adjust, lane align, offset and all + * other training states into a new structure called + * training states, so link_training_settings becomes + * a constant input pre-decided prior to link training. + * + * The goal is to strictly decouple link training settings + * decision making process from link training states to + * prevent it from messy code practice of changing training + * decision on the fly. + */ + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX]; + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]; }; /*TODO: Move this enum test harness*/ From 75c2830c9157ee4ffae09e7502f20f4aee33529a Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Sun, 12 Sep 2021 00:32:43 -0400 Subject: [PATCH 541/554] drm/amd/display: decouple hw_lane_settings from dpcd_lane_settings [why] As DP features expands, we have encountered many situations where we must configure a different DPCD lane setting from hw lane settings we output. The change is to decouple hw lane settings from dpcd lane settings to provide flexibility to configure dpcd and hw individually. Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 148 +++++++----------- .../drm/amd/display/dc/core/dc_link_dpia.c | 11 +- drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 5 - .../amd/display/include/link_service_types.h | 5 +- 4 files changed, 63 insertions(+), 106 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index d780888d7f7f..9c956fe69b61 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -516,8 +516,6 @@ static void dpcd_set_lt_pattern_and_lane_settings( enum dc_dp_training_pattern pattern, uint32_t offset) { - union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } }; - uint32_t dpcd_base_lt_offset; uint8_t dpcd_lt_buffer[5] = {0}; @@ -555,16 +553,14 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_pattern.v1_4.TRAINING_PATTERN_SET); } - dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->lane_settings, dpcd_lane); - /* concatenate everything into one buffer*/ - - size_in_bytes = lt_settings->link_settings.lane_count * sizeof(dpcd_lane[0]); + size_in_bytes = lt_settings->link_settings.lane_count * + sizeof(lt_settings->dpcd_lane_settings[0]); // 0x00103 - 0x00102 memmove( &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET], - dpcd_lane, + lt_settings->dpcd_lane_settings, size_in_bytes); if (is_repeater(link, offset)) { @@ -576,7 +572,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( __func__, offset, dpcd_base_lt_offset, - dpcd_lane[0].tx_ffe.PRESET_VALUE); + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); else if (dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) #endif @@ -585,10 +581,10 @@ static void dpcd_set_lt_pattern_and_lane_settings( __func__, offset, dpcd_base_lt_offset, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); } else { #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(<_settings->link_settings) == @@ -596,17 +592,17 @@ static void dpcd_set_lt_pattern_and_lane_settings( DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", __func__, dpcd_base_lt_offset, - dpcd_lane[0].tx_ffe.PRESET_VALUE); + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); else if (dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) #endif DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, dpcd_base_lt_offset, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); } if (edp_workaround) { /* for eDP write in 2 parts because the 5-byte burst is @@ -621,7 +617,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( core_link_write_dpcd( link, DP_TRAINING_LANE0_SET, - (uint8_t *)(dpcd_lane), + (uint8_t *)(lt_settings->dpcd_lane_settings), size_in_bytes); #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -913,7 +909,6 @@ enum dc_status dpcd_set_lane_settings( const struct link_training_settings *link_training_setting, uint32_t offset) { - union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}}; unsigned int lane0_set_address; enum dc_status status; @@ -923,34 +918,11 @@ enum dc_status dpcd_set_lane_settings( lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - dp_hw_to_dpcd_lane_settings(link_training_setting, - link_training_setting->lane_settings, - dpcd_lane); - status = core_link_write_dpcd(link, lane0_set_address, - (uint8_t *)(dpcd_lane), + (uint8_t *)(link_training_setting->dpcd_lane_settings), link_training_setting->link_settings.lane_count); - /* - if (LTSettings.link.rate == LinkRate_High2) - { - DpcdTrainingLaneSet2 dpcd_lane2[lane_count_DPMax] = {0}; - for ( uint32_t lane = 0; - lane < lane_count_DPMax; lane++) - { - dpcd_lane2[lane].bits.post_cursor2_set = - static_cast( - LTSettings.laneSettings[lane].postCursor2); - dpcd_lane2[lane].bits.max_post_cursor2_reached = 0; - } - m_pDpcdAccessSrv->WriteDpcdData( - DpcdAddress_Lane0Set2, - reinterpret_cast(dpcd_lane2), - LTSettings.link.lanes); - } - */ - if (is_repeater(link, offset)) { #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link_training_setting->link_settings) == @@ -960,7 +932,7 @@ enum dc_status dpcd_set_lane_settings( __func__, offset, lane0_set_address, - dpcd_lane[0].tx_ffe.PRESET_VALUE); + link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); else if (dp_get_link_encoding_format(&link_training_setting->link_settings) == DP_8b_10b_ENCODING) #endif @@ -969,10 +941,10 @@ enum dc_status dpcd_set_lane_settings( __func__, offset, lane0_set_address, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); } else { #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -981,17 +953,17 @@ enum dc_status dpcd_set_lane_settings( DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", __func__, lane0_set_address, - dpcd_lane[0].tx_ffe.PRESET_VALUE); + link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); else if (dp_get_link_encoding_format(&link_training_setting->link_settings) == DP_8b_10b_ENCODING) #endif DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, lane0_set_address, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); } return status; @@ -1004,7 +976,7 @@ bool dp_is_max_vs_reached( for (lane = 0; lane < (uint32_t)(lt_settings->link_settings.lane_count); lane++) { - if (lt_settings->lane_settings[lane].VOLTAGE_SWING + if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET == VOLTAGE_SWING_MAX_LEVEL) return true; } @@ -1038,7 +1010,6 @@ static bool perform_post_lt_adj_req_sequence( union lane_align_status_updated dpcd_lane_status_updated; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; dp_get_lane_status_and_lane_adjust( link, @@ -1063,9 +1034,9 @@ static bool perform_post_lt_adj_req_sequence( for (lane = 0; lane < (uint32_t)(lane_count); lane++) { if (lt_settings-> - lane_settings[lane].VOLTAGE_SWING != + dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET != dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || - lt_settings->lane_settings[lane].PRE_EMPHASIS != + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET != dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { req_drv_setting_changed = true; @@ -1075,7 +1046,7 @@ static bool perform_post_lt_adj_req_sequence( if (req_drv_setting_changed) { dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); dc_link_dp_set_drive_settings(link, lt_settings); @@ -1162,10 +1133,8 @@ static enum link_training_result perform_channel_equalization_sequence( union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Note: also check that TPS4 is a supported feature*/ - tr_pattern = lt_settings->pattern_for_eq; #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -1231,7 +1200,7 @@ static enum link_training_result perform_channel_equalization_sequence( /* 7. update VS/PE/PC2 in lt_settings*/ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } return LINK_TRAINING_EQ_FAIL_EQ; @@ -1484,6 +1453,7 @@ static inline void decide_8b_10b_training_settings( lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); lt_settings->enhanced_framing = 1; lt_settings->should_set_fec_ready = true; + dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -1509,6 +1479,8 @@ static inline void decide_128b_132b_training_settings(struct dc_link *link, link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; lt_settings->lttpr_mode = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ? LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_TRANSPARENT; + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } #endif @@ -1571,6 +1543,9 @@ static void override_training_settings( : POST_CURSOR2_DISABLED; } + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + /* Initialize training timings */ if (overrides->cr_pattern_time != NULL) lt_settings->cr_pattern_time = *overrides->cr_pattern_time; @@ -1841,6 +1816,9 @@ void dc_link_dp_set_drive_settings( /* program ASIC PHY settings*/ dp_set_hw_lane_settings(link, lt_settings, DPRX); + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + /* Notify DP sink the PHY settings from source */ dpcd_set_lane_settings(link, lt_settings, DPRX); } @@ -1975,7 +1953,6 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; enum link_training_result status = LINK_TRAINING_SUCCESS; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Transmit 128b/132b_TPS1 over Main-Link */ dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX); @@ -1987,7 +1964,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); dp_set_hw_lane_settings(link, lt_settings, DPRX); dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX); @@ -2005,7 +1982,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, dpcd_lane_status)) { @@ -2120,7 +2097,7 @@ static enum link_training_result dp_perform_8b_10b_link_training( } for (lane = 0; lane < (uint8_t)lt_settings->link_settings.lane_count; lane++) - lt_settings->lane_settings[lane].VOLTAGE_SWING = VOLTAGE_SWING_LEVEL0; + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET = VOLTAGE_SWING_LEVEL0; } if (status == LINK_TRAINING_SUCCESS) { @@ -3496,15 +3473,13 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) #endif unsigned int test_pattern_size = 0; enum dp_test_pattern test_pattern; - struct dc_link_training_settings link_settings; union lane_adjust dpcd_lane_adjust; unsigned int lane; struct link_training_settings link_training_settings; - int i = 0; dpcd_test_pattern.raw = 0; memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment)); - memset(&link_settings, 0, sizeof(link_settings)); + memset(&link_training_settings, 0, sizeof(link_training_settings)); /* get phy test pattern and pattern parameters from DP receiver */ core_link_read_dpcd( @@ -3625,48 +3600,37 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) #endif /* prepare link training settings */ - link_settings.link = link->cur_link_settings; + link_training_settings.link_settings = link->cur_link_settings; for (lane = 0; lane < (unsigned int)(link->cur_link_settings.lane_count); lane++) { dpcd_lane_adjust.raw = get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); -#if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link->cur_link_settings) == - DP_128b_132b_ENCODING) { - link_settings.lane_settings[lane].FFE_PRESET.raw = - dpcd_lane_adjust.tx_ffe.PRESET_VALUE; - } else if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_8b_10b_ENCODING) { - link_settings.lane_settings[lane].VOLTAGE_SWING = + link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING = (enum dc_voltage_swing) (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE); - link_settings.lane_settings[lane].PRE_EMPHASIS = + link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS = (enum dc_pre_emphasis) (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE); - link_settings.lane_settings[lane].POST_CURSOR2 = + link_training_settings.hw_lane_settings[lane].POST_CURSOR2 = (enum dc_post_cursor2) ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); } -#else - link_settings.lane_settings[lane].VOLTAGE_SWING = - (enum dc_voltage_swing) - (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE); - link_settings.lane_settings[lane].PRE_EMPHASIS = - (enum dc_pre_emphasis) - (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE); - link_settings.lane_settings[lane].POST_CURSOR2 = - (enum dc_post_cursor2) - ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); +#if defined(CONFIG_DRM_AMD_DC_DCN) + else if (dp_get_link_encoding_format(&link->cur_link_settings) == + DP_128b_132b_ENCODING) { + link_training_settings.hw_lane_settings[lane].FFE_PRESET.raw = + dpcd_lane_adjust.tx_ffe.PRESET_VALUE; + } #endif } - for (i = 0; i < 4; i++) - link_training_settings.lane_settings[i] = - link_settings.lane_settings[i]; - link_training_settings.link_settings = link_settings.link; - link_training_settings.allow_invalid_msa_timing_param = false; + dp_hw_to_dpcd_lane_settings(&link_training_settings, + link_training_settings.hw_lane_settings, + link_training_settings.dpcd_lane_settings); /*Usage: Measure DP physical lane signal * by DP SI test equipment automatically. * PHY test pattern request is generated by equipment via HPD interrupt. diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c index c971f8c761ca..b1c9f77d6bf4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c @@ -267,8 +267,6 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; - uint8_t set_cfg_data; enum dpia_set_config_ts ts; @@ -385,7 +383,7 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link /* Update VS/PE. */ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, lt_settings->lane_settings, - dpcd_lane_settings); + lt_settings->dpcd_lane_settings); retry_count++; } @@ -425,7 +423,6 @@ static enum link_training_result dpia_training_cr_transparent(struct dc_link *li union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery. * Fix inherited from perform_clock_recovery_sequence() - @@ -578,7 +575,6 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; uint8_t set_cfg_data; enum dpia_set_config_ts ts; @@ -675,7 +671,7 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link /* Update VS/PE. */ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } /* Abort link training if equalization failed due to HPD unplug. */ @@ -716,7 +712,6 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; - union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX] = { { {0} } }; wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX); @@ -759,7 +754,7 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li /* Update VS/PE. */ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->lane_settings, dpcd_lane_settings); + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } /* Abort link training if equalization failed due to HPD unplug. */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index a23937e1dc5c..bc87ea0adf94 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -174,11 +174,6 @@ struct dc_lane_settings { #endif }; -struct dc_link_training_settings { - struct dc_link_settings link; - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; -}; - struct dc_link_training_overrides { enum dc_voltage_swing *voltage_swing; enum dc_pre_emphasis *pre_emphasis; diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index dc30dcd918bb..622c03f15df2 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -90,8 +90,11 @@ enum lttpr_mode { struct link_training_settings { struct dc_link_settings link_settings; - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; + /* TODO: turn lane settings below into mandatory fields + * as initial lane configuration + */ + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; enum dc_voltage_swing *voltage_swing; enum dc_pre_emphasis *pre_emphasis; enum dc_post_cursor2 *post_cursor2; From 9c92c79b05f6c9ed70511dbf160030ad20f4124c Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Sun, 12 Sep 2021 01:20:22 -0400 Subject: [PATCH 542/554] drm/amd/display: add two lane settings training options [why] option 1: disallow different lanes to have different lane settings option 2: dpcd lane settings will always use the same hw lane settings even if it doesn't match requested lane adjust Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 14 +++++++++++++- .../drm/amd/display/include/link_service_types.h | 1 - 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 9c956fe69b61..4b89a2727c1c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -737,8 +737,17 @@ void dp_decide_lane_settings( /* we find the maximum of the requested settings across all lanes*/ /* and set this maximum for all lanes*/ - maximize_lane_settings(lt_settings, hw_lane_settings); dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); + + if (lt_settings->disallow_per_lane_settings) { + /* we find the maximum of the requested settings across all lanes*/ + /* and set this maximum for all lanes*/ + maximize_lane_settings(lt_settings, hw_lane_settings); + + if (lt_settings->always_match_dpcd_with_hw_lane_settings) + dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); + } + } static uint8_t get_nibble_at_index(const uint8_t *buf, @@ -1453,6 +1462,8 @@ static inline void decide_8b_10b_training_settings( lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); lt_settings->enhanced_framing = 1; lt_settings->should_set_fec_ready = true; + lt_settings->disallow_per_lane_settings = true; + lt_settings->always_match_dpcd_with_hw_lane_settings = true; dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } @@ -1479,6 +1490,7 @@ static inline void decide_128b_132b_training_settings(struct dc_link *link, link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; lt_settings->lttpr_mode = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ? LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_TRANSPARENT; + lt_settings->disallow_per_lane_settings = true; dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); } diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 622c03f15df2..424bccd36434 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -118,7 +118,6 @@ struct link_training_settings { #endif bool enhanced_framing; - bool allow_invalid_msa_timing_param; enum lttpr_mode lttpr_mode; /* disallow different lanes to have different lane settings */ From e72aa36ef88f18d541acacaa4051de615ba78efa Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Mon, 27 Sep 2021 13:10:07 -0400 Subject: [PATCH 543/554] drm/amd/display: fix link training regression for 1 or 2 lane [why] We have a regression that cause maximize lane settings to use uninitialized data from unused lanes. This will cause link training to fail for 1 or 2 lanes because the lane adjust is populated incorrectly sometimes. v2: fix build without CONFIG_DRM_AMD_DC_DCN (Alex) Reviewed-by: Eric Yang Acked-by: Rodrigo Siqueira Tested-by: Daniel Wheeler Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 4b89a2727c1c..cc25ba0ec7db 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -108,6 +108,9 @@ static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_b); static void maximize_lane_settings(const struct link_training_settings *lt_settings, struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); +static void override_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); + static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link, const struct dc_link_settings *link_settings) { @@ -734,15 +737,13 @@ void dp_decide_lane_settings( } #endif } - - /* we find the maximum of the requested settings across all lanes*/ - /* and set this maximum for all lanes*/ dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); if (lt_settings->disallow_per_lane_settings) { /* we find the maximum of the requested settings across all lanes*/ /* and set this maximum for all lanes*/ maximize_lane_settings(lt_settings, hw_lane_settings); + override_lane_settings(lt_settings, hw_lane_settings); if (lt_settings->always_match_dpcd_with_hw_lane_settings) dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); @@ -833,6 +834,34 @@ static void maximize_lane_settings(const struct link_training_settings *lt_setti } } +static void override_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) +{ + uint32_t lane; + + if (lt_settings->voltage_swing == NULL && + lt_settings->pre_emphasis == NULL && +#if defined(CONFIG_DRM_AMD_DC_DCN) + lt_settings->ffe_preset == NULL && +#endif + lt_settings->post_cursor2 == NULL) + + return; + + for (lane = 1; lane < LANE_COUNT_DP_MAX; lane++) { + if (lt_settings->voltage_swing) + lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; + if (lt_settings->pre_emphasis) + lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis; + if (lt_settings->post_cursor2) + lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2; +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (lt_settings->ffe_preset) + lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset; +#endif + } +} + enum dc_status dp_get_lane_status_and_lane_adjust( struct dc_link *link, const struct link_training_settings *link_training_setting, From 31484207feb23e6cdb12827560442ab294855923 Mon Sep 17 00:00:00 2001 From: Qingqing Zhuo Date: Wed, 6 Oct 2021 17:56:55 +0800 Subject: [PATCH 544/554] drm/amd/display: move FPU associated DCN301 code to DML folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why & How] As part of the FPU isolation work documented in https://patchwork.freedesktop.org/series/93042/, isolate code that uses FPU in DCN301 to DML, where all FPU code should locate. Cc: Christian König Cc: Harry Wentland Cc: Rodrigo Siqueira Tested-by: Zhan Liu Tested-by: Daniel Wheeler Signed-off-by: Qingqing Zhuo Reviewed-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dcn30/dcn30_resource.c | 2 + .../gpu/drm/amd/display/dc/dcn301/Makefile | 26 -- .../amd/display/dc/dcn301/dcn301_resource.c | 349 +--------------- .../amd/display/dc/dcn301/dcn301_resource.h | 3 + drivers/gpu/drm/amd/display/dc/dml/Makefile | 3 + .../amd/display/dc/dml/dcn301/dcn301_fpu.c | 390 ++++++++++++++++++ .../amd/display/dc/dml/dcn301/dcn301_fpu.h | 42 ++ 7 files changed, 450 insertions(+), 365 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 6dda20f3741c..e50c695e3c96 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -2322,7 +2322,9 @@ bool dcn30_validate_bandwidth(struct dc *dc, goto validate_out; } + DC_FP_START(); dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); BW_VAL_TRACE_END_WATERMARKS(); diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile index 09264716d1dc..7aa628c21973 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile @@ -13,32 +13,6 @@ DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \ dcn301_dio_link_encoder.o dcn301_hwseq.o dcn301_panel_cntl.o dcn301_hubbub.o -ifdef CONFIG_X86 -CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -msse -endif - -ifdef CONFIG_PPC64 -CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o := -mhard-float -maltivec -endif - -ifdef CONFIG_CC_IS_GCC -ifeq ($(call cc-ifversion, -lt, 0701, y), y) -IS_OLD_GCC = 1 -endif -CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -mhard-float -endif - -ifdef CONFIG_X86 -ifdef IS_OLD_GCC -# Stack alignment mismatch, proceed with caution. -# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 -# (8B stack alignment). -CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -mpreferred-stack-boundary=4 -else -CFLAGS_$(AMDDALPATH)/dc/dcn301/dcn301_resource.o += -msse2 -endif -endif - AMD_DAL_DCN301 = $(addprefix $(AMDDALPATH)/dc/dcn301/,$(DCN301)) AMD_DISPLAY_FILES += $(AMD_DAL_DCN301) diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index 5350c93d7772..fbaa03f26d8b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -82,6 +82,7 @@ #include "dce/dce_i2c.h" #include "dml/dcn30/display_mode_vba_30.h" +#include "dml/dcn301/dcn301_fpu.h" #include "vm_helper.h" #include "dcn20/dcn20_vmid.h" #include "amdgpu_socbb.h" @@ -91,184 +92,6 @@ #define DC_LOGGER_INIT(logger) -struct _vcs_dpi_ip_params_st dcn3_01_ip = { - .odm_capable = 1, - .gpuvm_enable = 1, - .hostvm_enable = 1, - .gpuvm_max_page_table_levels = 1, - .hostvm_max_page_table_levels = 2, - .hostvm_cached_page_table_levels = 0, - .pte_group_size_bytes = 2048, - .num_dsc = 3, - .rob_buffer_size_kbytes = 184, - .det_buffer_size_kbytes = 184, - .dpte_buffer_size_in_pte_reqs_luma = 64, - .dpte_buffer_size_in_pte_reqs_chroma = 32, - .pde_proc_buffer_size_64k_reqs = 48, - .dpp_output_buffer_pixels = 2560, - .opp_output_buffer_lines = 1, - .pixel_chunk_size_kbytes = 8, - .meta_chunk_size_kbytes = 2, - .writeback_chunk_size_kbytes = 8, - .line_buffer_size_bits = 789504, - .is_line_buffer_bpp_fixed = 0, // ? - .line_buffer_fixed_bpp = 48, // ? - .dcc_supported = true, - .writeback_interface_buffer_size_kbytes = 90, - .writeback_line_buffer_buffer_size = 656640, - .max_line_buffer_lines = 12, - .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640 - .writeback_chroma_buffer_size_kbytes = 8, - .writeback_chroma_line_buffer_width_pixels = 4, - .writeback_max_hscl_ratio = 1, - .writeback_max_vscl_ratio = 1, - .writeback_min_hscl_ratio = 1, - .writeback_min_vscl_ratio = 1, - .writeback_max_hscl_taps = 1, - .writeback_max_vscl_taps = 1, - .writeback_line_buffer_luma_buffer_size = 0, - .writeback_line_buffer_chroma_buffer_size = 14643, - .cursor_buffer_size = 8, - .cursor_chunk_size = 2, - .max_num_otg = 4, - .max_num_dpp = 4, - .max_num_wb = 1, - .max_dchub_pscl_bw_pix_per_clk = 4, - .max_pscl_lb_bw_pix_per_clk = 2, - .max_lb_vscl_bw_pix_per_clk = 4, - .max_vscl_hscl_bw_pix_per_clk = 4, - .max_hscl_ratio = 6, - .max_vscl_ratio = 6, - .hscl_mults = 4, - .vscl_mults = 4, - .max_hscl_taps = 8, - .max_vscl_taps = 8, - .dispclk_ramp_margin_percent = 1, - .underscan_factor = 1.11, - .min_vblank_lines = 32, - .dppclk_delay_subtotal = 46, - .dynamic_metadata_vm_enabled = true, - .dppclk_delay_scl_lb_only = 16, - .dppclk_delay_scl = 50, - .dppclk_delay_cnvc_formatter = 27, - .dppclk_delay_cnvc_cursor = 6, - .dispclk_delay_subtotal = 119, - .dcfclk_cstate_latency = 5.2, // SRExitTime - .max_inter_dcn_tile_repeaters = 8, - .max_num_hdmi_frl_outputs = 0, - .odm_combine_4to1_supported = true, - - .xfc_supported = false, - .xfc_fill_bw_overhead_percent = 10.0, - .xfc_fill_constant_bytes = 0, - .gfx7_compat_tiling_supported = 0, - .number_of_cursors = 1, -}; - -struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc = { - .clock_limits = { - { - .state = 0, - .dram_speed_mts = 2400.0, - .fabricclk_mhz = 600, - .socclk_mhz = 278.0, - .dcfclk_mhz = 400.0, - .dscclk_mhz = 206.0, - .dppclk_mhz = 1015.0, - .dispclk_mhz = 1015.0, - .phyclk_mhz = 600.0, - }, - { - .state = 1, - .dram_speed_mts = 2400.0, - .fabricclk_mhz = 688, - .socclk_mhz = 278.0, - .dcfclk_mhz = 400.0, - .dscclk_mhz = 206.0, - .dppclk_mhz = 1015.0, - .dispclk_mhz = 1015.0, - .phyclk_mhz = 600.0, - }, - { - .state = 2, - .dram_speed_mts = 4267.0, - .fabricclk_mhz = 1067, - .socclk_mhz = 278.0, - .dcfclk_mhz = 608.0, - .dscclk_mhz = 296.0, - .dppclk_mhz = 1015.0, - .dispclk_mhz = 1015.0, - .phyclk_mhz = 810.0, - }, - - { - .state = 3, - .dram_speed_mts = 4267.0, - .fabricclk_mhz = 1067, - .socclk_mhz = 715.0, - .dcfclk_mhz = 676.0, - .dscclk_mhz = 338.0, - .dppclk_mhz = 1015.0, - .dispclk_mhz = 1015.0, - .phyclk_mhz = 810.0, - }, - - { - .state = 4, - .dram_speed_mts = 4267.0, - .fabricclk_mhz = 1067, - .socclk_mhz = 953.0, - .dcfclk_mhz = 810.0, - .dscclk_mhz = 338.0, - .dppclk_mhz = 1015.0, - .dispclk_mhz = 1015.0, - .phyclk_mhz = 810.0, - }, - }, - - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .urgent_latency_us = 4.0, - .urgent_latency_pixel_data_only_us = 4.0, - .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, - .urgent_latency_vm_data_only_us = 4.0, - .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, - .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, - .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, - .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, - .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0, - .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, - .max_avg_sdp_bw_use_normal_percent = 60.0, - .max_avg_dram_bw_use_normal_percent = 60.0, - .writeback_latency_us = 12.0, - .max_request_size_bytes = 256, - .dram_channel_width_bytes = 4, - .fabric_datapath_to_dcn_data_return_bytes = 32, - .dcn_downspread_percent = 0.5, - .downspread_percent = 0.38, - .dram_page_open_time_ns = 50.0, - .dram_rw_turnaround_time_ns = 17.5, - .dram_return_buffer_per_channel_bytes = 8192, - .round_trip_ping_latency_dcfclk_cycles = 191, - .urgent_out_of_order_return_per_channel_bytes = 4096, - .channel_interleave_bytes = 256, - .num_banks = 8, - .num_chans = 4, - .gpuvm_min_page_size_bytes = 4096, - .hostvm_min_page_size_bytes = 4096, - .dram_clock_change_latency_us = 23.84, - .writeback_dram_clock_change_latency_us = 23.0, - .return_bus_width_bytes = 64, - .dispclk_dppclk_vco_speed_mhz = 3550, - .xfc_bus_transport_time_us = 20, // ? - .xfc_xbuf_latency_tolerance_us = 4, // ? - .use_urgent_burst_bw = 1, // ? - .num_states = 5, - .do_urgent_latency_adjustment = false, - .urgent_latency_adjustment_fabric_clock_component_us = 0, - .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, -}; - enum dcn301_clk_src_array_id { DCN301_CLK_SRC_PLL0, DCN301_CLK_SRC_PLL1, @@ -1480,8 +1303,6 @@ static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap }; -#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) -#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) static bool is_soc_bounding_box_valid(struct dc *dc) { @@ -1508,26 +1329,24 @@ static bool init_soc_bounding_box(struct dc *dc, loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; loaded_ip->max_num_dpp = pool->base.pipe_count; + DC_FP_START(); dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_END(); if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { struct bp_soc_bb_info bb_info = {0}; if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { - if (bb_info.dram_clock_change_latency_100ns > 0) - dcn3_01_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10; - - if (bb_info.dram_sr_enter_exit_latency_100ns > 0) - dcn3_01_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10; - - if (bb_info.dram_sr_exit_latency_100ns > 0) - dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10; + DC_FP_START(); + dcn301_fpu_init_soc_bounding_box(bb_info); + DC_FP_END(); } } return true; } + static void set_wm_ranges( struct pp_smu_funcs *pp_smu, struct _vcs_dpi_soc_bounding_box_st *loaded_bb) @@ -1550,9 +1369,9 @@ static void set_wm_ranges( ranges.reader_wm_sets[i].wm_inst = i; ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; - ranges.reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; - + DC_FP_START(); + dcn301_fpu_set_wm_ranges(i, &ranges, loaded_bb); + DC_FP_END(); ranges.num_reader_wm_sets = i + 1; } @@ -1572,154 +1391,6 @@ static void set_wm_ranges( pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges); } -static void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - struct dcn301_resource_pool *pool = TO_DCN301_RES_POOL(dc->res_pool); - struct clk_limit_table *clk_table = &bw_params->clk_table; - struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; - unsigned int i, closest_clk_lvl; - int j; - - // Default clock levels are used for diags, which may lead to overclocking. - if (!IS_DIAG_DC(dc->ctx->dce_environment)) { - dcn3_01_ip.max_num_otg = pool->base.res_cap->num_timing_generator; - dcn3_01_ip.max_num_dpp = pool->base.pipe_count; - dcn3_01_soc.num_chans = bw_params->num_channels; - - ASSERT(clk_table->num_entries); - for (i = 0; i < clk_table->num_entries; i++) { - /* loop backwards*/ - for (closest_clk_lvl = 0, j = dcn3_01_soc.num_states - 1; j >= 0; j--) { - if ((unsigned int) dcn3_01_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) { - closest_clk_lvl = j; - break; - } - } - - clock_limits[i].state = i; - clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; - clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; - clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; - clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; - - clock_limits[i].dispclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dispclk_mhz; - clock_limits[i].dppclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dppclk_mhz; - clock_limits[i].dram_bw_per_chan_gbps = dcn3_01_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; - clock_limits[i].dscclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dscclk_mhz; - clock_limits[i].dtbclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; - clock_limits[i].phyclk_d18_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; - clock_limits[i].phyclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_mhz; - } - for (i = 0; i < clk_table->num_entries; i++) - dcn3_01_soc.clock_limits[i] = clock_limits[i]; - if (clk_table->num_entries) { - dcn3_01_soc.num_states = clk_table->num_entries; - /* duplicate last level */ - dcn3_01_soc.clock_limits[dcn3_01_soc.num_states] = dcn3_01_soc.clock_limits[dcn3_01_soc.num_states - 1]; - dcn3_01_soc.clock_limits[dcn3_01_soc.num_states].state = dcn3_01_soc.num_states; - } - } - - dcn3_01_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; - dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; - - dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); -} - -static void calculate_wm_set_for_vlevel( - int vlevel, - struct wm_range_table_entry *table_entry, - struct dcn_watermarks *wm_set, - struct display_mode_lib *dml, - display_e2e_pipe_params_st *pipes, - int pipe_cnt) -{ - double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; - - ASSERT(vlevel < dml->soc.num_states); - /* only pipe 0 is read for voltage and dcf/soc clocks */ - pipes[0].clks_cfg.voltage = vlevel; - pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; - pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; - - dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; - dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; - dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; - - wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; - wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; - wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; - wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; - wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; - dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; - -} - -static void dcn301_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel_req) -{ - int i, pipe_idx; - int vlevel, vlevel_max; - struct wm_range_table_entry *table_entry; - struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; - - ASSERT(bw_params); - - vlevel_max = bw_params->clk_table.num_entries - 1; - - /* WM Set D */ - table_entry = &bw_params->wm_table.entries[WM_D]; - if (table_entry->wm_type == WM_TYPE_RETRAINING) - vlevel = 0; - else - vlevel = vlevel_max; - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, - &context->bw_ctx.dml, pipes, pipe_cnt); - /* WM Set C */ - table_entry = &bw_params->wm_table.entries[WM_C]; - vlevel = min(max(vlevel_req, 2), vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, - &context->bw_ctx.dml, pipes, pipe_cnt); - /* WM Set B */ - table_entry = &bw_params->wm_table.entries[WM_B]; - vlevel = min(max(vlevel_req, 1), vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, - &context->bw_ctx.dml, pipes, pipe_cnt); - - /* WM Set A */ - table_entry = &bw_params->wm_table.entries[WM_A]; - vlevel = min(vlevel_req, vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, - &context->bw_ctx.dml, pipes, pipe_cnt); - - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); - pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); - - if (dc->config.forced_clocks) { - pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; - pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; - } - if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) - pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; - if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) - pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; - - pipe_idx++; - } - - dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); -} - static struct resource_funcs dcn301_res_pool_funcs = { .destroy = dcn301_destroy_resource_pool, .link_enc_create = dcn301_link_encoder_create, diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h index 17e4e91ff4b8..ae8672680cdd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h @@ -32,6 +32,9 @@ struct dc; struct resource_pool; struct _vcs_dpi_display_pipe_params_st; +extern struct _vcs_dpi_ip_params_st dcn3_01_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc; + struct dcn301_resource_pool { struct resource_pool base; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index e7bb69ec99b6..eee6672bd32d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -70,6 +70,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) @@ -84,6 +85,7 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_rcflags) endif @@ -101,6 +103,7 @@ DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o +DML += dcn301/dcn301_fpu.o DML += dsc/rc_calc_fpu.o endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c new file mode 100644 index 000000000000..94c32832a0e7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c @@ -0,0 +1,390 @@ +/* + * Copyright 2019-2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include "resource.h" +#include "clk_mgr.h" +#include "dcn20/dcn20_resource.h" +#include "dcn301/dcn301_resource.h" + +#include "dml/dcn20/dcn20_fpu.h" +#include "dcn301_fpu.h" + +#define TO_DCN301_RES_POOL(pool)\ + container_of(pool, struct dcn301_resource_pool, base) + +/* Based on: //vidip/dc/dcn3/doc/architecture/DCN3x_Display_Mode.xlsm#83 */ +struct _vcs_dpi_ip_params_st dcn3_01_ip = { + .odm_capable = 1, + .gpuvm_enable = 1, + .hostvm_enable = 1, + .gpuvm_max_page_table_levels = 1, + .hostvm_max_page_table_levels = 2, + .hostvm_cached_page_table_levels = 0, + .pte_group_size_bytes = 2048, + .num_dsc = 3, + .rob_buffer_size_kbytes = 184, + .det_buffer_size_kbytes = 184, + .dpte_buffer_size_in_pte_reqs_luma = 64, + .dpte_buffer_size_in_pte_reqs_chroma = 32, + .pde_proc_buffer_size_64k_reqs = 48, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 8, + .line_buffer_size_bits = 789504, + .is_line_buffer_bpp_fixed = 0, // ? + .line_buffer_fixed_bpp = 48, // ? + .dcc_supported = true, + .writeback_interface_buffer_size_kbytes = 90, + .writeback_line_buffer_buffer_size = 656640, + .max_line_buffer_lines = 12, + .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640 + .writeback_chroma_buffer_size_kbytes = 8, + .writeback_chroma_line_buffer_width_pixels = 4, + .writeback_max_hscl_ratio = 1, + .writeback_max_vscl_ratio = 1, + .writeback_min_hscl_ratio = 1, + .writeback_min_vscl_ratio = 1, + .writeback_max_hscl_taps = 1, + .writeback_max_vscl_taps = 1, + .writeback_line_buffer_luma_buffer_size = 0, + .writeback_line_buffer_chroma_buffer_size = 14643, + .cursor_buffer_size = 8, + .cursor_chunk_size = 2, + .max_num_otg = 4, + .max_num_dpp = 4, + .max_num_wb = 1, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 6, + .max_vscl_ratio = 6, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.11, + .min_vblank_lines = 32, + .dppclk_delay_subtotal = 46, + .dynamic_metadata_vm_enabled = true, + .dppclk_delay_scl_lb_only = 16, + .dppclk_delay_scl = 50, + .dppclk_delay_cnvc_formatter = 27, + .dppclk_delay_cnvc_cursor = 6, + .dispclk_delay_subtotal = 119, + .dcfclk_cstate_latency = 5.2, // SRExitTime + .max_inter_dcn_tile_repeaters = 8, + .max_num_hdmi_frl_outputs = 0, + .odm_combine_4to1_supported = true, + + .xfc_supported = false, + .xfc_fill_bw_overhead_percent = 10.0, + .xfc_fill_constant_bytes = 0, + .gfx7_compat_tiling_supported = 0, + .number_of_cursors = 1, +}; + +struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc = { + .clock_limits = { + { + .state = 0, + .dram_speed_mts = 2400.0, + .fabricclk_mhz = 600, + .socclk_mhz = 278.0, + .dcfclk_mhz = 400.0, + .dscclk_mhz = 206.0, + .dppclk_mhz = 1015.0, + .dispclk_mhz = 1015.0, + .phyclk_mhz = 600.0, + }, + + { + .state = 1, + .dram_speed_mts = 2400.0, + .fabricclk_mhz = 688, + .socclk_mhz = 278.0, + .dcfclk_mhz = 400.0, + .dscclk_mhz = 206.0, + .dppclk_mhz = 1015.0, + .dispclk_mhz = 1015.0, + .phyclk_mhz = 600.0, + }, + + { + .state = 2, + .dram_speed_mts = 4267.0, + .fabricclk_mhz = 1067, + .socclk_mhz = 278.0, + .dcfclk_mhz = 608.0, + .dscclk_mhz = 296.0, + .dppclk_mhz = 1015.0, + .dispclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + }, + + { + .state = 3, + .dram_speed_mts = 4267.0, + .fabricclk_mhz = 1067, + .socclk_mhz = 715.0, + .dcfclk_mhz = 676.0, + .dscclk_mhz = 338.0, + .dppclk_mhz = 1015.0, + .dispclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + }, + + { + .state = 4, + .dram_speed_mts = 4267.0, + .fabricclk_mhz = 1067, + .socclk_mhz = 953.0, + .dcfclk_mhz = 810.0, + .dscclk_mhz = 338.0, + .dppclk_mhz = 1015.0, + .dispclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + }, + }, + + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, + .max_avg_sdp_bw_use_normal_percent = 60.0, + .max_avg_dram_bw_use_normal_percent = 60.0, + .writeback_latency_us = 12.0, + .max_request_size_bytes = 256, + .dram_channel_width_bytes = 4, + .fabric_datapath_to_dcn_data_return_bytes = 32, + .dcn_downspread_percent = 0.5, + .downspread_percent = 0.38, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 191, + .urgent_out_of_order_return_per_channel_bytes = 4096, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 4, + .gpuvm_min_page_size_bytes = 4096, + .hostvm_min_page_size_bytes = 4096, + .dram_clock_change_latency_us = 23.84, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, + .dispclk_dppclk_vco_speed_mhz = 3550, + .xfc_bus_transport_time_us = 20, // ? + .xfc_xbuf_latency_tolerance_us = 4, // ? + .use_urgent_burst_bw = 1, // ? + .num_states = 5, + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, +}; + +static void calculate_wm_set_for_vlevel(int vlevel, + struct wm_range_table_entry *table_entry, + struct dcn_watermarks *wm_set, + struct display_mode_lib *dml, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; + + ASSERT(vlevel < dml->soc.num_states); + /* only pipe 0 is read for voltage and dcf/soc clocks */ + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; + + dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; + dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; + dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; + + wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; + wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; + wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; + wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; + wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; + dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; + +} + +void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + struct dcn301_resource_pool *pool = TO_DCN301_RES_POOL(dc->res_pool); + struct clk_limit_table *clk_table = &bw_params->clk_table; + struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; + unsigned int i, closest_clk_lvl; + int j; + + dc_assert_fp_enabled(); + + /* Default clock levels are used for diags, which may lead to overclocking. */ + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { + dcn3_01_ip.max_num_otg = pool->base.res_cap->num_timing_generator; + dcn3_01_ip.max_num_dpp = pool->base.pipe_count; + dcn3_01_soc.num_chans = bw_params->num_channels; + + ASSERT(clk_table->num_entries); + for (i = 0; i < clk_table->num_entries; i++) { + /* loop backwards*/ + for (closest_clk_lvl = 0, j = dcn3_01_soc.num_states - 1; j >= 0; j--) { + if ((unsigned int) dcn3_01_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) { + closest_clk_lvl = j; + break; + } + } + + clock_limits[i].state = i; + clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; + clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; + clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; + clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; + + clock_limits[i].dispclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dispclk_mhz; + clock_limits[i].dppclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dppclk_mhz; + clock_limits[i].dram_bw_per_chan_gbps = dcn3_01_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; + clock_limits[i].dscclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dscclk_mhz; + clock_limits[i].dtbclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; + clock_limits[i].phyclk_d18_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; + clock_limits[i].phyclk_mhz = dcn3_01_soc.clock_limits[closest_clk_lvl].phyclk_mhz; + } + + for (i = 0; i < clk_table->num_entries; i++) + dcn3_01_soc.clock_limits[i] = clock_limits[i]; + + if (clk_table->num_entries) { + dcn3_01_soc.num_states = clk_table->num_entries; + /* duplicate last level */ + dcn3_01_soc.clock_limits[dcn3_01_soc.num_states] = dcn3_01_soc.clock_limits[dcn3_01_soc.num_states - 1]; + dcn3_01_soc.clock_limits[dcn3_01_soc.num_states].state = dcn3_01_soc.num_states; + } + } + + dcn3_01_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; + + dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); +} + +void dcn301_fpu_set_wm_ranges(int i, + struct pp_smu_wm_range_sets *ranges, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb) +{ + dc_assert_fp_enabled(); + + ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; +} + +void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info) +{ + dc_assert_fp_enabled(); + + if (bb_info.dram_clock_change_latency_100ns > 0) + dcn3_01_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10; + + if (bb_info.dram_sr_enter_exit_latency_100ns > 0) + dcn3_01_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10; + + if (bb_info.dram_sr_exit_latency_100ns > 0) + dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10; +} + +void dcn301_calculate_wm_and_dlg(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel_req) +{ + int i, pipe_idx; + int vlevel, vlevel_max; + struct wm_range_table_entry *table_entry; + struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; + + ASSERT(bw_params); + dc_assert_fp_enabled(); + + vlevel_max = bw_params->clk_table.num_entries - 1; + + /* WM Set D */ + table_entry = &bw_params->wm_table.entries[WM_D]; + if (table_entry->wm_type == WM_TYPE_RETRAINING) + vlevel = 0; + else + vlevel = vlevel_max; + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, + &context->bw_ctx.dml, pipes, pipe_cnt); + /* WM Set C */ + table_entry = &bw_params->wm_table.entries[WM_C]; + vlevel = min(max(vlevel_req, 2), vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, + &context->bw_ctx.dml, pipes, pipe_cnt); + /* WM Set B */ + table_entry = &bw_params->wm_table.entries[WM_B]; + vlevel = min(max(vlevel_req, 1), vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, + &context->bw_ctx.dml, pipes, pipe_cnt); + + /* WM Set A */ + table_entry = &bw_params->wm_table.entries[WM_A]; + vlevel = min(vlevel_req, vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, + &context->bw_ctx.dml, pipes, pipe_cnt); + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); + pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + + if (dc->config.forced_clocks) { + pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; + pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; + } + if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) + pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; + if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) + pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; + pipe_idx++; + } + + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h new file mode 100644 index 000000000000..fc7065d17842 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DCN301_FPU_H__ +#define __DCN301_FPU_H__ + +void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + +void dcn301_fpu_set_wm_ranges(int i, + struct pp_smu_wm_range_sets *ranges, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb); + +void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info); + +void dcn301_calculate_wm_and_dlg(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel_req); +#endif /* __DCN301_FPU_H__*/ From 1e5588d14065eeb154ef15fbe3f74ace9460a386 Mon Sep 17 00:00:00 2001 From: Michael Strauss Date: Thu, 21 Oct 2021 13:27:16 -0400 Subject: [PATCH 545/554] drm/amd/display: Fallback to clocks which meet requested voltage on DCN31 [WHY] On certain configs, SMU clock table voltages don't match which cause parser to behave incorrectly by leaving dcfclk and socclk table entries unpopulated. [HOW] Currently the function that finds the corresponding clock for a given voltage only checks for exact voltage level matches. In the case that no match gets found, parser now falls back to searching for the max clock which meets the requested voltage (i.e. its corresponding voltage is below requested). Signed-off-by: Michael Strauss Reviewed-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 0088dff441da..f4c9a458ace8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -523,14 +523,21 @@ static unsigned int find_clk_for_voltage( unsigned int voltage) { int i; + int max_voltage = 0; + int clock = 0; for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) { - if (clock_table->SocVoltage[i] == voltage) + if (clock_table->SocVoltage[i] == voltage) { return clocks[i]; + } else if (clock_table->SocVoltage[i] >= max_voltage && + clock_table->SocVoltage[i] < voltage) { + max_voltage = clock_table->SocVoltage[i]; + clock = clocks[i]; + } } - ASSERT(0); - return 0; + ASSERT(clock); + return clock; } void dcn31_clk_mgr_helper_populate_bw_params( From f638d7505f99bca9436aac37b2a1ecb3f84803a5 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 22 Oct 2021 16:14:24 -0400 Subject: [PATCH 546/554] drm/amd/display: Fix deadlock when falling back to v2 from v3 [Why] A deadlock in the kernel occurs when we fallback from the V3 to V2 add_topology_to_display or remove_topology_to_display because they both try to acquire the dtm_mutex but recursive locking isn't supported on mutex_lock(). [How] Make the mutex_lock/unlock more fine grained and move them up such that they're only required for the psp invocation itself. Fixes: bf62221e9d0e ("drm/amd/display: Add DCN3.1 HDCP support") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index e9bd84ec027d..be61975f1470 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -105,6 +105,7 @@ static enum mod_hdcp_status remove_display_from_topology_v3( dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE; psp_dtm_invoke(psp, dtm_cmd->cmd_id); + mutex_unlock(&psp->dtm_context.mutex); if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { status = remove_display_from_topology_v2(hdcp, index); @@ -115,8 +116,6 @@ static enum mod_hdcp_status remove_display_from_topology_v3( HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index); } - mutex_unlock(&psp->dtm_context.mutex); - return status; } @@ -205,6 +204,7 @@ static enum mod_hdcp_status add_display_to_topology_v3( dtm_cmd->dtm_in_message.topology_update_v3.link_hdcp_cap = link->hdcp_supported_informational; psp_dtm_invoke(psp, dtm_cmd->cmd_id); + mutex_unlock(&psp->dtm_context.mutex); if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { status = add_display_to_topology_v2(hdcp, display); @@ -214,8 +214,6 @@ static enum mod_hdcp_status add_display_to_topology_v3( HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index); } - mutex_unlock(&psp->dtm_context.mutex); - return status; } From 094b21c1a3578234f06a28b80f4d2f6446b5f533 Mon Sep 17 00:00:00 2001 From: Jude Shih Date: Mon, 18 Oct 2021 12:04:23 +0800 Subject: [PATCH 547/554] drm/amd/display: Fix USB4 hot plug crash issue [Why] Notify data from outbox corrupt, the notify type should be 2 (HPD) instead of 0 (No data). We copied the address instead of the value. The memory might be freed in the end of outbox IRQ [How] We should allocate the memory of notify and copy the whole content from outbox to hpd handle function Fixes: 88f52b1fff891e ("drm/amd/display: Support for SET_CONFIG processing with DMUB") Signed-off-by: Jude Shih Reviewed-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 4b6c021c02f4..6f980938fae9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -730,6 +730,8 @@ static void dm_handle_hpd_work(struct work_struct *work) dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev, dmub_hpd_wrk->dmub_notify); } + + kfree(dmub_hpd_wrk->dmub_notify); kfree(dmub_hpd_wrk); } @@ -755,12 +757,6 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) if (dc_enable_dmub_notifications(adev->dm.dc) && irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) { - dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); - if (!dmub_hpd_wrk) { - DRM_ERROR("Failed to allocate dmub_hpd_wrk"); - return; - } - INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); do { dc_stat_get_dmub_notification(adev->dm.dc, ¬ify); @@ -769,7 +765,20 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) continue; } if (dm->dmub_thread_offload[notify.type] == true) { - dmub_hpd_wrk->dmub_notify = ¬ify; + dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); + if (!dmub_hpd_wrk) { + DRM_ERROR("Failed to allocate dmub_hpd_wrk"); + return; + } + dmub_hpd_wrk->dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_ATOMIC); + if (!dmub_hpd_wrk->dmub_notify) { + kfree(dmub_hpd_wrk); + DRM_ERROR("Failed to allocate dmub_hpd_wrk->dmub_notify"); + return; + } + INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); + if (dmub_hpd_wrk->dmub_notify) + memcpy(dmub_hpd_wrk->dmub_notify, ¬ify, sizeof(struct dmub_notification)); dmub_hpd_wrk->adev = adev; if (notify.type == DMUB_NOTIFICATION_HPD) { plink = adev->dm.dc->links[notify.link_index]; From 5b109397503acfaf6fac044cbde76937d20eb708 Mon Sep 17 00:00:00 2001 From: Jude Shih Date: Thu, 21 Oct 2021 22:00:13 +0800 Subject: [PATCH 548/554] drm/amd/display: Enable dpia in dmub only for DCN31 B0 [Why] DMUB binary is common for both A0 and B0. Hence, driver should notify FW about the support for DPIA in B0. [How] Added dpia_supported bit in dmub_fw_boot_options and will be set only for B0. Assign dpia_supported to true before dm_dmub_hw_init in B0 case. v2: fix build without CONFIG_DRM_AMD_DC_DCN (Alex) Signed-off-by: Jude Shih Reviewed-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 ++++++++++++++ drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 1 + drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 6f980938fae9..43e983e42c0f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1017,6 +1017,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) const unsigned char *fw_inst_const, *fw_bss_data; uint32_t i, fw_inst_const_size, fw_bss_data_size; bool has_hw_support; + struct dc *dc = adev->dm.dc; if (!dmub_srv) /* DMUB isn't supported on the ASIC. */ @@ -1103,6 +1104,19 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) for (i = 0; i < fb_info->num_fb; ++i) hw_params.fb[i] = &fb_info->fb[i]; + switch (adev->asic_type) { + case CHIP_YELLOW_CARP: + if (dc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_A0) { + hw_params.dpia_supported = true; +#if defined(CONFIG_DRM_AMD_DC_DCN) + hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; +#endif + } + break; + default: + break; + } + status = dmub_srv_hw_init(dmub_srv, &hw_params); if (status != DMUB_STATUS_OK) { DRM_ERROR("Error initializing DMUB HW: %d\n", status); diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 6c4f0ada163f..717c0e572d2f 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -238,6 +238,7 @@ struct dmub_srv_hw_params { bool load_inst_const; bool skip_panel_power_sequence; bool disable_z10; + bool dpia_supported; bool disable_dpia; }; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 5df990277dd4..10ebf20eaa41 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -338,6 +338,7 @@ void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu union dmub_fw_boot_options boot_options = {0}; boot_options.bits.z10_disable = params->disable_z10; + boot_options.bits.dpia_supported = params->dpia_supported; boot_options.bits.enable_dpia = params->disable_dpia ? 0 : 1; boot_options.bits.sel_mux_phy_c_d_phy_f_g = (dmub->asic == DMUB_ASIC_DCN31B) ? 1 : 0; From 72f4c9d57082cdd4054b599b3387220efd944095 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Oct 2021 15:06:34 -0400 Subject: [PATCH 549/554] drm/amdgpu/UAPI: rearrange header to better align related items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the RAS query parameters to align with the INFO query where they are used. No functional change. Reviewed-by: Christian König Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- include/uapi/drm/amdgpu_drm.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 0cbd1540aeac..26e45fc5eb1a 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -786,13 +786,6 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_VRAM_LOST_COUNTER 0x1F /* query ras mask of enabled features*/ #define AMDGPU_INFO_RAS_ENABLED_FEATURES 0x20 -/* query video encode/decode caps */ -#define AMDGPU_INFO_VIDEO_CAPS 0x21 - /* Subquery id: Decode */ - #define AMDGPU_INFO_VIDEO_CAPS_DECODE 0 - /* Subquery id: Encode */ - #define AMDGPU_INFO_VIDEO_CAPS_ENCODE 1 - /* RAS MASK: UMC (VRAM) */ #define AMDGPU_INFO_RAS_ENABLED_UMC (1 << 0) /* RAS MASK: SDMA */ @@ -821,6 +814,12 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_RAS_ENABLED_MP1 (1 << 12) /* RAS MASK: FUSE */ #define AMDGPU_INFO_RAS_ENABLED_FUSE (1 << 13) +/* query video encode/decode caps */ +#define AMDGPU_INFO_VIDEO_CAPS 0x21 + /* Subquery id: Decode */ + #define AMDGPU_INFO_VIDEO_CAPS_DECODE 0 + /* Subquery id: Encode */ + #define AMDGPU_INFO_VIDEO_CAPS_ENCODE 1 #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 #define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff From 074b2092d9f7cbfd686f0501563a310de5feae7f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Oct 2021 15:51:49 -0400 Subject: [PATCH 550/554] drm/amdgpu/discovery: add UVD/VCN IP instance info for soc15 parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add secondary instance version info for vega20, arcturure, and aldebaran. Acked-by: Christian König Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 208a784475bd..44b0821b6ca3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1018,6 +1018,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[SMUIO_HWIP][0] = IP_VERSION(11, 0, 2); adev->ip_versions[GC_HWIP][0] = IP_VERSION(9, 4, 0); adev->ip_versions[UVD_HWIP][0] = IP_VERSION(7, 2, 0); + adev->ip_versions[UVD_HWIP][1] = IP_VERSION(7, 2, 0); adev->ip_versions[VCE_HWIP][0] = IP_VERSION(4, 1, 0); adev->ip_versions[DCI_HWIP][0] = IP_VERSION(12, 1, 0); break; @@ -1039,6 +1040,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[SMUIO_HWIP][0] = IP_VERSION(11, 0, 3); adev->ip_versions[GC_HWIP][0] = IP_VERSION(9, 4, 1); adev->ip_versions[UVD_HWIP][0] = IP_VERSION(2, 5, 0); + adev->ip_versions[UVD_HWIP][1] = IP_VERSION(2, 5, 0); break; case CHIP_ALDEBARAN: aldebaran_reg_base_init(adev); @@ -1058,6 +1060,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[SMUIO_HWIP][0] = IP_VERSION(13, 0, 2); adev->ip_versions[GC_HWIP][0] = IP_VERSION(9, 4, 2); adev->ip_versions[UVD_HWIP][0] = IP_VERSION(2, 6, 0); + adev->ip_versions[UVD_HWIP][1] = IP_VERSION(2, 6, 0); adev->ip_versions[XGMI_HWIP][0] = IP_VERSION(6, 1, 0); break; default: From 58f8c7fa886115f4449539694a52f354b540fbbe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Oct 2021 16:21:52 -0400 Subject: [PATCH 551/554] drm/amdgpu/discovery: add SDMA IP instance info for soc15 parts Add secondary instance version info for soc15 parts. Reviewed-by: Luben Tuikov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 44b0821b6ca3..d7c8d9e3c203 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -931,6 +931,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 0, 0); adev->ip_versions[HDP_HWIP][0] = IP_VERSION(4, 0, 0); adev->ip_versions[SDMA0_HWIP][0] = IP_VERSION(4, 0, 0); + adev->ip_versions[SDMA1_HWIP][0] = IP_VERSION(4, 0, 0); adev->ip_versions[DF_HWIP][0] = IP_VERSION(2, 1, 0); adev->ip_versions[NBIO_HWIP][0] = IP_VERSION(6, 1, 0); adev->ip_versions[UMC_HWIP][0] = IP_VERSION(6, 0, 0); @@ -951,6 +952,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 0, 1); adev->ip_versions[HDP_HWIP][0] = IP_VERSION(4, 0, 1); adev->ip_versions[SDMA0_HWIP][0] = IP_VERSION(4, 0, 1); + adev->ip_versions[SDMA1_HWIP][0] = IP_VERSION(4, 0, 1); adev->ip_versions[DF_HWIP][0] = IP_VERSION(2, 5, 0); adev->ip_versions[NBIO_HWIP][0] = IP_VERSION(6, 2, 0); adev->ip_versions[UMC_HWIP][0] = IP_VERSION(6, 1, 0); @@ -1009,6 +1011,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 2, 0); adev->ip_versions[HDP_HWIP][0] = IP_VERSION(4, 2, 0); adev->ip_versions[SDMA0_HWIP][0] = IP_VERSION(4, 2, 0); + adev->ip_versions[SDMA1_HWIP][0] = IP_VERSION(4, 2, 0); adev->ip_versions[DF_HWIP][0] = IP_VERSION(3, 6, 0); adev->ip_versions[NBIO_HWIP][0] = IP_VERSION(7, 4, 0); adev->ip_versions[UMC_HWIP][0] = IP_VERSION(6, 1, 1); @@ -1031,6 +1034,13 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 2, 1); adev->ip_versions[HDP_HWIP][0] = IP_VERSION(4, 2, 1); adev->ip_versions[SDMA0_HWIP][0] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][0] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][1] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][2] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][3] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][4] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][5] = IP_VERSION(4, 2, 2); + adev->ip_versions[SDMA1_HWIP][6] = IP_VERSION(4, 2, 2); adev->ip_versions[DF_HWIP][0] = IP_VERSION(3, 6, 1); adev->ip_versions[NBIO_HWIP][0] = IP_VERSION(7, 4, 1); adev->ip_versions[UMC_HWIP][0] = IP_VERSION(6, 1, 2); @@ -1051,6 +1061,10 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 4, 0); adev->ip_versions[HDP_HWIP][0] = IP_VERSION(4, 4, 0); adev->ip_versions[SDMA0_HWIP][0] = IP_VERSION(4, 4, 0); + adev->ip_versions[SDMA0_HWIP][1] = IP_VERSION(4, 4, 0); + adev->ip_versions[SDMA0_HWIP][2] = IP_VERSION(4, 4, 0); + adev->ip_versions[SDMA0_HWIP][3] = IP_VERSION(4, 4, 0); + adev->ip_versions[SDMA0_HWIP][4] = IP_VERSION(4, 4, 0); adev->ip_versions[DF_HWIP][0] = IP_VERSION(3, 6, 2); adev->ip_versions[NBIO_HWIP][0] = IP_VERSION(7, 4, 4); adev->ip_versions[UMC_HWIP][0] = IP_VERSION(6, 7, 0); From 839e59a34394905fef73093e8605f50a9eb6d802 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 27 Oct 2021 16:27:30 +0200 Subject: [PATCH 552/554] drm/amdgpu: Fix even more out of bound writes from debugfs CVE-2021-42327 was fixed by: commit f23750b5b3d98653b31d4469592935ef6364ad67 Author: Thelford Williams Date: Wed Oct 13 16:04:13 2021 -0400 drm/amdgpu: fix out of bounds write but amdgpu_dm_debugfs.c contains more of the same issue so fix the remaining ones. v2: * Add missing fix in dp_max_bpc_write (Harry Wentland) Fixes: 918698d5c2b5 ("drm/amd/display: Return the number of bytes parsed than allocated") Signed-off-by: Patrik Jakobsson Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 1a68a674913c..3655663e079b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -491,7 +491,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -643,7 +643,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -918,7 +918,7 @@ static ssize_t dp_dsc_passthrough_set(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, ¶m, buf, max_param_num, ¶m_nums)) { @@ -1215,7 +1215,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1400,7 +1400,7 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1585,7 +1585,7 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1770,7 +1770,7 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1948,7 +1948,7 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -2386,7 +2386,7 @@ static ssize_t dp_max_bpc_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { From 139a33112f170e0a29748138fbdb849031527791 Mon Sep 17 00:00:00 2001 From: Meenakshikumar Somasundaram Date: Thu, 2 Sep 2021 14:09:30 -0400 Subject: [PATCH 553/554] drm/amd/display: MST support for DPIA [Why] - DPIA MST slot registers are not programmed during payload allocation and hence MST does not work with DPIA. - HPD RX interrupts are not handled for DPIA. [How] - Added inbox command to program the MST slots whenever payload allocation happens for DPIA links. - Added support for handling HPD RX interrupts Signed-off-by: Meenakshikumar Somasundaram Reviewed-by: Jun Lei Acked-by: Nicholas Kazlauskas Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 54 +++++++++++++++++++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 28 ++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 6 +++ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 23 ++++++++ 4 files changed, 111 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 9d33b00b7e27..12e5470fa567 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3750,6 +3750,60 @@ bool dc_process_dmub_set_config_async(struct dc *dc, return is_cmd_complete; } +/** + ***************************************************************************** + * Function: dc_process_dmub_set_mst_slots + * + * @brief + * Submits mst slot allocation command to dmub via inbox message + * + * @param + * [in] dc: dc structure + * [in] link_index: link index + * [in] mst_alloc_slots: mst slots to be allotted + * [out] mst_slots_in_use: mst slots in use returned in failure case + * + * @return + * DC_OK if successful, DC_ERROR if failure + ***************************************************************************** + */ +enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, + uint32_t link_index, + uint8_t mst_alloc_slots, + uint8_t *mst_slots_in_use) +{ + union dmub_rb_cmd cmd = {0}; + struct dc_dmub_srv *dmub_srv = dc->ctx->dmub_srv; + + /* prepare MST_ALLOC_SLOTS command */ + cmd.set_mst_alloc_slots.header.type = DMUB_CMD__DPIA; + cmd.set_mst_alloc_slots.header.sub_type = DMUB_CMD__DPIA_MST_ALLOC_SLOTS; + + cmd.set_mst_alloc_slots.mst_slots_control.instance = dc->links[link_index]->ddc_hw_inst; + cmd.set_mst_alloc_slots.mst_slots_control.mst_alloc_slots = mst_alloc_slots; + + if (!dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd)) + /* command is not processed by dmub */ + return DC_ERROR_UNEXPECTED; + + /* command processed by dmub, if ret_status is 1 */ + if (cmd.set_config_access.header.ret_status != 1) + /* command processing error */ + return DC_ERROR_UNEXPECTED; + + /* command processed and we have a status of 2, mst not enabled in dpia */ + if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 2) + return DC_FAIL_UNSUPPORTED_1; + + /* previously configured mst alloc and used slots did not match */ + if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 3) { + *mst_slots_in_use = cmd.set_mst_alloc_slots.mst_slots_control.mst_slots_in_use; + return DC_NOT_SUPPORTED; + } + + return DC_OK; +} + /** * dc_disable_accelerated_mode - disable accelerated mode * @dc: dc structure diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 27b9ff98a569..2796bdd17de1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3499,6 +3499,20 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) ASSERT(proposed_table.stream_count > 0); + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + static enum dc_status status; + uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF; + + for (i = 0; i < link->mst_stream_alloc_table.stream_count; i++) + mst_alloc_slots += link->mst_stream_alloc_table.stream_allocations[i].slot_count; + + status = dc_process_dmub_set_mst_slots(link->dc, link->link_index, + mst_alloc_slots, &prev_mst_slots_in_use); + ASSERT(status == DC_OK); + DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n", + status, mst_alloc_slots, prev_mst_slots_in_use); + } + /* program DP source TX for payload */ #if defined(CONFIG_DRM_AMD_DC_DCN) switch (dp_get_link_encoding_format(&link->cur_link_settings)) { @@ -3842,6 +3856,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) #endif } + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + enum dc_status status; + uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF; + + for (i = 0; i < link->mst_stream_alloc_table.stream_count; i++) + mst_alloc_slots += link->mst_stream_alloc_table.stream_allocations[i].slot_count; + + status = dc_process_dmub_set_mst_slots(link->dc, link->link_index, + mst_alloc_slots, &prev_mst_slots_in_use); + ASSERT(status != DC_NOT_SUPPORTED); + DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n", + status, mst_alloc_slots, prev_mst_slots_in_use); + } + #if defined(CONFIG_DRM_AMD_DC_DCN) switch (dp_get_link_encoding_format(&link->cur_link_settings)) { case DP_8b_10b_ENCODING: diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 33c4f74a0add..a5339796902a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1428,6 +1428,12 @@ bool dc_process_dmub_set_config_async(struct dc *dc, uint32_t link_index, struct set_config_cmd_payload *payload, struct dmub_notification *notify); + +enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, + uint32_t link_index, + uint8_t mst_alloc_slots, + uint8_t *mst_slots_in_use); + /******************************************************************************* * DSC Interfaces ******************************************************************************/ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 48982bc3e243..0293c58f0701 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -697,6 +697,7 @@ enum dmub_out_cmd_type { enum dmub_cmd_dpia_type { DMUB_CMD__DPIA_DIG1_DPIA_CONTROL = 0, DMUB_CMD__DPIA_SET_CONFIG_ACCESS = 1, + DMUB_CMD__DPIA_MST_ALLOC_SLOTS = 2, }; #pragma pack(push, 1) @@ -1071,6 +1072,24 @@ struct dmub_rb_cmd_set_config_access { struct dmub_cmd_set_config_control_data set_config_control; /* set config data */ }; +/** + * Data passed from driver to FW in a DMUB_CMD__DPIA_MST_ALLOC_SLOTS command. + */ +struct dmub_cmd_mst_alloc_slots_control_data { + uint8_t mst_alloc_slots; /* mst slots to be allotted */ + uint8_t instance; /* DPIA instance */ + uint8_t immed_status; /* Immediate status returned as there is no outbox msg posted */ + uint8_t mst_slots_in_use; /* returns slots in use for error cases */ +}; + +/** + * DMUB command structure for SET_ command. + */ +struct dmub_rb_cmd_set_mst_alloc_slots { + struct dmub_cmd_header header; /* header */ + struct dmub_cmd_mst_alloc_slots_control_data mst_slots_control; /* mst slots control */ +}; + /** * struct dmub_rb_cmd_dpphy_init - DPPHY init. */ @@ -2593,6 +2612,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__DPIA_SET_CONFIG_ACCESS command. */ struct dmub_rb_cmd_set_config_access set_config_access; + /** + * Definition of a DMUB_CMD__DPIA_MST_ALLOC_SLOTS command. + */ + struct dmub_rb_cmd_set_mst_alloc_slots set_mst_alloc_slots; /** * Definition of a DMUB_CMD__EDID_CEA command. */ From 403475be6d8b122c3e6b8a47e075926d7299e5ef Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 27 Oct 2021 13:26:19 -0400 Subject: [PATCH 554/554] drm/amdgpu/gmc6: fix DMA mask from 44 to 40 bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DMA mask on SI parts is 40 bits not 44. Copy paste typo. Fixes: 244511f386ccb9 ("drm/amdgpu: simplify and cleanup setting the dma mask") Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1762 Acked-by: Christian König Tested-by: Paul Menzel Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 0e81e03e9b49..0fe714f54cca 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -841,12 +841,12 @@ static int gmc_v6_0_sw_init(void *handle) adev->gmc.mc_mask = 0xffffffffffULL; - r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44)); + r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40)); if (r) { dev_warn(adev->dev, "No suitable DMA available.\n"); return r; } - adev->need_swiotlb = drm_need_swiotlb(44); + adev->need_swiotlb = drm_need_swiotlb(40); r = gmc_v6_0_init_microcode(adev); if (r) {