xref: /freebsd/sys/dev/thunderbolt/tb_debug.c (revision 2ed9833791f28e14843ac813f90cb030e45948dc)
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