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