[Intel-gfx] [PATCH] drm/i915: Fix TypeC mode initialization during system resume
Kahola, Mika
mika.kahola at intel.com
Mon Sep 26 07:49:19 UTC 2022
> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces at lists.freedesktop.org> On Behalf Of Imre
> Deak
> Sent: Thursday, September 22, 2022 8:22 PM
> To: intel-gfx at lists.freedesktop.org
> Subject: [Intel-gfx] [PATCH] drm/i915: Fix TypeC mode initialization during
> system resume
>
> During system resume DP MST requires AUX to be working already before the
> HW state readout of the given encoder. Since AUX requires the encoder/PHY
> TypeC mode to be initialized, which atm only happens during HW state readout,
> these AUX transfers can change the TypeC mode incorrectly (disconnecting the
> PHY for an enabled encoder) and trigger the state check WARNs in
> intel_tc_port_sanitize().
>
> Fix this by initializing the TypeC mode earlier both during driver loading and
> system resume and making sure that the mode can't change until the encoder's
> state is read out. While at it add the missing DocBook comments and rename
> intel_tc_port_sanitize()->intel_tc_port_sanitize_mode() for consistency.
>
> Signed-off-by: Imre Deak <imre.deak at intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_ddi.c | 8 ++-
> drivers/gpu/drm/i915/display/intel_tc.c | 68 ++++++++++++++++++------
> drivers/gpu/drm/i915/display/intel_tc.h | 3 +-
> 3 files changed, 61 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c
> b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 643832d55c282..5ce5e885694c8 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -3591,7 +3591,7 @@ static void intel_ddi_sync_state(struct intel_encoder
> *encoder,
> 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));
> + intel_tc_port_sanitize_mode(enc_to_dig_port(encoder));
>
> if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
> intel_dp_sync_state(encoder, crtc_state); @@ -3789,11
> +3789,17 @@ static void intel_ddi_encoder_destroy(struct drm_encoder
> *encoder)
>
> static void intel_ddi_encoder_reset(struct drm_encoder *encoder) {
> + struct drm_i915_private *i915 = to_i915(encoder->dev);
> struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder));
> + 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->reset_link_params = true;
>
> intel_pps_encoder_reset(intel_dp);
> +
> + if (intel_phy_is_tc(i915, phy))
> + intel_tc_port_init_mode(dig_port);
> }
>
> static const struct drm_encoder_funcs intel_ddi_funcs = { diff --git
> a/drivers/gpu/drm/i915/display/intel_tc.c
> b/drivers/gpu/drm/i915/display/intel_tc.c
> index e5af955b5600f..b0aa1edd83028 100644
> --- a/drivers/gpu/drm/i915/display/intel_tc.c
> +++ b/drivers/gpu/drm/i915/display/intel_tc.c
> @@ -687,18 +687,58 @@ static void
> intel_tc_port_link_init_refcount(struct intel_digital_port *dig_port,
> int refcount)
> {
> - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> - drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount);
I was thinking whether we should drop this function or not? This is now reduced as one liner.
Anyway, patch looks ok to me.
Reviewed-by: Mika Kahola <mika.kahola at intel.com>
> dig_port->tc_link_refcount = refcount; }
>
> -void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
> +/**
> + * intel_tc_port_init_mode: Read out HW state and init the given port's
> +TypeC mode
> + * @dig_port: digital port
> + *
> + * Read out the HW state and initialize the TypeC mode of @dig_port.
> +The mode
> + * will be locked until intel_tc_port_sanitize_mode() is called.
> + */
> +void intel_tc_port_init_mode(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;
> enum intel_display_power_domain domain;
> +
> + mutex_lock(&dig_port->tc_lock);
> +
> + drm_WARN_ON(&i915->drm, dig_port->tc_mode !=
> TC_PORT_DISCONNECTED);
> + drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
> + drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount);
> +
> + tc_cold_wref = tc_cold_block(dig_port, &domain);
> +
> + dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
> + /* Prevent changing dig_port->tc_mode until
> intel_tc_port_sanitize_mode() is called. */
> + intel_tc_port_link_init_refcount(dig_port, 1);
> + 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);
> +
> + drm_dbg_kms(&i915->drm, "Port %s: init mode (%s)\n",
> + dig_port->tc_port_name,
> + tc_port_mode_name(dig_port->tc_mode));
> +
> + mutex_unlock(&dig_port->tc_lock);
> +}
> +
> +/**
> + * intel_tc_port_sanitize_mode: Sanitize the given port's TypeC mode
> + * @dig_port: digital port
> + *
> + * Sanitize @dig_port's TypeC mode wrt. the encoder's state right after
> +driver
> + * loading and system resume:
> + * If the encoder is enabled keep the TypeC mode/PHY connected state
> +locked until
> + * the encoder is disabled.
> + * If the encoder is disabled make sure the PHY is disconnected.
> + */
> +void intel_tc_port_sanitize_mode(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;
> int active_links = 0;
>
> mutex_lock(&dig_port->tc_lock);
> @@ -708,21 +748,14 @@ void intel_tc_port_sanitize(struct intel_digital_port
> *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);
> - drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
> + drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount != 1);
> + intel_tc_port_link_init_refcount(dig_port, active_links);
>
> - tc_cold_wref = tc_cold_block(dig_port, &domain);
> -
> - dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
> if (active_links) {
> 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);
> -
> - dig_port->tc_lock_wakeref = tc_cold_block(dig_port,
> - &dig_port-
> >tc_lock_power_domain);
> } else {
> /*
> * TBT-alt is the default mode in any case the PHY ownership is
> not @@ -736,9 +769,10 @@ void intel_tc_port_sanitize(struct intel_digital_port
> *dig_port)
> dig_port->tc_port_name,
> tc_port_mode_name(dig_port->tc_mode));
> icl_tc_phy_disconnect(dig_port);
> - }
>
> - tc_cold_unblock(dig_port, domain, tc_cold_wref);
> + tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain,
> + fetch_and_zero(&dig_port->tc_lock_wakeref));
> + }
>
> drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n",
> dig_port->tc_port_name,
> @@ -923,4 +957,6 @@ void intel_tc_port_init(struct intel_digital_port
> *dig_port, bool is_legacy)
> dig_port->tc_mode = TC_PORT_DISCONNECTED;
> dig_port->tc_link_refcount = 0;
> tc_port_load_fia_params(i915, dig_port);
> +
> + intel_tc_port_init_mode(dig_port);
> }
> diff --git a/drivers/gpu/drm/i915/display/intel_tc.h
> b/drivers/gpu/drm/i915/display/intel_tc.h
> index 6b47b29f551c9..d54082e2d5e8d 100644
> --- a/drivers/gpu/drm/i915/display/intel_tc.h
> +++ b/drivers/gpu/drm/i915/display/intel_tc.h
> @@ -24,7 +24,8 @@ int intel_tc_port_fia_max_lane_count(struct
> intel_digital_port *dig_port); void intel_tc_port_set_fia_lane_count(struct
> intel_digital_port *dig_port,
> int required_lanes);
>
> -void intel_tc_port_sanitize(struct intel_digital_port *dig_port);
> +void intel_tc_port_init_mode(struct intel_digital_port *dig_port); void
> +intel_tc_port_sanitize_mode(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);
> --
> 2.37.1
More information about the Intel-gfx
mailing list