Example #1
0
int tb_switch_resume(struct tb_switch *sw)
{
	int i, err;
	u64 uid;
	tb_sw_info(sw, "resuming switch\n");

	err = tb_drom_read_uid_only(sw, &uid);
	if (err) {
		tb_sw_warn(sw, "uid read failed\n");
		return err;
	}
	if (sw != sw->tb->root_switch && sw->uid != uid) {
		tb_sw_info(sw,
			"changed while suspended (uid %#llx -> %#llx)\n",
			sw->uid, uid);
		return -ENODEV;
	}

	/* upload configuration */
	err = tb_sw_write(sw, 1 + (u32 *) &sw->config, TB_CFG_SWITCH, 1, 3);
	if (err)
		return err;

	err = tb_plug_events_active(sw, true);
	if (err)
		return err;

	/* check for surviving downstream switches */
	for (i = 1; i <= sw->config.max_port_number; i++) {
		struct tb_port *port = &sw->ports[i];
		if (tb_is_upstream_port(port))
			continue;
		if (!port->remote)
			continue;
		if (tb_wait_for_port(port, true) <= 0
			|| tb_switch_resume(port->remote->sw)) {
			tb_port_warn(port,
				     "lost during suspend, disconnecting\n");
			tb_sw_set_unplugged(port->remote->sw);
		}
	}
	return 0;
}
Example #2
0
/**
 * tb_drom_read - copy drom to sw->drom and parse it
 */
int tb_drom_read(struct tb_switch *sw)
{
	u16 drom_offset;
	u16 size;
	u32 crc;
	struct tb_drom_header *header;
	int res;
	if (sw->drom)
		return 0;

	if (tb_route(sw) == 0) {
		/*
		 * The root switch contains only a dummy drom (header only,
		 * no entries). Hardcode the configuration here.
		 */
		tb_drom_read_uid_only(sw, &sw->uid);

		sw->ports[1].link_nr = 0;
		sw->ports[2].link_nr = 1;
		sw->ports[1].dual_link_port = &sw->ports[2];
		sw->ports[2].dual_link_port = &sw->ports[1];

		sw->ports[3].link_nr = 0;
		sw->ports[4].link_nr = 1;
		sw->ports[3].dual_link_port = &sw->ports[4];
		sw->ports[4].dual_link_port = &sw->ports[3];
		return 0;
	}

	res = tb_eeprom_get_drom_offset(sw, &drom_offset);
	if (res)
		return res;

	res = tb_eeprom_read_n(sw, drom_offset + 14, (u8 *) &size, 2);
	if (res)
		return res;
	size &= 0x3ff;
	size += TB_DROM_DATA_START;
	tb_sw_info(sw, "reading drom (length: %#x)\n", size);
	if (size < sizeof(*header)) {
		tb_sw_warn(sw, "drom too small, aborting\n");
		return -EIO;
	}

	sw->drom = kzalloc(size, GFP_KERNEL);
	if (!sw->drom)
		return -ENOMEM;
	res = tb_eeprom_read_n(sw, drom_offset, sw->drom, size);
	if (res)
		goto err;

	header = (void *) sw->drom;

	if (header->data_len + TB_DROM_DATA_START != size) {
		tb_sw_warn(sw, "drom size mismatch, aborting\n");
		goto err;
	}

	crc = tb_crc8((u8 *) &header->uid, 8);
	if (crc != header->uid_crc8) {
		tb_sw_warn(sw,
			"drom uid crc8 mismatch (expected: %#x, got: %#x), aborting\n",
			header->uid_crc8, crc);
		goto err;
	}
	sw->uid = header->uid;

	crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len);
	if (crc != header->data_crc32) {
		tb_sw_warn(sw,
			"drom data crc32 mismatch (expected: %#x, got: %#x), aborting\n",
			header->data_crc32, crc);
		goto err;
	}

	if (header->device_rom_revision > 1)
		tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n",
			header->device_rom_revision);

	return tb_drom_parse_entries(sw);
err:
	kfree(sw->drom);
	return -EIO;

}