1 // SPDX-License-Identifier: GPL-2.0
3 * Thunderbolt driver - path/tunnel functionality
5 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
6 * Copyright (C) 2019, Intel Corporation
9 #include <linux/slab.h>
10 #include <linux/errno.h>
11 #include <linux/delay.h>
12 #include <linux/ktime.h>
16 static void tb_dump_hop(const struct tb_path_hop
*hop
, const struct tb_regs_hop
*regs
)
18 const struct tb_port
*port
= hop
->in_port
;
20 tb_port_dbg(port
, " In HopID: %d => Out port: %d Out HopID: %d\n",
21 hop
->in_hop_index
, regs
->out_port
, regs
->next_hop
);
22 tb_port_dbg(port
, " Weight: %d Priority: %d Credits: %d Drop: %d\n",
23 regs
->weight
, regs
->priority
,
24 regs
->initial_credits
, regs
->drop_packages
);
25 tb_port_dbg(port
, " Counter enabled: %d Counter index: %d\n",
26 regs
->counter_enable
, regs
->counter
);
27 tb_port_dbg(port
, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n",
28 regs
->ingress_fc
, regs
->egress_fc
,
29 regs
->ingress_shared_buffer
, regs
->egress_shared_buffer
);
30 tb_port_dbg(port
, " Unknown1: %#x Unknown2: %#x Unknown3: %#x\n",
31 regs
->unknown1
, regs
->unknown2
, regs
->unknown3
);
34 static struct tb_port
*tb_path_find_dst_port(struct tb_port
*src
, int src_hopid
,
37 struct tb_port
*port
, *out_port
= NULL
;
38 struct tb_regs_hop hop
;
45 for (i
= 0; port
&& i
< TB_PATH_MAX_HOPS
; i
++) {
48 ret
= tb_port_read(port
, &hop
, TB_CFG_HOPS
, 2 * hopid
, 2);
50 tb_port_warn(port
, "failed to read path at %d\n", hopid
);
57 out_port
= &sw
->ports
[hop
.out_port
];
59 port
= out_port
->remote
;
62 return out_port
&& hopid
== dst_hopid
? out_port
: NULL
;
65 static int tb_path_find_src_hopid(struct tb_port
*src
,
66 const struct tb_port
*dst
, int dst_hopid
)
71 for (i
= TB_PATH_MIN_HOPID
; i
<= src
->config
.max_in_hop_id
; i
++) {
72 out
= tb_path_find_dst_port(src
, i
, dst_hopid
);
81 * tb_path_discover() - Discover a path
82 * @src: First input port of a path
83 * @src_hopid: Starting HopID of a path (%-1 if don't care)
84 * @dst: Expected destination port of the path (%NULL if don't care)
85 * @dst_hopid: HopID to the @dst (%-1 if don't care)
86 * @last: Last port is filled here if not %NULL
87 * @name: Name of the path
89 * Follows a path starting from @src and @src_hopid to the last output
90 * port of the path. Allocates HopIDs for the visited ports. Call
91 * tb_path_free() to release the path and allocated HopIDs when the path
92 * is not needed anymore.
94 * Note function discovers also incomplete paths so caller should check
95 * that the @dst port is the expected one. If it is not, the path can be
96 * cleaned up by calling tb_path_deactivate() before tb_path_free().
98 * Return: Discovered path on success, %NULL in case of failure
100 struct tb_path
*tb_path_discover(struct tb_port
*src
, int src_hopid
,
101 struct tb_port
*dst
, int dst_hopid
,
102 struct tb_port
**last
, const char *name
)
104 struct tb_port
*out_port
;
105 struct tb_regs_hop hop
;
106 struct tb_path
*path
;
107 struct tb_switch
*sw
;
112 if (src_hopid
< 0 && dst
) {
114 * For incomplete paths the intermediate HopID can be
115 * different from the one used by the protocol adapter
116 * so in that case find a path that ends on @dst with
117 * matching @dst_hopid. That should give us the correct
118 * HopID for the @src.
120 src_hopid
= tb_path_find_src_hopid(src
, dst
, dst_hopid
);
129 for (i
= 0; p
&& i
< TB_PATH_MAX_HOPS
; i
++) {
132 ret
= tb_port_read(p
, &hop
, TB_CFG_HOPS
, 2 * h
, 2);
134 tb_port_warn(p
, "failed to read path at %d\n", h
);
138 /* If the hop is not enabled we got an incomplete path */
142 out_port
= &sw
->ports
[hop
.out_port
];
147 p
= out_port
->remote
;
151 path
= kzalloc(sizeof(*path
), GFP_KERNEL
);
156 path
->tb
= src
->sw
->tb
;
157 path
->path_length
= num_hops
;
158 path
->activated
= true;
160 path
->hops
= kcalloc(num_hops
, sizeof(*path
->hops
), GFP_KERNEL
);
169 for (i
= 0; i
< num_hops
; i
++) {
174 ret
= tb_port_read(p
, &hop
, TB_CFG_HOPS
, 2 * h
, 2);
176 tb_port_warn(p
, "failed to read path at %d\n", h
);
180 if (tb_port_alloc_in_hopid(p
, h
, h
) < 0)
183 out_port
= &sw
->ports
[hop
.out_port
];
184 next_hop
= hop
.next_hop
;
186 if (tb_port_alloc_out_hopid(out_port
, next_hop
, next_hop
) < 0) {
187 tb_port_release_in_hopid(p
, h
);
191 path
->hops
[i
].in_port
= p
;
192 path
->hops
[i
].in_hop_index
= h
;
193 path
->hops
[i
].in_counter_index
= -1;
194 path
->hops
[i
].out_port
= out_port
;
195 path
->hops
[i
].next_hop_index
= next_hop
;
198 p
= out_port
->remote
;
204 tb_port_warn(src
, "failed to discover path starting at HopID %d\n",
211 * tb_path_alloc() - allocate a thunderbolt path between two ports
212 * @tb: Domain pointer
213 * @src: Source port of the path
214 * @src_hopid: HopID used for the first ingress port in the path
215 * @dst: Destination port of the path
216 * @dst_hopid: HopID used for the last egress port in the path
217 * @link_nr: Preferred link if there are dual links on the path
218 * @name: Name of the path
220 * Creates path between two ports starting with given @src_hopid. Reserves
221 * HopIDs for each port (they can be different from @src_hopid depending on
222 * how many HopIDs each port already have reserved). If there are dual
223 * links on the path, prioritizes using @link_nr but takes into account
224 * that the lanes may be bonded.
226 * Return: Returns a tb_path on success or NULL on failure.
228 struct tb_path
*tb_path_alloc(struct tb
*tb
, struct tb_port
*src
, int src_hopid
,
229 struct tb_port
*dst
, int dst_hopid
, int link_nr
,
232 struct tb_port
*in_port
, *out_port
, *first_port
, *last_port
;
233 int in_hopid
, out_hopid
;
234 struct tb_path
*path
;
238 path
= kzalloc(sizeof(*path
), GFP_KERNEL
);
242 first_port
= last_port
= NULL
;
244 tb_for_each_port_on_path(src
, dst
, in_port
) {
246 first_port
= in_port
;
251 /* Check that src and dst are reachable */
252 if (first_port
!= src
|| last_port
!= dst
) {
257 /* Each hop takes two ports */
260 path
->hops
= kcalloc(num_hops
, sizeof(*path
->hops
), GFP_KERNEL
);
266 in_hopid
= src_hopid
;
269 for (i
= 0; i
< num_hops
; i
++) {
270 in_port
= tb_next_port_on_path(src
, dst
, out_port
);
274 /* When lanes are bonded primary link must be used */
275 if (!in_port
->bonded
&& in_port
->dual_link_port
&&
276 in_port
->link_nr
!= link_nr
)
277 in_port
= in_port
->dual_link_port
;
279 ret
= tb_port_alloc_in_hopid(in_port
, in_hopid
, in_hopid
);
284 out_port
= tb_next_port_on_path(src
, dst
, in_port
);
289 * Pick up right port when going from non-bonded to
290 * bonded or from bonded to non-bonded.
292 if (out_port
->dual_link_port
) {
293 if (!in_port
->bonded
&& out_port
->bonded
&&
296 * Use primary link when going from
297 * non-bonded to bonded.
299 out_port
= out_port
->dual_link_port
;
300 } else if (!out_port
->bonded
&&
301 out_port
->link_nr
!= link_nr
) {
303 * If out port is not bonded follow
306 out_port
= out_port
->dual_link_port
;
310 if (i
== num_hops
- 1)
311 ret
= tb_port_alloc_out_hopid(out_port
, dst_hopid
,
314 ret
= tb_port_alloc_out_hopid(out_port
, -1, -1);
320 path
->hops
[i
].in_hop_index
= in_hopid
;
321 path
->hops
[i
].in_port
= in_port
;
322 path
->hops
[i
].in_counter_index
= -1;
323 path
->hops
[i
].out_port
= out_port
;
324 path
->hops
[i
].next_hop_index
= out_hopid
;
326 in_hopid
= out_hopid
;
330 path
->path_length
= num_hops
;
341 * tb_path_free() - free a path
342 * @path: Path to free
344 * Frees a path. The path does not need to be deactivated.
346 void tb_path_free(struct tb_path
*path
)
350 for (i
= 0; i
< path
->path_length
; i
++) {
351 const struct tb_path_hop
*hop
= &path
->hops
[i
];
354 tb_port_release_in_hopid(hop
->in_port
,
357 tb_port_release_out_hopid(hop
->out_port
,
358 hop
->next_hop_index
);
365 static void __tb_path_deallocate_nfc(struct tb_path
*path
, int first_hop
)
368 for (i
= first_hop
; i
< path
->path_length
; i
++) {
369 res
= tb_port_add_nfc_credits(path
->hops
[i
].in_port
,
372 tb_port_warn(path
->hops
[i
].in_port
,
373 "nfc credits deallocation failed for hop %d\n",
378 static int __tb_path_deactivate_hop(struct tb_port
*port
, int hop_index
,
381 struct tb_regs_hop hop
;
385 /* Disable the path */
386 ret
= tb_port_read(port
, &hop
, TB_CFG_HOPS
, 2 * hop_index
, 2);
390 /* Already disabled */
396 ret
= tb_port_write(port
, &hop
, TB_CFG_HOPS
, 2 * hop_index
, 2);
400 /* Wait until it is drained */
401 timeout
= ktime_add_ms(ktime_get(), 500);
403 ret
= tb_port_read(port
, &hop
, TB_CFG_HOPS
, 2 * hop_index
, 2);
410 * Clear flow control. Protocol adapters
411 * IFC and ISE bits are vendor defined
412 * in the USB4 spec so we clear them
413 * only for pre-USB4 adapters.
415 if (!tb_switch_is_usb4(port
->sw
)) {
417 hop
.ingress_shared_buffer
= 0;
420 hop
.egress_shared_buffer
= 0;
422 return tb_port_write(port
, &hop
, TB_CFG_HOPS
,
429 usleep_range(10, 20);
430 } while (ktime_before(ktime_get(), timeout
));
435 static void __tb_path_deactivate_hops(struct tb_path
*path
, int first_hop
)
439 for (i
= first_hop
; i
< path
->path_length
; i
++) {
440 res
= __tb_path_deactivate_hop(path
->hops
[i
].in_port
,
441 path
->hops
[i
].in_hop_index
,
443 if (res
&& res
!= -ENODEV
)
444 tb_port_warn(path
->hops
[i
].in_port
,
445 "hop deactivation failed for hop %d, index %d\n",
446 i
, path
->hops
[i
].in_hop_index
);
450 void tb_path_deactivate(struct tb_path
*path
)
452 if (!path
->activated
) {
453 tb_WARN(path
->tb
, "trying to deactivate an inactive path\n");
457 "deactivating %s path from %llx:%u to %llx:%u\n",
458 path
->name
, tb_route(path
->hops
[0].in_port
->sw
),
459 path
->hops
[0].in_port
->port
,
460 tb_route(path
->hops
[path
->path_length
- 1].out_port
->sw
),
461 path
->hops
[path
->path_length
- 1].out_port
->port
);
462 __tb_path_deactivate_hops(path
, 0);
463 __tb_path_deallocate_nfc(path
, 0);
464 path
->activated
= false;
468 * tb_path_activate() - activate a path
470 * Activate a path starting with the last hop and iterating backwards. The
471 * caller must fill path->hops before calling tb_path_activate().
473 * Return: Returns 0 on success or an error code on failure.
475 int tb_path_activate(struct tb_path
*path
)
478 enum tb_path_port out_mask
, in_mask
;
479 if (path
->activated
) {
480 tb_WARN(path
->tb
, "trying to activate already activated path\n");
485 "activating %s path from %llx:%u to %llx:%u\n",
486 path
->name
, tb_route(path
->hops
[0].in_port
->sw
),
487 path
->hops
[0].in_port
->port
,
488 tb_route(path
->hops
[path
->path_length
- 1].out_port
->sw
),
489 path
->hops
[path
->path_length
- 1].out_port
->port
);
491 /* Clear counters. */
492 for (i
= path
->path_length
- 1; i
>= 0; i
--) {
493 if (path
->hops
[i
].in_counter_index
== -1)
495 res
= tb_port_clear_counter(path
->hops
[i
].in_port
,
496 path
->hops
[i
].in_counter_index
);
501 /* Add non flow controlled credits. */
502 for (i
= path
->path_length
- 1; i
>= 0; i
--) {
503 res
= tb_port_add_nfc_credits(path
->hops
[i
].in_port
,
506 __tb_path_deallocate_nfc(path
, i
);
512 for (i
= path
->path_length
- 1; i
>= 0; i
--) {
513 struct tb_regs_hop hop
= { 0 };
515 /* If it is left active deactivate it first */
516 __tb_path_deactivate_hop(path
->hops
[i
].in_port
,
517 path
->hops
[i
].in_hop_index
, path
->clear_fc
);
520 hop
.next_hop
= path
->hops
[i
].next_hop_index
;
521 hop
.out_port
= path
->hops
[i
].out_port
->port
;
522 hop
.initial_credits
= path
->hops
[i
].initial_credits
;
527 out_mask
= (i
== path
->path_length
- 1) ?
528 TB_PATH_DESTINATION
: TB_PATH_INTERNAL
;
529 in_mask
= (i
== 0) ? TB_PATH_SOURCE
: TB_PATH_INTERNAL
;
530 hop
.weight
= path
->weight
;
532 hop
.priority
= path
->priority
;
533 hop
.drop_packages
= path
->drop_packages
;
534 hop
.counter
= path
->hops
[i
].in_counter_index
;
535 hop
.counter_enable
= path
->hops
[i
].in_counter_index
!= -1;
536 hop
.ingress_fc
= path
->ingress_fc_enable
& in_mask
;
537 hop
.egress_fc
= path
->egress_fc_enable
& out_mask
;
538 hop
.ingress_shared_buffer
= path
->ingress_shared_buffer
540 hop
.egress_shared_buffer
= path
->egress_shared_buffer
544 tb_port_dbg(path
->hops
[i
].in_port
, "Writing hop %d\n", i
);
545 tb_dump_hop(&path
->hops
[i
], &hop
);
546 res
= tb_port_write(path
->hops
[i
].in_port
, &hop
, TB_CFG_HOPS
,
547 2 * path
->hops
[i
].in_hop_index
, 2);
549 __tb_path_deactivate_hops(path
, i
);
550 __tb_path_deallocate_nfc(path
, 0);
554 path
->activated
= true;
555 tb_dbg(path
->tb
, "path activation complete\n");
558 tb_WARN(path
->tb
, "path activation failed\n");
563 * tb_path_is_invalid() - check whether any ports on the path are invalid
565 * Return: Returns true if the path is invalid, false otherwise.
567 bool tb_path_is_invalid(struct tb_path
*path
)
570 for (i
= 0; i
< path
->path_length
; i
++) {
571 if (path
->hops
[i
].in_port
->sw
->is_unplugged
)
573 if (path
->hops
[i
].out_port
->sw
->is_unplugged
)
580 * tb_path_port_on_path() - Does the path go through certain port
581 * @path: Path to check
582 * @port: Switch to check
584 * Goes over all hops on path and checks if @port is any of them.
585 * Direction does not matter.
587 bool tb_path_port_on_path(const struct tb_path
*path
, const struct tb_port
*port
)
591 for (i
= 0; i
< path
->path_length
; i
++) {
592 if (path
->hops
[i
].in_port
== port
||
593 path
->hops
[i
].out_port
== port
)