aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt
diff options
context:
space:
mode:
authorAndreas Noever <andreas.noever@gmail.com>2014-06-12 17:11:47 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-19 17:14:35 -0400
commit343fcb8c70d76967ba64493ca984e40baad9d0f6 (patch)
tree8e8b8731fe2094124f459ba33b66b703dcab2178 /drivers/thunderbolt
parentcd22e73bdf5eff7e68a0f8bdfbce123ad43651f6 (diff)
thunderbolt: Fix nontrivial endpoint devices.
Fix issues observed with the Startech docking station: Fix the type of the route parameter in tb_ctl_rx. It should be u64 and not u8 (which only worked for short routes). A thunderbolt cable contains two lanes. If both endpoints support it a connection will be established on both lanes. Previously we tried to scan below both "dual link ports". Use the information extracted from the drom to only scan behind ports with lane_nr == 0. Endpoints with more complex thunderbolt controllers have some of their ports disabled (for example the NHI port or one of the HDMI/DP ports). Accessing them results in an error so we now ignore ports which are marked as disabled in the drom. Signed-off-by: Andreas Noever <andreas.noever@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/thunderbolt')
-rw-r--r--drivers/thunderbolt/ctl.c2
-rw-r--r--drivers/thunderbolt/switch.c42
-rw-r--r--drivers/thunderbolt/tb.c5
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:
439 */ 439 */
440static struct tb_cfg_result tb_ctl_rx(struct tb_ctl *ctl, void *buffer, 440static struct tb_cfg_result tb_ctl_rx(struct tb_ctl *ctl, void *buffer,
441 size_t length, int timeout_msec, 441 size_t length, int timeout_msec,
442 u8 route, enum tb_cfg_pkg_type type) 442 u64 route, enum tb_cfg_pkg_type type)
443{ 443{
444 struct tb_cfg_result res; 444 struct tb_cfg_result res;
445 struct ctl_pkg *pkg; 445 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)
180 * 180 *
181 * Return: Returns 0 on success or an error code on failure. 181 * Return: Returns 0 on success or an error code on failure.
182 */ 182 */
183static int tb_init_port(struct tb_switch *sw, u8 port_nr) 183static int tb_init_port(struct tb_port *port)
184{ 184{
185 int res; 185 int res;
186 int cap; 186 int cap;
187 struct tb_port *port = &sw->ports[port_nr]; 187
188 port->sw = sw;
189 port->port = port_nr;
190 port->remote = NULL;
191 res = tb_port_read(port, &port->config, TB_CFG_PORT, 0, 8); 188 res = tb_port_read(port, &port->config, TB_CFG_PORT, 0, 8);
192 if (res) 189 if (res)
193 return res; 190 return res;
194 191
195 /* Port 0 is the switch itself and has no PHY. */ 192 /* Port 0 is the switch itself and has no PHY. */
196 if (port->config.type == TB_TYPE_PORT && port_nr != 0) { 193 if (port->config.type == TB_TYPE_PORT && port->port != 0) {
197 cap = tb_find_cap(port, TB_CFG_PORT, TB_CAP_PHY); 194 cap = tb_find_cap(port, TB_CFG_PORT, TB_CAP_PHY);
198 195
199 if (cap > 0) 196 if (cap > 0)
@@ -202,7 +199,7 @@ static int tb_init_port(struct tb_switch *sw, u8 port_nr)
202 tb_port_WARN(port, "non switch port without a PHY\n"); 199 tb_port_WARN(port, "non switch port without a PHY\n");
203 } 200 }
204 201
205 tb_dump_port(sw->tb, &port->config); 202 tb_dump_port(port->sw->tb, &port->config);
206 203
207 /* TODO: Read dual link port, DP port and more from EEPROM. */ 204 /* TODO: Read dual link port, DP port and more from EEPROM. */
208 return 0; 205 return 0;
@@ -329,6 +326,7 @@ void tb_switch_free(struct tb_switch *sw)
329 tb_plug_events_active(sw, false); 326 tb_plug_events_active(sw, false);
330 327
331 kfree(sw->ports); 328 kfree(sw->ports);
329 kfree(sw->drom);
332 kfree(sw); 330 kfree(sw);
333} 331}
334 332
@@ -381,18 +379,16 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
381 379
382 /* initialize ports */ 380 /* initialize ports */
383 sw->ports = kcalloc(sw->config.max_port_number + 1, sizeof(*sw->ports), 381 sw->ports = kcalloc(sw->config.max_port_number + 1, sizeof(*sw->ports),
384 GFP_KERNEL); 382 GFP_KERNEL);
385 if (!sw->ports) 383 if (!sw->ports)
386 goto err; 384 goto err;
387 385
388 for (i = 0; i <= sw->config.max_port_number; i++) { 386 for (i = 0; i <= sw->config.max_port_number; i++) {
389 if (tb_init_port(sw, i)) 387 /* minimum setup for tb_find_cap and tb_drom_read to work */
390 goto err; 388 sw->ports[i].sw = sw;
391 /* TODO: check if port is disabled (EEPROM) */ 389 sw->ports[i].port = i;
392 } 390 }
393 391
394 /* TODO: I2C, IECS, EEPROM, link controller */
395
396 cap = tb_find_cap(&sw->ports[0], TB_CFG_SWITCH, TB_CAP_PLUG_EVENTS); 392 cap = tb_find_cap(&sw->ports[0], TB_CFG_SWITCH, TB_CAP_PLUG_EVENTS);
397 if (cap < 0) { 393 if (cap < 0) {
398 tb_sw_warn(sw, "cannot find TB_CAP_PLUG_EVENTS aborting\n"); 394 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)
400 } 396 }
401 sw->cap_plug_events = cap; 397 sw->cap_plug_events = cap;
402 398
403 if (tb_drom_read_uid_only(sw, &sw->uid)) 399 /* read drom */
404 tb_sw_warn(sw, "could not read uid from eeprom\n"); 400 if (tb_drom_read(sw))
405 else 401 tb_sw_warn(sw, "tb_eeprom_read_rom failed, continuing\n");
406 tb_sw_info(sw, "uid: %#llx\n", sw->uid); 402 tb_sw_info(sw, "uid: %#llx\n", sw->uid);
403
404 for (i = 0; i <= sw->config.max_port_number; i++) {
405 if (sw->ports[i].disabled) {
406 tb_port_info(&sw->ports[i], "disabled by eeprom\n");
407 continue;
408 }
409 if (tb_init_port(&sw->ports[i]))
410 goto err;
411 }
412
413 /* TODO: I2C, IECS, link controller */
407 414
408 if (tb_plug_events_active(sw, true)) 415 if (tb_plug_events_active(sw, true))
409 goto err; 416 goto err;
@@ -411,6 +418,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
411 return sw; 418 return sw;
412err: 419err:
413 kfree(sw->ports); 420 kfree(sw->ports);
421 kfree(sw->drom);
414 kfree(sw); 422 kfree(sw);
415 return NULL; 423 return NULL;
416} 424}
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)
38 return; 38 return;
39 if (port->config.type != TB_TYPE_PORT) 39 if (port->config.type != TB_TYPE_PORT)
40 return; 40 return;
41 if (port->dual_link_port && port->link_nr)
42 return; /*
43 * Downstream switch is reachable through two ports.
44 * Only scan on the primary port (link_nr == 0).
45 */
41 if (tb_wait_for_port(port, false) <= 0) 46 if (tb_wait_for_port(port, false) <= 0)
42 return; 47 return;
43 if (port->remote) { 48 if (port->remote) {