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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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