diff options
Diffstat (limited to 'sys/dev/thunderbolt/tb_debug.c')
-rw-r--r-- | sys/dev/thunderbolt/tb_debug.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/sys/dev/thunderbolt/tb_debug.c b/sys/dev/thunderbolt/tb_debug.c new file mode 100644 index 000000000000..f455ee72e9f6 --- /dev/null +++ b/sys/dev/thunderbolt/tb_debug.c @@ -0,0 +1,334 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Scott Long + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_thunderbolt.h" + +/* PCIe bridge for Thunderbolt */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> + +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/sbuf.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> +#include <sys/gsb_crc32.h> +#include <sys/endian.h> + +#include <machine/bus.h> +#include <machine/stdarg.h> + +#include <dev/thunderbolt/nhi_reg.h> +#include <dev/thunderbolt/nhi_var.h> +#include <dev/thunderbolt/tb_reg.h> +#include <dev/thunderbolt/tb_var.h> +#include <dev/thunderbolt/tbcfg_reg.h> +#include <dev/thunderbolt/tb_debug.h> + +tb_string_t nhi_outmailcmd_opmode[] = { + { 0x000, "Safe Mode" }, + { 0x100, "Authentication Mode" }, + { 0x200, "Endpoint Mode" }, + { 0x300, "Connection Manager Fully Functional" }, + { 0, NULL } +}; + +tb_string_t nhi_frame_pdf[] = { + { 0x01, "PDF_READ" }, + { 0x02, "PDF_WRITE" }, + { 0x03, "PDF_NOTIFY" }, + { 0x04, "PDF_NOTIFY_ACK" }, + { 0x05, "PDF_HOTPLUG" }, + { 0x06, "PDF_XDOMAIN_REQ" }, + { 0x07, "PDF_XDOMAIN_RESP" }, + { 0x0a, "PDF_CM_EVENT" }, + { 0x0b, "PDF_CM_REQ" }, + { 0x0c, "PDF_CM_RESP" }, + { 0, NULL } +}; + +tb_string_t tb_security_level[] = { + { TBSEC_NONE, "None" }, + { TBSEC_USER, "User" }, + { TBSEC_SECURE, "Secure Authorization" }, + { TBSEC_DP, "Display Port" }, + { TBSEC_UNKNOWN,"Unknown" }, + { 0, NULL } +}; + +tb_string_t tb_mbox_connmode[] = { + { INMAILCMD_SETMODE_CERT_TB_1ST_DEPTH, "Certified/1st" }, + { INMAILCMD_SETMODE_ANY_TB_1ST_DEPTH, "Any/1st" }, + { INMAILCMD_SETMODE_CERT_TB_ANY_DEPTH, "Certified/Any" }, + { INMAILCMD_SETMODE_ANY_TB_ANY_DEPTH, "Any/Any" }, + { 0, NULL } +}; + +tb_string_t tb_device_power[] = { + { 0x0, "Self-powered" }, + { 0x1, "Normal power" }, + { 0x2, "High power" }, + { 0x3, "Unknown power draw" }, + { 0, NULL } +}; + +tb_string_t tb_notify_code[] = { + { 0x03, "DEVCONN" }, + { 0x04, "DISCONN" }, + { 0x05, "DPCONN" }, + { 0x06, "DOMCONN" }, + { 0x07, "DOMDISCONN" }, + { 0x08, "DPCHANGE" }, + { 0x09, "I2C" }, + { 0x0a, "RTD3" }, + { 0, NULL } +}; + +tb_string_t tb_adapter_type[] = { + { ADP_CS2_UNSUPPORTED, "Unsupported Adapter" }, + { ADP_CS2_LANE, "Lane Adapter" }, + { ADP_CS2_HOSTIF, "Host Interface Adapter" }, + { ADP_CS2_PCIE_DFP, "Downstream PCIe Adapter" }, + { ADP_CS2_PCIE_UFP, "Upstream PCIe Adapter" }, + { ADP_CS2_DP_OUT, "DP OUT Adapter" }, + { ADP_CS2_DP_IN, "DP IN Adapter" }, + { ADP_CS2_USB3_DFP, "Downstream USB3 Adapter" }, + { ADP_CS2_USB3_UFP, "Upstream USB3 Adapter" }, + { 0, NULL } +}; + +tb_string_t tb_adapter_state[] = { + { CAP_LANE_STATE_DISABLE, "Disabled" }, + { CAP_LANE_STATE_TRAINING, "Training" }, + { CAP_LANE_STATE_CL0, "CL0" }, + { CAP_LANE_STATE_TXCL0, "TX CL0s" }, + { CAP_LANE_STATE_RXCL0, "RX CL0s" }, + { CAP_LANE_STATE_CL1, "CL1" }, + { CAP_LANE_STATE_CL2, "CL2" }, + { CAP_LANE_STATE_CLD, "CLd" }, + { 0, NULL } +}; + +tb_string_t tb_notify_event[] = { + { TB_CFG_ERR_CONN, "Connection error" }, + { TB_CFG_ERR_LINK, "Link error" }, + { TB_CFG_ERR_ADDR, "Addressing error" }, + { TB_CFG_ERR_ADP, "Invalid adapter" }, + { TB_CFG_ERR_ENUM, "Enumeration error" }, + { TB_CFG_ERR_NUA, "Adapter not enumerated" }, + { TB_CFG_ERR_LEN, "Invalid request length" }, + { TB_CFG_ERR_HEC, "Invalid packet header" }, + { TB_CFG_ERR_FC, "Flow control error" }, + { TB_CFG_ERR_PLUG, "Hot plug error" }, + { TB_CFG_ERR_LOCK, "Adapter locked" }, + { TB_CFG_HP_ACK, "Hotplug acknowledgement" }, + { TB_CFG_DP_BW, "Display port bandwidth change" }, + { 0, NULL } +}; + +const char * +tb_get_string(uintmax_t key, tb_string_t *table) +{ + + if (table == NULL) + return ("<null>"); + + while (table->value != NULL) { + if (table->key == key) + return (table->value); + table++; + } + + return ("<unknown>"); +} + +static struct tb_debug_string { + char *name; + int flag; +} tb_debug_strings[] = { + {"info", DBG_INFO}, + {"init", DBG_INIT}, + {"info", DBG_INFO}, + {"rxq", DBG_RXQ}, + {"txq", DBG_TXQ}, + {"intr", DBG_INTR}, + {"tb", DBG_TB}, + {"mbox", DBG_MBOX}, + {"bridge", DBG_BRIDGE}, + {"cfg", DBG_CFG}, + {"router", DBG_ROUTER}, + {"port", DBG_PORT}, + {"hcm", DBG_HCM}, + {"extra", DBG_EXTRA}, + {"noisy", DBG_NOISY}, + {"full", DBG_FULL} +}; + +enum tb_debug_level_combiner { + COMB_NONE, + COMB_ADD, + COMB_SUB +}; + +int +tb_debug_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sbuf; +#if defined (THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0) + struct tb_debug_string *string; + char *buffer; + size_t sz; + u_int *debug; + int i, len; +#endif + int error; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + + sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); + +#if defined (THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0) + debug = (u_int *)arg1; + + sbuf_printf(sbuf, "%#x", *debug); + + sz = sizeof(tb_debug_strings) / sizeof(tb_debug_strings[0]); + for (i = 0; i < sz; i++) { + string = &tb_debug_strings[i]; + if (*debug & string->flag) + sbuf_printf(sbuf, ",%s", string->name); + } + + error = sbuf_finish(sbuf); + sbuf_delete(sbuf); + + if (error || req->newptr == NULL) + return (error); + + len = req->newlen - req->newidx; + if (len == 0) + return (0); + + buffer = malloc(len, M_THUNDERBOLT, M_ZERO|M_WAITOK); + error = SYSCTL_IN(req, buffer, len); + + tb_parse_debug(debug, buffer); + + free(buffer, M_THUNDERBOLT); +#else + sbuf_printf(sbuf, "debugging unavailable"); + error = sbuf_finish(sbuf); + sbuf_delete(sbuf); +#endif + + return (error); +} + +void +tb_parse_debug(u_int *debug, char *list) +{ + struct tb_debug_string *string; + enum tb_debug_level_combiner op; + char *token, *endtoken; + size_t sz; + int flags, i; + + if (list == NULL || *list == '\0') + return; + + if (*list == '+') { + op = COMB_ADD; + list++; + } else if (*list == '-') { + op = COMB_SUB; + list++; + } else + op = COMB_NONE; + if (*list == '\0') + return; + + flags = 0; + sz = sizeof(tb_debug_strings) / sizeof(tb_debug_strings[0]); + while ((token = strsep(&list, ":,")) != NULL) { + + /* Handle integer flags */ + flags |= strtol(token, &endtoken, 0); + if (token != endtoken) + continue; + + /* Handle text flags */ + for (i = 0; i < sz; i++) { + string = &tb_debug_strings[i]; + if (strcasecmp(token, string->name) == 0) { + flags |= string->flag; + break; + } + } + } + + switch (op) { + case COMB_NONE: + *debug = flags; + break; + case COMB_ADD: + *debug |= flags; + break; + case COMB_SUB: + *debug &= (~flags); + break; + } + return; +} + +void +tbdbg_dprintf(device_t dev, u_int debug, u_int val, const char *fmt, ...) +{ +#if defined(THUNDERBOLT_DEBUG) && (THUNDERBOLT_DEBUG > 0) + va_list ap; + u_int lvl, dbg; + + lvl = debug & 0xc0000000; + dbg = debug & 0x3fffffff; + va_start(ap, fmt); + if ((lvl >= (val & 0xc0000000)) && + ((dbg & (val & 0x3fffffff)) != 0)) { + device_printf(dev, ""); + vprintf(fmt, ap); + } + va_end(ap); +#endif +} |