]>
Commit | Line | Data |
---|---|---|
d6cc51cd AN |
1 | /* |
2 | * Thunderbolt Cactus Ridge driver - bus logic (NHI independent) | |
3 | * | |
4 | * Copyright (c) 2014 Andreas Noever <[email protected]> | |
5 | */ | |
6 | ||
7 | #ifndef TB_H_ | |
8 | #define TB_H_ | |
9 | ||
a25c8b2f AN |
10 | #include <linux/pci.h> |
11 | ||
12 | #include "tb_regs.h" | |
d6cc51cd AN |
13 | #include "ctl.h" |
14 | ||
a25c8b2f AN |
15 | /** |
16 | * struct tb_switch - a thunderbolt switch | |
17 | */ | |
18 | struct tb_switch { | |
19 | struct tb_regs_switch_header config; | |
20 | struct tb_port *ports; | |
21 | struct tb *tb; | |
ca389f71 | 22 | int cap_plug_events; /* offset, zero if not found */ |
053596d9 | 23 | bool is_unplugged; /* unplugged, will go away */ |
a25c8b2f AN |
24 | }; |
25 | ||
26 | /** | |
27 | * struct tb_port - a thunderbolt port, part of a tb_switch | |
28 | */ | |
29 | struct tb_port { | |
30 | struct tb_regs_port_header config; | |
31 | struct tb_switch *sw; | |
32 | struct tb_port *remote; /* remote port, NULL if not connected */ | |
9da672a4 | 33 | int cap_phy; /* offset, zero if not found */ |
a25c8b2f AN |
34 | u8 port; /* port number on switch */ |
35 | }; | |
36 | ||
d6cc51cd AN |
37 | /** |
38 | * struct tb - main thunderbolt bus structure | |
39 | */ | |
40 | struct tb { | |
41 | struct mutex lock; /* | |
42 | * Big lock. Must be held when accessing cfg or | |
43 | * any struct tb_switch / struct tb_port. | |
44 | */ | |
45 | struct tb_nhi *nhi; | |
46 | struct tb_ctl *ctl; | |
47 | struct workqueue_struct *wq; /* ordered workqueue for plug events */ | |
a25c8b2f | 48 | struct tb_switch *root_switch; |
d6cc51cd AN |
49 | bool hotplug_active; /* |
50 | * tb_handle_hotplug will stop progressing plug | |
51 | * events and exit if this is not set (it needs to | |
52 | * acquire the lock one more time). Used to drain | |
53 | * wq after cfg has been paused. | |
54 | */ | |
55 | ||
56 | }; | |
57 | ||
a25c8b2f AN |
58 | /* helper functions & macros */ |
59 | ||
60 | /** | |
61 | * tb_upstream_port() - return the upstream port of a switch | |
62 | * | |
63 | * Every switch has an upstream port (for the root switch it is the NHI). | |
64 | * | |
65 | * During switch alloc/init tb_upstream_port()->remote may be NULL, even for | |
66 | * non root switches (on the NHI port remote is always NULL). | |
67 | * | |
68 | * Return: Returns the upstream port of the switch. | |
69 | */ | |
70 | static inline struct tb_port *tb_upstream_port(struct tb_switch *sw) | |
71 | { | |
72 | return &sw->ports[sw->config.upstream_port_number]; | |
73 | } | |
74 | ||
75 | static inline u64 tb_route(struct tb_switch *sw) | |
76 | { | |
77 | return ((u64) sw->config.route_hi) << 32 | sw->config.route_lo; | |
78 | } | |
79 | ||
80 | static inline int tb_sw_read(struct tb_switch *sw, void *buffer, | |
81 | enum tb_cfg_space space, u32 offset, u32 length) | |
82 | { | |
83 | return tb_cfg_read(sw->tb->ctl, | |
84 | buffer, | |
85 | tb_route(sw), | |
86 | 0, | |
87 | space, | |
88 | offset, | |
89 | length); | |
90 | } | |
91 | ||
92 | static inline int tb_sw_write(struct tb_switch *sw, void *buffer, | |
93 | enum tb_cfg_space space, u32 offset, u32 length) | |
94 | { | |
95 | return tb_cfg_write(sw->tb->ctl, | |
96 | buffer, | |
97 | tb_route(sw), | |
98 | 0, | |
99 | space, | |
100 | offset, | |
101 | length); | |
102 | } | |
103 | ||
104 | static inline int tb_port_read(struct tb_port *port, void *buffer, | |
105 | enum tb_cfg_space space, u32 offset, u32 length) | |
106 | { | |
107 | return tb_cfg_read(port->sw->tb->ctl, | |
108 | buffer, | |
109 | tb_route(port->sw), | |
110 | port->port, | |
111 | space, | |
112 | offset, | |
113 | length); | |
114 | } | |
115 | ||
116 | static inline int tb_port_write(struct tb_port *port, void *buffer, | |
117 | enum tb_cfg_space space, u32 offset, u32 length) | |
118 | { | |
119 | return tb_cfg_write(port->sw->tb->ctl, | |
120 | buffer, | |
121 | tb_route(port->sw), | |
122 | port->port, | |
123 | space, | |
124 | offset, | |
125 | length); | |
126 | } | |
127 | ||
128 | #define tb_err(tb, fmt, arg...) dev_err(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
129 | #define tb_WARN(tb, fmt, arg...) dev_WARN(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
130 | #define tb_warn(tb, fmt, arg...) dev_warn(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
131 | #define tb_info(tb, fmt, arg...) dev_info(&(tb)->nhi->pdev->dev, fmt, ## arg) | |
132 | ||
133 | ||
134 | #define __TB_SW_PRINT(level, sw, fmt, arg...) \ | |
135 | do { \ | |
136 | struct tb_switch *__sw = (sw); \ | |
137 | level(__sw->tb, "%llx: " fmt, \ | |
138 | tb_route(__sw), ## arg); \ | |
139 | } while (0) | |
140 | #define tb_sw_WARN(sw, fmt, arg...) __TB_SW_PRINT(tb_WARN, sw, fmt, ##arg) | |
141 | #define tb_sw_warn(sw, fmt, arg...) __TB_SW_PRINT(tb_warn, sw, fmt, ##arg) | |
142 | #define tb_sw_info(sw, fmt, arg...) __TB_SW_PRINT(tb_info, sw, fmt, ##arg) | |
143 | ||
144 | ||
145 | #define __TB_PORT_PRINT(level, _port, fmt, arg...) \ | |
146 | do { \ | |
147 | struct tb_port *__port = (_port); \ | |
148 | level(__port->sw->tb, "%llx:%x: " fmt, \ | |
149 | tb_route(__port->sw), __port->port, ## arg); \ | |
150 | } while (0) | |
151 | #define tb_port_WARN(port, fmt, arg...) \ | |
152 | __TB_PORT_PRINT(tb_WARN, port, fmt, ##arg) | |
153 | #define tb_port_warn(port, fmt, arg...) \ | |
154 | __TB_PORT_PRINT(tb_warn, port, fmt, ##arg) | |
155 | #define tb_port_info(port, fmt, arg...) \ | |
156 | __TB_PORT_PRINT(tb_info, port, fmt, ##arg) | |
157 | ||
158 | ||
d6cc51cd AN |
159 | struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi); |
160 | void thunderbolt_shutdown_and_free(struct tb *tb); | |
161 | ||
a25c8b2f AN |
162 | struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route); |
163 | void tb_switch_free(struct tb_switch *sw); | |
053596d9 AN |
164 | void tb_sw_set_unpplugged(struct tb_switch *sw); |
165 | struct tb_switch *get_switch_at_route(struct tb_switch *sw, u64 route); | |
a25c8b2f | 166 | |
9da672a4 AN |
167 | int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged); |
168 | ||
e2b8785e AN |
169 | int tb_find_cap(struct tb_port *port, enum tb_cfg_space space, u32 value); |
170 | ||
a25c8b2f AN |
171 | |
172 | static inline int tb_route_length(u64 route) | |
173 | { | |
174 | return (fls64(route) + TB_ROUTE_SHIFT - 1) / TB_ROUTE_SHIFT; | |
175 | } | |
176 | ||
177 | static inline bool tb_is_upstream_port(struct tb_port *port) | |
178 | { | |
179 | return port == tb_upstream_port(port->sw); | |
180 | } | |
181 | ||
9da672a4 AN |
182 | /** |
183 | * tb_downstream_route() - get route to downstream switch | |
184 | * | |
185 | * Port must not be the upstream port (otherwise a loop is created). | |
186 | * | |
187 | * Return: Returns a route to the switch behind @port. | |
188 | */ | |
189 | static inline u64 tb_downstream_route(struct tb_port *port) | |
190 | { | |
191 | return tb_route(port->sw) | |
192 | | ((u64) port->port << (port->sw->config.depth * 8)); | |
193 | } | |
194 | ||
d6cc51cd | 195 | #endif |