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