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 * 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 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 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 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