blob: 661f1828527a66881397b07664d94e5201c6d995 [file] [log] [blame]
Andreas Noeverd6cc51c2014-06-03 22:04:00 +02001/*
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
Andreas Noevera25c8b22014-06-03 22:04:02 +020010#include <linux/pci.h>
11
12#include "tb_regs.h"
Andreas Noeverd6cc51c2014-06-03 22:04:00 +020013#include "ctl.h"
14
15/**
Andreas Noevera25c8b22014-06-03 22:04:02 +020016 * struct tb_switch - a thunderbolt switch
17 */
18struct tb_switch {
19 struct tb_regs_switch_header config;
20 struct tb_port *ports;
21 struct tb *tb;
Andreas Noeverca389f72014-06-03 22:04:04 +020022 int cap_plug_events; /* offset, zero if not found */
Andreas Noever053596d2014-06-03 22:04:06 +020023 bool is_unplugged; /* unplugged, will go away */
Andreas Noevera25c8b22014-06-03 22:04:02 +020024};
25
26/**
27 * struct tb_port - a thunderbolt port, part of a tb_switch
28 */
29struct 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 */
Andreas Noever9da672a2014-06-03 22:04:05 +020033 int cap_phy; /* offset, zero if not found */
Andreas Noevera25c8b22014-06-03 22:04:02 +020034 u8 port; /* port number on switch */
35};
36
37/**
Andreas Noeverd6cc51c2014-06-03 22:04:00 +020038 * struct tb - main thunderbolt bus structure
39 */
40struct 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 */
Andreas Noevera25c8b22014-06-03 22:04:02 +020048 struct tb_switch *root_switch;
Andreas Noeverd6cc51c2014-06-03 22:04:00 +020049 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
Andreas Noevera25c8b22014-06-03 22:04:02 +020058/* 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 */
70static inline struct tb_port *tb_upstream_port(struct tb_switch *sw)
71{
72 return &sw->ports[sw->config.upstream_port_number];
73}
74
75static inline u64 tb_route(struct tb_switch *sw)
76{
77 return ((u64) sw->config.route_hi) << 32 | sw->config.route_lo;
78}
79
80static 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
92static 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
104static 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
116static 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
Andreas Noeverd6cc51c2014-06-03 22:04:00 +0200159struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi);
160void thunderbolt_shutdown_and_free(struct tb *tb);
161
Andreas Noevera25c8b22014-06-03 22:04:02 +0200162struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route);
163void tb_switch_free(struct tb_switch *sw);
Andreas Noever053596d2014-06-03 22:04:06 +0200164void tb_sw_set_unpplugged(struct tb_switch *sw);
165struct tb_switch *get_switch_at_route(struct tb_switch *sw, u64 route);
Andreas Noevera25c8b22014-06-03 22:04:02 +0200166
Andreas Noever9da672a2014-06-03 22:04:05 +0200167int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
168
Andreas Noevere2b87852014-06-03 22:04:03 +0200169int tb_find_cap(struct tb_port *port, enum tb_cfg_space space, u32 value);
170
Andreas Noevera25c8b22014-06-03 22:04:02 +0200171
172static inline int tb_route_length(u64 route)
173{
174 return (fls64(route) + TB_ROUTE_SHIFT - 1) / TB_ROUTE_SHIFT;
175}
176
177static inline bool tb_is_upstream_port(struct tb_port *port)
178{
179 return port == tb_upstream_port(port->sw);
180}
181
Andreas Noever9da672a2014-06-03 22:04:05 +0200182/**
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 */
189static 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
Andreas Noeverd6cc51c2014-06-03 22:04:00 +0200195#endif