1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 Scott Long
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "opt_thunderbolt.h"
30
31 /* PCIe bridge for Thunderbolt */
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37
38 #include <sys/bus.h>
39 #include <sys/conf.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/malloc.h>
43 #include <sys/queue.h>
44 #include <sys/sbuf.h>
45 #include <sys/sysctl.h>
46 #include <sys/taskqueue.h>
47 #include <sys/gsb_crc32.h>
48 #include <sys/endian.h>
49
50 #include <machine/bus.h>
51 #include <machine/stdarg.h>
52
53 #include <dev/thunderbolt/nhi_reg.h>
54 #include <dev/thunderbolt/nhi_var.h>
55 #include <dev/thunderbolt/tb_reg.h>
56 #include <dev/thunderbolt/tb_var.h>
57 #include <dev/thunderbolt/tbcfg_reg.h>
58 #include <dev/thunderbolt/tb_debug.h>
59
60 tb_string_t nhi_outmailcmd_opmode[] = {
61 { 0x000, "Safe Mode" },
62 { 0x100, "Authentication Mode" },
63 { 0x200, "Endpoint Mode" },
64 { 0x300, "Connection Manager Fully Functional" },
65 { 0, NULL }
66 };
67
68 tb_string_t nhi_frame_pdf[] = {
69 { 0x01, "PDF_READ" },
70 { 0x02, "PDF_WRITE" },
71 { 0x03, "PDF_NOTIFY" },
72 { 0x04, "PDF_NOTIFY_ACK" },
73 { 0x05, "PDF_HOTPLUG" },
74 { 0x06, "PDF_XDOMAIN_REQ" },
75 { 0x07, "PDF_XDOMAIN_RESP" },
76 { 0x0a, "PDF_CM_EVENT" },
77 { 0x0b, "PDF_CM_REQ" },
78 { 0x0c, "PDF_CM_RESP" },
79 { 0, NULL }
80 };
81
82 tb_string_t tb_security_level[] = {
83 { TBSEC_NONE, "None" },
84 { TBSEC_USER, "User" },
85 { TBSEC_SECURE, "Secure Authorization" },
86 { TBSEC_DP, "Display Port" },
87 { TBSEC_UNKNOWN,"Unknown" },
88 { 0, NULL }
89 };
90
91 tb_string_t tb_mbox_connmode[] = {
92 { INMAILCMD_SETMODE_CERT_TB_1ST_DEPTH, "Certified/1st" },
93 { INMAILCMD_SETMODE_ANY_TB_1ST_DEPTH, "Any/1st" },
94 { INMAILCMD_SETMODE_CERT_TB_ANY_DEPTH, "Certified/Any" },
95 { INMAILCMD_SETMODE_ANY_TB_ANY_DEPTH, "Any/Any" },
96 { 0, NULL }
97 };
98
99 tb_string_t tb_device_power[] = {
100 { 0x0, "Self-powered" },
101 { 0x1, "Normal power" },
102 { 0x2, "High power" },
103 { 0x3, "Unknown power draw" },
104 { 0, NULL }
105 };
106
107 tb_string_t tb_notify_code[] = {
108 { 0x03, "DEVCONN" },
109 { 0x04, "DISCONN" },
110 { 0x05, "DPCONN" },
111 { 0x06, "DOMCONN" },
112 { 0x07, "DOMDISCONN" },
113 { 0x08, "DPCHANGE" },
114 { 0x09, "I2C" },
115 { 0x0a, "RTD3" },
116 { 0, NULL }
117 };
118
119 tb_string_t tb_adapter_type[] = {
120 { ADP_CS2_UNSUPPORTED, "Unsupported Adapter" },
121 { ADP_CS2_LANE, "Lane Adapter" },
122 { ADP_CS2_HOSTIF, "Host Interface Adapter" },
123 { ADP_CS2_PCIE_DFP, "Downstream PCIe Adapter" },
124 { ADP_CS2_PCIE_UFP, "Upstream PCIe Adapter" },
125 { ADP_CS2_DP_OUT, "DP OUT Adapter" },
126 { ADP_CS2_DP_IN, "DP IN Adapter" },
127 { ADP_CS2_USB3_DFP, "Downstream USB3 Adapter" },
128 { ADP_CS2_USB3_UFP, "Upstream USB3 Adapter" },
129 { 0, NULL }
130 };
131
132 tb_string_t tb_adapter_state[] = {
133 { CAP_LANE_STATE_DISABLE, "Disabled" },
134 { CAP_LANE_STATE_TRAINING, "Training" },
135 { CAP_LANE_STATE_CL0, "CL0" },
136 { CAP_LANE_STATE_TXCL0, "TX CL0s" },
137 { CAP_LANE_STATE_RXCL0, "RX CL0s" },
138 { CAP_LANE_STATE_CL1, "CL1" },
139 { CAP_LANE_STATE_CL2, "CL2" },
140 { CAP_LANE_STATE_CLD, "CLd" },
141 { 0, NULL }
142 };
143
144 tb_string_t tb_notify_event[] = {
145 { TB_CFG_ERR_CONN, "Connection error" },
146 { TB_CFG_ERR_LINK, "Link error" },
147 { TB_CFG_ERR_ADDR, "Addressing error" },
148 { TB_CFG_ERR_ADP, "Invalid adapter" },
149 { TB_CFG_ERR_ENUM, "Enumeration error" },
150 { TB_CFG_ERR_NUA, "Adapter not enumerated" },
151 { TB_CFG_ERR_LEN, "Invalid request length" },
152 { TB_CFG_ERR_HEC, "Invalid packet header" },
153 { TB_CFG_ERR_FC, "Flow control error" },
154 { TB_CFG_ERR_PLUG, "Hot plug error" },
155 { TB_CFG_ERR_LOCK, "Adapter locked" },
156 { TB_CFG_HP_ACK, "Hotplug acknowledgement" },
157 { TB_CFG_DP_BW, "Display port bandwidth change" },
158 { 0, NULL }
159 };
160
161 const char *
tb_get_string(uintmax_t key,tb_string_t * table)162 tb_get_string(uintmax_t key, tb_string_t *table)
163 {
164
165 if (table == NULL)
166 return ("<null>");
167
168 while (table->value != NULL) {
169 if (table->key == key)
170 return (table->value);
171 table++;
172 }
173
174 return ("<unknown>");
175 }
176
177 static struct tb_debug_string {
178 char *name;
179 int flag;
180 } tb_debug_strings[] = {
181 {"info", DBG_INFO},
182 {"init", DBG_INIT},
183 {"info", DBG_INFO},
184 {"rxq", DBG_RXQ},
185 {"txq", DBG_TXQ},
186 {"intr", DBG_INTR},
187 {"tb", DBG_TB},
188 {"mbox", DBG_MBOX},
189 {"bridge", DBG_BRIDGE},
190 {"cfg", DBG_CFG},
191 {"router", DBG_ROUTER},
192 {"port", DBG_PORT},
193 {"hcm", DBG_HCM},
194 {"extra", DBG_EXTRA},
195 {"noisy", DBG_NOISY},
196 {"full", DBG_FULL}
197 };
198
199 enum tb_debug_level_combiner {
200 COMB_NONE,
201 COMB_ADD,
202 COMB_SUB
203 };
204
205 int
tb_debug_sysctl(SYSCTL_HANDLER_ARGS)206 tb_debug_sysctl(SYSCTL_HANDLER_ARGS)
207 {
208 struct sbuf *sbuf;
209 #if defined (THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0)
210 struct tb_debug_string *string;
211 char *buffer;
212 size_t sz;
213 u_int *debug;
214 int i, len;
215 #endif
216 int error;
217
218 error = sysctl_wire_old_buffer(req, 0);
219 if (error != 0)
220 return (error);
221
222 sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
223
224 #if defined (THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0)
225 debug = (u_int *)arg1;
226
227 sbuf_printf(sbuf, "%#x", *debug);
228
229 sz = sizeof(tb_debug_strings) / sizeof(tb_debug_strings[0]);
230 for (i = 0; i < sz; i++) {
231 string = &tb_debug_strings[i];
232 if (*debug & string->flag)
233 sbuf_printf(sbuf, ",%s", string->name);
234 }
235
236 error = sbuf_finish(sbuf);
237 sbuf_delete(sbuf);
238
239 if (error || req->newptr == NULL)
240 return (error);
241
242 len = req->newlen - req->newidx;
243 if (len == 0)
244 return (0);
245
246 buffer = malloc(len, M_THUNDERBOLT, M_ZERO|M_WAITOK);
247 error = SYSCTL_IN(req, buffer, len);
248
249 tb_parse_debug(debug, buffer);
250
251 free(buffer, M_THUNDERBOLT);
252 #else
253 sbuf_printf(sbuf, "debugging unavailable");
254 error = sbuf_finish(sbuf);
255 sbuf_delete(sbuf);
256 #endif
257
258 return (error);
259 }
260
261 void
tb_parse_debug(u_int * debug,char * list)262 tb_parse_debug(u_int *debug, char *list)
263 {
264 struct tb_debug_string *string;
265 enum tb_debug_level_combiner op;
266 char *token, *endtoken;
267 size_t sz;
268 int flags, i;
269
270 if (list == NULL || *list == '\0')
271 return;
272
273 if (*list == '+') {
274 op = COMB_ADD;
275 list++;
276 } else if (*list == '-') {
277 op = COMB_SUB;
278 list++;
279 } else
280 op = COMB_NONE;
281 if (*list == '\0')
282 return;
283
284 flags = 0;
285 sz = sizeof(tb_debug_strings) / sizeof(tb_debug_strings[0]);
286 while ((token = strsep(&list, ":,")) != NULL) {
287
288 /* Handle integer flags */
289 flags |= strtol(token, &endtoken, 0);
290 if (token != endtoken)
291 continue;
292
293 /* Handle text flags */
294 for (i = 0; i < sz; i++) {
295 string = &tb_debug_strings[i];
296 if (strcasecmp(token, string->name) == 0) {
297 flags |= string->flag;
298 break;
299 }
300 }
301 }
302
303 switch (op) {
304 case COMB_NONE:
305 *debug = flags;
306 break;
307 case COMB_ADD:
308 *debug |= flags;
309 break;
310 case COMB_SUB:
311 *debug &= (~flags);
312 break;
313 }
314 return;
315 }
316
317 void
tbdbg_dprintf(device_t dev,u_int debug,u_int val,const char * fmt,...)318 tbdbg_dprintf(device_t dev, u_int debug, u_int val, const char *fmt, ...)
319 {
320 #if defined(THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0)
321 va_list ap;
322 u_int lvl, dbg;
323
324 lvl = debug & 0xc0000000;
325 dbg = debug & 0x3fffffff;
326 va_start(ap, fmt);
327 if ((lvl >= (val & 0xc0000000)) &&
328 ((dbg & (val & 0x3fffffff)) != 0)) {
329 device_printf(dev, "");
330 vprintf(fmt, ap);
331 }
332 va_end(ap);
333 #endif
334 }
335