xref: /freebsd/sys/dev/thunderbolt/router.c (revision c4fde87a3236b500246d4fce76dbca2a3d64f73a)
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 /* Config space access for switches, ports, and devices in TB3 and USB4 */
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/tbcfg_reg.h>
58 #include <dev/thunderbolt/router_var.h>
59 #include <dev/thunderbolt/tb_debug.h>
60 
61 static int router_alloc_cmd(struct router_softc *, struct router_command **);
62 static void router_free_cmd(struct router_softc *, struct router_command *);
63 static int _tb_router_attach(struct router_softc *);
64 static void router_prepare_cmd(struct router_softc *, struct router_command *,
65     size_t, uint16_t);
66 static void router_prepare_read(struct router_softc *, struct router_command *,
67     size_t);
68 static void router_prepare_write(struct router_softc *, struct router_command *,
69     size_t);
70 static int _tb_config_read(struct router_softc *, u_int, u_int, u_int, u_int,
71     uint32_t *, void *, struct router_command **);
72 static int _tb_config_write(struct router_softc *, u_int, u_int, u_int, u_int,
73     uint32_t *, void *, struct router_command **);
74 static int router_schedule(struct router_softc *, struct router_command *);
75 static int router_schedule_locked(struct router_softc *,
76     struct router_command *);
77 static nhi_ring_cb_t router_complete_intr;
78 static nhi_ring_cb_t router_response_intr;
79 static nhi_ring_cb_t router_notify_intr;
80 
81 #define CFG_DEFAULT_RETRIES	3
82 #define CFG_DEFAULT_TIMEOUT	2
83 
84 static int
85 router_lookup_device(struct router_softc *sc, tb_route_t route,
86     struct router_softc **dev)
87 {
88 	struct router_softc *cursor;
89 	uint64_t search_rt, remainder_rt, this_rt;
90 	uint8_t hop;
91 
92 	KASSERT(dev != NULL, ("dev cannot be NULL\n"));
93 
94 	cursor = tb_config_get_root(sc);
95 	remainder_rt = search_rt = route.lo | ((uint64_t)route.hi << 32);
96 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
97 	    "%s: Searching for router 0x%016jx\n", __func__, search_rt);
98 
99 	while (cursor != NULL) {
100 		this_rt = TB_ROUTE(cursor);
101 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
102 		    "Comparing cursor route 0x%016jx\n", this_rt);
103 		if (this_rt == search_rt)
104 			break;
105 
106 		/* Prepare to go to the next hop node in the route */
107 		hop = remainder_rt & 0xff;
108 		remainder_rt >>= 8;
109 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
110 		    "hop= 0x%02x, remainder= 0x%016jx\n", hop, remainder_rt);
111 
112 		/*
113 		 * An adapter index of 0x0 is only for the host interface
114 		 * adapter on the root route.  The only time that
115 		 * it's valid for searches is when you're looking for the
116 		 * root route, and that case has already been handled.
117 		 */
118 		if (hop == 0) {
119 			tb_debug(sc, DBG_ROUTER,
120 			    "End of route chain, route not found\n");
121 			return (ENOENT);
122 		}
123 
124 		if (hop > cursor->max_adap) {
125 			tb_debug(sc, DBG_ROUTER,
126 			    "Route hop out of range for parent\n");
127 			return (EINVAL);
128 		}
129 
130 		if (cursor->adapters == NULL) {
131 			tb_debug(sc, DBG_ROUTER,
132 			    "Error, router not fully initialized\n");
133 			return (EINVAL);
134 		}
135 
136 		cursor = cursor->adapters[hop];
137 	}
138 
139 	if (cursor == NULL)
140 		return (ENOENT);
141 
142 	*dev = cursor;
143 	return (0);
144 }
145 
146 static int
147 router_insert(struct router_softc *sc, struct router_softc *parent)
148 {
149 	uint64_t this_rt;
150 	uint8_t this_hop;
151 
152 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_insert called\n");
153 
154 	if (parent == NULL) {
155 		tb_debug(sc, DBG_ROUTER, "Parent cannot be NULL in insert\n");
156 		return (EINVAL);
157 	}
158 
159 	this_rt = TB_ROUTE(sc);
160 	if (((this_rt >> (sc->depth * 8)) > 0xffULL) ||
161 	    (parent->depth + 1 != sc->depth)) {
162 		tb_debug(sc, DBG_ROUTER, "Added route 0x%08x%08x is not a "
163 		    "direct child of the parent route 0x%08x%08x\n",
164 		    sc->route.hi, sc->route.lo, parent->route.hi,
165 		    parent->route.lo);
166 		return (EINVAL);
167 	}
168 
169 	this_hop = (uint8_t)(this_rt >> (sc->depth * 8));
170 
171 	tb_debug(sc, DBG_ROUTER, "Inserting route 0x%08x%08x with last hop "
172 	    "of 0x%02x and depth of %d\n", sc->route.hi, sc->route.lo,
173 	    this_hop, sc->depth);
174 
175 	if (this_hop > parent->max_adap) {
176 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
177 		    "Inserted route is out of range of the parent\n");
178 		return (EINVAL);
179 	}
180 
181 	if (parent->adapters[this_hop] != NULL) {
182 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
183 		    "Inserted route already exists\n");
184 		return (EEXIST);
185 	}
186 
187 	parent->adapters[this_hop] = sc;
188 
189 	tb_debug(sc, DBG_ROUTER, "Added router 0x%08x%08x to parent "
190 	    "0x%08x%08x\n", sc->route.hi, sc->route.lo, parent->route.hi,
191 	    parent->route.lo);
192 	return (0);
193 }
194 
195 static int
196 router_register_interrupts(struct router_softc *sc)
197 {
198 	struct nhi_dispatch tx[] = { { PDF_READ, router_complete_intr, sc },
199 				     { PDF_WRITE, router_complete_intr, sc },
200 				     { 0, NULL, NULL } };
201 	struct nhi_dispatch rx[] = { { PDF_READ, router_response_intr, sc },
202 				     { PDF_WRITE, router_response_intr, sc },
203 				     { PDF_NOTIFY, router_notify_intr, sc },
204 				     { 0, NULL, NULL } };
205 
206 	return (nhi_register_pdf(sc->ring0, tx, rx));
207 }
208 
209 int
210 tb_router_attach(struct router_softc *parent, tb_route_t route)
211 {
212 	struct router_softc *sc;
213 
214 	tb_debug(parent, DBG_ROUTER|DBG_EXTRA, "tb_router_attach called\n");
215 
216 	sc = malloc(sizeof(*sc), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
217 	if (sc == NULL) {
218 		tb_debug(parent, DBG_ROUTER, "Cannot allocate root router\n");
219 		return (ENOMEM);
220 	}
221 
222 	sc->dev = parent->dev;
223 	sc->debug = parent->debug;
224 	sc->ring0 = parent->ring0;
225 	sc->route = route;
226 	sc->nsc = parent->nsc;
227 
228 	mtx_init(&sc->mtx, "tbcfg", "Thunderbolt Router Config", MTX_DEF);
229 	TAILQ_INIT(&sc->cmd_queue);
230 
231 	router_insert(sc, parent);
232 
233 	return (_tb_router_attach(sc));
234 }
235 
236 int
237 tb_router_attach_root(struct nhi_softc *nsc, tb_route_t route)
238 {
239 	struct router_softc *sc;
240 	int error;
241 
242 	tb_debug(nsc, DBG_ROUTER|DBG_EXTRA, "tb_router_attach_root called\n");
243 
244 	sc = malloc(sizeof(*sc), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
245 	if (sc == NULL) {
246 		tb_debug(nsc, DBG_ROUTER, "Cannot allocate root router\n");
247 		return (ENOMEM);
248 	}
249 
250 	sc->dev = nsc->dev;
251 	sc->debug = nsc->debug;
252 	sc->ring0 = nsc->ring0;
253 	sc->route = route;
254 	sc->nsc = nsc;
255 	sc->suspended = false;
256 
257 	mtx_init(&sc->mtx, "tbcfg", "Thunderbolt Router Config", MTX_DEF);
258 	TAILQ_INIT(&sc->cmd_queue);
259 
260 	/*
261 	 * This router is semi-virtual and represents the router that's part
262 	 * of the NHI DMA engine.  Commands can't be issued to the topology
263 	 * until the NHI is initialized and this router is initialized, so
264 	 * there's no point in registering router interrupts earlier than this,
265 	 * even if other routers are found first.
266 	 */
267 	tb_config_set_root(sc);
268 	error = router_register_interrupts(sc);
269 	if (error) {
270 		tb_router_detach(sc);
271 		return (error);
272 	}
273 
274 	error = _tb_router_attach(sc);
275 	if (error)
276 		return (error);
277 
278 	bcopy((uint8_t *)sc->uuid, nsc->uuid, 16);
279 	return (0);
280 }
281 
282 static int
283 _tb_router_attach(struct router_softc *sc)
284 {
285 	struct tb_cfg_router *cfg;
286 	uint32_t *buf;
287 	int error;
288 	int up __maybe_unused;
289 
290 	buf = malloc(9 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
291 	if (buf == NULL)
292 		return (ENOMEM);
293 
294 	error = tb_config_router_read_polled(sc, 0, 9, buf);
295 	if (error != 0) {
296 		free(buf, M_THUNDERBOLT);
297 		return (error);
298 	}
299 
300 	cfg = (struct tb_cfg_router *)buf;
301 	up = GET_ROUTER_CS_UPSTREAM_ADAP(cfg);
302 	sc->max_adap = GET_ROUTER_CS_MAX_ADAP(cfg);
303 	sc->depth = GET_ROUTER_CS_DEPTH(cfg);
304 	sc->uuid[0] = cfg->uuid_lo;
305 	sc->uuid[1] = cfg->uuid_hi;
306 	sc->uuid[2] = 0xffffffff;
307 	sc->uuid[3] = 0xffffffff;
308 	tb_debug(sc, DBG_ROUTER,
309 	    "Router upstream_port= %d, max_port= %d, depth= %d\n",
310 	    up, sc->max_adap, sc->depth);
311 	free(buf, M_THUNDERBOLT);
312 
313 	/* Downstream adapters are indexed in the array allocated here. */
314 	sc->max_adap = MIN(sc->max_adap, ROUTER_CS1_MAX_ADAPTERS);
315 	sc->adapters = malloc((1 + sc->max_adap) * sizeof(void *),
316 	    M_THUNDERBOLT, M_NOWAIT|M_ZERO);
317 	if (sc->adapters == NULL) {
318 		tb_debug(sc, DBG_ROUTER,
319 		    "Cannot allocate downstream adapter memory\n");
320 		return (ENOMEM);
321 	}
322 
323 	tb_debug(sc, DBG_ROUTER, "Router created, route 0x%08x%08x\n",
324 	    sc->route.hi, sc->route.lo);
325 
326 	return (0);
327 }
328 
329 int
330 tb_router_detach(struct router_softc *sc)
331 {
332 
333 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_router_deattach called\n");
334 
335 	if (TAILQ_FIRST(&sc->cmd_queue) != NULL)
336 		return (EBUSY);
337 
338 	mtx_destroy(&sc->mtx);
339 
340 	if (sc->adapters != NULL)
341 		free(sc->adapters, M_THUNDERBOLT);
342 
343 	if (sc != NULL)
344 		free(sc, M_THUNDERBOLT);
345 
346 	return (0);
347 }
348 
349 /*
350  * Suspend a USB4 router and it's downstreams.
351  *
352  * TODO(Bug 299199): fully flesh out the implementation.
353  */
354 int
355 tb_router_suspend(struct router_softc *sc)
356 {
357 	int		err;
358 	uint32_t	reg;
359 
360 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "%s called\n", __func__);
361 	if (sc->suspended) {
362 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Already suspended\n");
363 		return (0);
364 	}
365 
366 	/*
367 	 * TODO Before we do anything, we've first got to make sure that the
368 	 * USB3 hub is in the U3 state, and the PCIe endpoint is in D3.
369 	 *
370 	 * Also check for "USB4 Port is Configured" to know if we support
371 	 * sleep state.
372 	 */
373 
374 	/* First, we've got to set ROUTER_CS_5.SLP (enter sleep). */
375 	err = tb_config_router_read(sc, ROUTER_CS_5, 1, &reg);
376 	if (err != 0) {
377 		tb_debug(sc, DBG_ROUTER, "Cannot read ROUTER_CS5\n");
378 		return (err);
379 	}
380 	/*
381 	 * We want to set the enter sleep bit, as well as preventing wake
382 	 * events from:
383 	 * - Wake on PCIe (WoP).
384 	 * - Wake on USB3 (WoU).
385 	 * - Wake on DisplayPort (WoD).
386 	 * TODO Eventually, we will want the user to be able to control this.
387 	 */
388 	reg |= ROUTER_SLP;
389 	reg &= ~(ROUTER_WOP | ROUTER_WOU | ROUTER_WOD);
390 	err = tb_config_router_write(sc, ROUTER_CS_5, 1, &reg);
391 	if (err != 0) {
392 		tb_debug(sc, DBG_ROUTER, "Cannot write to ROUTER_CS5\n");
393 		return (err);
394 	}
395 
396 	/*
397 	 * The ROUTER_CS_6.SLPR (sleep ready) bit should be set tSetSR after
398 	 * we set the SLP bit.  Poll for it to be set.
399 	 *
400 	 * TODO On a v2 router, we should wait for the ROP_CMPLT notification,
401 	 * but in the meantime just polling is also valid.
402 	 */
403 	for (size_t i = 0; i < NHI_SLPR_POLL_TRIES; i++) {
404 		pause_sbt("tbrouter", ustosbt(NHI_SLPR_POLL_US), 0, 0);
405 		err = tb_config_router_read(sc, ROUTER_CS_6, 1, &reg);
406 		if (err != 0) {
407 			tb_debug(sc, DBG_ROUTER, "Cannot read ROUTER_CS6\n");
408 			return (err);
409 		}
410 		if ((reg & ROUTER_SLPR) != 0)
411 			goto ready;
412 	}
413 	tb_printf(sc, "Timed out waiting for the sleep ready bit to be set\n");
414 	return (ETIMEDOUT);
415 
416 ready:
417 	tb_printf(sc, "Ready to enter sleep\n");
418 	sc->suspended = true;
419 	/*
420 	 * TODO We must tell the host router to send LT_LRoff on the sideband
421 	 * channel of each DFP.
422 	 */
423 	return (0);
424 }
425 
426 static void
427 router_get_config_cb(struct router_softc *sc, struct router_command *cmd,
428     void *arg)
429 {
430 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_get_config_cb called\n");
431 
432 	/*
433 	 * Only do the copy if the command didn't have a notify event thrown.
434 	 * These events serve as asynchronous exception signals, which is
435 	 * cumbersome.
436 	 */
437 	if (cmd->ev == 0)
438 		bcopy((uint8_t *)cmd->resp_buffer,
439 		    (uint8_t *)cmd->callback_arg, cmd->dwlen * 4);
440 
441 	mtx_lock(&sc->mtx);
442 	sc->inflight_cmd = NULL;
443 
444 	if ((cmd->flags & RCMD_POLLED) == 0)
445 		wakeup(cmd);
446 	else
447 		cmd->flags |= RCMD_POLL_COMPLETE;
448 
449 	router_schedule_locked(sc, NULL);
450 	mtx_unlock(&sc->mtx);
451 }
452 
453 int
454 tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
455     u_int offset, u_int dwlen, uint32_t *buf)
456 {
457 	struct router_command *cmd;
458 	int error, retries;
459 
460 	if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
461 	    router_get_config_cb, &cmd)) != 0)
462 		return (error);
463 
464 	retries = cmd->retries;
465 	mtx_lock(&sc->mtx);
466 	while (retries-- >= 0) {
467 		error = router_schedule_locked(sc, cmd);
468 		if (error)
469 			break;
470 
471 		error = msleep(cmd, &sc->mtx, 0, "tbtcfg", cmd->timeout * hz);
472 		if (error != EWOULDBLOCK)
473 			break;
474 		sc->inflight_cmd = NULL;
475 		tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
476 	}
477 
478 	if (cmd->ev != 0)
479 		error = EINVAL;
480 	router_free_cmd(sc, cmd);
481 	mtx_unlock(&sc->mtx);
482 	return (error);
483 }
484 
485 int
486 tb_config_read_polled(struct router_softc *sc, u_int space, u_int adapter,
487     u_int offset, u_int dwlen, uint32_t *buf)
488 {
489 	struct router_command *cmd;
490 	int error, retries, timeout;
491 
492 	if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
493 	    router_get_config_cb, &cmd)) != 0)
494 		return (error);
495 
496 	retries = cmd->retries;
497 	cmd->flags |= RCMD_POLLED;
498 	timeout = cmd->timeout * 1000000;
499 
500 	mtx_lock(&sc->mtx);
501 	while (retries-- >= 0) {
502 		error = router_schedule_locked(sc, cmd);
503 		if (error)
504 			break;
505 		mtx_unlock(&sc->mtx);
506 
507 		while (timeout > 0) {
508 			DELAY(100 * 1000);
509 			if ((cmd->flags & RCMD_POLL_COMPLETE) != 0)
510 				break;
511 			timeout -= 100000;
512 		}
513 
514 		mtx_lock(&sc->mtx);
515 		if ((cmd->flags & RCMD_POLL_COMPLETE) == 0) {
516 			error = ETIMEDOUT;
517 			sc->inflight_cmd = NULL;
518 			tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
519 			continue;
520 		} else
521 			break;
522 	}
523 
524 	if (cmd->ev != 0)
525 		error = EINVAL;
526 	router_free_cmd(sc, cmd);
527 	mtx_unlock(&sc->mtx);
528 	return (error);
529 }
530 
531 int
532 tb_config_read_async(struct router_softc *sc, u_int space, u_int adapter,
533     u_int offset, u_int dwlen, uint32_t *buf, void *cb)
534 {
535 	struct router_command *cmd;
536 	int error;
537 
538 	if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
539 	    cb, &cmd)) != 0)
540 		return (error);
541 
542 	error = router_schedule(sc, cmd);
543 
544 	return (error);
545 }
546 
547 static int
548 _tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
549     u_int offset, u_int dwlen, uint32_t *buf, void *cb,
550     struct router_command **rcmd)
551 {
552 	struct router_command *cmd;
553 	struct tb_cfg_read *msg;
554 	int error;
555 
556 	if ((error = router_alloc_cmd(sc, &cmd)) != 0)
557 		return (error);
558 
559 	msg = router_get_frame_data(cmd);
560 	bzero(msg, sizeof(*msg));
561 	msg->route.hi = sc->route.hi;
562 	msg->route.lo = sc->route.lo;
563 	msg->addr_attrs = TB_CONFIG_ADDR(0, space, adapter, dwlen, offset);
564 	cmd->callback = cb;
565 	cmd->callback_arg = buf;
566 	cmd->dwlen = dwlen;
567 	router_prepare_read(sc, cmd, sizeof(*msg));
568 
569 	if (rcmd != NULL)
570 		*rcmd = cmd;
571 
572 	return (0);
573 }
574 
575 int
576 tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
577     u_int offset, u_int dwlen, uint32_t *buf)
578 {
579 	struct router_command *cmd;
580 	int error, retries;
581 
582 	if ((error = _tb_config_write(sc, space, adapter, offset, dwlen, buf,
583 	    router_get_config_cb, &cmd)) != 0)
584 		return (error);
585 
586 	retries = cmd->retries;
587 	mtx_lock(&sc->mtx);
588 	while (retries-- >= 0) {
589 		error = router_schedule_locked(sc, cmd);
590 		if (error)
591 			break;
592 
593 		error = msleep(cmd, &sc->mtx, 0, "tbtcfg", cmd->timeout * hz);
594 		if (error != EWOULDBLOCK)
595 			break;
596 		sc->inflight_cmd = NULL;
597 		tb_debug(sc, DBG_ROUTER, "Config command timed out, "
598 		    "retries=%d\n", retries);
599 	}
600 
601 	if (cmd->ev != 0)
602 		error = EINVAL;
603 	router_free_cmd(sc, cmd);
604 	mtx_unlock(&sc->mtx);
605 	return (error);
606 }
607 
608 static int
609 _tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
610     u_int offset, u_int dwlen, uint32_t *buf, void *cb,
611     struct router_command **rcmd)
612 {
613 	struct router_command *cmd;
614 	struct tb_cfg_write *msg;
615 	/* +4 to account for the CRC at the end. */
616 	size_t msglen = sizeof(*msg) + dwlen * 4 + 4;
617 	int error;
618 
619 	if ((error = router_alloc_cmd(sc, &cmd)) != 0)
620 		return (error);
621 
622 	msg = router_get_frame_data(cmd);
623 	bzero(msg, msglen);
624 	msg->route.hi = sc->route.hi;
625 	msg->route.lo = sc->route.lo;
626 	msg->addr_attrs = TB_CONFIG_ADDR(0, space, adapter, dwlen, offset);
627 	for (size_t i = 0; i < dwlen; i++)
628 		msg->data[i] = buf[i];
629 	cmd->callback = cb;
630 	cmd->callback_arg = buf;
631 	cmd->dwlen = dwlen;
632 	router_prepare_write(sc, cmd, msglen);
633 
634 	if (rcmd != NULL)
635 		*rcmd = cmd;
636 
637 	return (0);
638 }
639 
640 static int
641 router_alloc_cmd(struct router_softc *sc, struct router_command **rcmd)
642 {
643 	struct router_command *cmd;
644 
645 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_alloc_cmd\n");
646 
647 	cmd = malloc(sizeof(*cmd), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
648 	if (cmd == NULL) {
649 		tb_debug(sc, DBG_ROUTER, "Cannot allocate cmd/response\n");
650 		return (ENOMEM);
651 	}
652 
653 	cmd->nhicmd = nhi_alloc_tx_frame(sc->ring0);
654 	if (cmd->nhicmd == NULL) {
655 		tb_debug(sc, DBG_ROUTER, "Cannot allocate command frame\n");
656 		free(cmd, M_THUNDERBOLT);
657 		return (EBUSY);
658 	}
659 
660 	cmd->sc = sc;
661 	*rcmd = cmd;
662 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Allocated command with index %d\n",
663 	    cmd->nhicmd->idx);
664 
665 	return (0);
666 }
667 
668 static void
669 router_free_cmd(struct router_softc *sc, struct router_command *cmd)
670 {
671 
672 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_free_cmd\n");
673 
674 	if (cmd == NULL)
675 		return;
676 
677 	if (cmd->nhicmd != NULL) {
678 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Freeing nhi command %d\n",
679 		    cmd->nhicmd->idx);
680 		nhi_free_tx_frame(sc->ring0, cmd->nhicmd);
681 	}
682 	free(cmd, M_THUNDERBOLT);
683 
684 	return;
685 }
686 
687 static void
688 router_prepare_cmd(struct router_softc *sc, struct router_command *cmd,
689     size_t len, uint16_t pdf)
690 {
691 	struct nhi_cmd_frame *nhicmd;
692 	uint32_t *msg;
693 	int msglen, i;
694 
695 	KASSERT(cmd != NULL, ("cmd cannot be NULL\n"));
696 	KASSERT(len != 0, ("Invalid zero-length command\n"));
697 	KASSERT(len % 4 == 0, ("Message must be 32bit padded\n"));
698 
699 	nhicmd = cmd->nhicmd;
700 	msglen = (len - 4) / 4;
701 	for (i = 0; i < msglen; i++)
702 		nhicmd->data[i] = htobe32(nhicmd->data[i]);
703 
704 	msg = (uint32_t *)nhicmd->data;
705 	/* The last 4 bytes of data is the CRC. Compute CRC for just data. */
706 	msg[msglen] = htobe32(tb_calc_crc(nhicmd->data, len - 4));
707 
708 	nhicmd->pdf = pdf;
709 	nhicmd->req_len = len;
710 
711 	nhicmd->timeout = NHI_CMD_TIMEOUT;
712 	nhicmd->retries = 0;
713 	nhicmd->context = cmd;
714 
715 	cmd->retries = CFG_DEFAULT_RETRIES;
716 	cmd->timeout = CFG_DEFAULT_TIMEOUT;
717 }
718 
719 static void
720 router_prepare_read(struct router_softc *sc, struct router_command *cmd,
721     size_t len)
722 {
723 	router_prepare_cmd(sc, cmd, len, PDF_READ);
724 
725 	cmd->nhicmd->resp_buffer = (uint32_t *)cmd->resp_buffer;
726 	cmd->nhicmd->resp_len = (cmd->dwlen + 3) * 4;
727 }
728 
729 static void
730 router_prepare_write(struct router_softc *sc, struct router_command *cmd,
731     size_t len)
732 {
733 	router_prepare_cmd(sc, cmd, len, PDF_WRITE);
734 
735 	cmd->nhicmd->resp_buffer = (uint32_t *)cmd->resp_buffer;
736 	cmd->nhicmd->resp_len = (cmd->dwlen + 3) * 4;
737 }
738 
739 static int
740 router_schedule(struct router_softc *sc, struct router_command *cmd)
741 {
742 	int error;
743 
744 	mtx_lock(&sc->mtx);
745 	error = router_schedule_locked(sc, cmd);
746 	mtx_unlock(&sc->mtx);
747 
748 	return(error);
749 }
750 
751 static int
752 router_schedule_locked(struct router_softc *sc, struct router_command *cmd)
753 {
754 	struct nhi_cmd_frame *nhicmd;
755 	int error;
756 
757 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_schedule\n");
758 
759 	if (cmd != NULL)
760 		TAILQ_INSERT_TAIL(&sc->cmd_queue, cmd, link);
761 
762 	while ((sc->inflight_cmd == NULL) &&
763 	    ((cmd = TAILQ_FIRST(&sc->cmd_queue)) != NULL)) {
764 
765 		TAILQ_REMOVE(&sc->cmd_queue, cmd, link);
766 		nhicmd = cmd->nhicmd;
767 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
768 		    "Scheduling command with index %d\n", nhicmd->idx);
769 		sc->inflight_cmd = cmd;
770 		if ((error = nhi_tx_schedule(sc->ring0, nhicmd)) != 0) {
771 			tb_debug(sc, DBG_ROUTER, "nhi ring error "
772 			    "%d\n", error);
773 			sc->inflight_cmd = NULL;
774 			if (error == EBUSY) {
775 				TAILQ_INSERT_HEAD(&sc->cmd_queue, cmd, link);
776 				error = 0;
777 			}
778 			break;
779 		}
780 	}
781 
782 	return (error);
783 }
784 
785 static void
786 router_complete_intr(void *context, union nhi_ring_desc *ring,
787     struct nhi_cmd_frame *nhicmd)
788 {
789 	struct router_softc *sc;
790 	struct router_command *cmd;
791 
792 	KASSERT(context != NULL, ("context cannot be NULL\n"));
793 	KASSERT(nhicmd != NULL, ("nhicmd cannot be NULL\n"));
794 
795 	cmd = (struct router_command *)(nhicmd->context);
796 	sc = cmd->sc;
797 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_complete_intr called\n");
798 
799 	if (nhicmd->flags & CMD_RESP_COMPLETE) {
800 		cmd->callback(sc, cmd, cmd->callback_arg);
801 	}
802 
803 	return;
804 }
805 
806 static void
807 router_response_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
808 {
809 	struct router_softc *sc, *dev;
810 	struct tb_cfg_read_resp *read;
811 	struct tb_cfg_write_resp *write;
812 	struct router_command *cmd;
813 	tb_route_t route;
814 	u_int error, i, eof, len;
815 	uint32_t attrs;
816 
817 	KASSERT(context != NULL, ("context cannot be NULL\n"));
818 
819 	sc = (struct router_softc *)context;
820 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_response_intr called\n");
821 
822 	eof = ring->rxpost.eof_len >> RX_BUFFER_DESC_EOF_SHIFT;
823 
824 	if (eof == PDF_WRITE) {
825 		write = (struct tb_cfg_write_resp *)nhicmd->data;
826 		route.hi = be32toh(write->route.hi);
827 		route.lo = be32toh(write->route.lo);
828 	} else {
829 		read = (struct tb_cfg_read_resp *)nhicmd->data;
830 		route.hi = be32toh(read->route.hi);
831 		route.lo = be32toh(read->route.lo);
832 		attrs = be32toh(read->addr_attrs);
833 		len = (attrs & TB_CFG_SIZE_MASK) >> TB_CFG_SIZE_SHIFT;
834 	}
835 
836 	/* XXX Is this a problem? */
837 	if ((route.hi & 0x80000000) == 0)
838 		tb_debug(sc, DBG_ROUTER, "Invalid route\n");
839 	route.hi &= ~0x80000000;
840 
841 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Looking up route 0x%08x%08x\n",
842 	    route.hi, route.lo);
843 
844 	error = router_lookup_device(sc, route, &dev);
845 	if (error != 0 || dev == NULL) {
846 		tb_debug(sc, DBG_ROUTER, "Cannot find device, error= %d\n",
847 		    error);
848 		return;
849 	}
850 
851 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Found device %s route 0x%08x%08x, "
852 	    "inflight_cmd= %p\n", device_get_nameunit(dev->dev), dev->route.hi,
853 	    dev->route.lo, dev->inflight_cmd);
854 
855 	cmd = dev->inflight_cmd;
856 	if (cmd == NULL) {
857 		tb_debug(dev, DBG_ROUTER, "Null inflight cmd\n");
858 		return;
859 	}
860 
861 	if (eof == PDF_READ) {
862 		for (i = 0; i < len; i++)
863 			cmd->nhicmd->resp_buffer[i] = be32toh(read->data[i]);
864 	}
865 
866 	cmd->nhicmd->flags |= CMD_RESP_COMPLETE;
867 	if (cmd->nhicmd->flags & CMD_REQ_COMPLETE) {
868 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "TX_COMPLETE set\n");
869 		cmd->callback(dev, cmd, cmd->callback_arg);
870 	}
871 
872 	return;
873 }
874 
875 static void
876 router_notify_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
877 {
878 	struct router_softc *sc;
879 	struct router_command *cmd;
880 	struct tb_cfg_notify event;
881 	u_int adap __maybe_unused;
882 	u_int ev;
883 
884 	KASSERT(context != NULL, ("context cannot be NULL\n"));
885 
886 	sc = (struct router_softc *)context;
887 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_notify_intr called\n");
888 
889 	event.route.hi = be32toh(nhicmd->data[0]);
890 	event.route.lo = be32toh(nhicmd->data[1]);
891 	event.event_adap = be32toh(nhicmd->data[2]);
892 
893 	ev = GET_NOTIFY_EVENT(&event);
894 	adap = GET_NOTIFY_ADAPTER(&event);
895 
896 	tb_debug(sc, DBG_ROUTER, "Event route 0x%08x%08x adap %d code %s\n",
897 	    event.route.hi, event.route.lo, adap,
898 	    tb_get_string(ev, tb_notify_event));
899 
900 	switch (ev) {
901 	case TB_CFG_ERR_CONN:
902 	case TB_CFG_ERR_LINK:
903 	case TB_CFG_ERR_ADDR:
904 	case TB_CFG_ERR_ADP:
905 	case TB_CFG_ERR_ENUM:
906 	case TB_CFG_ERR_NUA:
907 	case TB_CFG_ERR_LEN:
908 	case TB_CFG_ERR_HEC:
909 	case TB_CFG_ERR_FC:
910 	case TB_CFG_ERR_PLUG:
911 	case TB_CFG_ERR_LOCK:
912 	case TB_CFG_HP_ACK:
913 	case TB_CFG_DP_BW:
914 		if (sc->inflight_cmd != NULL) {
915 			cmd = sc->inflight_cmd;
916 			cmd->ev = ev;
917 			cmd->callback(sc, cmd, cmd->callback_arg);
918 		}
919 		break;
920 	default:
921 		break;
922 	}
923 	return;
924 }
925 
926 int
927 tb_config_next_cap(struct router_softc *sc, struct router_cfg_cap *cap)
928 {
929 	union tb_cfg_cap *tbcap;
930 	uint32_t *buf;
931 	uint16_t current;
932 	int error;
933 
934 	KASSERT(cap != NULL, ("cap cannot be NULL\n"));
935 	KASSERT(cap->next_cap != 0, ("next_cap cannot be 0\n"));
936 
937 	buf = malloc(sizeof(*tbcap), M_THUNDERBOLT, M_NOWAIT|M_ZERO);
938 
939 	current = cap->next_cap;
940 	error = tb_config_read(sc, cap->space, cap->adap, current, 1, buf);
941 	if (error)
942 		return (error);
943 
944 	tbcap = (union tb_cfg_cap *)buf;
945 	cap->cap_id = tbcap->hdr.cap_id;
946 	cap->next_cap = tbcap->hdr.next_cap;
947 	cap->current_cap = current;
948 
949 	if ((cap->space != TB_CFG_CS_ROUTER) &&
950 	    (tbcap->hdr.cap_id != TB_CFG_CAP_VSC)) {
951 		free(buf, M_THUNDERBOLT);
952 		return (0);
953 	}
954 
955 	tb_config_read(sc, cap->space, cap->adap, current, 2, buf);
956 	if (error) {
957 		free(buf, M_THUNDERBOLT);
958 		return (error);
959 	}
960 
961 	cap->vsc_id = tbcap->vsc.vsc_id;
962 	cap->vsc_len = tbcap->vsc.len;
963 	if (tbcap->vsc.len == 0) {
964 		cap->next_cap = tbcap->vsec.vsec_next_cap;
965 		cap->vsec_len = tbcap->vsec.vsec_len;
966 	}
967 
968 	free(buf, M_THUNDERBOLT);
969 	return (0);
970 }
971 
972 int
973 tb_config_find_cap(struct router_softc *sc, struct router_cfg_cap *cap)
974 {
975 	u_int cap_id, vsc_id;
976 	int error;
977 
978 	tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_config_find_cap called\n");
979 
980 	cap_id = cap->cap_id;
981 	vsc_id = cap->vsc_id;
982 
983 	cap->cap_id = cap->vsc_id = 0;
984 	while ((cap->cap_id != cap_id) || (cap->vsc_id != vsc_id)) {
985 		tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
986 		    "Looking for cap %d at offset %d\n", cap->cap_id,
987 		    cap->next_cap);
988 		if ((cap->next_cap == 0) ||
989 		    (cap->next_cap > TB_CFG_CAP_OFFSET_MAX))
990 			return (EINVAL);
991 		error = tb_config_next_cap(sc, cap);
992 		if (error)
993 			break;
994 	}
995 
996 	return (0);
997 }
998 
999 int
1000 tb_config_find_router_cap(struct router_softc *sc, u_int cap, u_int vsc, u_int *offset)
1001 {
1002 	struct router_cfg_cap rcap;
1003 	struct tb_cfg_router *cfg;
1004 	uint32_t *buf;
1005 	int error;
1006 
1007 	buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
1008 	if (buf == NULL)
1009 		return (ENOMEM);
1010 
1011 	error = tb_config_router_read(sc, 0, 5, buf);
1012 	if (error != 0) {
1013 		free(buf, M_THUNDERBOLT);
1014 		return (error);
1015 	}
1016 
1017 	cfg = (struct tb_cfg_router *)buf;
1018 	rcap.space = TB_CFG_CS_ROUTER;
1019 	rcap.adap = 0;
1020 	rcap.next_cap = GET_ROUTER_CS_NEXT_CAP(cfg);
1021 	rcap.cap_id = cap;
1022 	rcap.vsc_id = vsc;
1023 	error = tb_config_find_cap(sc, &rcap);
1024 	if (error == 0)
1025 		*offset = rcap.current_cap;
1026 
1027 	free(buf, M_THUNDERBOLT);
1028 	return (error);
1029 }
1030 
1031 int
1032 tb_config_find_router_vsc(struct router_softc *sc, u_int cap, u_int *offset)
1033 {
1034 
1035 	return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSC, cap, offset));
1036 }
1037 
1038 int
1039 tb_config_find_router_vsec(struct router_softc *sc, u_int cap, u_int *offset)
1040 {
1041 
1042 	return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSEC, cap, offset));
1043 }
1044 
1045 int
1046 tb_config_find_adapter_cap(struct router_softc *sc, u_int adap, u_int cap, u_int *offset)
1047 {
1048 	struct router_cfg_cap rcap;
1049 	struct tb_cfg_adapter *cfg;
1050 	uint32_t *buf;
1051 	int error;
1052 
1053 	buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
1054 	if (buf == NULL)
1055 		return (ENOMEM);
1056 
1057 	error = tb_config_adapter_read(sc, adap, 0, 8, buf);
1058 	if (error != 0) {
1059 		free(buf, M_THUNDERBOLT);
1060 		return (error);
1061 	}
1062 
1063 	cfg = (struct tb_cfg_adapter *)buf;
1064 	rcap.space = TB_CFG_CS_ADAPTER;
1065 	rcap.adap = adap;
1066 	rcap.next_cap = GET_ADP_CS_NEXT_CAP(cfg);
1067 	rcap.cap_id = cap;
1068 	rcap.vsc_id = 0;
1069 	error = tb_config_find_cap(sc, &rcap);
1070 	if (error == 0)
1071 		*offset = rcap.current_cap;
1072 
1073 	free(buf, M_THUNDERBOLT);
1074 	return (error);
1075 }
1076 
1077 int
1078 tb_config_get_lc_uuid(struct router_softc *rsc, uint8_t *uuid)
1079 {
1080 	u_int error, offset;
1081 	uint32_t buf[8];
1082 
1083 	bzero(buf, sizeof(buf));
1084 
1085 	error = tb_config_find_router_vsec(rsc, TB_CFG_VSEC_LC, &offset);
1086 	if (error != 0) {
1087 		tb_debug(rsc, DBG_ROUTER, "Error finding LC registers: %d\n",
1088 		    error);
1089 		return (error);
1090 	}
1091 
1092 	error = tb_config_router_read(rsc, offset + TB_LC_UUID, 4, buf);
1093 	if (error != 0) {
1094 		tb_debug(rsc, DBG_ROUTER, "Error fetching UUID: %d\n", error);
1095 		return (error);
1096 	}
1097 
1098 	bcopy(buf, uuid, 16);
1099 	return (0);
1100 }
1101