thunderbolt: Fixes for v6.9-rc5

This includes following USB4/Thunderbolt fixes for v6.9-rc5:
 
   - Avoid creating DisplayPort tunnels for the adapters on the same router
   - Correct wake configurations after device router unplug
   - Fix immediate wake when "wakeup_count" is used to enter system sleep.
 
 All these have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iQJUBAABCgA+FiEEVTdhRGBbNzLrSUBaAP2fSd+ZWKAFAmYcxVAgHG1pa2Eud2Vz
 dGVyYmVyZ0BsaW51eC5pbnRlbC5jb20ACgkQAP2fSd+ZWKB21w//bv0mVOJd06Pv
 /1yqZDT/5+0U2E4Rb3VAwinwKz/3RqtKQ9dC2iKI0P9oQ4s57LE3dIyrNiJhJ/Xz
 wixsLKqiqIcssOt9rd3WNLrfSjzLXmVucDiolVb8nvYleVvVQTp/uPz7tLrpUR+g
 xuCv6n63Cw33XxsCNJOEW+0iynkDsb2LA8lMbcGdJk96JVlmQPoIDsgbyZ5au/FA
 6qqxf08cYVkbrUs8/E/k5oDBRWZPr/Do05pSwO5LktF63JzjJ3vGJaGTOcojXC2a
 NGF0Z8PZvf0oDt2csgGnQNTN+I/yVXyaKcdh0rcaBBIOUBGluL4prnGlLcwGFmlH
 Hwv3IXFqLm7fk9Lvyt0QCV+RQ2mhA2DuSgXw09Z5yy3p/IvxcG6+Z4/2iov/lgZe
 4xn+kYT70BmJZP3JuatdbQeToejmpcm3qrGLLasqtFcq22bYTv3LmwyM6b2d4oqs
 pHRLkeGINlze/Fa8yjsfffMhO97kp0iAWzM7z7a29eZeu/JnYRLPhs27SQkgCOQI
 vuRCmn7KAmzHxtESByE8+rbrp7w1YcnEuCPSTEfrA0uy6+9gaPUeNFlow9W8iloo
 pzrIaPvLQKQ0O40BrKo5p3qbqA/Kg40QuDomLJbep49O/8CxNLzGtUWRfGmbi0iR
 QDxbHQmxN2vLlp1+rw6obklQ3Ws/0HU=
 =8qyc
 -----END PGP SIGNATURE-----

Merge tag 'thunderbolt-for-v6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-linus

Mika writes:

thunderbolt: Fixes for v6.9-rc5

This includes following USB4/Thunderbolt fixes for v6.9-rc5:

  - Avoid creating DisplayPort tunnels for the adapters on the same router
  - Correct wake configurations after device router unplug
  - Fix immediate wake when "wakeup_count" is used to enter system sleep.

All these have been in linux-next with no reported issues.

* tag 'thunderbolt-for-v6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Avoid notify PM core about runtime PM resume
  thunderbolt: Fix wake configurations after device unplug
  thunderbolt: Do not create DisplayPort tunnels on adapters of the same router
This commit is contained in:
Greg Kroah-Hartman 2024-04-15 09:23:29 +02:00
commit c281d18dda
4 changed files with 57 additions and 19 deletions

View file

@ -3180,22 +3180,29 @@ void tb_switch_unconfigure_link(struct tb_switch *sw)
{
struct tb_port *up, *down;
if (sw->is_unplugged)
return;
if (!tb_route(sw) || tb_switch_is_icm(sw))
return;
/*
* Unconfigure downstream port so that wake-on-connect can be
* configured after router unplug. No need to unconfigure upstream port
* since its router is unplugged.
*/
up = tb_upstream_port(sw);
down = up->remote;
if (tb_switch_is_usb4(down->sw))
usb4_port_unconfigure(down);
else
tb_lc_unconfigure_port(down);
if (sw->is_unplugged)
return;
up = tb_upstream_port(sw);
if (tb_switch_is_usb4(up->sw))
usb4_port_unconfigure(up);
else
tb_lc_unconfigure_port(up);
down = up->remote;
if (tb_switch_is_usb4(down->sw))
usb4_port_unconfigure(down);
else
tb_lc_unconfigure_port(down);
}
static void tb_switch_credits_init(struct tb_switch *sw)
@ -3441,7 +3448,26 @@ static int tb_switch_set_wake(struct tb_switch *sw, unsigned int flags)
return tb_lc_set_wake(sw, flags);
}
int tb_switch_resume(struct tb_switch *sw)
static void tb_switch_check_wakes(struct tb_switch *sw)
{
if (device_may_wakeup(&sw->dev)) {
if (tb_switch_is_usb4(sw))
usb4_switch_check_wakes(sw);
}
}
/**
* tb_switch_resume() - Resume a switch after sleep
* @sw: Switch to resume
* @runtime: Is this resume from runtime suspend or system sleep
*
* Resumes and re-enumerates router (and all its children), if still plugged
* after suspend. Don't enumerate device router whose UID was changed during
* suspend. If this is resume from system sleep, notifies PM core about the
* wakes occurred during suspend. Disables all wakes, except USB4 wake of
* upstream port for USB4 routers that shall be always enabled.
*/
int tb_switch_resume(struct tb_switch *sw, bool runtime)
{
struct tb_port *port;
int err;
@ -3490,6 +3516,9 @@ int tb_switch_resume(struct tb_switch *sw)
if (err)
return err;
if (!runtime)
tb_switch_check_wakes(sw);
/* Disable wakes */
tb_switch_set_wake(sw, 0);
@ -3519,7 +3548,8 @@ int tb_switch_resume(struct tb_switch *sw)
*/
if (tb_port_unlock(port))
tb_port_warn(port, "failed to unlock port\n");
if (port->remote && tb_switch_resume(port->remote->sw)) {
if (port->remote &&
tb_switch_resume(port->remote->sw, runtime)) {
tb_port_warn(port,
"lost during suspend, disconnecting\n");
tb_sw_set_unplugged(port->remote->sw);

View file

@ -1801,6 +1801,12 @@ static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
continue;
}
/* Needs to be on different routers */
if (in->sw == port->sw) {
tb_port_dbg(port, "skipping DP OUT on same router\n");
continue;
}
tb_port_dbg(port, "DP OUT available\n");
/*
@ -2936,7 +2942,7 @@ static int tb_resume_noirq(struct tb *tb)
if (!tb_switch_is_usb4(tb->root_switch))
tb_switch_reset(tb->root_switch);
tb_switch_resume(tb->root_switch);
tb_switch_resume(tb->root_switch, false);
tb_free_invalid_tunnels(tb);
tb_free_unplugged_children(tb->root_switch);
tb_restore_children(tb->root_switch);
@ -3062,7 +3068,7 @@ static int tb_runtime_resume(struct tb *tb)
struct tb_tunnel *tunnel, *n;
mutex_lock(&tb->lock);
tb_switch_resume(tb->root_switch);
tb_switch_resume(tb->root_switch, true);
tb_free_invalid_tunnels(tb);
tb_restore_children(tb->root_switch);
list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)

View file

@ -827,7 +827,7 @@ int tb_switch_configuration_valid(struct tb_switch *sw);
int tb_switch_add(struct tb_switch *sw);
void tb_switch_remove(struct tb_switch *sw);
void tb_switch_suspend(struct tb_switch *sw, bool runtime);
int tb_switch_resume(struct tb_switch *sw);
int tb_switch_resume(struct tb_switch *sw, bool runtime);
int tb_switch_reset(struct tb_switch *sw);
int tb_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit,
u32 value, int timeout_msec);
@ -1288,6 +1288,7 @@ static inline bool tb_switch_is_usb4(const struct tb_switch *sw)
return usb4_switch_version(sw) > 0;
}
void usb4_switch_check_wakes(struct tb_switch *sw);
int usb4_switch_setup(struct tb_switch *sw);
int usb4_switch_configuration_valid(struct tb_switch *sw);
int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid);

View file

@ -155,7 +155,13 @@ static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode,
tx_dwords, rx_data, rx_dwords);
}
static void usb4_switch_check_wakes(struct tb_switch *sw)
/**
* usb4_switch_check_wakes() - Check for wakes and notify PM core about them
* @sw: Router whose wakes to check
*
* Checks wakes occurred during suspend and notify the PM core about them.
*/
void usb4_switch_check_wakes(struct tb_switch *sw)
{
bool wakeup_usb4 = false;
struct usb4_port *usb4;
@ -163,9 +169,6 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
bool wakeup = false;
u32 val;
if (!device_may_wakeup(&sw->dev))
return;
if (tb_route(sw)) {
if (tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1))
return;
@ -244,8 +247,6 @@ int usb4_switch_setup(struct tb_switch *sw)
u32 val = 0;
int ret;
usb4_switch_check_wakes(sw);
if (!tb_route(sw))
return 0;