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