Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andreas Noever and committed by
Greg Kroah-Hartman
72ad366f 8e8248b1

+20 -1
+20 -1
drivers/thunderbolt/path.c
··· 150 150 151 151 /* Activate hops. */ 152 152 for (i = path->path_length - 1; i >= 0; i--) { 153 - struct tb_regs_hop hop; 153 + struct tb_regs_hop hop = { 0 }; 154 + 155 + /* 156 + * We do (currently) not tear down paths setup by the firmeware. 157 + * If a firmware device is unplugged and plugged in again then 158 + * it can happen that we reuse some of the hops from the (now 159 + * defunct) firmeware path. This causes the hotplug operation to 160 + * fail (the pci device does not show up). Clearing the hop 161 + * before overwriting it fixes the problem. 162 + * 163 + * Should be removed once we discover and tear down firmeware 164 + * paths. 165 + */ 166 + res = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS, 167 + 2 * path->hops[i].in_hop_index, 2); 168 + if (res) { 169 + __tb_path_deactivate_hops(path, i); 170 + __tb_path_deallocate_nfc(path, 0); 171 + goto err; 172 + } 154 173 155 174 /* dword 0 */ 156 175 hop.next_hop = path->hops[i].next_hop_index;