Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
d6cc51cd | 2 | /* |
15c6784c | 3 | * Thunderbolt driver - bus logic (NHI independent) |
d6cc51cd AN |
4 | * |
5 | * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> | |
15c6784c | 6 | * Copyright (C) 2018, Intel Corporation |
d6cc51cd AN |
7 | */ |
8 | ||
9 | #ifndef TB_H_ | |
10 | #define TB_H_ | |
11 | ||
e6b245cc | 12 | #include <linux/nvmem-provider.h> |
a25c8b2f | 13 | #include <linux/pci.h> |
d1ff7024 | 14 | #include <linux/thunderbolt.h> |
bfe778ac | 15 | #include <linux/uuid.h> |
a25c8b2f AN |
16 | |
17 | #include "tb_regs.h" | |
d6cc51cd | 18 | #include "ctl.h" |
3e136768 | 19 | #include "dma_port.h" |
d6cc51cd | 20 | |
e6b245cc MW |
21 | /** |
22 | * struct tb_switch_nvm - Structure holding switch NVM information | |
23 | * @major: Major version number of the active NVM portion | |
24 | * @minor: Minor version number of the active NVM portion | |
25 | * @id: Identifier used with both NVM portions | |
26 | * @active: Active portion NVMem device | |
27 | * @non_active: Non-active portion NVMem device | |
28 | * @buf: Buffer where the NVM image is stored before it is written to | |
29 | * the actual NVM flash device | |
30 | * @buf_data_size: Number of bytes actually consumed by the new NVM | |
31 | * image | |
32 | * @authenticating: The switch is authenticating the new NVM | |
33 | */ | |
34 | struct tb_switch_nvm { | |
35 | u8 major; | |
36 | u8 minor; | |
37 | int id; | |
38 | struct nvmem_device *active; | |
39 | struct nvmem_device *non_active; | |
40 | void *buf; | |
41 | size_t buf_data_size; | |
42 | bool authenticating; | |
43 | }; | |
44 | ||
f67cf491 | 45 | #define TB_SWITCH_KEY_SIZE 32 |
f0342e75 | 46 | #define TB_SWITCH_MAX_DEPTH 6 |
f67cf491 | 47 | |
a25c8b2f AN |
48 | /** |
49 | * struct tb_switch - a thunderbolt switch | |
bfe778ac MW |
50 | * @dev: Device for the switch |
51 | * @config: Switch configuration | |
52 | * @ports: Ports in this switch | |
3e136768 MW |
53 | * @dma_port: If the switch has port supporting DMA configuration based |
54 | * mailbox this will hold the pointer to that (%NULL | |
e6b245cc MW |
55 | * otherwise). If set it also means the switch has |
56 | * upgradeable NVM. | |
bfe778ac MW |
57 | * @tb: Pointer to the domain the switch belongs to |
58 | * @uid: Unique ID of the switch | |
59 | * @uuid: UUID of the switch (or %NULL if not supported) | |
60 | * @vendor: Vendor ID of the switch | |
61 | * @device: Device ID of the switch | |
72ee3390 MW |
62 | * @vendor_name: Name of the vendor (or %NULL if not known) |
63 | * @device_name: Name of the device (or %NULL if not known) | |
2c3c4197 | 64 | * @generation: Switch Thunderbolt generation |
bfe778ac | 65 | * @cap_plug_events: Offset to the plug events capability (%0 if not found) |
a9be5582 | 66 | * @cap_lc: Offset to the link controller capability (%0 if not found) |
bfe778ac MW |
67 | * @is_unplugged: The switch is going away |
68 | * @drom: DROM of the switch (%NULL if not found) | |
e6b245cc MW |
69 | * @nvm: Pointer to the NVM if the switch has one (%NULL otherwise) |
70 | * @no_nvm_upgrade: Prevent NVM upgrade of this switch | |
71 | * @safe_mode: The switch is in safe-mode | |
14862ee3 | 72 | * @boot: Whether the switch was already authorized on boot or not |
2d8ff0b5 | 73 | * @rpm: The switch supports runtime PM |
f67cf491 | 74 | * @authorized: Whether the switch is authorized by user or policy |
f67cf491 MW |
75 | * @security_level: Switch supported security level |
76 | * @key: Contains the key used to challenge the device or %NULL if not | |
77 | * supported. Size of the key is %TB_SWITCH_KEY_SIZE. | |
78 | * @connection_id: Connection ID used with ICM messaging | |
79 | * @connection_key: Connection key used with ICM messaging | |
80 | * @link: Root switch link this switch is connected (ICM only) | |
81 | * @depth: Depth in the chain this switch is connected (ICM only) | |
82 | * | |
83 | * When the switch is being added or removed to the domain (other | |
09f11b6c | 84 | * switches) you need to have domain lock held. |
a25c8b2f AN |
85 | */ |
86 | struct tb_switch { | |
bfe778ac | 87 | struct device dev; |
a25c8b2f AN |
88 | struct tb_regs_switch_header config; |
89 | struct tb_port *ports; | |
3e136768 | 90 | struct tb_dma_port *dma_port; |
a25c8b2f | 91 | struct tb *tb; |
c90553b3 | 92 | u64 uid; |
7c39ffe7 | 93 | uuid_t *uuid; |
bfe778ac MW |
94 | u16 vendor; |
95 | u16 device; | |
72ee3390 MW |
96 | const char *vendor_name; |
97 | const char *device_name; | |
2c3c4197 | 98 | unsigned int generation; |
bfe778ac | 99 | int cap_plug_events; |
a9be5582 | 100 | int cap_lc; |
bfe778ac | 101 | bool is_unplugged; |
cd22e73b | 102 | u8 *drom; |
e6b245cc MW |
103 | struct tb_switch_nvm *nvm; |
104 | bool no_nvm_upgrade; | |
105 | bool safe_mode; | |
14862ee3 | 106 | bool boot; |
2d8ff0b5 | 107 | bool rpm; |
f67cf491 | 108 | unsigned int authorized; |
f67cf491 MW |
109 | enum tb_security_level security_level; |
110 | u8 *key; | |
111 | u8 connection_id; | |
112 | u8 connection_key; | |
113 | u8 link; | |
114 | u8 depth; | |
a25c8b2f AN |
115 | }; |
116 | ||
117 | /** | |
118 | * struct tb_port - a thunderbolt port, part of a tb_switch | |
d1ff7024 MW |
119 | * @config: Cached port configuration read from registers |
120 | * @sw: Switch the port belongs to | |
121 | * @remote: Remote port (%NULL if not connected) | |
122 | * @xdomain: Remote host (%NULL if not connected) | |
123 | * @cap_phy: Offset, zero if not found | |
56183c88 | 124 | * @cap_adap: Offset of the adapter specific capability (%0 if not present) |
d1ff7024 MW |
125 | * @port: Port number on switch |
126 | * @disabled: Disabled by eeprom | |
127 | * @dual_link_port: If the switch is connected using two ports, points | |
128 | * to the other port. | |
129 | * @link_nr: Is this primary or secondary port on the dual_link. | |
0b2863ac MW |
130 | * @in_hopids: Currently allocated input HopIDs |
131 | * @out_hopids: Currently allocated output HopIDs | |
a25c8b2f AN |
132 | */ |
133 | struct tb_port { | |
134 | struct tb_regs_port_header config; | |
135 | struct tb_switch *sw; | |
d1ff7024 MW |
136 | struct tb_port *remote; |
137 | struct tb_xdomain *xdomain; | |
138 | int cap_phy; | |
56183c88 | 139 | int cap_adap; |
d1ff7024 MW |
140 | u8 port; |
141 | bool disabled; | |
cd22e73b AN |
142 | struct tb_port *dual_link_port; |
143 | u8 link_nr:1; | |
0b2863ac MW |
144 | struct ida in_hopids; |
145 | struct ida out_hopids; | |
a25c8b2f AN |
146 | }; |
147 | ||
520b6702 AN |
148 | /** |
149 | * struct tb_path_hop - routing information for a tb_path | |
8c7acaaf MW |
150 | * @in_port: Ingress port of a switch |
151 | * @out_port: Egress port of a switch where the packet is routed out | |
152 | * (must be on the same switch than @in_port) | |
153 | * @in_hop_index: HopID where the path configuration entry is placed in | |
154 | * the path config space of @in_port. | |
155 | * @in_counter_index: Used counter index (not used in the driver | |
156 | * currently, %-1 to disable) | |
157 | * @next_hop_index: HopID of the packet when it is routed out from @out_port | |
0414bec5 MW |
158 | * @initial_credits: Number of initial flow control credits allocated for |
159 | * the path | |
520b6702 AN |
160 | * |
161 | * Hop configuration is always done on the IN port of a switch. | |
162 | * in_port and out_port have to be on the same switch. Packets arriving on | |
163 | * in_port with "hop" = in_hop_index will get routed to through out_port. The | |
8c7acaaf MW |
164 | * next hop to take (on out_port->remote) is determined by |
165 | * next_hop_index. When routing packet to another switch (out->remote is | |
166 | * set) the @next_hop_index must match the @in_hop_index of that next | |
167 | * hop to make routing possible. | |
520b6702 AN |
168 | * |
169 | * in_counter_index is the index of a counter (in TB_CFG_COUNTERS) on the in | |
170 | * port. | |
171 | */ | |
172 | struct tb_path_hop { | |
173 | struct tb_port *in_port; | |
174 | struct tb_port *out_port; | |
175 | int in_hop_index; | |
8c7acaaf | 176 | int in_counter_index; |
520b6702 | 177 | int next_hop_index; |
0414bec5 | 178 | unsigned int initial_credits; |
520b6702 AN |
179 | }; |
180 | ||
181 | /** | |
182 | * enum tb_path_port - path options mask | |
8c7acaaf MW |
183 | * @TB_PATH_NONE: Do not activate on any hop on path |
184 | * @TB_PATH_SOURCE: Activate on the first hop (out of src) | |
185 | * @TB_PATH_INTERNAL: Activate on the intermediate hops (not the first/last) | |
186 | * @TB_PATH_DESTINATION: Activate on the last hop (into dst) | |
187 | * @TB_PATH_ALL: Activate on all hops on the path | |
520b6702 AN |
188 | */ |
189 | enum tb_path_port { | |
190 | TB_PATH_NONE = 0, | |
8c7acaaf MW |
191 | TB_PATH_SOURCE = 1, |
192 | TB_PATH_INTERNAL = 2, | |
193 | TB_PATH_DESTINATION = 4, | |
520b6702 AN |
194 | TB_PATH_ALL = 7, |
195 | }; | |
196 | ||
197 | /** | |
198 | * struct tb_path - a unidirectional path between two ports | |
8c7acaaf MW |
199 | * @tb: Pointer to the domain structure |
200 | * @name: Name of the path (used for debugging) | |
201 | * @nfc_credits: Number of non flow controlled credits allocated for the path | |
202 | * @ingress_shared_buffer: Shared buffering used for ingress ports on the path | |
203 | * @egress_shared_buffer: Shared buffering used for egress ports on the path | |
204 | * @ingress_fc_enable: Flow control for ingress ports on the path | |
205 | * @egress_fc_enable: Flow control for egress ports on the path | |
206 | * @priority: Priority group if the path | |
207 | * @weight: Weight of the path inside the priority group | |
208 | * @drop_packages: Drop packages from queue tail or head | |
209 | * @activated: Is the path active | |
210 | * @hops: Path hops | |
211 | * @path_length: How many hops the path uses | |
520b6702 | 212 | * |
8c7acaaf MW |
213 | * A path consists of a number of hops (see &struct tb_path_hop). To |
214 | * establish a PCIe tunnel two paths have to be created between the two | |
215 | * PCIe ports. | |
520b6702 AN |
216 | */ |
217 | struct tb_path { | |
218 | struct tb *tb; | |
8c7acaaf MW |
219 | const char *name; |
220 | int nfc_credits; | |
520b6702 AN |
221 | enum tb_path_port ingress_shared_buffer; |
222 | enum tb_path_port egress_shared_buffer; | |
223 | enum tb_path_port ingress_fc_enable; | |
224 | enum tb_path_port egress_fc_enable; | |
225 | ||
226 | int priority:3; | |
227 | int weight:4; | |
228 | bool drop_packages; | |
229 | bool activated; | |
230 | struct tb_path_hop *hops; | |
8c7acaaf | 231 | int path_length; |
520b6702 AN |
232 | }; |
233 | ||
0b2863ac MW |
234 | /* HopIDs 0-7 are reserved by the Thunderbolt protocol */ |
235 | #define TB_PATH_MIN_HOPID 8 | |
0414bec5 | 236 | #define TB_PATH_MAX_HOPS 7 |
0b2863ac | 237 | |
9d3cce0b MW |
238 | /** |
239 | * struct tb_cm_ops - Connection manager specific operations vector | |
f67cf491 MW |
240 | * @driver_ready: Called right after control channel is started. Used by |
241 | * ICM to send driver ready message to the firmware. | |
9d3cce0b MW |
242 | * @start: Starts the domain |
243 | * @stop: Stops the domain | |
244 | * @suspend_noirq: Connection manager specific suspend_noirq | |
245 | * @resume_noirq: Connection manager specific resume_noirq | |
f67cf491 MW |
246 | * @suspend: Connection manager specific suspend |
247 | * @complete: Connection manager specific complete | |
2d8ff0b5 MW |
248 | * @runtime_suspend: Connection manager specific runtime_suspend |
249 | * @runtime_resume: Connection manager specific runtime_resume | |
81a54b5e | 250 | * @handle_event: Handle thunderbolt event |
9aaa3b8b MW |
251 | * @get_boot_acl: Get boot ACL list |
252 | * @set_boot_acl: Set boot ACL list | |
f67cf491 MW |
253 | * @approve_switch: Approve switch |
254 | * @add_switch_key: Add key to switch | |
255 | * @challenge_switch_key: Challenge switch using key | |
e6b245cc | 256 | * @disconnect_pcie_paths: Disconnects PCIe paths before NVM update |
d1ff7024 MW |
257 | * @approve_xdomain_paths: Approve (establish) XDomain DMA paths |
258 | * @disconnect_xdomain_paths: Disconnect XDomain DMA paths | |
9d3cce0b MW |
259 | */ |
260 | struct tb_cm_ops { | |
f67cf491 | 261 | int (*driver_ready)(struct tb *tb); |
9d3cce0b MW |
262 | int (*start)(struct tb *tb); |
263 | void (*stop)(struct tb *tb); | |
264 | int (*suspend_noirq)(struct tb *tb); | |
265 | int (*resume_noirq)(struct tb *tb); | |
f67cf491 MW |
266 | int (*suspend)(struct tb *tb); |
267 | void (*complete)(struct tb *tb); | |
2d8ff0b5 MW |
268 | int (*runtime_suspend)(struct tb *tb); |
269 | int (*runtime_resume)(struct tb *tb); | |
81a54b5e MW |
270 | void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type, |
271 | const void *buf, size_t size); | |
9aaa3b8b MW |
272 | int (*get_boot_acl)(struct tb *tb, uuid_t *uuids, size_t nuuids); |
273 | int (*set_boot_acl)(struct tb *tb, const uuid_t *uuids, size_t nuuids); | |
f67cf491 MW |
274 | int (*approve_switch)(struct tb *tb, struct tb_switch *sw); |
275 | int (*add_switch_key)(struct tb *tb, struct tb_switch *sw); | |
276 | int (*challenge_switch_key)(struct tb *tb, struct tb_switch *sw, | |
277 | const u8 *challenge, u8 *response); | |
e6b245cc | 278 | int (*disconnect_pcie_paths)(struct tb *tb); |
d1ff7024 MW |
279 | int (*approve_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd); |
280 | int (*disconnect_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd); | |
9d3cce0b | 281 | }; |
520b6702 | 282 | |
9d3cce0b MW |
283 | static inline void *tb_priv(struct tb *tb) |
284 | { | |
285 | return (void *)tb->privdata; | |
286 | } | |
287 | ||
2d8ff0b5 MW |
288 | #define TB_AUTOSUSPEND_DELAY 15000 /* ms */ |
289 | ||
a25c8b2f AN |
290 | /* helper functions & macros */ |
291 | ||
292 | /** | |
293 | * tb_upstream_port() - return the upstream port of a switch | |
294 | * | |
295 | * Every switch has an upstream port (for the root switch it is the NHI). | |
296 | * | |
297 | * During switch alloc/init tb_upstream_port()->remote may be NULL, even for | |
298 | * non root switches (on the NHI port remote is always NULL). | |
299 | * | |
300 | * Return: Returns the upstream port of the switch. | |
301 | */ | |
302 | static inline struct tb_port *tb_upstream_port(struct tb_switch *sw) | |
303 | { | |
304 | return &sw->ports[sw->config.upstream_port_number]; | |
305 | } | |
306 | ||
dfe40ca4 MW |
307 | /** |
308 | * tb_is_upstream_port() - Is the port upstream facing | |
309 | * @port: Port to check | |
310 | * | |
311 | * Returns true if @port is upstream facing port. In case of dual link | |
312 | * ports both return true. | |
313 | */ | |
314 | static inline bool tb_is_upstream_port(const struct tb_port *port) | |
315 | { | |
316 | const struct tb_port *upstream_port = tb_upstream_port(port->sw); | |
317 | return port == upstream_port || port->dual_link_port == upstream_port; | |
318 | } | |
319 | ||
a25c8b2f AN |
320 | static inline u64 tb_route(struct tb_switch *sw) |
321 | { | |
322 | return ((u64) sw->config.route_hi) << 32 | sw->config.route_lo; | |
323 | } | |
324 | ||
f67cf491 MW |
325 | static inline struct tb_port *tb_port_at(u64 route, struct tb_switch *sw) |
326 | { | |
327 | u8 port; | |
328 | ||
329 | port = route >> (sw->config.depth * 8); | |
330 | if (WARN_ON(port > sw->config.max_port_number)) | |
331 | return NULL; | |
332 | return &sw->ports[port]; | |
333 | } | |
334 | ||
dfe40ca4 MW |
335 | /** |
336 | * tb_port_has_remote() - Does the port have switch connected downstream | |
337 | * @port: Port to check | |
338 | * | |
339 | * Returns true only when the port is primary port and has remote set. | |
340 | */ | |
341 | static inline bool tb_port_has_remote(const struct tb_port *port) | |
342 | { | |
343 | if (tb_is_upstream_port(port)) | |
344 | return false; | |
345 | if (!port->remote) | |
346 | return false; | |
347 | if (port->dual_link_port && port->link_nr) | |
348 | return false; | |
349 | ||
350 | return true; | |
351 | } | |
352 | ||
344e0643 MW |
353 | static inline bool tb_port_is_null(const struct tb_port *port) |
354 | { | |
355 | return port && port->port && port->config.type == TB_TYPE_PORT; | |
356 | } | |
357 | ||
99cabbb0 MW |
358 | static inline bool tb_port_is_pcie_down(const struct tb_port *port) |
359 | { | |
360 | return port && port->config.type == TB_TYPE_PCIE_DOWN; | |
361 | } | |
362 | ||
0414bec5 MW |
363 | static inline bool tb_port_is_pcie_up(const struct tb_port *port) |
364 | { | |
365 | return port && port->config.type == TB_TYPE_PCIE_UP; | |
366 | } | |
367 | ||
4f807e47 MW |
368 | static inline bool tb_port_is_dpin(const struct tb_port *port) |
369 | { | |
370 | return port && port->config.type == TB_TYPE_DP_HDMI_IN; | |
371 | } | |
372 | ||
373 | static inline bool tb_port_is_dpout(const struct tb_port *port) | |
374 | { | |
375 | return port && port->config.type == TB_TYPE_DP_HDMI_OUT; | |
376 | } | |
377 | ||
a25c8b2f AN |
378 | static inline int tb_sw_read(struct tb_switch *sw, void *buffer, |
379 | enum tb_cfg_space space, u32 offset, u32 length) | |
380 | { | |
4708384f MW |
381 | if (sw->is_unplugged) |
382 | return -ENODEV; | |
a25c8b2f AN |
383 | return tb_cfg_read(sw->tb->ctl, |
384 | buffer, | |
385 | tb_route(sw), | |
386 | 0, | |
387 | space, | |
388 | offset, | |
389 | length); | |
390 | } | |
391 | ||
392 | static inline int tb_sw_write(struct tb_switch *sw, void *buffer, | |
393 | enum tb_cfg_space space, u32 offset, u32 length) | |
394 | { | |
4708384f MW |
395 | if (sw->is_unplugged) |
396 | return -ENODEV; | |
a25c8b2f AN |
397 | return tb_cfg_write(sw->tb->ctl, |
398 | buffer, | |
399 | tb_route(sw), | |
400 | 0, | |
401 | space, | |
402 | offset, | |
403 | length); | |
404 | } | |
405 | ||
406 | static inline int tb_port_read(struct tb_port *port, void *buffer, | |
407 | enum tb_cfg_space space, u32 offset, u32 length) | |
408 | { | |
4708384f MW |
409 | if (port->sw->is_unplugged) |
410 | return -ENODEV; | |
a25c8b2f AN |
411 | return tb_cfg_read(port->sw->tb->ctl, |
412 | buffer, | |
413 | tb_route(port->sw), | |
414 | port->port, | |
415 | space, | |
416 | offset, | |
417 | length); | |
418 | } | |
419 | ||
16a1258a | 420 | static inline int tb_port_write(struct tb_port *port, const void *buffer, |
a25c8b2f AN |
421 | enum tb_cfg_space space, u32 offset, u32 length) |
422 | { | |
4708384f MW |
423 | if (port->sw->is_unplugged) |
424 | return -ENODEV; | |
a25c8b2f AN |
425 | return tb_cfg_write(port->sw->tb->ctl, |
426 | buffer, | |
427 | tb_route(port->sw), | |
428 | port->port, | |
429 | space, | |
430 | offset, | |
431 | length); | |
432 | } | |
433 | ||
434 | #define tb_err(tb, fmt, arg...) dev_err(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
435 | #define tb_WARN(tb, fmt, arg...) dev_WARN(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
436 | #define tb_warn(tb, fmt, arg...) dev_warn(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
437 | #define tb_info(tb, fmt, arg...) dev_info(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
daa5140f | 438 | #define tb_dbg(tb, fmt, arg...) dev_dbg(&(tb)->nhi->pdev->dev, fmt, ## arg) |
a25c8b2f AN |
439 | |
440 | #define __TB_SW_PRINT(level, sw, fmt, arg...) \ | |
441 | do { \ | |
442 | struct tb_switch *__sw = (sw); \ | |
443 | level(__sw->tb, "%llx: " fmt, \ | |
444 | tb_route(__sw), ## arg); \ | |
445 | } while (0) | |
446 | #define tb_sw_WARN(sw, fmt, arg...) __TB_SW_PRINT(tb_WARN, sw, fmt, ##arg) | |
447 | #define tb_sw_warn(sw, fmt, arg...) __TB_SW_PRINT(tb_warn, sw, fmt, ##arg) | |
448 | #define tb_sw_info(sw, fmt, arg...) __TB_SW_PRINT(tb_info, sw, fmt, ##arg) | |
daa5140f | 449 | #define tb_sw_dbg(sw, fmt, arg...) __TB_SW_PRINT(tb_dbg, sw, fmt, ##arg) |
a25c8b2f AN |
450 | |
451 | #define __TB_PORT_PRINT(level, _port, fmt, arg...) \ | |
452 | do { \ | |
453 | struct tb_port *__port = (_port); \ | |
454 | level(__port->sw->tb, "%llx:%x: " fmt, \ | |
455 | tb_route(__port->sw), __port->port, ## arg); \ | |
456 | } while (0) | |
457 | #define tb_port_WARN(port, fmt, arg...) \ | |
458 | __TB_PORT_PRINT(tb_WARN, port, fmt, ##arg) | |
459 | #define tb_port_warn(port, fmt, arg...) \ | |
460 | __TB_PORT_PRINT(tb_warn, port, fmt, ##arg) | |
461 | #define tb_port_info(port, fmt, arg...) \ | |
462 | __TB_PORT_PRINT(tb_info, port, fmt, ##arg) | |
daa5140f MW |
463 | #define tb_port_dbg(port, fmt, arg...) \ |
464 | __TB_PORT_PRINT(tb_dbg, port, fmt, ##arg) | |
a25c8b2f | 465 | |
f67cf491 | 466 | struct tb *icm_probe(struct tb_nhi *nhi); |
9d3cce0b MW |
467 | struct tb *tb_probe(struct tb_nhi *nhi); |
468 | ||
9d3cce0b | 469 | extern struct device_type tb_domain_type; |
bfe778ac | 470 | extern struct device_type tb_switch_type; |
9d3cce0b MW |
471 | |
472 | int tb_domain_init(void); | |
473 | void tb_domain_exit(void); | |
e6b245cc | 474 | void tb_switch_exit(void); |
d1ff7024 MW |
475 | int tb_xdomain_init(void); |
476 | void tb_xdomain_exit(void); | |
a25c8b2f | 477 | |
9d3cce0b MW |
478 | struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize); |
479 | int tb_domain_add(struct tb *tb); | |
480 | void tb_domain_remove(struct tb *tb); | |
481 | int tb_domain_suspend_noirq(struct tb *tb); | |
482 | int tb_domain_resume_noirq(struct tb *tb); | |
f67cf491 MW |
483 | int tb_domain_suspend(struct tb *tb); |
484 | void tb_domain_complete(struct tb *tb); | |
2d8ff0b5 MW |
485 | int tb_domain_runtime_suspend(struct tb *tb); |
486 | int tb_domain_runtime_resume(struct tb *tb); | |
f67cf491 MW |
487 | int tb_domain_approve_switch(struct tb *tb, struct tb_switch *sw); |
488 | int tb_domain_approve_switch_key(struct tb *tb, struct tb_switch *sw); | |
489 | int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw); | |
e6b245cc | 490 | int tb_domain_disconnect_pcie_paths(struct tb *tb); |
d1ff7024 MW |
491 | int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd); |
492 | int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd); | |
493 | int tb_domain_disconnect_all_paths(struct tb *tb); | |
9d3cce0b | 494 | |
559c1e1e MW |
495 | static inline struct tb *tb_domain_get(struct tb *tb) |
496 | { | |
497 | if (tb) | |
498 | get_device(&tb->dev); | |
499 | return tb; | |
500 | } | |
501 | ||
9d3cce0b MW |
502 | static inline void tb_domain_put(struct tb *tb) |
503 | { | |
504 | put_device(&tb->dev); | |
505 | } | |
d6cc51cd | 506 | |
bfe778ac MW |
507 | struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, |
508 | u64 route); | |
e6b245cc MW |
509 | struct tb_switch *tb_switch_alloc_safe_mode(struct tb *tb, |
510 | struct device *parent, u64 route); | |
bfe778ac MW |
511 | int tb_switch_configure(struct tb_switch *sw); |
512 | int tb_switch_add(struct tb_switch *sw); | |
513 | void tb_switch_remove(struct tb_switch *sw); | |
23dd5bb4 AN |
514 | void tb_switch_suspend(struct tb_switch *sw); |
515 | int tb_switch_resume(struct tb_switch *sw); | |
516 | int tb_switch_reset(struct tb *tb, u64 route); | |
aae20bb6 | 517 | void tb_sw_set_unplugged(struct tb_switch *sw); |
f67cf491 MW |
518 | struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, |
519 | u8 depth); | |
7c39ffe7 | 520 | struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid); |
8e9267bb | 521 | struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route); |
f67cf491 | 522 | |
b6b0ea70 MW |
523 | static inline struct tb_switch *tb_switch_get(struct tb_switch *sw) |
524 | { | |
525 | if (sw) | |
526 | get_device(&sw->dev); | |
527 | return sw; | |
528 | } | |
529 | ||
bfe778ac MW |
530 | static inline void tb_switch_put(struct tb_switch *sw) |
531 | { | |
532 | put_device(&sw->dev); | |
533 | } | |
534 | ||
535 | static inline bool tb_is_switch(const struct device *dev) | |
536 | { | |
537 | return dev->type == &tb_switch_type; | |
538 | } | |
539 | ||
540 | static inline struct tb_switch *tb_to_switch(struct device *dev) | |
541 | { | |
542 | if (tb_is_switch(dev)) | |
543 | return container_of(dev, struct tb_switch, dev); | |
544 | return NULL; | |
545 | } | |
546 | ||
0414bec5 MW |
547 | static inline struct tb_switch *tb_switch_parent(struct tb_switch *sw) |
548 | { | |
549 | return tb_to_switch(sw->dev.parent); | |
550 | } | |
551 | ||
8b0110d9 MW |
552 | static inline bool tb_switch_is_lr(const struct tb_switch *sw) |
553 | { | |
554 | return sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE; | |
555 | } | |
556 | ||
557 | static inline bool tb_switch_is_er(const struct tb_switch *sw) | |
558 | { | |
559 | return sw->config.device_id == PCI_DEVICE_ID_INTEL_EAGLE_RIDGE; | |
560 | } | |
561 | ||
99cabbb0 MW |
562 | static inline bool tb_switch_is_cr(const struct tb_switch *sw) |
563 | { | |
564 | switch (sw->config.device_id) { | |
565 | case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_2C: | |
566 | case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C: | |
567 | return true; | |
568 | default: | |
569 | return false; | |
570 | } | |
571 | } | |
572 | ||
573 | static inline bool tb_switch_is_fr(const struct tb_switch *sw) | |
574 | { | |
575 | switch (sw->config.device_id) { | |
576 | case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_BRIDGE: | |
577 | case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE: | |
578 | return true; | |
579 | default: | |
580 | return false; | |
581 | } | |
582 | } | |
583 | ||
9da672a4 | 584 | int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged); |
520b6702 AN |
585 | int tb_port_add_nfc_credits(struct tb_port *port, int credits); |
586 | int tb_port_clear_counter(struct tb_port *port, int counter); | |
0b2863ac MW |
587 | int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); |
588 | void tb_port_release_in_hopid(struct tb_port *port, int hopid); | |
589 | int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); | |
590 | void tb_port_release_out_hopid(struct tb_port *port, int hopid); | |
fb19fac1 MW |
591 | struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, |
592 | struct tb_port *prev); | |
9da672a4 | 593 | |
da2da04b MW |
594 | int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec); |
595 | int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap); | |
e78db6f0 | 596 | bool tb_port_is_enabled(struct tb_port *port); |
e2b8785e | 597 | |
0414bec5 | 598 | bool tb_pci_port_is_enabled(struct tb_port *port); |
93f36ade MW |
599 | int tb_pci_port_enable(struct tb_port *port, bool enable); |
600 | ||
4f807e47 MW |
601 | int tb_dp_port_hpd_is_active(struct tb_port *port); |
602 | int tb_dp_port_hpd_clear(struct tb_port *port); | |
603 | int tb_dp_port_set_hops(struct tb_port *port, unsigned int video, | |
604 | unsigned int aux_tx, unsigned int aux_rx); | |
605 | bool tb_dp_port_is_enabled(struct tb_port *port); | |
606 | int tb_dp_port_enable(struct tb_port *port, bool enable); | |
607 | ||
0414bec5 MW |
608 | struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, |
609 | struct tb_port *dst, int dst_hopid, | |
610 | struct tb_port **last, const char *name); | |
8c7acaaf MW |
611 | struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, |
612 | struct tb_port *dst, int dst_hopid, int link_nr, | |
613 | const char *name); | |
520b6702 AN |
614 | void tb_path_free(struct tb_path *path); |
615 | int tb_path_activate(struct tb_path *path); | |
616 | void tb_path_deactivate(struct tb_path *path); | |
617 | bool tb_path_is_invalid(struct tb_path *path); | |
618 | ||
cd22e73b AN |
619 | int tb_drom_read(struct tb_switch *sw); |
620 | int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid); | |
c90553b3 | 621 | |
a9be5582 | 622 | int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid); |
e879a709 MW |
623 | int tb_lc_configure_link(struct tb_switch *sw); |
624 | void tb_lc_unconfigure_link(struct tb_switch *sw); | |
5480dfc2 | 625 | int tb_lc_set_sleep(struct tb_switch *sw); |
a25c8b2f AN |
626 | |
627 | static inline int tb_route_length(u64 route) | |
628 | { | |
629 | return (fls64(route) + TB_ROUTE_SHIFT - 1) / TB_ROUTE_SHIFT; | |
630 | } | |
631 | ||
9da672a4 AN |
632 | /** |
633 | * tb_downstream_route() - get route to downstream switch | |
634 | * | |
635 | * Port must not be the upstream port (otherwise a loop is created). | |
636 | * | |
637 | * Return: Returns a route to the switch behind @port. | |
638 | */ | |
639 | static inline u64 tb_downstream_route(struct tb_port *port) | |
640 | { | |
641 | return tb_route(port->sw) | |
642 | | ((u64) port->port << (port->sw->config.depth * 8)); | |
643 | } | |
644 | ||
d1ff7024 MW |
645 | bool tb_xdomain_handle_request(struct tb *tb, enum tb_cfg_pkg_type type, |
646 | const void *buf, size_t size); | |
647 | struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, | |
648 | u64 route, const uuid_t *local_uuid, | |
649 | const uuid_t *remote_uuid); | |
650 | void tb_xdomain_add(struct tb_xdomain *xd); | |
651 | void tb_xdomain_remove(struct tb_xdomain *xd); | |
652 | struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, | |
653 | u8 depth); | |
654 | ||
d6cc51cd | 655 | #endif |