diff options
author | Andreas Noever <andreas.noever@gmail.com> | 2014-08-26 15:42:21 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-08-26 21:54:48 (GMT) |
commit | 72ad366f687d45f30a82d8b6e70ce757b21b5aab (patch) | |
tree | 76d191e82bc3cadf548bc9338214fd7274b95345 /drivers/thunderbolt/path.c | |
parent | 8e8248b1369c97c7bb6f8bcaee1f05deeabab8ef (diff) | |
download | linux-72ad366f687d45f30a82d8b6e70ce757b21b5aab.tar.xz |
thunderbolt: Clear hops before overwriting
Zero hops in tb_path_activate before writing a new path.
This fixes the following scenario:
- Boot with a coldplugged device
- Unplug device
- Plug device back in
- PCI hotplug fails
The hotplug operation fails because our new path matches the (now
defunct) path which was setup by the firmware for the coldplugged
device. By writing zeros before writing our path configuration we can
force thunderbolt to retrain the path.
Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/thunderbolt/path.c')
-rw-r--r-- | drivers/thunderbolt/path.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index 8fcf8a7..9562cd0 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -150,7 +150,26 @@ int tb_path_activate(struct tb_path *path) /* Activate hops. */ for (i = path->path_length - 1; i >= 0; i--) { - struct tb_regs_hop hop; + struct tb_regs_hop hop = { 0 }; + + /* + * We do (currently) not tear down paths setup by the firmeware. + * If a firmware device is unplugged and plugged in again then + * it can happen that we reuse some of the hops from the (now + * defunct) firmeware path. This causes the hotplug operation to + * fail (the pci device does not show up). Clearing the hop + * before overwriting it fixes the problem. + * + * Should be removed once we discover and tear down firmeware + * paths. + */ + res = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS, + 2 * path->hops[i].in_hop_index, 2); + if (res) { + __tb_path_deactivate_hops(path, i); + __tb_path_deallocate_nfc(path, 0); + goto err; + } /* dword 0 */ hop.next_hop = path->hops[i].next_hop_index; |