in tb.c [450:531]
static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw)
{
struct tb_switch *parent = tb_switch_parent(sw);
int ret, available_up, available_down;
struct tb_port *up, *down, *port;
struct tb_cm *tcm = tb_priv(tb);
struct tb_tunnel *tunnel;
if (!tb_acpi_may_tunnel_usb3()) {
tb_dbg(tb, "USB3 tunneling disabled, not creating tunnel\n");
return 0;
}
up = tb_switch_find_port(sw, TB_TYPE_USB3_UP);
if (!up)
return 0;
if (!sw->link_usb4)
return 0;
/*
* Look up available down port. Since we are chaining it should
* be found right above this switch.
*/
port = tb_port_at(tb_route(sw), parent);
down = tb_find_usb3_down(parent, port);
if (!down)
return 0;
if (tb_route(parent)) {
struct tb_port *parent_up;
/*
* Check first that the parent switch has its upstream USB3
* port enabled. Otherwise the chain is not complete and
* there is no point setting up a new tunnel.
*/
parent_up = tb_switch_find_port(parent, TB_TYPE_USB3_UP);
if (!parent_up || !tb_port_is_enabled(parent_up))
return 0;
/* Make all unused bandwidth available for the new tunnel */
ret = tb_release_unused_usb3_bandwidth(tb, down, up);
if (ret)
return ret;
}
ret = tb_available_bandwidth(tb, down, up, &available_up,
&available_down);
if (ret)
goto err_reclaim;
tb_port_dbg(up, "available bandwidth for new USB3 tunnel %d/%d Mb/s\n",
available_up, available_down);
tunnel = tb_tunnel_alloc_usb3(tb, up, down, available_up,
available_down);
if (!tunnel) {
ret = -ENOMEM;
goto err_reclaim;
}
if (tb_tunnel_activate(tunnel)) {
tb_port_info(up,
"USB3 tunnel activation failed, aborting\n");
ret = -EIO;
goto err_free;
}
list_add_tail(&tunnel->list, &tcm->tunnel_list);
if (tb_route(parent))
tb_reclaim_usb3_bandwidth(tb, down, up);
return 0;
err_free:
tb_tunnel_free(tunnel);
err_reclaim:
if (tb_route(parent))
tb_reclaim_usb3_bandwidth(tb, down, up);
return ret;
}