Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thunderbolt: Fix wake on connect at runtime

commit 1a760d10ded37 ("thunderbolt: Fix a logic error in wake on connect")
fixated on the USB4 port sysfs wakeup file not working properly to control
policy, but it had an unintended side effect that the sysfs file controls
policy both at runtime and at suspend time. The sysfs file is supposed to
only control behavior while system is suspended.

Pass whether programming a port for runtime into usb4_switch_set_wake()
and if runtime then ignore the value in the sysfs file.

Cc: stable@vger.kernel.org
Reported-by: Alexander Kovacs <Alexander.Kovacs@amd.com>
Tested-by: Alexander Kovacs <Alexander.Kovacs@amd.com>
Fixes: 1a760d10ded37 ("thunderbolt: Fix a logic error in wake on connect")
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

authored by

Mario Limonciello and committed by
Mika Westerberg
58d71d42 86731a2a

+10 -12
+4 -4
drivers/thunderbolt/switch.c
··· 3437 3437 } 3438 3438 } 3439 3439 3440 - static int tb_switch_set_wake(struct tb_switch *sw, unsigned int flags) 3440 + static int tb_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime) 3441 3441 { 3442 3442 if (flags) 3443 3443 tb_sw_dbg(sw, "enabling wakeup: %#x\n", flags); ··· 3445 3445 tb_sw_dbg(sw, "disabling wakeup\n"); 3446 3446 3447 3447 if (tb_switch_is_usb4(sw)) 3448 - return usb4_switch_set_wake(sw, flags); 3448 + return usb4_switch_set_wake(sw, flags, runtime); 3449 3449 return tb_lc_set_wake(sw, flags); 3450 3450 } 3451 3451 ··· 3521 3521 tb_switch_check_wakes(sw); 3522 3522 3523 3523 /* Disable wakes */ 3524 - tb_switch_set_wake(sw, 0); 3524 + tb_switch_set_wake(sw, 0, true); 3525 3525 3526 3526 err = tb_switch_tmu_init(sw); 3527 3527 if (err) ··· 3603 3603 flags |= TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE; 3604 3604 } 3605 3605 3606 - tb_switch_set_wake(sw, flags); 3606 + tb_switch_set_wake(sw, flags, runtime); 3607 3607 3608 3608 if (tb_switch_is_usb4(sw)) 3609 3609 usb4_switch_set_sleep(sw);
+1 -1
drivers/thunderbolt/tb.h
··· 1317 1317 int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, 1318 1318 size_t size); 1319 1319 bool usb4_switch_lane_bonding_possible(struct tb_switch *sw); 1320 - int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags); 1320 + int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime); 1321 1321 int usb4_switch_set_sleep(struct tb_switch *sw); 1322 1322 int usb4_switch_nvm_sector_size(struct tb_switch *sw); 1323 1323 int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
+5 -7
drivers/thunderbolt/usb4.c
··· 403 403 * usb4_switch_set_wake() - Enabled/disable wake 404 404 * @sw: USB4 router 405 405 * @flags: Wakeup flags (%0 to disable) 406 + * @runtime: Wake is being programmed during system runtime 406 407 * 407 408 * Enables/disables router to wake up from sleep. 408 409 */ 409 - int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags) 410 + int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime) 410 411 { 411 - struct usb4_port *usb4; 412 412 struct tb_port *port; 413 413 u64 route = tb_route(sw); 414 414 u32 val; ··· 438 438 val |= PORT_CS_19_WOU4; 439 439 } else { 440 440 bool configured = val & PORT_CS_19_PC; 441 - usb4 = port->usb4; 441 + bool wakeup = runtime || device_may_wakeup(&port->usb4->dev); 442 442 443 - if (((flags & TB_WAKE_ON_CONNECT) && 444 - device_may_wakeup(&usb4->dev)) && !configured) 443 + if ((flags & TB_WAKE_ON_CONNECT) && wakeup && !configured) 445 444 val |= PORT_CS_19_WOC; 446 - if (((flags & TB_WAKE_ON_DISCONNECT) && 447 - device_may_wakeup(&usb4->dev)) && configured) 445 + if ((flags & TB_WAKE_ON_DISCONNECT) && wakeup && configured) 448 446 val |= PORT_CS_19_WOD; 449 447 if ((flags & TB_WAKE_ON_USB4) && configured) 450 448 val |= PORT_CS_19_WOU4;