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 /* Host Configuration Manager (HCM) for USB4 and later TB3 */ 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 #include <sys/bus.h> 38 #include <sys/conf.h> 39 #include <sys/malloc.h> 40 #include <sys/queue.h> 41 #include <sys/sysctl.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <sys/taskqueue.h> 45 #include <sys/gsb_crc32.h> 46 #include <sys/endian.h> 47 #include <vm/vm.h> 48 #include <vm/pmap.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/tb_debug.h> 58 #include <dev/thunderbolt/tbcfg_reg.h> 59 #include <dev/thunderbolt/router_var.h> 60 #include <dev/thunderbolt/hcm_var.h> 61 62 static void hcm_cfg_task(void *, int); 63 64 int 65 hcm_attach(struct nhi_softc *nsc) 66 { 67 struct hcm_softc *hcm; 68 69 tb_debug(nsc, DBG_HCM|DBG_EXTRA, "hcm_attach called\n"); 70 71 hcm = malloc(sizeof(struct hcm_softc), M_THUNDERBOLT, M_NOWAIT|M_ZERO); 72 if (hcm == NULL) { 73 tb_debug(nsc, DBG_HCM, "Cannot allocate hcm object\n"); 74 return (ENOMEM); 75 } 76 77 hcm->dev = nsc->dev; 78 hcm->nsc = nsc; 79 nsc->hcm = hcm; 80 81 hcm->taskqueue = taskqueue_create("hcm_event", M_NOWAIT, 82 taskqueue_thread_enqueue, &hcm->taskqueue); 83 if (hcm->taskqueue == NULL) 84 return (ENOMEM); 85 taskqueue_start_threads(&hcm->taskqueue, 1, PI_DISK, "tbhcm%d_tq", 86 device_get_unit(nsc->dev)); 87 TASK_INIT(&hcm->cfg_task, 0, hcm_cfg_task, hcm); 88 89 return (0); 90 } 91 92 int 93 hcm_detach(struct nhi_softc *nsc) 94 { 95 struct hcm_softc *hcm; 96 97 hcm = nsc->hcm; 98 if (hcm->taskqueue) 99 taskqueue_free(hcm->taskqueue); 100 101 return (0); 102 } 103 104 int 105 hcm_router_discover(struct hcm_softc *hcm) 106 { 107 108 taskqueue_enqueue(hcm->taskqueue, &hcm->cfg_task); 109 110 return (0); 111 } 112 113 static void 114 hcm_cfg_task(void *arg, int pending) 115 { 116 struct hcm_softc *hcm; 117 struct router_softc *rsc; 118 struct router_cfg_cap cap; 119 struct tb_cfg_router *cfg; 120 struct tb_cfg_adapter *adp; 121 struct tb_cfg_cap_lane *lane; 122 uint32_t *buf; 123 uint8_t *u; 124 u_int error, i, offset; 125 126 hcm = (struct hcm_softc *)arg; 127 128 tb_debug(hcm, DBG_HCM|DBG_EXTRA, "hcm_cfg_task called\n"); 129 130 buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO); 131 if (buf == NULL) { 132 tb_debug(hcm, DBG_HCM, "Cannot alloc memory for discovery\n"); 133 return; 134 } 135 136 rsc = hcm->nsc->root_rsc; 137 error = tb_config_router_read(rsc, 0, 5, buf); 138 if (error != 0) { 139 free(buf, M_NHI); 140 return; 141 } 142 143 cfg = (struct tb_cfg_router *)buf; 144 145 cap.space = TB_CFG_CS_ROUTER; 146 cap.adap = 0; 147 cap.next_cap = GET_ROUTER_CS_NEXT_CAP(cfg); 148 while (cap.next_cap != 0) { 149 error = tb_config_next_cap(rsc, &cap); 150 if (error != 0) 151 break; 152 153 if ((cap.cap_id == TB_CFG_CAP_VSEC) && (cap.vsc_len == 0)) { 154 tb_debug(hcm, DBG_HCM, "Router Cap= %d, vsec= %d, " 155 "len= %d, next_cap= %d\n", cap.cap_id, 156 cap.vsc_id, cap.vsec_len, cap.next_cap); 157 } else if (cap.cap_id == TB_CFG_CAP_VSC) { 158 tb_debug(hcm, DBG_HCM, "Router cap= %d, vsc= %d, " 159 "len= %d, next_cap= %d\n", cap.cap_id, 160 cap.vsc_id, cap.vsc_len, cap.next_cap); 161 } else 162 tb_debug(hcm, DBG_HCM, "Router cap= %d, " 163 "next_cap= %d\n", cap.cap_id, cap.next_cap); 164 if (cap.next_cap > TB_CFG_CAP_OFFSET_MAX) 165 cap.next_cap = 0; 166 } 167 168 u = (uint8_t *)buf; 169 error = tb_config_get_lc_uuid(rsc, u); 170 if (error == 0) { 171 tb_debug(hcm, DBG_HCM, "Router LC UUID: %02x%02x%02x%02x-" 172 "%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", 173 u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], 174 u[9], u[10], u[11], u[12], u[13], u[14], u[15]); 175 } else 176 tb_printf(hcm, "Error finding LC registers: %d\n", error); 177 178 for (i = 1; i <= rsc->max_adap; i++) { 179 error = tb_config_adapter_read(rsc, i, 0, 8, buf); 180 if (error != 0) { 181 tb_debug(hcm, DBG_HCM, "Adapter %d: no adapter\n", i); 182 continue; 183 } 184 adp = (struct tb_cfg_adapter *)buf; 185 tb_debug(hcm, DBG_HCM, "Adapter %d: %s, max_counters= 0x%08x," 186 " adapter_num= %d\n", i, 187 tb_get_string(GET_ADP_CS_TYPE(adp), tb_adapter_type), 188 GET_ADP_CS_MAX_COUNTERS(adp), GET_ADP_CS_ADP_NUM(adp)); 189 190 if (GET_ADP_CS_TYPE(adp) != ADP_CS2_LANE) 191 continue; 192 193 error = tb_config_find_adapter_cap(rsc, i, TB_CFG_CAP_LANE, 194 &offset); 195 if (error) 196 continue; 197 198 error = tb_config_adapter_read(rsc, i, offset, 3, buf); 199 if (error) 200 continue; 201 202 lane = (struct tb_cfg_cap_lane *)buf; 203 tb_debug(hcm, DBG_HCM, "Lane Adapter State= %s %s\n", 204 tb_get_string((lane->current_lws & CAP_LANE_STATE_MASK), 205 tb_adapter_state), (lane->targ_lwp & CAP_LANE_DISABLE) ? 206 "disabled" : "enabled"); 207 208 if ((lane->current_lws & CAP_LANE_STATE_MASK) == 209 CAP_LANE_STATE_CL0) { 210 tb_route_t newr; 211 212 newr.hi = rsc->route.hi; 213 newr.lo = rsc->route.lo | (i << rsc->depth * 8); 214 215 tb_printf(hcm, "want to add router at 0x%08x%08x\n", 216 newr.hi, newr.lo); 217 error = tb_router_attach(rsc, newr); 218 tb_printf(rsc, "tb_router_attach returned %d\n", error); 219 } 220 } 221 222 free(buf, M_THUNDERBOLT); 223 } 224