summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2017-02-19 16:43:26 -0500
committerMika Westerberg <mika.westerberg@linux.intel.com>2019-04-18 04:18:53 -0400
commit0414bec5f39a3c73fa56474b1bcd899101c2727d (patch)
treee1a9715e38db40ea9b783be0129959f09b7f6311
parentaae9e27f3b72ed58d6b87c8f511e7812601a93c5 (diff)
thunderbolt: Discover preboot PCIe paths the boot firmware established
In Apple Macs the boot firmware (EFI) connects all devices automatically when the system is started, before it hands over to the OS. Instead of ignoring we discover all those PCIe tunnels and record them using our internal structures, just like we do when a device is connected after the OS is already up. By doing this we can properly tear down tunnels when devices are disconnected. Also this allows us to resume the existing tunnels after system suspend/resume cycle. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--drivers/thunderbolt/path.c204
-rw-r--r--drivers/thunderbolt/switch.c14
-rw-r--r--drivers/thunderbolt/tb.c39
-rw-r--r--drivers/thunderbolt/tb.h18
-rw-r--r--drivers/thunderbolt/tunnel.c86
-rw-r--r--drivers/thunderbolt/tunnel.h4
6 files changed, 340 insertions, 25 deletions
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index a7cdac7f6808..670a12e60d66 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -1,8 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2/* 2/*
3 * Thunderbolt Cactus Ridge driver - path/tunnel functionality 3 * Thunderbolt driver - path/tunnel functionality
4 * 4 *
5 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> 5 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
6 * Copyright (C) 2019, Intel Corporation
6 */ 7 */
7 8
8#include <linux/slab.h> 9#include <linux/slab.h>
@@ -12,7 +13,6 @@
12 13
13#include "tb.h" 14#include "tb.h"
14 15
15
16static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop) 16static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop)
17{ 17{
18 tb_port_dbg(port, " Hop through port %d to hop %d (%s)\n", 18 tb_port_dbg(port, " Hop through port %d to hop %d (%s)\n",
@@ -30,6 +30,182 @@ static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop)
30 hop->unknown1, hop->unknown2, hop->unknown3); 30 hop->unknown1, hop->unknown2, hop->unknown3);
31} 31}
32 32
33static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid,
34 int dst_hopid)
35{
36 struct tb_port *port, *out_port = NULL;
37 struct tb_regs_hop hop;
38 struct tb_switch *sw;
39 int i, ret, hopid;
40
41 hopid = src_hopid;
42 port = src;
43
44 for (i = 0; port && i < TB_PATH_MAX_HOPS; i++) {
45 sw = port->sw;
46
47 ret = tb_port_read(port, &hop, TB_CFG_HOPS, 2 * hopid, 2);
48 if (ret) {
49 tb_port_warn(port, "failed to read path at %d\n", hopid);
50 return NULL;
51 }
52
53 if (!hop.enable)
54 return NULL;
55
56 out_port = &sw->ports[hop.out_port];
57 hopid = hop.next_hop;
58 port = out_port->remote;
59 }
60
61 return out_port && hopid == dst_hopid ? out_port : NULL;
62}
63
64static int tb_path_find_src_hopid(struct tb_port *src,
65 const struct tb_port *dst, int dst_hopid)
66{
67 struct tb_port *out;
68 int i;
69
70 for (i = TB_PATH_MIN_HOPID; i <= src->config.max_in_hop_id; i++) {
71 out = tb_path_find_dst_port(src, i, dst_hopid);
72 if (out == dst)
73 return i;
74 }
75
76 return 0;
77}
78
79/**
80 * tb_path_discover() - Discover a path
81 * @src: First input port of a path
82 * @src_hopid: Starting HopID of a path (%-1 if don't care)
83 * @dst: Expected destination port of the path (%NULL if don't care)
84 * @dst_hopid: HopID to the @dst (%-1 if don't care)
85 * @last: Last port is filled here if not %NULL
86 * @name: Name of the path
87 *
88 * Follows a path starting from @src and @src_hopid to the last output
89 * port of the path. Allocates HopIDs for the visited ports. Call
90 * tb_path_free() to release the path and allocated HopIDs when the path
91 * is not needed anymore.
92 *
93 * Note function discovers also incomplete paths so caller should check
94 * that the @dst port is the expected one. If it is not, the path can be
95 * cleaned up by calling tb_path_deactivate() before tb_path_free().
96 *
97 * Return: Discovered path on success, %NULL in case of failure
98 */
99struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
100 struct tb_port *dst, int dst_hopid,
101 struct tb_port **last, const char *name)
102{
103 struct tb_port *out_port;
104 struct tb_regs_hop hop;
105 struct tb_path *path;
106 struct tb_switch *sw;
107 struct tb_port *p;
108 size_t num_hops;
109 int ret, i, h;
110
111 if (src_hopid < 0 && dst) {
112 /*
113 * For incomplete paths the intermediate HopID can be
114 * different from the one used by the protocol adapter
115 * so in that case find a path that ends on @dst with
116 * matching @dst_hopid. That should give us the correct
117 * HopID for the @src.
118 */
119 src_hopid = tb_path_find_src_hopid(src, dst, dst_hopid);
120 if (!src_hopid)
121 return NULL;
122 }
123
124 p = src;
125 h = src_hopid;
126 num_hops = 0;
127
128 for (i = 0; p && i < TB_PATH_MAX_HOPS; i++) {
129 sw = p->sw;
130
131 ret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);
132 if (ret) {
133 tb_port_warn(p, "failed to read path at %d\n", h);
134 return NULL;
135 }
136
137 /* If the hop is not enabled we got an incomplete path */
138 if (!hop.enable)
139 break;
140
141 out_port = &sw->ports[hop.out_port];
142 if (last)
143 *last = out_port;
144
145 h = hop.next_hop;
146 p = out_port->remote;
147 num_hops++;
148 }
149
150 path = kzalloc(sizeof(*path), GFP_KERNEL);
151 if (!path)
152 return NULL;
153
154 path->name = name;
155 path->tb = src->sw->tb;
156 path->path_length = num_hops;
157 path->activated = true;
158
159 path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL);
160 if (!path->hops) {
161 kfree(path);
162 return NULL;
163 }
164
165 p = src;
166 h = src_hopid;
167
168 for (i = 0; i < num_hops; i++) {
169 int next_hop;
170
171 sw = p->sw;
172
173 ret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);
174 if (ret) {
175 tb_port_warn(p, "failed to read path at %d\n", h);
176 goto err;
177 }
178
179 if (tb_port_alloc_in_hopid(p, h, h) < 0)
180 goto err;
181
182 out_port = &sw->ports[hop.out_port];
183 next_hop = hop.next_hop;
184
185 if (tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) {
186 tb_port_release_in_hopid(p, h);
187 goto err;
188 }
189
190 path->hops[i].in_port = p;
191 path->hops[i].in_hop_index = h;
192 path->hops[i].in_counter_index = -1;
193 path->hops[i].out_port = out_port;
194 path->hops[i].next_hop_index = next_hop;
195
196 h = next_hop;
197 p = out_port->remote;
198 }
199
200 return path;
201
202err:
203 tb_port_warn(src, "failed to discover path starting at HopID %d\n",
204 src_hopid);
205 tb_path_free(path);
206 return NULL;
207}
208
33/** 209/**
34 * tb_path_alloc() - allocate a thunderbolt path between two ports 210 * tb_path_alloc() - allocate a thunderbolt path between two ports
35 * @tb: Domain pointer 211 * @tb: Domain pointer
@@ -283,30 +459,14 @@ int tb_path_activate(struct tb_path *path)
283 for (i = path->path_length - 1; i >= 0; i--) { 459 for (i = path->path_length - 1; i >= 0; i--) {
284 struct tb_regs_hop hop = { 0 }; 460 struct tb_regs_hop hop = { 0 };
285 461
286 /* 462 /* If it is left active deactivate it first */
287 * We do (currently) not tear down paths setup by the firmeware. 463 __tb_path_deactivate_hop(path->hops[i].in_port,
288 * If a firmware device is unplugged and plugged in again then 464 path->hops[i].in_hop_index);
289 * it can happen that we reuse some of the hops from the (now
290 * defunct) firmeware path. This causes the hotplug operation to
291 * fail (the pci device does not show up). Clearing the hop
292 * before overwriting it fixes the problem.
293 *
294 * Should be removed once we discover and tear down firmeware
295 * paths.
296 */
297 res = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS,
298 2 * path->hops[i].in_hop_index, 2);
299 if (res) {
300 __tb_path_deactivate_hops(path, i);
301 __tb_path_deallocate_nfc(path, 0);
302 goto err;
303 }
304 465
305 /* dword 0 */ 466 /* dword 0 */
306 hop.next_hop = path->hops[i].next_hop_index; 467 hop.next_hop = path->hops[i].next_hop_index;
307 hop.out_port = path->hops[i].out_port->port; 468 hop.out_port = path->hops[i].out_port->port;
308 /* TODO: figure out why these are good values */ 469 hop.initial_credits = path->hops[i].initial_credits;
309 hop.initial_credits = (i == path->path_length - 1) ? 16 : 7;
310 hop.unknown1 = 0; 470 hop.unknown1 = 0;
311 hop.enable = 1; 471 hop.enable = 1;
312 472
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index ecd41f7b7649..00aec2124f79 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -731,6 +731,20 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
731} 731}
732 732
733/** 733/**
734 * tb_pci_port_is_enabled() - Is the PCIe adapter port enabled
735 * @port: PCIe port to check
736 */
737bool tb_pci_port_is_enabled(struct tb_port *port)
738{
739 u32 data;
740
741 if (tb_port_read(port, &data, TB_CFG_PORT, port->cap_adap, 1))
742 return false;
743
744 return !!(data & TB_PCI_EN);
745}
746
747/**
734 * tb_pci_port_enable() - Enable PCIe adapter port 748 * tb_pci_port_enable() - Enable PCIe adapter port
735 * @port: PCIe port to enable 749 * @port: PCIe port to enable
736 * @enable: Enable/disable the PCIe adapter 750 * @enable: Enable/disable the PCIe adapter
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 0485f4ef9a62..a62695a99835 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -29,6 +29,43 @@ struct tb_cm {
29 29
30/* enumeration & hot plug handling */ 30/* enumeration & hot plug handling */
31 31
32static void tb_discover_tunnels(struct tb_switch *sw)
33{
34 struct tb *tb = sw->tb;
35 struct tb_cm *tcm = tb_priv(tb);
36 struct tb_port *port;
37 int i;
38
39 for (i = 1; i <= sw->config.max_port_number; i++) {
40 struct tb_tunnel *tunnel = NULL;
41
42 port = &sw->ports[i];
43 switch (port->config.type) {
44 case TB_TYPE_PCIE_DOWN:
45 tunnel = tb_tunnel_discover_pci(tb, port);
46 break;
47
48 default:
49 break;
50 }
51
52 if (tunnel) {
53 struct tb_switch *parent = tunnel->dst_port->sw;
54
55 while (parent != tunnel->src_port->sw) {
56 parent->boot = true;
57 parent = tb_switch_parent(parent);
58 }
59
60 list_add_tail(&tunnel->list, &tcm->tunnel_list);
61 }
62 }
63
64 for (i = 1; i <= sw->config.max_port_number; i++) {
65 if (tb_port_has_remote(&sw->ports[i]))
66 tb_discover_tunnels(sw->ports[i].remote->sw);
67 }
68}
32 69
33static void tb_scan_port(struct tb_port *port); 70static void tb_scan_port(struct tb_port *port);
34 71
@@ -408,6 +445,8 @@ static int tb_start(struct tb *tb)
408 445
409 /* Full scan to discover devices added before the driver was loaded. */ 446 /* Full scan to discover devices added before the driver was loaded. */
410 tb_scan_switch(tb->root_switch); 447 tb_scan_switch(tb->root_switch);
448 /* Find out tunnels created by the boot firmware */
449 tb_discover_tunnels(tb->root_switch);
411 tb_activate_pcie_devices(tb); 450 tb_activate_pcie_devices(tb);
412 451
413 /* Allow tb_handle_hotplug to progress events */ 452 /* Allow tb_handle_hotplug to progress events */
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 322bbdc00d95..a558adf6ff10 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -155,6 +155,8 @@ struct tb_port {
155 * @in_counter_index: Used counter index (not used in the driver 155 * @in_counter_index: Used counter index (not used in the driver
156 * currently, %-1 to disable) 156 * currently, %-1 to disable)
157 * @next_hop_index: HopID of the packet when it is routed out from @out_port 157 * @next_hop_index: HopID of the packet when it is routed out from @out_port
158 * @initial_credits: Number of initial flow control credits allocated for
159 * the path
158 * 160 *
159 * Hop configuration is always done on the IN port of a switch. 161 * Hop configuration is always done on the IN port of a switch.
160 * in_port and out_port have to be on the same switch. Packets arriving on 162 * in_port and out_port have to be on the same switch. Packets arriving on
@@ -173,6 +175,7 @@ struct tb_path_hop {
173 int in_hop_index; 175 int in_hop_index;
174 int in_counter_index; 176 int in_counter_index;
175 int next_hop_index; 177 int next_hop_index;
178 unsigned int initial_credits;
176}; 179};
177 180
178/** 181/**
@@ -230,6 +233,7 @@ struct tb_path {
230 233
231/* HopIDs 0-7 are reserved by the Thunderbolt protocol */ 234/* HopIDs 0-7 are reserved by the Thunderbolt protocol */
232#define TB_PATH_MIN_HOPID 8 235#define TB_PATH_MIN_HOPID 8
236#define TB_PATH_MAX_HOPS 7
233 237
234/** 238/**
235 * struct tb_cm_ops - Connection manager specific operations vector 239 * struct tb_cm_ops - Connection manager specific operations vector
@@ -346,6 +350,11 @@ static inline bool tb_port_has_remote(const struct tb_port *port)
346 return true; 350 return true;
347} 351}
348 352
353static inline bool tb_port_is_pcie_up(const struct tb_port *port)
354{
355 return port && port->config.type == TB_TYPE_PCIE_UP;
356}
357
349static inline int tb_sw_read(struct tb_switch *sw, void *buffer, 358static inline int tb_sw_read(struct tb_switch *sw, void *buffer,
350 enum tb_cfg_space space, u32 offset, u32 length) 359 enum tb_cfg_space space, u32 offset, u32 length)
351{ 360{
@@ -508,6 +517,11 @@ static inline struct tb_switch *tb_to_switch(struct device *dev)
508 return NULL; 517 return NULL;
509} 518}
510 519
520static inline struct tb_switch *tb_switch_parent(struct tb_switch *sw)
521{
522 return tb_to_switch(sw->dev.parent);
523}
524
511static inline bool tb_switch_is_lr(const struct tb_switch *sw) 525static inline bool tb_switch_is_lr(const struct tb_switch *sw)
512{ 526{
513 return sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE; 527 return sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE;
@@ -531,8 +545,12 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
531int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec); 545int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
532int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap); 546int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
533 547
548bool tb_pci_port_is_enabled(struct tb_port *port);
534int tb_pci_port_enable(struct tb_port *port, bool enable); 549int tb_pci_port_enable(struct tb_port *port, bool enable);
535 550
551struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
552 struct tb_port *dst, int dst_hopid,
553 struct tb_port **last, const char *name);
536struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, 554struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
537 struct tb_port *dst, int dst_hopid, int link_nr, 555 struct tb_port *dst, int dst_hopid, int link_nr,
538 const char *name); 556 const char *name);
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index e109578da175..71c712300326 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -35,6 +35,8 @@
35 __TB_TUNNEL_PRINT(tb_warn, tunnel, fmt, ##arg) 35 __TB_TUNNEL_PRINT(tb_warn, tunnel, fmt, ##arg)
36#define tb_tunnel_info(tunnel, fmt, arg...) \ 36#define tb_tunnel_info(tunnel, fmt, arg...) \
37 __TB_TUNNEL_PRINT(tb_info, tunnel, fmt, ##arg) 37 __TB_TUNNEL_PRINT(tb_info, tunnel, fmt, ##arg)
38#define tb_tunnel_dbg(tunnel, fmt, arg...) \
39 __TB_TUNNEL_PRINT(tb_dbg, tunnel, fmt, ##arg)
38 40
39static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths) 41static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths)
40{ 42{
@@ -65,7 +67,10 @@ static int tb_pci_activate(struct tb_tunnel *tunnel, bool activate)
65 if (res) 67 if (res)
66 return res; 68 return res;
67 69
68 return tb_pci_port_enable(tunnel->dst_port, activate); 70 if (tb_port_is_pcie_up(tunnel->dst_port))
71 return tb_pci_port_enable(tunnel->dst_port, activate);
72
73 return 0;
69} 74}
70 75
71static void tb_pci_init_path(struct tb_path *path) 76static void tb_pci_init_path(struct tb_path *path)
@@ -78,6 +83,83 @@ static void tb_pci_init_path(struct tb_path *path)
78 path->weight = 1; 83 path->weight = 1;
79 path->drop_packages = 0; 84 path->drop_packages = 0;
80 path->nfc_credits = 0; 85 path->nfc_credits = 0;
86 path->hops[0].initial_credits = 7;
87 path->hops[1].initial_credits = 16;
88}
89
90/**
91 * tb_tunnel_discover_pci() - Discover existing PCIe tunnels
92 * @tb: Pointer to the domain structure
93 * @down: PCIe downstream adapter
94 *
95 * If @down adapter is active, follows the tunnel to the PCIe upstream
96 * adapter and back. Returns the discovered tunnel or %NULL if there was
97 * no tunnel.
98 */
99struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down)
100{
101 struct tb_tunnel *tunnel;
102 struct tb_path *path;
103
104 if (!tb_pci_port_is_enabled(down))
105 return NULL;
106
107 tunnel = tb_tunnel_alloc(tb, 2);
108 if (!tunnel)
109 return NULL;
110
111 tunnel->activate = tb_pci_activate;
112 tunnel->src_port = down;
113
114 /*
115 * Discover both paths even if they are not complete. We will
116 * clean them up by calling tb_tunnel_deactivate() below in that
117 * case.
118 */
119 path = tb_path_discover(down, TB_PCI_HOPID, NULL, -1,
120 &tunnel->dst_port, "PCIe Up");
121 if (!path) {
122 /* Just disable the downstream port */
123 tb_pci_port_enable(down, false);
124 goto err_free;
125 }
126 tunnel->paths[TB_PCI_PATH_UP] = path;
127 tb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP]);
128
129 path = tb_path_discover(tunnel->dst_port, -1, down, TB_PCI_HOPID, NULL,
130 "PCIe Down");
131 if (!path)
132 goto err_deactivate;
133 tunnel->paths[TB_PCI_PATH_DOWN] = path;
134 tb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN]);
135
136 /* Validate that the tunnel is complete */
137 if (!tb_port_is_pcie_up(tunnel->dst_port)) {
138 tb_port_warn(tunnel->dst_port,
139 "path does not end on a PCIe adapter, cleaning up\n");
140 goto err_deactivate;
141 }
142
143 if (down != tunnel->src_port) {
144 tb_tunnel_warn(tunnel, "path is not complete, cleaning up\n");
145 goto err_deactivate;
146 }
147
148 if (!tb_pci_port_is_enabled(tunnel->dst_port)) {
149 tb_tunnel_warn(tunnel,
150 "tunnel is not fully activated, cleaning up\n");
151 goto err_deactivate;
152 }
153
154 tb_tunnel_dbg(tunnel, "discovered\n");
155 return tunnel;
156
157err_deactivate:
158 tb_tunnel_deactivate(tunnel);
159err_free:
160 tb_tunnel_free(tunnel);
161
162 return NULL;
81} 163}
82 164
83/** 165/**
@@ -253,7 +335,7 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel)
253 tunnel->activate(tunnel, false); 335 tunnel->activate(tunnel, false);
254 336
255 for (i = 0; i < tunnel->npaths; i++) { 337 for (i = 0; i < tunnel->npaths; i++) {
256 if (tunnel->paths[i]->activated) 338 if (tunnel->paths[i] && tunnel->paths[i]->activated)
257 tb_path_deactivate(tunnel->paths[i]); 339 tb_path_deactivate(tunnel->paths[i]);
258 } 340 }
259} 341}
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index b4e992165e56..07bf587bed80 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -15,7 +15,8 @@
15 * struct tb_tunnel - Tunnel between two ports 15 * struct tb_tunnel - Tunnel between two ports
16 * @tb: Pointer to the domain 16 * @tb: Pointer to the domain
17 * @src_port: Source port of the tunnel 17 * @src_port: Source port of the tunnel
18 * @dst_port: Destination port of the tunnel 18 * @dst_port: Destination port of the tunnel. For discovered incomplete
19 * tunnels may be %NULL or null adapter port instead.
19 * @paths: All paths required by the tunnel 20 * @paths: All paths required by the tunnel
20 * @npaths: Number of paths in @paths 21 * @npaths: Number of paths in @paths
21 * @activate: Optional tunnel specific activation/deactivation 22 * @activate: Optional tunnel specific activation/deactivation
@@ -31,6 +32,7 @@ struct tb_tunnel {
31 struct list_head list; 32 struct list_head list;
32}; 33};
33 34
35struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down);
34struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, 36struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
35 struct tb_port *down); 37 struct tb_port *down);
36void tb_tunnel_free(struct tb_tunnel *tunnel); 38void tb_tunnel_free(struct tb_tunnel *tunnel);