static int tb_tunnel_usb3()

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;
}