Re: [Intel-gfx] [PATCH v2 12/12] drm/i915/tc: Reset TypeC PHYs left enabled in DP-alt mode after the sink disconnects

2023-05-04 Thread Imre Deak
On Thu, May 04, 2023 at 08:41:49PM +0300, Ville Syrjälä wrote:
> On Thu, May 04, 2023 at 02:10:48AM +0300, Imre Deak wrote:
> > If the output on a DP-alt link with its sink disconnected is kept
> > enabled for too long (about 20 sec), then some IOM/TCSS firmware timeout
> > will cause havoc on the PCI bus, at least for other GFX devices on it
> > which will stop powering up. Since user space is not guaranteed to do a
> > disabling modeset in time, switch such disconnected but active links to
> > TBT mode - which is without such shortcomings - with a 2 second delay.
> > 
> > If the above condition is detected already during the driver load/system
> > resume sanitization step disable the output instead, as at that point no
> > user space or kernel client depends on a consistent output state yet and
> > because subsequent atomic modeset on such connectors - without the
> > actual sink capabilities available - can fail.
> > 
> > An active/disconnected port as above will also block the HPD status of
> > other active/disconnected ports to get updated (stuck in the connected
> > state), until the former port is disabled, its PHY is disconnected and
> > a ~10 ms delay has elapsed. This means the link state for all TypeC
> > ports/CRTCs must be rechecked after a CRTC is disabled due to the above
> > reason. For this disconnect the PHY synchronously after the CRTC/port is
> > disabled and recheck all CRTCs for the above condition whenever such a
> > port is disabled.
> > 
> > To account for a race condition during driver loading where the sink is
> > disconnected after the above sanitization step and before the HPD
> > interrupts get enabled, do an explicit check/link reset if needed from
> > the encoder's late_register hook, which is called after the HPD
> > interrupts are enabled already.
> > 
> > v2:
> > - Handle an active/disconnected port blocking the HPD state update of
> >   another active/disconnected port.
> > - Cancel the delayed work resetting the link also from the encoder
> >   enable/suspend/shutdown hooks.
> > - Rebase on the earlier intel_modeset_lock_ctx_retry() addition,
> >   fixing here the missed atomic state reset in case of a retry.
> > - Fix handling of an error return from intel_atomic_get_crtc_state().
> > - Recheck if the port needs to be reset after all the atomic state
> >   is locked and async commits are waited on.
> > 
> > Cc: Kai-Heng Feng 
> > Tested-by: Kai-Heng Feng 
> > Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5860
> > Signed-off-by: Imre Deak 
> > ---
> >  drivers/gpu/drm/i915/display/intel_ddi.c  | 68 +--
> >  .../drm/i915/display/intel_display_types.h|  2 +
> >  drivers/gpu/drm/i915/display/intel_dp.c   | 59 +
> >  drivers/gpu/drm/i915/display/intel_dp.h   |  1 +
> >  .../drm/i915/display/intel_modeset_setup.c| 83 ++-
> >  drivers/gpu/drm/i915/display/intel_tc.c   | 29 +++
> >  drivers/gpu/drm/i915/display/intel_tc.h   |  1 +
> >  7 files changed, 215 insertions(+), 28 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c 
> > b/drivers/gpu/drm/i915/display/intel_ddi.c
> > index eb391fff0f1be..db390b9c824ec 100644
> > --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> > @@ -3313,6 +3313,8 @@ static void intel_disable_ddi(struct 
> > intel_atomic_state *state,
> >   const struct intel_crtc_state *old_crtc_state,
> >   const struct drm_connector_state *old_conn_state)
> >  {
> > +   cancel_delayed_work(_to_dig_port(encoder)->reset_link_work);
> > +
> > intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
> >  
> > if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
> > @@ -3381,6 +3383,8 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state 
> > *state,
> > enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
> > bool is_tc_port = intel_phy_is_tc(dev_priv, phy);
> >  
> > +   cancel_delayed_work(_port->reset_link_work);
> > +
> > if (is_tc_port) {
> > struct intel_crtc *master_crtc =
> > to_intel_crtc(crtc_state->uapi.crtc);
> > @@ -4229,9 +4233,53 @@ static void intel_ddi_encoder_reset(struct 
> > drm_encoder *encoder)
> > intel_tc_port_init_mode(dig_port);
> >  }
> >  
> > +static void intel_ddi_tc_port_reset_link_work(struct work_struct *work)
> > +{
> > +   struct intel_digital_port *dig_port =
> > +   container_of(work, struct intel_digital_port, 
> > reset_link_work.work);
> > +   struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > +   struct intel_encoder *encoder = _port->base;
> > +
> > +   mutex_lock(>drm.mode_config.mutex);
> > +
> > +   if (intel_tc_port_link_needs_reset(dig_port)) {
> > +   int ret;
> > +
> > +   drm_dbg_kms(>drm,
> > +   "[ENCODER:%d:%s] TypeC DP-alt sink disconnected, 
> > resetting link\n",

Re: [Intel-gfx] [PATCH v2 12/12] drm/i915/tc: Reset TypeC PHYs left enabled in DP-alt mode after the sink disconnects

2023-05-04 Thread Ville Syrjälä
On Thu, May 04, 2023 at 02:10:48AM +0300, Imre Deak wrote:
> If the output on a DP-alt link with its sink disconnected is kept
> enabled for too long (about 20 sec), then some IOM/TCSS firmware timeout
> will cause havoc on the PCI bus, at least for other GFX devices on it
> which will stop powering up. Since user space is not guaranteed to do a
> disabling modeset in time, switch such disconnected but active links to
> TBT mode - which is without such shortcomings - with a 2 second delay.
> 
> If the above condition is detected already during the driver load/system
> resume sanitization step disable the output instead, as at that point no
> user space or kernel client depends on a consistent output state yet and
> because subsequent atomic modeset on such connectors - without the
> actual sink capabilities available - can fail.
> 
> An active/disconnected port as above will also block the HPD status of
> other active/disconnected ports to get updated (stuck in the connected
> state), until the former port is disabled, its PHY is disconnected and
> a ~10 ms delay has elapsed. This means the link state for all TypeC
> ports/CRTCs must be rechecked after a CRTC is disabled due to the above
> reason. For this disconnect the PHY synchronously after the CRTC/port is
> disabled and recheck all CRTCs for the above condition whenever such a
> port is disabled.
> 
> To account for a race condition during driver loading where the sink is
> disconnected after the above sanitization step and before the HPD
> interrupts get enabled, do an explicit check/link reset if needed from
> the encoder's late_register hook, which is called after the HPD
> interrupts are enabled already.
> 
> v2:
> - Handle an active/disconnected port blocking the HPD state update of
>   another active/disconnected port.
> - Cancel the delayed work resetting the link also from the encoder
>   enable/suspend/shutdown hooks.
> - Rebase on the earlier intel_modeset_lock_ctx_retry() addition,
>   fixing here the missed atomic state reset in case of a retry.
> - Fix handling of an error return from intel_atomic_get_crtc_state().
> - Recheck if the port needs to be reset after all the atomic state
>   is locked and async commits are waited on.
> 
> Cc: Kai-Heng Feng 
> Tested-by: Kai-Heng Feng 
> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5860
> Signed-off-by: Imre Deak 
> ---
>  drivers/gpu/drm/i915/display/intel_ddi.c  | 68 +--
>  .../drm/i915/display/intel_display_types.h|  2 +
>  drivers/gpu/drm/i915/display/intel_dp.c   | 59 +
>  drivers/gpu/drm/i915/display/intel_dp.h   |  1 +
>  .../drm/i915/display/intel_modeset_setup.c| 83 ++-
>  drivers/gpu/drm/i915/display/intel_tc.c   | 29 +++
>  drivers/gpu/drm/i915/display/intel_tc.h   |  1 +
>  7 files changed, 215 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c 
> b/drivers/gpu/drm/i915/display/intel_ddi.c
> index eb391fff0f1be..db390b9c824ec 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -3313,6 +3313,8 @@ static void intel_disable_ddi(struct intel_atomic_state 
> *state,
> const struct intel_crtc_state *old_crtc_state,
> const struct drm_connector_state *old_conn_state)
>  {
> + cancel_delayed_work(_to_dig_port(encoder)->reset_link_work);
> +
>   intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
>  
>   if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
> @@ -3381,6 +3383,8 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state 
> *state,
>   enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
>   bool is_tc_port = intel_phy_is_tc(dev_priv, phy);
>  
> + cancel_delayed_work(_port->reset_link_work);
> +
>   if (is_tc_port) {
>   struct intel_crtc *master_crtc =
>   to_intel_crtc(crtc_state->uapi.crtc);
> @@ -4229,9 +4233,53 @@ static void intel_ddi_encoder_reset(struct drm_encoder 
> *encoder)
>   intel_tc_port_init_mode(dig_port);
>  }
>  
> +static void intel_ddi_tc_port_reset_link_work(struct work_struct *work)
> +{
> + struct intel_digital_port *dig_port =
> + container_of(work, struct intel_digital_port, 
> reset_link_work.work);
> + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> + struct intel_encoder *encoder = _port->base;
> +
> + mutex_lock(>drm.mode_config.mutex);
> +
> + if (intel_tc_port_link_needs_reset(dig_port)) {
> + int ret;
> +
> + drm_dbg_kms(>drm,
> + "[ENCODER:%d:%s] TypeC DP-alt sink disconnected, 
> resetting link\n",
> + encoder->base.base.id, encoder->base.name);
> + ret = intel_dp_reset_link(encoder);
> + drm_WARN_ON(>drm, ret);
> + }
> +
> +