On Tue, Mar 24, 2026 at 10:30:12AM +0000, Andrei Kuchynski wrote: > In the current implementation, if a cable's alternate mode enter operation > is not supported, the tbt->plug[TYPEC_PLUG_SOP_P] pointer is cleared by the > time tbt_enter_mode() is called. This prevents the driver from identifying > the cable's VDO. > > As a result, the Thunderbolt connection falls back to the default > TBT_CABLE_USB3_PASSIVE speed, even if the cable supports higher speeds. > To ensure the correct VDO value is used during mode entry, calculate and > store the enter_vdo earlier during the initialization phase in tbt_ready(). > > Cc: stable@vger.kernel.org > Fixes: 100e25738659 ("usb: typec: Add driver for Thunderbolt 3 Alternate Mode") > Tested-by: Madhu M > Signed-off-by: Andrei Kuchynski > Reviewed-by: Heikki Krogerus Reviewed-by: Benson Leung > --- > Changes in V2: > - Marked as a Fix > > drivers/usb/typec/altmodes/thunderbolt.c | 44 ++++++++++++------------ > 1 file changed, 22 insertions(+), 22 deletions(-) > > diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/altmodes/thunderbolt.c > index c4c5da6154da9..32250b94262a9 100644 > --- a/drivers/usb/typec/altmodes/thunderbolt.c > +++ b/drivers/usb/typec/altmodes/thunderbolt.c > @@ -39,28 +39,7 @@ static bool tbt_ready(struct typec_altmode *alt); > > static int tbt_enter_mode(struct tbt_altmode *tbt) > { > - struct typec_altmode *plug = tbt->plug[TYPEC_PLUG_SOP_P]; > - u32 vdo; > - > - vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1); > - vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0; > - vdo |= TBT_MODE; > - > - if (plug) { > - if (typec_cable_is_active(tbt->cable)) > - vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; > - > - vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo)); > - vdo |= plug->vdo & TBT_CABLE_ROUNDED; > - vdo |= plug->vdo & TBT_CABLE_OPTICAL; > - vdo |= plug->vdo & TBT_CABLE_RETIMER; > - vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING; > - } else { > - vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE); > - } > - > - tbt->enter_vdo = vdo; > - return typec_altmode_enter(tbt->alt, &vdo); > + return typec_altmode_enter(tbt->alt, &tbt->enter_vdo); > } > > static void tbt_altmode_work(struct work_struct *work) > @@ -337,6 +316,7 @@ static bool tbt_ready(struct typec_altmode *alt) > { > struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt); > struct typec_altmode *plug; > + u32 vdo; > > if (tbt->cable) > return true; > @@ -364,6 +344,26 @@ static bool tbt_ready(struct typec_altmode *alt) > tbt->plug[i] = plug; > } > > + vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1); > + vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0; > + vdo |= TBT_MODE; > + plug = tbt->plug[TYPEC_PLUG_SOP_P]; > + > + if (plug) { > + if (typec_cable_is_active(tbt->cable)) > + vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; > + > + vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo)); > + vdo |= plug->vdo & TBT_CABLE_ROUNDED; > + vdo |= plug->vdo & TBT_CABLE_OPTICAL; > + vdo |= plug->vdo & TBT_CABLE_RETIMER; > + vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING; > + } else { > + vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE); > + } > + > + tbt->enter_vdo = vdo; > + > return true; > } > > -- > 2.53.0.983.g0bb29b3bc5-goog > >