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