blob: e109578da175f19cb3a3dd1c609a2e3b48572e06 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Andreas Noever3364f0c2014-06-03 22:04:08 +02002/*
Mika Westerberg93f36ad2017-02-19 13:48:29 +02003 * Thunderbolt driver - Tunneling support
Andreas Noever3364f0c2014-06-03 22:04:08 +02004 *
5 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
Mika Westerberg93f36ad2017-02-19 13:48:29 +02006 * Copyright (C) 2019, Intel Corporation
Andreas Noever3364f0c2014-06-03 22:04:08 +02007 */
8
9#include <linux/slab.h>
10#include <linux/list.h>
11
Mika Westerberg1752b9f2017-02-19 10:58:35 +020012#include "tunnel.h"
Andreas Noever3364f0c2014-06-03 22:04:08 +020013#include "tb.h"
14
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +020015/* PCIe adapters use always HopID of 8 for both directions */
16#define TB_PCI_HOPID 8
17
Mika Westerberg93f36ad2017-02-19 13:48:29 +020018#define TB_PCI_PATH_DOWN 0
19#define TB_PCI_PATH_UP 1
20
Andreas Noever3364f0c2014-06-03 22:04:08 +020021#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \
22 do { \
Mika Westerberg93f36ad2017-02-19 13:48:29 +020023 struct tb_tunnel *__tunnel = (tunnel); \
Andreas Noever3364f0c2014-06-03 22:04:08 +020024 level(__tunnel->tb, "%llx:%x <-> %llx:%x (PCI): " fmt, \
Mika Westerberg93f36ad2017-02-19 13:48:29 +020025 tb_route(__tunnel->src_port->sw), \
26 __tunnel->src_port->port, \
27 tb_route(__tunnel->dst_port->sw), \
28 __tunnel->dst_port->port, \
Andreas Noever3364f0c2014-06-03 22:04:08 +020029 ## arg); \
30 } while (0)
31
32#define tb_tunnel_WARN(tunnel, fmt, arg...) \
33 __TB_TUNNEL_PRINT(tb_WARN, tunnel, fmt, ##arg)
34#define tb_tunnel_warn(tunnel, fmt, arg...) \
35 __TB_TUNNEL_PRINT(tb_warn, tunnel, fmt, ##arg)
36#define tb_tunnel_info(tunnel, fmt, arg...) \
37 __TB_TUNNEL_PRINT(tb_info, tunnel, fmt, ##arg)
38
Mika Westerberg93f36ad2017-02-19 13:48:29 +020039static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths)
40{
41 struct tb_tunnel *tunnel;
42
43 tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL);
44 if (!tunnel)
45 return NULL;
46
47 tunnel->paths = kcalloc(npaths, sizeof(tunnel->paths[0]), GFP_KERNEL);
48 if (!tunnel->paths) {
49 tb_tunnel_free(tunnel);
50 return NULL;
51 }
52
53 INIT_LIST_HEAD(&tunnel->list);
54 tunnel->tb = tb;
55 tunnel->npaths = npaths;
56
57 return tunnel;
58}
59
60static int tb_pci_activate(struct tb_tunnel *tunnel, bool activate)
61{
62 int res;
63
64 res = tb_pci_port_enable(tunnel->src_port, activate);
65 if (res)
66 return res;
67
68 return tb_pci_port_enable(tunnel->dst_port, activate);
69}
70
Andreas Noever3364f0c2014-06-03 22:04:08 +020071static void tb_pci_init_path(struct tb_path *path)
72{
73 path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
74 path->egress_shared_buffer = TB_PATH_NONE;
75 path->ingress_fc_enable = TB_PATH_ALL;
76 path->ingress_shared_buffer = TB_PATH_NONE;
77 path->priority = 3;
78 path->weight = 1;
79 path->drop_packages = 0;
80 path->nfc_credits = 0;
81}
82
83/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +020084 * tb_tunnel_alloc_pci() - allocate a pci tunnel
85 * @tb: Pointer to the domain structure
86 * @up: PCIe upstream adapter port
87 * @down: PCIe downstream adapter port
Andreas Noever3364f0c2014-06-03 22:04:08 +020088 *
89 * Allocate a PCI tunnel. The ports must be of type TB_TYPE_PCIE_UP and
90 * TB_TYPE_PCIE_DOWN.
91 *
Mika Westerberg93f36ad2017-02-19 13:48:29 +020092 * Return: Returns a tb_tunnel on success or NULL on failure.
Andreas Noever3364f0c2014-06-03 22:04:08 +020093 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +020094struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
95 struct tb_port *down)
Andreas Noever3364f0c2014-06-03 22:04:08 +020096{
Mika Westerberg93f36ad2017-02-19 13:48:29 +020097 struct tb_tunnel *tunnel;
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +020098 struct tb_path *path;
Mika Westerberg93f36ad2017-02-19 13:48:29 +020099
100 tunnel = tb_tunnel_alloc(tb, 2);
Andreas Noever3364f0c2014-06-03 22:04:08 +0200101 if (!tunnel)
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200102 return NULL;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200103
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200104 tunnel->activate = tb_pci_activate;
105 tunnel->src_port = down;
106 tunnel->dst_port = up;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200107
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +0200108 path = tb_path_alloc(tb, down, TB_PCI_HOPID, up, TB_PCI_HOPID, 0,
109 "PCIe Down");
110 if (!path) {
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200111 tb_tunnel_free(tunnel);
112 return NULL;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200113 }
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +0200114 tb_pci_init_path(path);
115 tunnel->paths[TB_PCI_PATH_UP] = path;
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200116
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +0200117 path = tb_path_alloc(tb, up, TB_PCI_HOPID, down, TB_PCI_HOPID, 0,
118 "PCIe Up");
119 if (!path) {
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200120 tb_tunnel_free(tunnel);
121 return NULL;
122 }
Mika Westerberg8c7acaaf2017-02-19 22:11:41 +0200123 tb_pci_init_path(path);
124 tunnel->paths[TB_PCI_PATH_DOWN] = path;
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200125
126 return tunnel;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200127}
128
129/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200130 * tb_tunnel_free() - free a tunnel
131 * @tunnel: Tunnel to be freed
Andreas Noever3364f0c2014-06-03 22:04:08 +0200132 *
133 * The tunnel must have been deactivated.
134 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200135void tb_tunnel_free(struct tb_tunnel *tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200136{
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200137 int i;
138
139 if (!tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200140 return;
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200141
142 for (i = 0; i < tunnel->npaths; i++) {
143 if (tunnel->paths[i] && tunnel->paths[i]->activated) {
144 tb_tunnel_WARN(tunnel,
145 "trying to free an activated tunnel\n");
146 return;
147 }
Andreas Noever3364f0c2014-06-03 22:04:08 +0200148 }
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200149
150 for (i = 0; i < tunnel->npaths; i++) {
151 if (tunnel->paths[i])
152 tb_path_free(tunnel->paths[i]);
153 }
154
155 kfree(tunnel->paths);
Andreas Noever3364f0c2014-06-03 22:04:08 +0200156 kfree(tunnel);
157}
158
159/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200160 * tb_tunnel_is_invalid - check whether an activated path is still valid
161 * @tunnel: Tunnel to check
Andreas Noever3364f0c2014-06-03 22:04:08 +0200162 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200163bool tb_tunnel_is_invalid(struct tb_tunnel *tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200164{
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200165 int i;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200166
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200167 for (i = 0; i < tunnel->npaths; i++) {
168 WARN_ON(!tunnel->paths[i]->activated);
169 if (tb_path_is_invalid(tunnel->paths[i]))
170 return true;
171 }
172
173 return false;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200174}
175
176/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200177 * tb_tunnel_restart() - activate a tunnel after a hardware reset
178 * @tunnel: Tunnel to restart
Andreas Noever3364f0c2014-06-03 22:04:08 +0200179 *
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200180 * Return: 0 on success and negative errno in case if failure
Andreas Noever3364f0c2014-06-03 22:04:08 +0200181 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200182int tb_tunnel_restart(struct tb_tunnel *tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200183{
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200184 int res, i;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200185
186 tb_tunnel_info(tunnel, "activating\n");
187
Mika Westerbergaae9e272017-02-19 23:37:35 +0200188 /*
189 * Make sure all paths are properly disabled before enabling
190 * them again.
191 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200192 for (i = 0; i < tunnel->npaths; i++) {
Mika Westerbergaae9e272017-02-19 23:37:35 +0200193 if (tunnel->paths[i]->activated) {
194 tb_path_deactivate(tunnel->paths[i]);
195 tunnel->paths[i]->activated = false;
196 }
197 }
198
199 for (i = 0; i < tunnel->npaths; i++) {
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200200 res = tb_path_activate(tunnel->paths[i]);
201 if (res)
202 goto err;
203 }
Andreas Noever3364f0c2014-06-03 22:04:08 +0200204
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200205 if (tunnel->activate) {
206 res = tunnel->activate(tunnel, true);
207 if (res)
208 goto err;
209 }
Andreas Noever3364f0c2014-06-03 22:04:08 +0200210
Andreas Noever3364f0c2014-06-03 22:04:08 +0200211 return 0;
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200212
Andreas Noever3364f0c2014-06-03 22:04:08 +0200213err:
214 tb_tunnel_warn(tunnel, "activation failed\n");
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200215 tb_tunnel_deactivate(tunnel);
Andreas Noever3364f0c2014-06-03 22:04:08 +0200216 return res;
217}
218
219/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200220 * tb_tunnel_activate() - activate a tunnel
221 * @tunnel: Tunnel to activate
Andreas Noever3364f0c2014-06-03 22:04:08 +0200222 *
223 * Return: Returns 0 on success or an error code on failure.
224 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200225int tb_tunnel_activate(struct tb_tunnel *tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200226{
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200227 int i;
228
229 tb_tunnel_info(tunnel, "activating\n");
230
231 for (i = 0; i < tunnel->npaths; i++) {
232 if (tunnel->paths[i]->activated) {
233 tb_tunnel_WARN(tunnel,
234 "trying to activate an already activated tunnel\n");
235 return -EINVAL;
236 }
Andreas Noever3364f0c2014-06-03 22:04:08 +0200237 }
238
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200239 return tb_tunnel_restart(tunnel);
Andreas Noever3364f0c2014-06-03 22:04:08 +0200240}
241
Andreas Noever3364f0c2014-06-03 22:04:08 +0200242/**
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200243 * tb_tunnel_deactivate() - deactivate a tunnel
244 * @tunnel: Tunnel to deactivate
Andreas Noever3364f0c2014-06-03 22:04:08 +0200245 */
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200246void tb_tunnel_deactivate(struct tb_tunnel *tunnel)
Andreas Noever3364f0c2014-06-03 22:04:08 +0200247{
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200248 int i;
Andreas Noever3364f0c2014-06-03 22:04:08 +0200249
Mika Westerberg93f36ad2017-02-19 13:48:29 +0200250 tb_tunnel_info(tunnel, "deactivating\n");
251
252 if (tunnel->activate)
253 tunnel->activate(tunnel, false);
254
255 for (i = 0; i < tunnel->npaths; i++) {
256 if (tunnel->paths[i]->activated)
257 tb_path_deactivate(tunnel->paths[i]);
258 }
259}