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