summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
16b4b0f)
commit
23257cfc1cb7202fd0065e9f4a6a0aac1c04c4a9 upstream.
We cannot call PM runtime functions in tb_retimer_scan() because it will
also be called when retimers are scanned from userspace (happens when
there is no device connected on ChromeOS for instance) and at the same
USB4 port runtime resume hook. This leads to hang because neither can
proceed.
Fix this by runtime resuming USB4 ports in tb_scan_port() instead. This
makes sure the ports are runtime PM active when retimers are added under
it while avoiding the reported hang as well.
Reported-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
Fixes:
1e56c88adecc ("thunderbolt: Runtime resume USB4 port when retimers are scanned")
Cc: stable@vger.kernel.org
Acked-by: Yehezkel Bernat <YehezkelShB@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
{
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
int ret, i, last_idx = 0;
{
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
int ret, i, last_idx = 0;
- struct usb4_port *usb4;
-
- usb4 = port->usb4;
- if (!usb4)
- return 0;
-
- pm_runtime_get_sync(&usb4->dev);
/*
* Send broadcast RT to make sure retimer indices facing this
/*
* Send broadcast RT to make sure retimer indices facing this
*/
ret = usb4_port_enumerate_retimers(port);
if (ret)
*/
ret = usb4_port_enumerate_retimers(port);
if (ret)
/*
* Enable sideband channel for each retimer. We can do this
/*
* Enable sideband channel for each retimer. We can do this
/* Add on-board retimers if they do not exist already */
/* Add on-board retimers if they do not exist already */
for (i = 1; i <= last_idx; i++) {
struct tb_retimer *rt;
for (i = 1; i <= last_idx; i++) {
struct tb_retimer *rt;
-out:
- pm_runtime_mark_last_busy(&usb4->dev);
- pm_runtime_put_autosuspend(&usb4->dev);
-
* Downstream switch is reachable through two ports.
* Only scan on the primary port (link_nr == 0).
*/
* Downstream switch is reachable through two ports.
* Only scan on the primary port (link_nr == 0).
*/
+
+ if (port->usb4)
+ pm_runtime_get_sync(&port->usb4->dev);
+
if (tb_wait_for_port(port, false) <= 0)
if (tb_wait_for_port(port, false) <= 0)
if (port->remote) {
tb_port_dbg(port, "port already has a remote\n");
if (port->remote) {
tb_port_dbg(port, "port already has a remote\n");
}
tb_retimer_scan(port, true);
}
tb_retimer_scan(port, true);
*/
if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
tb_scan_xdomain(port);
*/
if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
tb_scan_xdomain(port);
}
if (tb_switch_configure(sw)) {
tb_switch_put(sw);
}
if (tb_switch_configure(sw)) {
tb_switch_put(sw);
if (tb_switch_add(sw)) {
tb_switch_put(sw);
if (tb_switch_add(sw)) {
tb_switch_put(sw);
}
/* Link the switches using both links if available */
}
/* Link the switches using both links if available */
tb_add_dp_resources(sw);
tb_scan_switch(sw);
tb_add_dp_resources(sw);
tb_scan_switch(sw);
+
+out_rpm_put:
+ if (port->usb4) {
+ pm_runtime_mark_last_busy(&port->usb4->dev);
+ pm_runtime_put_autosuspend(&port->usb4->dev);
+ }
}
static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
}
static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)