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, up;
281
282 buf = malloc(9 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
283 if (buf == NULL)
284 return (ENOMEM);
285
286 error = tb_config_router_read_polled(sc, 0, 9, buf);
287 if (error != 0) {
288 free(buf, M_THUNDERBOLT);
289 return (error);
290 }
291
292 cfg = (struct tb_cfg_router *)buf;
293 up = GET_ROUTER_CS_UPSTREAM_ADAP(cfg);
294 sc->max_adap = GET_ROUTER_CS_MAX_ADAP(cfg);
295 sc->depth = GET_ROUTER_CS_DEPTH(cfg);
296 sc->uuid[0] = cfg->uuid_lo;
297 sc->uuid[1] = cfg->uuid_hi;
298 sc->uuid[2] = 0xffffffff;
299 sc->uuid[3] = 0xffffffff;
300 tb_debug(sc, DBG_ROUTER, "Router upstream_port= %d, max_port= %d, "
301 "depth= %d\n", up, sc->max_adap, sc->depth);
302 free(buf, M_THUNDERBOLT);
303
304 /* Downstream adapters are indexed in the array allocated here. */
305 sc->max_adap = MIN(sc->max_adap, ROUTER_CS1_MAX_ADAPTERS);
306 sc->adapters = malloc((1 + sc->max_adap) * sizeof(void *),
307 M_THUNDERBOLT, M_NOWAIT|M_ZERO);
308 if (sc->adapters == NULL) {
309 tb_debug(sc, DBG_ROUTER,
310 "Cannot allocate downstream adapter memory\n");
311 return (ENOMEM);
312 }
313
314 tb_debug(sc, DBG_ROUTER, "Router created, route 0x%08x%08x\n",
315 sc->route.hi, sc->route.lo);
316
317 return (0);
318 }
319
320 int
tb_router_detach(struct router_softc * sc)321 tb_router_detach(struct router_softc *sc)
322 {
323
324 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_router_deattach called\n");
325
326 if (TAILQ_FIRST(&sc->cmd_queue) != NULL)
327 return (EBUSY);
328
329 mtx_destroy(&sc->mtx);
330
331 if (sc->adapters != NULL)
332 free(sc->adapters, M_THUNDERBOLT);
333
334 if (sc != NULL)
335 free(sc, M_THUNDERBOLT);
336
337 return (0);
338 }
339
340 static void
router_get_config_cb(struct router_softc * sc,struct router_command * cmd,void * arg)341 router_get_config_cb(struct router_softc *sc, struct router_command *cmd,
342 void *arg)
343 {
344 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_get_config_cb called\n");
345
346 /*
347 * Only do the copy if the command didn't have a notify event thrown.
348 * These events serve as asynchronous exception signals, which is
349 * cumbersome.
350 */
351 if (cmd->ev == 0)
352 bcopy((uint8_t *)cmd->resp_buffer,
353 (uint8_t *)cmd->callback_arg, cmd->dwlen * 4);
354
355 mtx_lock(&sc->mtx);
356 sc->inflight_cmd = NULL;
357
358 if ((cmd->flags & RCMD_POLLED) == 0)
359 wakeup(cmd);
360 else
361 cmd->flags |= RCMD_POLL_COMPLETE;
362
363 router_schedule_locked(sc, NULL);
364 mtx_unlock(&sc->mtx);
365 }
366
367 int
tb_config_read(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)368 tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
369 u_int offset, u_int dwlen, uint32_t *buf)
370 {
371 struct router_command *cmd;
372 int error, retries;
373
374 if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
375 router_get_config_cb, &cmd)) != 0)
376 return (error);
377
378 retries = cmd->retries;
379 mtx_lock(&sc->mtx);
380 while (retries-- >= 0) {
381 error = router_schedule_locked(sc, cmd);
382 if (error)
383 break;
384
385 error = msleep(cmd, &sc->mtx, 0, "tbtcfg", cmd->timeout * hz);
386 if (error != EWOULDBLOCK)
387 break;
388 sc->inflight_cmd = NULL;
389 tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
390 }
391
392 if (cmd->ev != 0)
393 error = EINVAL;
394 router_free_cmd(sc, cmd);
395 mtx_unlock(&sc->mtx);
396 return (error);
397 }
398
399 int
tb_config_read_polled(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)400 tb_config_read_polled(struct router_softc *sc, u_int space, u_int adapter,
401 u_int offset, u_int dwlen, uint32_t *buf)
402 {
403 struct router_command *cmd;
404 int error, retries, timeout;
405
406 if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
407 router_get_config_cb, &cmd)) != 0)
408 return (error);
409
410 retries = cmd->retries;
411 cmd->flags |= RCMD_POLLED;
412 timeout = cmd->timeout * 1000000;
413
414 mtx_lock(&sc->mtx);
415 while (retries-- >= 0) {
416 error = router_schedule_locked(sc, cmd);
417 if (error)
418 break;
419 mtx_unlock(&sc->mtx);
420
421 while (timeout > 0) {
422 DELAY(100 * 1000);
423 if ((cmd->flags & RCMD_POLL_COMPLETE) != 0)
424 break;
425 timeout -= 100000;
426 }
427
428 mtx_lock(&sc->mtx);
429 if ((cmd->flags & RCMD_POLL_COMPLETE) == 0) {
430 error = ETIMEDOUT;
431 sc->inflight_cmd = NULL;
432 tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
433 continue;
434 } else
435 break;
436 }
437
438 if (cmd->ev != 0)
439 error = EINVAL;
440 router_free_cmd(sc, cmd);
441 mtx_unlock(&sc->mtx);
442 return (error);
443 }
444
445 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)446 tb_config_read_async(struct router_softc *sc, u_int space, u_int adapter,
447 u_int offset, u_int dwlen, uint32_t *buf, void *cb)
448 {
449 struct router_command *cmd;
450 int error;
451
452 if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
453 cb, &cmd)) != 0)
454 return (error);
455
456 error = router_schedule(sc, cmd);
457
458 return (error);
459 }
460
461 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)462 _tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
463 u_int offset, u_int dwlen, uint32_t *buf, void *cb,
464 struct router_command **rcmd)
465 {
466 struct router_command *cmd;
467 struct tb_cfg_read *msg;
468 int error;
469
470 if ((error = router_alloc_cmd(sc, &cmd)) != 0)
471 return (error);
472
473 msg = router_get_frame_data(cmd);
474 bzero(msg, sizeof(*msg));
475 msg->route.hi = sc->route.hi;
476 msg->route.lo = sc->route.lo;
477 msg->addr_attrs = TB_CONFIG_ADDR(0, space, adapter, dwlen, offset);
478 cmd->callback = cb;
479 cmd->callback_arg = buf;
480 cmd->dwlen = dwlen;
481 router_prepare_read(sc, cmd, sizeof(*msg));
482
483 if (rcmd != NULL)
484 *rcmd = cmd;
485
486 return (0);
487 }
488
489 int
tb_config_write(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)490 tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
491 u_int offset, u_int dwlen, uint32_t *buf)
492 {
493
494 return(0);
495 }
496
497 static int
router_alloc_cmd(struct router_softc * sc,struct router_command ** rcmd)498 router_alloc_cmd(struct router_softc *sc, struct router_command **rcmd)
499 {
500 struct router_command *cmd;
501
502 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_alloc_cmd\n");
503
504 cmd = malloc(sizeof(*cmd), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
505 if (cmd == NULL) {
506 tb_debug(sc, DBG_ROUTER, "Cannot allocate cmd/response\n");
507 return (ENOMEM);
508 }
509
510 cmd->nhicmd = nhi_alloc_tx_frame(sc->ring0);
511 if (cmd->nhicmd == NULL) {
512 tb_debug(sc, DBG_ROUTER, "Cannot allocate command frame\n");
513 free(cmd, M_THUNDERBOLT);
514 return (EBUSY);
515 }
516
517 cmd->sc = sc;
518 *rcmd = cmd;
519 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Allocated command with index %d\n",
520 cmd->nhicmd->idx);
521
522 return (0);
523 }
524
525 static void
router_free_cmd(struct router_softc * sc,struct router_command * cmd)526 router_free_cmd(struct router_softc *sc, struct router_command *cmd)
527 {
528
529 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_free_cmd\n");
530
531 if (cmd == NULL)
532 return;
533
534 if (cmd->nhicmd != NULL) {
535 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Freeing nhi command %d\n",
536 cmd->nhicmd->idx);
537 nhi_free_tx_frame(sc->ring0, cmd->nhicmd);
538 }
539 free(cmd, M_THUNDERBOLT);
540
541 return;
542 }
543
544 static void
router_prepare_read(struct router_softc * sc,struct router_command * cmd,int len)545 router_prepare_read(struct router_softc *sc, struct router_command *cmd,
546 int len)
547 {
548 struct nhi_cmd_frame *nhicmd;
549 uint32_t *msg;
550 int msglen, i;
551
552 KASSERT(cmd != NULL, ("cmd cannot be NULL\n"));
553 KASSERT(len != 0, ("Invalid zero-length command\n"));
554 KASSERT(len % 4 == 0, ("Message must be 32bit padded\n"));
555
556 nhicmd = cmd->nhicmd;
557 msglen = (len - 4) / 4;
558 for (i = 0; i < msglen; i++)
559 nhicmd->data[i] = htobe32(nhicmd->data[i]);
560
561 msg = (uint32_t *)nhicmd->data;
562 msg[msglen] = htobe32(tb_calc_crc(nhicmd->data, len-4));
563
564 nhicmd->pdf = PDF_READ;
565 nhicmd->req_len = len;
566
567 nhicmd->timeout = NHI_CMD_TIMEOUT;
568 nhicmd->retries = 0;
569 nhicmd->resp_buffer = (uint32_t *)cmd->resp_buffer;
570 nhicmd->resp_len = (cmd->dwlen + 3) * 4;
571 nhicmd->context = cmd;
572
573 cmd->retries = CFG_DEFAULT_RETRIES;
574 cmd->timeout = CFG_DEFAULT_TIMEOUT;
575
576 return;
577 }
578
579 static int
router_schedule(struct router_softc * sc,struct router_command * cmd)580 router_schedule(struct router_softc *sc, struct router_command *cmd)
581 {
582 int error;
583
584 mtx_lock(&sc->mtx);
585 error = router_schedule_locked(sc, cmd);
586 mtx_unlock(&sc->mtx);
587
588 return(error);
589 }
590
591 static int
router_schedule_locked(struct router_softc * sc,struct router_command * cmd)592 router_schedule_locked(struct router_softc *sc, struct router_command *cmd)
593 {
594 struct nhi_cmd_frame *nhicmd;
595 int error;
596
597 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_schedule\n");
598
599 if (cmd != NULL)
600 TAILQ_INSERT_TAIL(&sc->cmd_queue, cmd, link);
601
602 while ((sc->inflight_cmd == NULL) &&
603 ((cmd = TAILQ_FIRST(&sc->cmd_queue)) != NULL)) {
604
605 TAILQ_REMOVE(&sc->cmd_queue, cmd, link);
606 nhicmd = cmd->nhicmd;
607 tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
608 "Scheduling command with index %d\n", nhicmd->idx);
609 sc->inflight_cmd = cmd;
610 if ((error = nhi_tx_schedule(sc->ring0, nhicmd)) != 0) {
611 tb_debug(sc, DBG_ROUTER, "nhi ring error "
612 "%d\n", error);
613 sc->inflight_cmd = NULL;
614 if (error == EBUSY) {
615 TAILQ_INSERT_HEAD(&sc->cmd_queue, cmd, link);
616 error = 0;
617 }
618 break;
619 }
620 }
621
622 return (error);
623 }
624
625 static void
router_complete_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)626 router_complete_intr(void *context, union nhi_ring_desc *ring,
627 struct nhi_cmd_frame *nhicmd)
628 {
629 struct router_softc *sc;
630 struct router_command *cmd;
631
632 KASSERT(context != NULL, ("context cannot be NULL\n"));
633 KASSERT(nhicmd != NULL, ("nhicmd cannot be NULL\n"));
634
635 cmd = (struct router_command *)(nhicmd->context);
636 sc = cmd->sc;
637 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_complete_intr called\n");
638
639 if (nhicmd->flags & CMD_RESP_COMPLETE) {
640 cmd->callback(sc, cmd, cmd->callback_arg);
641 }
642
643 return;
644 }
645
646 static void
router_response_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)647 router_response_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
648 {
649 struct router_softc *sc, *dev;
650 struct tb_cfg_read_resp *read;
651 struct tb_cfg_write_resp *write;
652 struct router_command *cmd;
653 tb_route_t route;
654 u_int error, i, eof, len;
655 uint32_t attrs;
656
657 KASSERT(context != NULL, ("context cannot be NULL\n"));
658
659 sc = (struct router_softc *)context;
660 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_response_intr called\n");
661
662 eof = ring->rxpost.eof_len >> RX_BUFFER_DESC_EOF_SHIFT;
663
664 if (eof == PDF_WRITE) {
665 write = (struct tb_cfg_write_resp *)nhicmd->data;
666 route.hi = be32toh(write->route.hi);
667 route.lo = be32toh(write->route.lo);
668 } else {
669 read = (struct tb_cfg_read_resp *)nhicmd->data;
670 route.hi = be32toh(read->route.hi);
671 route.lo = be32toh(read->route.lo);
672 attrs = be32toh(read->addr_attrs);
673 len = (attrs & TB_CFG_SIZE_MASK) >> TB_CFG_SIZE_SHIFT;
674 }
675
676 /* XXX Is this a problem? */
677 if ((route.hi & 0x80000000) == 0)
678 tb_debug(sc, DBG_ROUTER, "Invalid route\n");
679 route.hi &= ~0x80000000;
680
681 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Looking up route 0x%08x%08x\n",
682 route.hi, route.lo);
683
684 error = router_lookup_device(sc, route, &dev);
685 if (error != 0 || dev == NULL) {
686 tb_debug(sc, DBG_ROUTER, "Cannot find device, error= %d\n",
687 error);
688 return;
689 }
690
691 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Found device %s route 0x%08x%08x, "
692 "inflight_cmd= %p\n", device_get_nameunit(dev->dev), dev->route.hi,
693 dev->route.lo, dev->inflight_cmd);
694
695 cmd = dev->inflight_cmd;
696 if (cmd == NULL) {
697 tb_debug(dev, DBG_ROUTER, "Null inflight cmd\n");
698 return;
699 }
700
701 if (eof == PDF_READ) {
702 for (i = 0; i < len; i++)
703 cmd->nhicmd->resp_buffer[i] = be32toh(read->data[i]);
704 }
705
706 cmd->nhicmd->flags |= CMD_RESP_COMPLETE;
707 if (cmd->nhicmd->flags & CMD_REQ_COMPLETE) {
708 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "TX_COMPLETE set\n");
709 cmd->callback(dev, cmd, cmd->callback_arg);
710 }
711
712 return;
713 }
714
715 static void
router_notify_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)716 router_notify_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
717 {
718 struct router_softc *sc;
719 struct router_command *cmd;
720 struct tb_cfg_notify event;
721 u_int ev, adap;
722
723 KASSERT(context != NULL, ("context cannot be NULL\n"));
724
725 sc = (struct router_softc *)context;
726 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_notify_intr called\n");
727
728 event.route.hi = be32toh(nhicmd->data[0]);
729 event.route.lo = be32toh(nhicmd->data[1]);
730 event.event_adap = be32toh(nhicmd->data[2]);
731
732 ev = GET_NOTIFY_EVENT(&event);
733 adap = GET_NOTIFY_ADAPTER(&event);
734
735 tb_debug(sc, DBG_ROUTER, "Event route 0x%08x%08x adap %d code %s\n",
736 event.route.hi, event.route.lo, adap,
737 tb_get_string(ev, tb_notify_event));
738
739 switch (ev) {
740 case TB_CFG_ERR_CONN:
741 case TB_CFG_ERR_LINK:
742 case TB_CFG_ERR_ADDR:
743 case TB_CFG_ERR_ADP:
744 case TB_CFG_ERR_ENUM:
745 case TB_CFG_ERR_NUA:
746 case TB_CFG_ERR_LEN:
747 case TB_CFG_ERR_HEC:
748 case TB_CFG_ERR_FC:
749 case TB_CFG_ERR_PLUG:
750 case TB_CFG_ERR_LOCK:
751 case TB_CFG_HP_ACK:
752 case TB_CFG_DP_BW:
753 if (sc->inflight_cmd != NULL) {
754 cmd = sc->inflight_cmd;
755 cmd->ev = ev;
756 cmd->callback(sc, cmd, cmd->callback_arg);
757 }
758 break;
759 default:
760 break;
761 }
762 return;
763 }
764
765 int
tb_config_next_cap(struct router_softc * sc,struct router_cfg_cap * cap)766 tb_config_next_cap(struct router_softc *sc, struct router_cfg_cap *cap)
767 {
768 union tb_cfg_cap *tbcap;
769 uint32_t *buf;
770 uint16_t current;
771 int error;
772
773 KASSERT(cap != NULL, ("cap cannot be NULL\n"));
774 KASSERT(cap->next_cap != 0, ("next_cap cannot be 0\n"));
775
776 buf = malloc(sizeof(*tbcap), M_THUNDERBOLT, M_NOWAIT|M_ZERO);
777
778 current = cap->next_cap;
779 error = tb_config_read(sc, cap->space, cap->adap, current, 1, buf);
780 if (error)
781 return (error);
782
783 tbcap = (union tb_cfg_cap *)buf;
784 cap->cap_id = tbcap->hdr.cap_id;
785 cap->next_cap = tbcap->hdr.next_cap;
786 cap->current_cap = current;
787
788 if ((cap->space != TB_CFG_CS_ROUTER) &&
789 (tbcap->hdr.cap_id != TB_CFG_CAP_VSC)) {
790 free(buf, M_THUNDERBOLT);
791 return (0);
792 }
793
794 tb_config_read(sc, cap->space, cap->adap, current, 2, buf);
795 if (error) {
796 free(buf, M_THUNDERBOLT);
797 return (error);
798 }
799
800 cap->vsc_id = tbcap->vsc.vsc_id;
801 cap->vsc_len = tbcap->vsc.len;
802 if (tbcap->vsc.len == 0) {
803 cap->next_cap = tbcap->vsec.vsec_next_cap;
804 cap->vsec_len = tbcap->vsec.vsec_len;
805 }
806
807 free(buf, M_THUNDERBOLT);
808 return (0);
809 }
810
811 int
tb_config_find_cap(struct router_softc * sc,struct router_cfg_cap * cap)812 tb_config_find_cap(struct router_softc *sc, struct router_cfg_cap *cap)
813 {
814 u_int cap_id, vsc_id;
815 int error;
816
817 tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_config_find_cap called\n");
818
819 cap_id = cap->cap_id;
820 vsc_id = cap->vsc_id;
821
822 cap->cap_id = cap->vsc_id = 0;
823 while ((cap->cap_id != cap_id) || (cap->vsc_id != vsc_id)) {
824 tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
825 "Looking for cap %d at offset %d\n", cap->cap_id,
826 cap->next_cap);
827 if ((cap->next_cap == 0) ||
828 (cap->next_cap > TB_CFG_CAP_OFFSET_MAX))
829 return (EINVAL);
830 error = tb_config_next_cap(sc, cap);
831 if (error)
832 break;
833 }
834
835 return (0);
836 }
837
838 int
tb_config_find_router_cap(struct router_softc * sc,u_int cap,u_int vsc,u_int * offset)839 tb_config_find_router_cap(struct router_softc *sc, u_int cap, u_int vsc, u_int *offset)
840 {
841 struct router_cfg_cap rcap;
842 struct tb_cfg_router *cfg;
843 uint32_t *buf;
844 int error;
845
846 buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
847 if (buf == NULL)
848 return (ENOMEM);
849
850 error = tb_config_router_read(sc, 0, 5, buf);
851 if (error != 0) {
852 free(buf, M_THUNDERBOLT);
853 return (error);
854 }
855
856 cfg = (struct tb_cfg_router *)buf;
857 rcap.space = TB_CFG_CS_ROUTER;
858 rcap.adap = 0;
859 rcap.next_cap = GET_ROUTER_CS_NEXT_CAP(cfg);
860 rcap.cap_id = cap;
861 rcap.vsc_id = vsc;
862 error = tb_config_find_cap(sc, &rcap);
863 if (error == 0)
864 *offset = rcap.current_cap;
865
866 free(buf, M_THUNDERBOLT);
867 return (error);
868 }
869
870 int
tb_config_find_router_vsc(struct router_softc * sc,u_int cap,u_int * offset)871 tb_config_find_router_vsc(struct router_softc *sc, u_int cap, u_int *offset)
872 {
873
874 return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSC, cap, offset));
875 }
876
877 int
tb_config_find_router_vsec(struct router_softc * sc,u_int cap,u_int * offset)878 tb_config_find_router_vsec(struct router_softc *sc, u_int cap, u_int *offset)
879 {
880
881 return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSEC, cap, offset));
882 }
883
884 int
tb_config_find_adapter_cap(struct router_softc * sc,u_int adap,u_int cap,u_int * offset)885 tb_config_find_adapter_cap(struct router_softc *sc, u_int adap, u_int cap, u_int *offset)
886 {
887 struct router_cfg_cap rcap;
888 struct tb_cfg_adapter *cfg;
889 uint32_t *buf;
890 int error;
891
892 buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
893 if (buf == NULL)
894 return (ENOMEM);
895
896 error = tb_config_adapter_read(sc, adap, 0, 8, buf);
897 if (error != 0) {
898 free(buf, M_THUNDERBOLT);
899 return (error);
900 }
901
902 cfg = (struct tb_cfg_adapter *)buf;
903 rcap.space = TB_CFG_CS_ADAPTER;
904 rcap.adap = adap;
905 rcap.next_cap = GET_ADP_CS_NEXT_CAP(cfg);
906 rcap.cap_id = cap;
907 rcap.vsc_id = 0;
908 error = tb_config_find_cap(sc, &rcap);
909 if (error == 0)
910 *offset = rcap.current_cap;
911
912 free(buf, M_THUNDERBOLT);
913 return (error);
914 }
915
916 int
tb_config_get_lc_uuid(struct router_softc * rsc,uint8_t * uuid)917 tb_config_get_lc_uuid(struct router_softc *rsc, uint8_t *uuid)
918 {
919 u_int error, offset;
920 uint32_t buf[8];
921
922 bzero(buf, sizeof(buf));
923
924 error = tb_config_find_router_vsec(rsc, TB_CFG_VSEC_LC, &offset);
925 if (error != 0) {
926 tb_debug(rsc, DBG_ROUTER, "Error finding LC registers: %d\n",
927 error);
928 return (error);
929 }
930
931 error = tb_config_router_read(rsc, offset + TB_LC_UUID, 4, buf);
932 if (error != 0) {
933 tb_debug(rsc, DBG_ROUTER, "Error fetching UUID: %d\n", error);
934 return (error);
935 }
936
937 bcopy(buf, uuid, 16);
938 return (0);
939 }
940