diff options
-rw-r--r-- | drivers/thunderbolt/ctl.c | 2 | ||||
-rw-r--r-- | drivers/thunderbolt/switch.c | 42 | ||||
-rw-r--r-- | drivers/thunderbolt/tb.c | 5 |
3 files changed, 31 insertions, 18 deletions
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 9b0120bede51..d04fee4acb2e 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -439,7 +439,7 @@ rx: */ static struct tb_cfg_result tb_ctl_rx(struct tb_ctl *ctl, void *buffer, size_t length, int timeout_msec, - u8 route, enum tb_cfg_pkg_type type) + u64 route, enum tb_cfg_pkg_type type) { struct tb_cfg_result res; struct ctl_pkg *pkg; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 9dfb8e18cdf7..0d50e7e7b29b 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -180,20 +180,17 @@ int tb_port_clear_counter(struct tb_port *port, int counter) * * Return: Returns 0 on success or an error code on failure. */ -static int tb_init_port(struct tb_switch *sw, u8 port_nr) +static int tb_init_port(struct tb_port *port) { int res; int cap; - struct tb_port *port = &sw->ports[port_nr]; - port->sw = sw; - port->port = port_nr; - port->remote = NULL; + res = tb_port_read(port, &port->config, TB_CFG_PORT, 0, 8); if (res) return res; /* Port 0 is the switch itself and has no PHY. */ - if (port->config.type == TB_TYPE_PORT && port_nr != 0) { + if (port->config.type == TB_TYPE_PORT && port->port != 0) { cap = tb_find_cap(port, TB_CFG_PORT, TB_CAP_PHY); if (cap > 0) @@ -202,7 +199,7 @@ static int tb_init_port(struct tb_switch *sw, u8 port_nr) tb_port_WARN(port, "non switch port without a PHY\n"); } - tb_dump_port(sw->tb, &port->config); + tb_dump_port(port->sw->tb, &port->config); /* TODO: Read dual link port, DP port and more from EEPROM. */ return 0; @@ -329,6 +326,7 @@ void tb_switch_free(struct tb_switch *sw) tb_plug_events_active(sw, false); kfree(sw->ports); + kfree(sw->drom); kfree(sw); } @@ -381,18 +379,16 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route) /* initialize ports */ sw->ports = kcalloc(sw->config.max_port_number + 1, sizeof(*sw->ports), - GFP_KERNEL); + GFP_KERNEL); if (!sw->ports) goto err; for (i = 0; i <= sw->config.max_port_number; i++) { - if (tb_init_port(sw, i)) - goto err; - /* TODO: check if port is disabled (EEPROM) */ + /* minimum setup for tb_find_cap and tb_drom_read to work */ + sw->ports[i].sw = sw; + sw->ports[i].port = i; } - /* TODO: I2C, IECS, EEPROM, link controller */ - cap = tb_find_cap(&sw->ports[0], TB_CFG_SWITCH, TB_CAP_PLUG_EVENTS); if (cap < 0) { tb_sw_warn(sw, "cannot find TB_CAP_PLUG_EVENTS aborting\n"); @@ -400,10 +396,21 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route) } sw->cap_plug_events = cap; - if (tb_drom_read_uid_only(sw, &sw->uid)) - tb_sw_warn(sw, "could not read uid from eeprom\n"); - else - tb_sw_info(sw, "uid: %#llx\n", sw->uid); + /* read drom */ + if (tb_drom_read(sw)) + tb_sw_warn(sw, "tb_eeprom_read_rom failed, continuing\n"); + tb_sw_info(sw, "uid: %#llx\n", sw->uid); + + for (i = 0; i <= sw->config.max_port_number; i++) { + if (sw->ports[i].disabled) { + tb_port_info(&sw->ports[i], "disabled by eeprom\n"); + continue; + } + if (tb_init_port(&sw->ports[i])) + goto err; + } + + /* TODO: I2C, IECS, link controller */ if (tb_plug_events_active(sw, true)) goto err; @@ -411,6 +418,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route) return sw; err: kfree(sw->ports); + kfree(sw->drom); kfree(sw); return NULL; } diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 1aa6dd7dc68b..d2c3fe346e91 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -38,6 +38,11 @@ static void tb_scan_port(struct tb_port *port) return; if (port->config.type != TB_TYPE_PORT) return; + if (port->dual_link_port && port->link_nr) + return; /* + * Downstream switch is reachable through two ports. + * Only scan on the primary port (link_nr == 0). + */ if (tb_wait_for_port(port, false) <= 0) return; if (port->remote) { |