]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
usb: typec: thunderbolt: Set enter_vdo during initialization
authorAndrei Kuchynski <akuchynski@chromium.org>
Tue, 24 Mar 2026 10:30:12 +0000 (10:30 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2026 15:17:40 +0000 (17:17 +0200)
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 <stable@kernel.org>
Fixes: 100e25738659 ("usb: typec: Add driver for Thunderbolt 3 Alternate Mode")
Tested-by: Madhu M <madhu.m@intel.corp-partner.google.com>
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Benson Leung <bleung@chromium.org>
Link: https://patch.msgid.link/20260324103012.1417616-1-akuchynski@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/altmodes/thunderbolt.c

index c4c5da6154da95e9ee7b874a25aebead7b7c830a..32250b94262a90c8eda648500a2e7fe02c457f51 100644 (file)
@@ -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;
 }