int tb_switch_add()

in switch.c [2759:2869]


int tb_switch_add(struct tb_switch *sw)
{
	int i, ret;

	/*
	 * Initialize DMA control port now before we read DROM. Recent
	 * host controllers have more complete DROM on NVM that includes
	 * vendor and model identification strings which we then expose
	 * to the userspace. NVM can be accessed through DMA
	 * configuration based mailbox.
	 */
	ret = tb_switch_add_dma_port(sw);
	if (ret) {
		dev_err(&sw->dev, "failed to add DMA port\n");
		return ret;
	}

	if (!sw->safe_mode) {
		tb_switch_credits_init(sw);

		/* read drom */
		ret = tb_drom_read(sw);
		if (ret) {
			dev_err(&sw->dev, "reading DROM failed\n");
			return ret;
		}
		tb_sw_dbg(sw, "uid: %#llx\n", sw->uid);

		tb_check_quirks(sw);

		ret = tb_switch_set_uuid(sw);
		if (ret) {
			dev_err(&sw->dev, "failed to set UUID\n");
			return ret;
		}

		for (i = 0; i <= sw->config.max_port_number; i++) {
			if (sw->ports[i].disabled) {
				tb_port_dbg(&sw->ports[i], "disabled by eeprom\n");
				continue;
			}
			ret = tb_init_port(&sw->ports[i]);
			if (ret) {
				dev_err(&sw->dev, "failed to initialize port %d\n", i);
				return ret;
			}
		}

		tb_switch_default_link_ports(sw);

		ret = tb_switch_update_link_attributes(sw);
		if (ret)
			return ret;

		ret = tb_switch_tmu_init(sw);
		if (ret)
			return ret;
	}

	ret = device_add(&sw->dev);
	if (ret) {
		dev_err(&sw->dev, "failed to add device: %d\n", ret);
		return ret;
	}

	if (tb_route(sw)) {
		dev_info(&sw->dev, "new device found, vendor=%#x device=%#x\n",
			 sw->vendor, sw->device);
		if (sw->vendor_name && sw->device_name)
			dev_info(&sw->dev, "%s %s\n", sw->vendor_name,
				 sw->device_name);
	}

	ret = usb4_switch_add_ports(sw);
	if (ret) {
		dev_err(&sw->dev, "failed to add USB4 ports\n");
		goto err_del;
	}

	ret = tb_switch_nvm_add(sw);
	if (ret) {
		dev_err(&sw->dev, "failed to add NVM devices\n");
		goto err_ports;
	}

	/*
	 * Thunderbolt routers do not generate wakeups themselves but
	 * they forward wakeups from tunneled protocols, so enable it
	 * here.
	 */
	device_init_wakeup(&sw->dev, true);

	pm_runtime_set_active(&sw->dev);
	if (sw->rpm) {
		pm_runtime_set_autosuspend_delay(&sw->dev, TB_AUTOSUSPEND_DELAY);
		pm_runtime_use_autosuspend(&sw->dev);
		pm_runtime_mark_last_busy(&sw->dev);
		pm_runtime_enable(&sw->dev);
		pm_request_autosuspend(&sw->dev);
	}

	tb_switch_debugfs_init(sw);
	return 0;

err_ports:
	usb4_switch_remove_ports(sw);
err_del:
	device_del(&sw->dev);

	return ret;
}