1 /*- 2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * Abstract BHND Bridge Device Driver 35 * 36 * Provides generic support for bridging from a parent bus (such as PCI) to 37 * a BHND-compatible bus (e.g. bcma or siba). 38 */ 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/bus.h> 43 #include <sys/module.h> 44 #include <sys/systm.h> 45 46 #include <machine/bus.h> 47 #include <sys/rman.h> 48 #include <machine/resource.h> 49 50 #include <dev/bhnd/bhndvar.h> 51 #include <dev/bhnd/bhndreg.h> 52 53 #include <dev/bhnd/cores/chipc/chipcreg.h> 54 55 #include "bhndbvar.h" 56 #include "bhndb_bus_if.h" 57 #include "bhndb_hwdata.h" 58 #include "bhndb_private.h" 59 60 /* Debugging flags */ 61 static u_long bhndb_debug = 0; 62 TUNABLE_ULONG("hw.bhndb.debug", &bhndb_debug); 63 64 enum { 65 BHNDB_DEBUG_PRIO = 1 << 0, 66 }; 67 68 #define BHNDB_DEBUG(_type) (BHNDB_DEBUG_ ## _type & bhndb_debug) 69 70 static bool bhndb_hw_matches(device_t *devlist, 71 int num_devs, 72 const struct bhndb_hw *hw); 73 74 static int bhndb_initialize_region_cfg( 75 struct bhndb_softc *sc, device_t *devs, 76 int ndevs, 77 const struct bhndb_hw_priority *table, 78 struct bhndb_resources *r); 79 80 static int bhndb_find_hwspec(struct bhndb_softc *sc, 81 device_t *devs, int ndevs, 82 const struct bhndb_hw **hw); 83 84 static int bhndb_read_chipid(struct bhndb_softc *sc, 85 const struct bhndb_hwcfg *cfg, 86 struct bhnd_chipid *result); 87 88 static struct rman *bhndb_get_rman(struct bhndb_softc *sc, 89 int type); 90 91 static int bhndb_init_child_resource(struct resource *r, 92 struct resource *parent, 93 bhnd_size_t offset, 94 bhnd_size_t size); 95 96 static int bhndb_activate_static_region( 97 struct bhndb_softc *sc, 98 struct bhndb_region *region, 99 device_t child, int type, int rid, 100 struct resource *r); 101 102 static int bhndb_try_activate_resource( 103 struct bhndb_softc *sc, device_t child, 104 int type, int rid, struct resource *r, 105 bool *indirect); 106 107 108 /** 109 * Default bhndb(4) implementation of DEVICE_PROBE(). 110 * 111 * This function provides the default bhndb implementation of DEVICE_PROBE(), 112 * and is compatible with bhndb(4) bridges attached via bhndb_attach_bridge(). 113 */ 114 int 115 bhndb_generic_probe(device_t dev) 116 { 117 return (BUS_PROBE_NOWILDCARD); 118 } 119 120 static void 121 bhndb_probe_nomatch(device_t dev, device_t child) 122 { 123 const char *name; 124 125 name = device_get_name(child); 126 if (name == NULL) 127 name = "unknown device"; 128 129 device_printf(dev, "<%s> (no driver attached)\n", name); 130 } 131 132 static int 133 bhndb_print_child(device_t dev, device_t child) 134 { 135 struct bhndb_softc *sc; 136 struct resource_list *rl; 137 int retval = 0; 138 139 sc = device_get_softc(dev); 140 141 retval += bus_print_child_header(dev, child); 142 143 rl = BUS_GET_RESOURCE_LIST(dev, child); 144 if (rl != NULL) { 145 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, 146 "%#lx"); 147 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, 148 "%ld"); 149 } 150 151 retval += bus_print_child_domain(dev, child); 152 retval += bus_print_child_footer(dev, child); 153 154 return (retval); 155 } 156 157 static int 158 bhndb_child_pnpinfo_str(device_t bus, device_t child, char *buf, 159 size_t buflen) 160 { 161 *buf = '\0'; 162 return (0); 163 } 164 165 static int 166 bhndb_child_location_str(device_t dev, device_t child, char *buf, 167 size_t buflen) 168 { 169 struct bhndb_softc *sc; 170 171 sc = device_get_softc(dev); 172 173 snprintf(buf, buflen, "base=0x%llx", 174 (unsigned long long) sc->chipid.enum_addr); 175 return (0); 176 } 177 178 /** 179 * Return true if @p devlist matches the @p hw specification. 180 * 181 * @param devlist A device table to match against. 182 * @param num_devs The number of devices in @p devlist. 183 * @param hw The hardware description to be matched against. 184 */ 185 static bool 186 bhndb_hw_matches(device_t *devlist, int num_devs, const struct bhndb_hw *hw) 187 { 188 for (u_int i = 0; i < hw->num_hw_reqs; i++) { 189 const struct bhnd_core_match *match; 190 bool found; 191 192 match = &hw->hw_reqs[i]; 193 found = false; 194 195 for (int d = 0; d < num_devs; d++) { 196 if (!bhnd_device_matches(devlist[d], match)) 197 continue; 198 199 found = true; 200 break; 201 } 202 203 if (!found) 204 return (false); 205 } 206 207 return (true); 208 } 209 210 /** 211 * Initialize the region maps and priority configuration in @p r using 212 * the provided priority @p table and the set of devices attached to 213 * the bridged @p bus_dev . 214 * 215 * @param sc The bhndb device state. 216 * @param devs All devices enumerated on the bridged bhnd bus. 217 * @param ndevs The length of @p devs. 218 * @param table Hardware priority table to be used to determine the relative 219 * priorities of per-core port resources. 220 * @param r The resource state to be configured. 221 */ 222 static int 223 bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs, 224 const struct bhndb_hw_priority *table, struct bhndb_resources *r) 225 { 226 const struct bhndb_hw_priority *hp; 227 bhnd_addr_t addr; 228 bhnd_size_t size; 229 size_t prio_low, prio_default, prio_high; 230 int error; 231 232 /* The number of port regions per priority band that must be accessible 233 * via dynamic register windows */ 234 prio_low = 0; 235 prio_default = 0; 236 prio_high = 0; 237 238 /* 239 * Register bridge regions covering all statically mapped ports. 240 */ 241 for (int i = 0; i < ndevs; i++) { 242 const struct bhndb_regwin *regw; 243 device_t child; 244 245 child = devs[i]; 246 247 for (regw = r->cfg->register_windows; 248 regw->win_type != BHNDB_REGWIN_T_INVALID; regw++) 249 { 250 /* Only core windows are supported */ 251 if (regw->win_type != BHNDB_REGWIN_T_CORE) 252 continue; 253 254 /* Skip non-applicable register windows. */ 255 if (!bhndb_regwin_matches_device(regw, child)) 256 continue; 257 258 /* Fetch the base address of the mapped port. */ 259 error = bhnd_get_region_addr(child, 260 regw->core.port_type, regw->core.port, 261 regw->core.region, &addr, &size); 262 if (error) 263 return (error); 264 265 /* 266 * Always defer to the register window's size. 267 * 268 * If the port size is smaller than the window size, 269 * this ensures that we fully utilize register windows 270 * larger than the referenced port. 271 * 272 * If the port size is larger than the window size, this 273 * ensures that we do not directly map the allocations 274 * within the region to a too-small window. 275 */ 276 size = regw->win_size; 277 278 /* 279 * Add to the bus region list. 280 * 281 * The window priority for a statically mapped 282 * region is always HIGH. 283 */ 284 error = bhndb_add_resource_region(r, addr, size, 285 BHNDB_PRIORITY_HIGH, regw); 286 if (error) 287 return (error); 288 } 289 } 290 291 /* 292 * Perform priority accounting and register bridge regions for all 293 * ports defined in the priority table 294 */ 295 for (int i = 0; i < ndevs; i++) { 296 struct bhndb_region *region; 297 device_t child; 298 299 child = devs[i]; 300 301 /* 302 * Skip priority accounting for cores that ... 303 */ 304 305 /* ... do not require bridge resources */ 306 if (bhnd_is_hw_disabled(child) || !device_is_enabled(child)) 307 continue; 308 309 /* ... do not have a priority table entry */ 310 hp = bhndb_hw_priority_find_device(table, child); 311 if (hp == NULL) 312 continue; 313 314 /* ... are explicitly disabled in the priority table. */ 315 if (hp->priority == BHNDB_PRIORITY_NONE) 316 continue; 317 318 /* Determine the number of dynamic windows required and 319 * register their bus_region entries. */ 320 for (u_int i = 0; i < hp->num_ports; i++) { 321 const struct bhndb_port_priority *pp; 322 323 pp = &hp->ports[i]; 324 325 /* Skip ports not defined on this device */ 326 if (!bhnd_is_region_valid(child, pp->type, pp->port, 327 pp->region)) 328 { 329 continue; 330 } 331 332 /* Fetch the address+size of the mapped port. */ 333 error = bhnd_get_region_addr(child, pp->type, pp->port, 334 pp->region, &addr, &size); 335 if (error) 336 return (error); 337 338 /* Skip ports with an existing static mapping */ 339 region = bhndb_find_resource_region(r, addr, size); 340 if (region != NULL && region->static_regwin != NULL) 341 continue; 342 343 /* Define a dynamic region for this port */ 344 error = bhndb_add_resource_region(r, addr, size, 345 pp->priority, NULL); 346 if (error) 347 return (error); 348 349 /* Update port mapping counts */ 350 switch (pp->priority) { 351 case BHNDB_PRIORITY_NONE: 352 break; 353 case BHNDB_PRIORITY_LOW: 354 prio_low++; 355 break; 356 case BHNDB_PRIORITY_DEFAULT: 357 prio_default++; 358 break; 359 case BHNDB_PRIORITY_HIGH: 360 prio_high++; 361 break; 362 } 363 } 364 } 365 366 /* Determine the minimum priority at which we'll allocate direct 367 * register windows from our dynamic pool */ 368 size_t prio_total = prio_low + prio_default + prio_high; 369 if (prio_total <= r->dwa_count) { 370 /* low+default+high priority regions get windows */ 371 r->min_prio = BHNDB_PRIORITY_LOW; 372 373 } else if (prio_default + prio_high <= r->dwa_count) { 374 /* default+high priority regions get windows */ 375 r->min_prio = BHNDB_PRIORITY_DEFAULT; 376 377 } else { 378 /* high priority regions get windows */ 379 r->min_prio = BHNDB_PRIORITY_HIGH; 380 } 381 382 if (BHNDB_DEBUG(PRIO)) { 383 struct bhndb_region *region; 384 const char *direct_msg, *type_msg; 385 bhndb_priority_t prio, prio_min; 386 387 prio_min = r->min_prio; 388 device_printf(sc->dev, "min_prio: %d\n", prio_min); 389 390 STAILQ_FOREACH(region, &r->bus_regions, link) { 391 prio = region->priority; 392 393 direct_msg = prio >= prio_min ? "direct" : "indirect"; 394 type_msg = region->static_regwin ? "static" : "dynamic"; 395 396 device_printf(sc->dev, "region 0x%llx+0x%llx priority " 397 "%u %s/%s\n", 398 (unsigned long long) region->addr, 399 (unsigned long long) region->size, 400 region->priority, 401 direct_msg, type_msg); 402 } 403 } 404 405 return (0); 406 } 407 408 /** 409 * Find a hardware specification for @p dev. 410 * 411 * @param sc The bhndb device state. 412 * @param devs All devices enumerated on the bridged bhnd bus. 413 * @param ndevs The length of @p devs. 414 * @param[out] hw On success, the matched hardware specification. 415 * with @p dev. 416 * 417 * @retval 0 success 418 * @retval non-zero if an error occurs fetching device info for comparison. 419 */ 420 static int 421 bhndb_find_hwspec(struct bhndb_softc *sc, device_t *devs, int ndevs, 422 const struct bhndb_hw **hw) 423 { 424 const struct bhndb_hw *next, *hw_table; 425 426 /* Search for the first matching hardware config. */ 427 hw_table = BHNDB_BUS_GET_HARDWARE_TABLE(sc->parent_dev, sc->dev); 428 for (next = hw_table; next->hw_reqs != NULL; next++) { 429 if (!bhndb_hw_matches(devs, ndevs, next)) 430 continue; 431 432 /* Found */ 433 *hw = next; 434 return (0); 435 } 436 437 return (ENOENT); 438 } 439 440 /** 441 * Read the ChipCommon identification data for this device. 442 * 443 * @param sc bhndb device state. 444 * @param cfg The hardware configuration to use when mapping the ChipCommon 445 * registers. 446 * @param[out] result the chip identification data. 447 * 448 * @retval 0 success 449 * @retval non-zero if the ChipCommon identification data could not be read. 450 */ 451 static int 452 bhndb_read_chipid(struct bhndb_softc *sc, const struct bhndb_hwcfg *cfg, 453 struct bhnd_chipid *result) 454 { 455 const struct bhnd_chipid *parent_cid; 456 const struct bhndb_regwin *cc_win; 457 struct resource_spec rs; 458 int error; 459 460 /* Let our parent device override the discovery process */ 461 parent_cid = BHNDB_BUS_GET_CHIPID(sc->parent_dev, sc->dev); 462 if (parent_cid != NULL) { 463 *result = *parent_cid; 464 return (0); 465 } 466 467 /* Find a register window we can use to map the first CHIPC_CHIPID_SIZE 468 * of ChipCommon registers. */ 469 cc_win = bhndb_regwin_find_best(cfg->register_windows, 470 BHND_DEVCLASS_CC, 0, BHND_PORT_DEVICE, 0, 0, CHIPC_CHIPID_SIZE); 471 if (cc_win == NULL) { 472 device_printf(sc->dev, "no chipcommon register window\n"); 473 return (0); 474 } 475 476 /* We can assume a device without a static ChipCommon window uses the 477 * default ChipCommon address. */ 478 if (cc_win->win_type == BHNDB_REGWIN_T_DYN) { 479 error = BHNDB_SET_WINDOW_ADDR(sc->dev, cc_win, 480 BHND_DEFAULT_CHIPC_ADDR); 481 482 if (error) { 483 device_printf(sc->dev, "failed to set chipcommon " 484 "register window\n"); 485 return (error); 486 } 487 } 488 489 /* Let the default bhnd implemenation alloc/release the resource and 490 * perform the read */ 491 rs.type = cc_win->res.type; 492 rs.rid = cc_win->res.rid; 493 rs.flags = RF_ACTIVE; 494 495 return (bhnd_read_chipid(sc->parent_dev, &rs, cc_win->win_offset, 496 result)); 497 } 498 499 /** 500 * Helper function that must be called by subclass bhndb(4) drivers 501 * when implementing DEVICE_ATTACH() before calling any bhnd(4) or bhndb(4) 502 * APIs on the bridge device. 503 * 504 * @param dev The bridge device to attach. 505 * @param bridge_devclass The device class of the bridging core. This is used 506 * to automatically detect the bridge core, and to disable additional bridge 507 * cores (e.g. PCMCIA on a PCIe device). 508 */ 509 int 510 bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass) 511 { 512 struct bhndb_softc *sc; 513 const struct bhndb_hwcfg *cfg; 514 int error; 515 516 sc = device_get_softc(dev); 517 sc->dev = dev; 518 sc->parent_dev = device_get_parent(dev); 519 sc->bridge_class = bridge_devclass; 520 521 BHNDB_LOCK_INIT(sc); 522 523 /* Read our chip identification data */ 524 cfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, sc->dev); 525 if ((error = bhndb_read_chipid(sc, cfg, &sc->chipid))) 526 return (error); 527 528 /* Set up a resource manager for the device's address space. */ 529 sc->mem_rman.rm_start = 0; 530 sc->mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT; 531 sc->mem_rman.rm_type = RMAN_ARRAY; 532 sc->mem_rman.rm_descr = "BHND I/O memory addresses"; 533 534 if ((error = rman_init(&sc->mem_rman))) { 535 device_printf(dev, "could not initialize mem_rman\n"); 536 return (error); 537 } 538 539 error = rman_manage_region(&sc->mem_rman, 0, BUS_SPACE_MAXADDR_32BIT); 540 if (error) { 541 device_printf(dev, "could not configure mem_rman\n"); 542 goto failed; 543 } 544 545 /* Initialize basic resource allocation state. */ 546 sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg); 547 if (sc->bus_res == NULL) { 548 error = ENXIO; 549 goto failed; 550 } 551 552 /* Attach our bridged bus device */ 553 sc->bus_dev = device_add_child(dev, devclass_get_name(bhnd_devclass), 554 -1); 555 if (sc->bus_dev == NULL) { 556 error = ENXIO; 557 goto failed; 558 } 559 560 return (bus_generic_attach(dev)); 561 562 failed: 563 BHNDB_LOCK_DESTROY(sc); 564 565 rman_fini(&sc->mem_rman); 566 567 if (sc->bus_res != NULL) 568 bhndb_free_resources(sc->bus_res); 569 570 return (error); 571 } 572 573 /** 574 * Default bhndb(4) implementation of BHNDB_INIT_FULL_CONFIG(). 575 * 576 * This function provides the default bhndb implementation of 577 * BHNDB_INIT_FULL_CONFIG(), and must be called by any subclass driver 578 * overriding BHNDB_INIT_FULL_CONFIG(). 579 * 580 * As documented by BHNDB_INIT_FULL_CONFIG, this function performs final 581 * bridge configuration based on the hardware information enumerated by the 582 * child bus, and will reset all resource allocation state on the bridge. 583 * 584 * When calling this method: 585 * - Any bus resources previously allocated by @p child must be deallocated. 586 * - The @p child bus must have performed initial enumeration -- but not 587 * probe or attachment -- of its children. 588 */ 589 int 590 bhndb_generic_init_full_config(device_t dev, device_t child, 591 const struct bhndb_hw_priority *hw_prio_table) 592 { 593 struct bhndb_softc *sc; 594 const struct bhndb_hw *hw; 595 struct bhndb_resources *r; 596 device_t *devs; 597 device_t hostb; 598 int ndevs; 599 int error; 600 601 sc = device_get_softc(dev); 602 hostb = NULL; 603 604 /* Fetch the full set of attached devices */ 605 if ((error = device_get_children(sc->bus_dev, &devs, &ndevs))) 606 return (error); 607 608 /* Find our host bridge device */ 609 for (int i = 0; i < ndevs; i++) { 610 if (bhnd_is_hostb_device(devs[i])) { 611 hostb = devs[i]; 612 break; 613 } 614 } 615 616 if (hostb == NULL) { 617 device_printf(sc->dev, "no host bridge core found\n"); 618 error = ENODEV; 619 goto cleanup; 620 } 621 622 /* Find our full register window configuration */ 623 if ((error = bhndb_find_hwspec(sc, devs, ndevs, &hw))) { 624 device_printf(sc->dev, "unable to identify device, " 625 " using generic bridge resource definitions\n"); 626 error = 0; 627 goto cleanup; 628 } 629 630 if (bootverbose) 631 device_printf(sc->dev, "%s resource configuration\n", hw->name); 632 633 /* Release existing resource state */ 634 BHNDB_LOCK(sc); 635 bhndb_free_resources(sc->bus_res); 636 sc->bus_res = NULL; 637 BHNDB_UNLOCK(sc); 638 639 /* Allocate new resource state */ 640 r = bhndb_alloc_resources(dev, sc->parent_dev, hw->cfg); 641 if (r == NULL) { 642 error = ENXIO; 643 goto cleanup; 644 } 645 646 /* Initialize our resource priority configuration */ 647 error = bhndb_initialize_region_cfg(sc, devs, ndevs, hw_prio_table, r); 648 if (error) { 649 bhndb_free_resources(r); 650 goto cleanup; 651 } 652 653 /* Update our bridge state */ 654 BHNDB_LOCK(sc); 655 sc->bus_res = r; 656 sc->hostb_dev = hostb; 657 BHNDB_UNLOCK(sc); 658 659 cleanup: 660 free(devs, M_TEMP); 661 return (error); 662 } 663 664 /** 665 * Default bhndb(4) implementation of DEVICE_DETACH(). 666 * 667 * This function detaches any child devices, and if successful, releases all 668 * resources held by the bridge device. 669 */ 670 int 671 bhndb_generic_detach(device_t dev) 672 { 673 struct bhndb_softc *sc; 674 int error; 675 676 sc = device_get_softc(dev); 677 678 /* Detach children */ 679 if ((error = bus_generic_detach(dev))) 680 return (error); 681 682 /* Clean up our driver state. */ 683 rman_fini(&sc->mem_rman); 684 bhndb_free_resources(sc->bus_res); 685 686 BHNDB_LOCK_DESTROY(sc); 687 688 return (0); 689 } 690 691 /** 692 * Default bhndb(4) implementation of DEVICE_SUSPEND(). 693 * 694 * This function calls bus_generic_suspend() (or implements equivalent 695 * behavior). 696 */ 697 int 698 bhndb_generic_suspend(device_t dev) 699 { 700 return (bus_generic_suspend(dev)); 701 } 702 703 /** 704 * Default bhndb(4) implementation of DEVICE_RESUME(). 705 * 706 * This function calls bus_generic_resume() (or implements equivalent 707 * behavior). 708 */ 709 int 710 bhndb_generic_resume(device_t dev) 711 { 712 struct bhndb_softc *sc; 713 struct bhndb_resources *bus_res; 714 struct bhndb_dw_alloc *dwa; 715 int error; 716 717 sc = device_get_softc(dev); 718 bus_res = sc->bus_res; 719 720 /* Guarantee that all in-use dynamic register windows are mapped to 721 * their previously configured target address. */ 722 BHNDB_LOCK(sc); 723 for (size_t i = 0; i < bus_res->dwa_count; i++) { 724 dwa = &bus_res->dw_alloc[i]; 725 726 /* Skip regions that were not previously used */ 727 if (bhndb_dw_is_free(bus_res, dwa) && dwa->target == 0x0) 728 continue; 729 730 /* Otherwise, ensure the register window is correct before 731 * any children attempt MMIO */ 732 error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target); 733 if (error) 734 break; 735 } 736 BHNDB_UNLOCK(sc); 737 738 /* Error restoring hardware state; children cannot be safely resumed */ 739 if (error) { 740 device_printf(dev, "Unable to restore hardware configuration; " 741 "cannot resume: %d\n", error); 742 return (error); 743 } 744 745 return (bus_generic_resume(dev)); 746 } 747 748 /** 749 * Default implementation of BHNDB_SUSPEND_RESOURCE. 750 */ 751 static void 752 bhndb_suspend_resource(device_t dev, device_t child, int type, 753 struct resource *r) 754 { 755 struct bhndb_softc *sc; 756 struct bhndb_dw_alloc *dwa; 757 758 sc = device_get_softc(dev); 759 760 // TODO: IRQs? 761 if (type != SYS_RES_MEMORY) 762 return; 763 764 BHNDB_LOCK(sc); 765 dwa = bhndb_dw_find_resource(sc->bus_res, r); 766 if (dwa == NULL) { 767 BHNDB_UNLOCK(sc); 768 return; 769 } 770 771 if (BHNDB_DEBUG(PRIO)) 772 device_printf(child, "suspend resource type=%d 0x%lx+0x%lx\n", 773 type, rman_get_start(r), rman_get_size(r)); 774 775 /* Release the resource's window reference */ 776 bhndb_dw_release(sc->bus_res, dwa, r); 777 BHNDB_UNLOCK(sc); 778 } 779 780 /** 781 * Default implementation of BHNDB_RESUME_RESOURCE. 782 */ 783 static int 784 bhndb_resume_resource(device_t dev, device_t child, int type, 785 struct resource *r) 786 { 787 struct bhndb_softc *sc; 788 789 sc = device_get_softc(dev); 790 791 // TODO: IRQs? 792 if (type != SYS_RES_MEMORY) 793 return (0); 794 795 /* Inactive resources don't require reallocation of bridge resources */ 796 if (!(rman_get_flags(r) & RF_ACTIVE)) 797 return (0); 798 799 if (BHNDB_DEBUG(PRIO)) 800 device_printf(child, "resume resource type=%d 0x%lx+0x%lx\n", 801 type, rman_get_start(r), rman_get_size(r)); 802 803 return (bhndb_try_activate_resource(sc, rman_get_device(r), type, 804 rman_get_rid(r), r, NULL)); 805 } 806 807 808 /** 809 * Default bhndb(4) implementation of BUS_READ_IVAR(). 810 */ 811 static int 812 bhndb_read_ivar(device_t dev, device_t child, int index, 813 uintptr_t *result) 814 { 815 return (ENOENT); 816 } 817 818 /** 819 * Default bhndb(4) implementation of BUS_WRITE_IVAR(). 820 */ 821 static int 822 bhndb_write_ivar(device_t dev, device_t child, int index, 823 uintptr_t value) 824 { 825 return (ENOENT); 826 } 827 828 /** 829 * Return the rman instance for a given resource @p type, if any. 830 * 831 * @param sc The bhndb device state. 832 * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...) 833 */ 834 static struct rman * 835 bhndb_get_rman(struct bhndb_softc *sc, int type) 836 { 837 switch (type) { 838 case SYS_RES_MEMORY: 839 return &sc->mem_rman; 840 case SYS_RES_IRQ: 841 // TODO 842 // return &sc->irq_rman; 843 return (NULL); 844 default: 845 return (NULL); 846 }; 847 } 848 849 /** 850 * Default implementation of BUS_ADD_CHILD() 851 */ 852 static device_t 853 bhndb_add_child(device_t dev, u_int order, const char *name, int unit) 854 { 855 struct bhndb_devinfo *dinfo; 856 device_t child; 857 858 child = device_add_child_ordered(dev, order, name, unit); 859 if (child == NULL) 860 return (NULL); 861 862 dinfo = malloc(sizeof(struct bhndb_devinfo), M_BHND, M_NOWAIT); 863 if (dinfo == NULL) { 864 device_delete_child(dev, child); 865 return (NULL); 866 } 867 868 resource_list_init(&dinfo->resources); 869 870 device_set_ivars(child, dinfo); 871 872 return (child); 873 } 874 875 /** 876 * Default implementation of BUS_CHILD_DELETED(). 877 */ 878 static void 879 bhndb_child_deleted(device_t dev, device_t child) 880 { 881 struct bhndb_devinfo *dinfo = device_get_ivars(child); 882 if (dinfo != NULL) { 883 resource_list_free(&dinfo->resources); 884 free(dinfo, M_BHND); 885 } 886 887 device_set_ivars(child, NULL); 888 } 889 890 /** 891 * Default implementation of BHNDB_GET_CHIPID(). 892 */ 893 static const struct bhnd_chipid * 894 bhndb_get_chipid(device_t dev, device_t child) 895 { 896 struct bhndb_softc *sc = device_get_softc(dev); 897 return (&sc->chipid); 898 } 899 900 901 /** 902 * Default implementation of BHNDB_IS_HW_DISABLED(). 903 */ 904 static bool 905 bhndb_is_hw_disabled(device_t dev, device_t child) { 906 struct bhndb_softc *sc; 907 struct bhnd_core_info core; 908 909 sc = device_get_softc(dev); 910 911 /* Requestor must be attached to the bhnd bus */ 912 if (device_get_parent(child) != sc->bus_dev) { 913 return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); 914 } 915 916 /* Fetch core info */ 917 core = bhnd_get_core_info(child); 918 919 /* Try to defer to the bhndb bus parent */ 920 if (BHNDB_BUS_IS_CORE_DISABLED(sc->parent_dev, dev, &core)) 921 return (true); 922 923 /* Otherwise, we treat bridge-capable cores as unpopulated if they're 924 * not the configured host bridge */ 925 if (BHND_DEVCLASS_SUPPORTS_HOSTB(bhnd_core_class(&core))) 926 return (!BHND_BUS_IS_HOSTB_DEVICE(dev, child)); 927 928 /* Otherwise, assume the core is populated */ 929 return (false); 930 } 931 932 /* ascending core index comparison used by bhndb_is_hostb_device() */ 933 static int 934 compare_core_index(const void *lhs, const void *rhs) 935 { 936 u_int left = bhnd_get_core_index(*(const device_t *) lhs); 937 u_int right = bhnd_get_core_index(*(const device_t *) rhs); 938 939 if (left < right) 940 return (-1); 941 else if (left > right) 942 return (1); 943 else 944 return (0); 945 } 946 947 /** 948 * Default bhndb(4) implementation of BHND_BUS_IS_HOSTB_DEVICE(). 949 * 950 * This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged 951 * bhnd(4) devices to determine the hostb core: 952 * 953 * - The core must have a Broadcom vendor ID. 954 * - The core devclass must match the bridge type. 955 * - The core must be the first device on the bus with the bridged device 956 * class. 957 * 958 * @param sc The bridge device state. 959 * @param cores The table of bridge-enumerated cores. 960 * @param num_cores The length of @p cores. 961 * @param core The core to check. 962 */ 963 static bool 964 bhndb_is_hostb_device(device_t dev, device_t child) 965 { 966 struct bhndb_softc *sc; 967 struct bhnd_core_match md; 968 device_t hostb_dev, *devlist; 969 int devcnt, error; 970 971 972 sc = device_get_softc(dev); 973 974 /* Requestor must be attached to the bhnd bus */ 975 if (device_get_parent(child) != sc->bus_dev) 976 return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), 977 child)); 978 979 /* Determine required device class and set up a match descriptor. */ 980 md = (struct bhnd_core_match) { 981 .vendor = BHND_MFGID_BCM, 982 .device = BHND_COREID_INVALID, 983 .hwrev = { BHND_HWREV_INVALID, BHND_HWREV_INVALID }, 984 .class = sc->bridge_class, 985 .unit = 0 986 }; 987 988 /* Pre-screen the device before searching over the full device list. */ 989 if (!bhnd_device_matches(child, &md)) 990 return (false); 991 992 /* Must be the absolute first matching device on the bus. */ 993 if ((error = device_get_children(sc->bus_dev, &devlist, &devcnt))) 994 return (false); 995 996 /* Sort by core index value, ascending */ 997 qsort(devlist, devcnt, sizeof(*devlist), compare_core_index); 998 999 /* Find the actual hostb device */ 1000 hostb_dev = NULL; 1001 for (int i = 0; i < devcnt; i++) { 1002 if (bhnd_device_matches(devlist[i], &md)) { 1003 hostb_dev = devlist[i]; 1004 break; 1005 } 1006 } 1007 1008 /* Clean up */ 1009 free(devlist, M_TEMP); 1010 1011 return (child == hostb_dev); 1012 } 1013 1014 /** 1015 * Default bhndb(4) implementation of BUS_ALLOC_RESOURCE(). 1016 */ 1017 static struct resource * 1018 bhndb_alloc_resource(device_t dev, device_t child, int type, 1019 int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1020 { 1021 struct bhndb_softc *sc; 1022 struct resource_list_entry *rle; 1023 struct resource *rv; 1024 struct rman *rm; 1025 int error; 1026 bool immed_child, defaults; 1027 1028 sc = device_get_softc(dev); 1029 immed_child = (device_get_parent(child) == dev); 1030 defaults = (start == 0UL && end == ~0UL); 1031 rle = NULL; 1032 1033 /* Populate defaults */ 1034 if (immed_child && defaults) { 1035 /* Fetch the resource list entry. */ 1036 rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), 1037 type, *rid); 1038 if (rle == NULL) { 1039 device_printf(dev, 1040 "default resource %#x type %d for child %s " 1041 "not found\n", *rid, type, 1042 device_get_nameunit(child)); 1043 1044 return (NULL); 1045 } 1046 1047 if (rle->res != NULL) { 1048 device_printf(dev, 1049 "resource entry %#x type %d for child %s is busy\n", 1050 *rid, type, device_get_nameunit(child)); 1051 1052 return (NULL); 1053 } 1054 1055 start = rle->start; 1056 end = rle->end; 1057 count = ulmax(count, rle->count); 1058 } 1059 1060 /* Validate resource addresses */ 1061 if (start > end || end < start || count > ((end - start) + 1)) 1062 return (NULL); 1063 1064 /* Fetch the resource manager */ 1065 rm = bhndb_get_rman(sc, type); 1066 if (rm == NULL) 1067 return (NULL); 1068 1069 /* Make our reservation */ 1070 rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 1071 child); 1072 if (rv == NULL) 1073 return (NULL); 1074 1075 rman_set_rid(rv, *rid); 1076 1077 /* Activate */ 1078 if (flags & RF_ACTIVE) { 1079 error = bus_activate_resource(child, type, *rid, rv); 1080 if (error) { 1081 device_printf(dev, 1082 "failed to activate entry %#x type %d for " 1083 "child %s\n", 1084 *rid, type, device_get_nameunit(child)); 1085 1086 rman_release_resource(rv); 1087 1088 return (NULL); 1089 } 1090 } 1091 1092 /* Update child's resource list entry */ 1093 if (rle != NULL) { 1094 rle->res = rv; 1095 rle->start = rman_get_start(rv); 1096 rle->end = rman_get_end(rv); 1097 rle->count = rman_get_size(rv); 1098 } 1099 1100 return (rv); 1101 } 1102 1103 /** 1104 * Default bhndb(4) implementation of BUS_RELEASE_RESOURCE(). 1105 */ 1106 static int 1107 bhndb_release_resource(device_t dev, device_t child, int type, int rid, 1108 struct resource *r) 1109 { 1110 int error; 1111 1112 /* Deactivate resources */ 1113 if (rman_get_flags(r) & RF_ACTIVE) { 1114 error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r); 1115 if (error) 1116 return (error); 1117 } 1118 1119 if ((error = rman_release_resource(r))) 1120 return (error); 1121 1122 return (0); 1123 } 1124 1125 /** 1126 * Default bhndb(4) implementation of BUS_ADJUST_RESOURCE(). 1127 */ 1128 static int 1129 bhndb_adjust_resource(device_t dev, device_t child, int type, 1130 struct resource *r, rman_res_t start, rman_res_t end) 1131 { 1132 struct bhndb_softc *sc; 1133 struct rman *rm; 1134 int error; 1135 1136 sc = device_get_softc(dev); 1137 error = 0; 1138 1139 /* Fetch resource manager */ 1140 rm = bhndb_get_rman(sc, type); 1141 if (rm == NULL) 1142 return (ENXIO); 1143 1144 if (!rman_is_region_manager(r, rm)) 1145 return (ENXIO); 1146 1147 /* If active, adjustment is limited by the assigned window. */ 1148 BHNDB_LOCK(sc); 1149 1150 // TODO: Currently unsupported 1151 error = ENODEV; 1152 1153 BHNDB_UNLOCK(sc); 1154 if (!error) 1155 error = rman_adjust_resource(r, start, end); 1156 1157 return (error); 1158 } 1159 1160 /** 1161 * Initialize child resource @p r with a virtual address, tag, and handle 1162 * copied from @p parent, adjusted to contain only the range defined by @p win. 1163 * 1164 * @param r The register to be initialized. 1165 * @param parent The parent bus resource that fully contains the subregion. 1166 * @param offset The subregion offset within @p parent. 1167 * @param size The subregion size. 1168 * @p r. 1169 */ 1170 static int 1171 bhndb_init_child_resource(struct resource *r, 1172 struct resource *parent, bhnd_size_t offset, bhnd_size_t size) 1173 { 1174 1175 bus_space_handle_t bh, child_bh; 1176 bus_space_tag_t bt; 1177 uintptr_t vaddr; 1178 int error; 1179 1180 /* Fetch the parent resource's real bus values */ 1181 vaddr = (uintptr_t) rman_get_virtual(parent); 1182 bt = rman_get_bustag(parent); 1183 bh = rman_get_bushandle(parent); 1184 1185 /* Configure child resource with window-adjusted real bus values */ 1186 vaddr += offset; 1187 error = bus_space_subregion(bt, bh, offset, size, &child_bh); 1188 if (error) 1189 return (error); 1190 1191 rman_set_virtual(r, (void *) vaddr); 1192 rman_set_bustag(r, bt); 1193 rman_set_bushandle(r, child_bh); 1194 1195 return (0); 1196 } 1197 1198 /** 1199 * Attempt activation of a fixed register window mapping for @p child. 1200 * 1201 * @param sc BHNDB device state. 1202 * @param region The static region definition capable of mapping @p r. 1203 * @param child A child requesting resource activation. 1204 * @param type Resource type. 1205 * @param rid Resource identifier. 1206 * @param r Resource to be activated. 1207 * 1208 * @retval 0 if @p r was activated successfully 1209 * @retval ENOENT if no fixed register window was found. 1210 * @retval non-zero if @p r could not be activated. 1211 */ 1212 static int 1213 bhndb_activate_static_region(struct bhndb_softc *sc, 1214 struct bhndb_region *region, device_t child, int type, int rid, 1215 struct resource *r) 1216 { 1217 struct resource *bridge_res; 1218 const struct bhndb_regwin *win; 1219 bhnd_size_t parent_offset; 1220 rman_res_t r_start, r_size; 1221 int error; 1222 1223 win = region->static_regwin; 1224 1225 KASSERT(win != NULL && BHNDB_REGWIN_T_IS_STATIC(win->win_type), 1226 ("can't activate non-static region")); 1227 1228 r_start = rman_get_start(r); 1229 r_size = rman_get_size(r); 1230 1231 /* Find the corresponding bridge resource */ 1232 bridge_res = bhndb_find_regwin_resource(sc->bus_res, win); 1233 if (bridge_res == NULL) 1234 return (ENXIO); 1235 1236 /* Calculate subregion offset within the parent resource */ 1237 parent_offset = r_start - region->addr; 1238 parent_offset += win->win_offset; 1239 1240 /* Configure resource with its real bus values. */ 1241 error = bhndb_init_child_resource(r, bridge_res, parent_offset, r_size); 1242 if (error) 1243 return (error); 1244 1245 /* Mark active */ 1246 if ((error = rman_activate_resource(r))) 1247 return (error); 1248 1249 return (0); 1250 } 1251 1252 /** 1253 * Attempt to allocate/retain a dynamic register window for @p r, returning 1254 * the retained window. 1255 * 1256 * @param sc The bhndb driver state. 1257 * @param r The resource for which a window will be retained. 1258 */ 1259 static struct bhndb_dw_alloc * 1260 bhndb_retain_dynamic_window(struct bhndb_softc *sc, struct resource *r) 1261 { 1262 struct bhndb_dw_alloc *dwa; 1263 rman_res_t r_start, r_size; 1264 int error; 1265 1266 BHNDB_LOCK_ASSERT(sc, MA_OWNED); 1267 1268 r_start = rman_get_start(r); 1269 r_size = rman_get_size(r); 1270 1271 /* Look for an existing dynamic window we can reference */ 1272 dwa = bhndb_dw_find_mapping(sc->bus_res, r_start, r_size); 1273 if (dwa != NULL) { 1274 if (bhndb_dw_retain(sc->bus_res, dwa, r) == 0) 1275 return (dwa); 1276 1277 return (NULL); 1278 } 1279 1280 /* Otherwise, try to reserve a free window */ 1281 dwa = bhndb_dw_next_free(sc->bus_res); 1282 if (dwa == NULL) { 1283 /* No free windows */ 1284 return (NULL); 1285 } 1286 1287 /* Set the window target */ 1288 error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, rman_get_start(r), 1289 rman_get_size(r)); 1290 if (error) { 1291 device_printf(sc->dev, "dynamic window initialization " 1292 "for 0x%llx-0x%llx failed\n", 1293 (unsigned long long) r_start, 1294 (unsigned long long) r_start + r_size - 1); 1295 return (NULL); 1296 } 1297 1298 /* Add our reservation */ 1299 if (bhndb_dw_retain(sc->bus_res, dwa, r)) 1300 return (NULL); 1301 1302 return (dwa); 1303 } 1304 1305 /** 1306 * Activate a resource using any viable static or dynamic register window. 1307 * 1308 * @param sc The bhndb driver state. 1309 * @param child The child holding ownership of @p r. 1310 * @param type The type of the resource to be activated. 1311 * @param rid The resource ID of @p r. 1312 * @param r The resource to be activated 1313 * @param[out] indirect On error and if not NULL, will be set to 'true' if 1314 * the caller should instead use an indirect resource mapping. 1315 * 1316 * @retval 0 success 1317 * @retval non-zero activation failed. 1318 */ 1319 static int 1320 bhndb_try_activate_resource(struct bhndb_softc *sc, device_t child, int type, 1321 int rid, struct resource *r, bool *indirect) 1322 { 1323 struct bhndb_region *region; 1324 struct bhndb_dw_alloc *dwa; 1325 bhndb_priority_t dw_priority; 1326 rman_res_t r_start, r_size; 1327 rman_res_t parent_offset; 1328 int error; 1329 1330 BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED); 1331 1332 // TODO - IRQs 1333 if (type != SYS_RES_MEMORY) 1334 return (ENXIO); 1335 1336 if (indirect) 1337 *indirect = false; 1338 1339 /* Default to low priority */ 1340 dw_priority = BHNDB_PRIORITY_LOW; 1341 1342 /* Look for a bus region matching the resource's address range */ 1343 r_start = rman_get_start(r); 1344 r_size = rman_get_size(r); 1345 region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); 1346 if (region != NULL) 1347 dw_priority = region->priority; 1348 1349 /* Prefer static mappings over consuming a dynamic windows. */ 1350 if (region && region->static_regwin) { 1351 error = bhndb_activate_static_region(sc, region, child, type, 1352 rid, r); 1353 if (error) 1354 device_printf(sc->dev, "static window allocation " 1355 "for 0x%llx-0x%llx failed\n", 1356 (unsigned long long) r_start, 1357 (unsigned long long) r_start + r_size - 1); 1358 return (error); 1359 } 1360 1361 /* A dynamic window will be required; is this resource high enough 1362 * priority to be reserved a dynamic window? */ 1363 if (dw_priority < sc->bus_res->min_prio) { 1364 if (indirect) 1365 *indirect = true; 1366 1367 return (ENOMEM); 1368 } 1369 1370 /* Find and retain a usable window */ 1371 BHNDB_LOCK(sc); { 1372 dwa = bhndb_retain_dynamic_window(sc, r); 1373 } BHNDB_UNLOCK(sc); 1374 1375 if (dwa == NULL) { 1376 if (indirect) 1377 *indirect = true; 1378 return (ENOMEM); 1379 } 1380 1381 /* Configure resource with its real bus values. */ 1382 parent_offset = dwa->win->win_offset; 1383 parent_offset += r_start - dwa->target; 1384 1385 error = bhndb_init_child_resource(r, dwa->parent_res, parent_offset, 1386 dwa->win->win_size); 1387 if (error) 1388 goto failed; 1389 1390 /* Mark active */ 1391 if ((error = rman_activate_resource(r))) 1392 goto failed; 1393 1394 return (0); 1395 1396 failed: 1397 /* Release our region allocation. */ 1398 BHNDB_LOCK(sc); 1399 bhndb_dw_release(sc->bus_res, dwa, r); 1400 BHNDB_UNLOCK(sc); 1401 1402 return (error); 1403 } 1404 1405 /** 1406 * Default bhndb(4) implementation of BUS_ACTIVATE_RESOURCE(). 1407 * 1408 * Maps resource activation requests to a viable static or dynamic 1409 * register window, if any. 1410 */ 1411 static int 1412 bhndb_activate_resource(device_t dev, device_t child, int type, int rid, 1413 struct resource *r) 1414 { 1415 struct bhndb_softc *sc = device_get_softc(dev); 1416 1417 return (bhndb_try_activate_resource(sc, child, type, rid, r, NULL)); 1418 } 1419 1420 /** 1421 * Default bhndb(4) implementation of BUS_DEACTIVATE_RESOURCE(). 1422 */ 1423 static int 1424 bhndb_deactivate_resource(device_t dev, device_t child, int type, 1425 int rid, struct resource *r) 1426 { 1427 struct bhndb_dw_alloc *dwa; 1428 struct bhndb_softc *sc; 1429 struct rman *rm; 1430 int error; 1431 1432 sc = device_get_softc(dev); 1433 1434 if ((rm = bhndb_get_rman(sc, type)) == NULL) 1435 return (EINVAL); 1436 1437 /* Mark inactive */ 1438 if ((error = rman_deactivate_resource(r))) 1439 return (error); 1440 1441 /* Free any dynamic window allocation. */ 1442 BHNDB_LOCK(sc); 1443 dwa = bhndb_dw_find_resource(sc->bus_res, r); 1444 if (dwa != NULL) 1445 bhndb_dw_release(sc->bus_res, dwa, r); 1446 BHNDB_UNLOCK(sc); 1447 1448 return (0); 1449 } 1450 1451 /** 1452 * Default bhndb(4) implementation of BUS_GET_RESOURCE_LIST(). 1453 */ 1454 static struct resource_list * 1455 bhndb_get_resource_list(device_t dev, device_t child) 1456 { 1457 struct bhndb_devinfo *dinfo = device_get_ivars(child); 1458 return (&dinfo->resources); 1459 } 1460 1461 /** 1462 * Default bhndb(4) implementation of BHND_BUS_ALLOC_RESOURCE(). 1463 */ 1464 static struct bhnd_resource * 1465 bhndb_alloc_bhnd_resource(device_t dev, device_t child, int type, 1466 int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1467 { 1468 struct bhndb_softc *sc; 1469 struct bhnd_resource *br; 1470 1471 sc = device_get_softc(dev); 1472 1473 /* Allocate resource wrapper */ 1474 br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT|M_ZERO); 1475 if (br == NULL) 1476 return (NULL); 1477 1478 /* Configure */ 1479 br->direct = false; 1480 br->res = bus_alloc_resource(child, type, rid, start, end, count, 1481 flags & ~RF_ACTIVE); 1482 if (br->res == NULL) 1483 goto failed; 1484 1485 1486 if (flags & RF_ACTIVE) { 1487 if (bhnd_activate_resource(child, type, *rid, br)) 1488 goto failed; 1489 } 1490 1491 return (br); 1492 1493 failed: 1494 if (br->res != NULL) 1495 bus_release_resource(child, type, *rid, br->res); 1496 1497 free(br, M_BHND); 1498 return (NULL); 1499 } 1500 1501 /** 1502 * Default bhndb(4) implementation of BHND_BUS_RELEASE_RESOURCE(). 1503 */ 1504 static int 1505 bhndb_release_bhnd_resource(device_t dev, device_t child, 1506 int type, int rid, struct bhnd_resource *r) 1507 { 1508 int error; 1509 1510 if ((error = bus_release_resource(child, type, rid, r->res))) 1511 return (error); 1512 1513 free(r, M_BHND); 1514 return (0); 1515 } 1516 1517 /** 1518 * Default bhndb(4) implementation of BHND_BUS_ACTIVATE_RESOURCE(). 1519 * 1520 * Attempts to activate a static register window, a dynamic register window, 1521 * or configures @p r as an indirect resource -- in that order. 1522 */ 1523 static int 1524 bhndb_activate_bhnd_resource(device_t dev, device_t child, 1525 int type, int rid, struct bhnd_resource *r) 1526 { 1527 struct bhndb_softc *sc; 1528 struct bhndb_region *region; 1529 bhndb_priority_t r_prio; 1530 rman_res_t r_start, r_size; 1531 int error; 1532 bool indirect; 1533 1534 KASSERT(!r->direct, 1535 ("direct flag set on inactive resource")); 1536 1537 KASSERT(!(rman_get_flags(r->res) & RF_ACTIVE), 1538 ("RF_ACTIVE set on inactive resource")); 1539 1540 sc = device_get_softc(dev); 1541 1542 /* Fetch the address range's resource priority */ 1543 r_start = rman_get_start(r->res); 1544 r_size = rman_get_size(r->res); 1545 r_prio = BHNDB_PRIORITY_NONE; 1546 1547 region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); 1548 if (region != NULL) 1549 r_prio = region->priority; 1550 1551 /* If less than the minimum dynamic window priority, this 1552 * resource should always be indirect. */ 1553 if (r_prio < sc->bus_res->min_prio) 1554 return (0); 1555 1556 /* Attempt direct activation */ 1557 error = bhndb_try_activate_resource(sc, child, type, rid, r->res, 1558 &indirect); 1559 if (!error) { 1560 r->direct = true; 1561 } else if (indirect) { 1562 /* The request was valid, but no viable register window is 1563 * available; indirection must be employed. */ 1564 error = 0; 1565 r->direct = false; 1566 } 1567 1568 if (BHNDB_DEBUG(PRIO)) { 1569 device_printf(child, "activated 0x%llx-0x%llx as %s " 1570 "resource\n", 1571 (unsigned long long) r_start, 1572 (unsigned long long) r_start + r_size - 1, 1573 r->direct ? "direct" : "indirect"); 1574 } 1575 1576 return (error); 1577 }; 1578 1579 /** 1580 * Default bhndb(4) implementation of BHND_BUS_DEACTIVATE_RESOURCE(). 1581 */ 1582 static int 1583 bhndb_deactivate_bhnd_resource(device_t dev, device_t child, 1584 int type, int rid, struct bhnd_resource *r) 1585 { 1586 int error; 1587 1588 /* Indirect resources don't require activation */ 1589 if (!r->direct) 1590 return (0); 1591 1592 KASSERT(rman_get_flags(r->res) & RF_ACTIVE, 1593 ("RF_ACTIVE not set on direct resource")); 1594 1595 /* Perform deactivation */ 1596 error = bus_deactivate_resource(child, type, rid, r->res); 1597 if (!error) 1598 r->direct = false; 1599 1600 return (error); 1601 }; 1602 1603 /** 1604 * Slow path for bhndb_io_resource(). 1605 * 1606 * Iterates over the existing allocated dynamic windows looking for a viable 1607 * in-use region; the first matching region is returned. 1608 */ 1609 static struct bhndb_dw_alloc * 1610 bhndb_io_resource_slow(struct bhndb_softc *sc, bus_addr_t addr, 1611 bus_size_t size, bus_size_t *offset) 1612 { 1613 struct bhndb_resources *br; 1614 struct bhndb_dw_alloc *dwa; 1615 1616 BHNDB_LOCK_ASSERT(sc, MA_OWNED); 1617 1618 br = sc->bus_res; 1619 1620 /* Search for an existing dynamic mapping of this address range. 1621 * Static regions are not searched, as a statically mapped 1622 * region would never be allocated as an indirect resource. */ 1623 for (size_t i = 0; i < br->dwa_count; i++) { 1624 const struct bhndb_regwin *win; 1625 1626 dwa = &br->dw_alloc[i]; 1627 win = dwa->win; 1628 1629 KASSERT(win->win_type == BHNDB_REGWIN_T_DYN, 1630 ("invalid register window type")); 1631 1632 /* Verify the range */ 1633 if (addr < dwa->target) 1634 continue; 1635 1636 if (addr + size > dwa->target + win->win_size) 1637 continue; 1638 1639 /* Found */ 1640 *offset = dwa->win->win_offset; 1641 *offset += addr - dwa->target; 1642 1643 return (dwa); 1644 } 1645 1646 /* not found */ 1647 return (NULL); 1648 } 1649 1650 /** 1651 * Find the bridge resource to be used for I/O requests. 1652 * 1653 * @param sc Bridge driver state. 1654 * @param addr The I/O target address. 1655 * @param size The size of the I/O operation to be performed at @p addr. 1656 * @param[out] offset The offset within the returned resource at which 1657 * to perform the I/O request. 1658 */ 1659 static inline struct bhndb_dw_alloc * 1660 bhndb_io_resource(struct bhndb_softc *sc, bus_addr_t addr, bus_size_t size, 1661 bus_size_t *offset) 1662 { 1663 struct bhndb_resources *br; 1664 struct bhndb_dw_alloc *dwa; 1665 int error; 1666 1667 BHNDB_LOCK_ASSERT(sc, MA_OWNED); 1668 1669 br = sc->bus_res; 1670 1671 /* Try to fetch a free window */ 1672 dwa = bhndb_dw_next_free(br); 1673 1674 /* 1675 * If no dynamic windows are available, look for an existing 1676 * region that maps the target range. 1677 * 1678 * If none are found, this is a child driver bug -- our window 1679 * over-commit should only fail in the case where a child driver leaks 1680 * resources, or perform operations out-of-order. 1681 * 1682 * Broadcom HND chipsets are designed to not require register window 1683 * swapping during execution; as long as the child devices are 1684 * attached/detached correctly, using the hardware's required order 1685 * of operations, there should always be a window available for the 1686 * current operation. 1687 */ 1688 if (dwa == NULL) { 1689 dwa = bhndb_io_resource_slow(sc, addr, size, offset); 1690 if (dwa == NULL) { 1691 panic("register windows exhausted attempting to map " 1692 "0x%llx-0x%llx\n", 1693 (unsigned long long) addr, 1694 (unsigned long long) addr+size-1); 1695 } 1696 1697 return (dwa); 1698 } 1699 1700 /* Adjust the window if the I/O request won't fit in the current 1701 * target range. */ 1702 if (addr < dwa->target || 1703 (dwa->target + dwa->win->win_size) - addr < size) 1704 { 1705 error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, addr, 1706 size); 1707 if (error) { 1708 panic("failed to set register window target mapping " 1709 "0x%llx-0x%llx\n", 1710 (unsigned long long) addr, 1711 (unsigned long long) addr+size-1); 1712 } 1713 } 1714 1715 /* Calculate the offset and return */ 1716 *offset = (addr - dwa->target) + dwa->win->win_offset; 1717 return (dwa); 1718 } 1719 1720 /* 1721 * BHND_BUS_(READ|WRITE_* implementations 1722 */ 1723 1724 /* bhndb_bus_(read|write) common implementation */ 1725 #define BHNDB_IO_COMMON_SETUP(_io_size) \ 1726 struct bhndb_softc *sc; \ 1727 struct bhndb_dw_alloc *dwa; \ 1728 struct resource *io_res; \ 1729 bus_size_t io_offset; \ 1730 \ 1731 sc = device_get_softc(dev); \ 1732 \ 1733 BHNDB_LOCK(sc); \ 1734 dwa = bhndb_io_resource(sc, rman_get_start(r->res) + \ 1735 offset, _io_size, &io_offset); \ 1736 io_res = dwa->parent_res; \ 1737 \ 1738 KASSERT(!r->direct, \ 1739 ("bhnd_bus slow path used for direct resource")); \ 1740 \ 1741 KASSERT(rman_get_flags(io_res) & RF_ACTIVE, \ 1742 ("i/o resource is not active")); 1743 1744 #define BHNDB_IO_COMMON_TEARDOWN() \ 1745 BHNDB_UNLOCK(sc); 1746 1747 /* Defines a bhndb_bus_read_* method implementation */ 1748 #define BHNDB_IO_READ(_type, _size) \ 1749 static _type \ 1750 bhndb_bus_read_ ## _size (device_t dev, device_t child, \ 1751 struct bhnd_resource *r, bus_size_t offset) \ 1752 { \ 1753 _type v; \ 1754 BHNDB_IO_COMMON_SETUP(sizeof(_type)); \ 1755 v = bus_read_ ## _size (io_res, io_offset); \ 1756 BHNDB_IO_COMMON_TEARDOWN(); \ 1757 \ 1758 return (v); \ 1759 } 1760 1761 /* Defines a bhndb_bus_write_* method implementation */ 1762 #define BHNDB_IO_WRITE(_type, _size) \ 1763 static void \ 1764 bhndb_bus_write_ ## _size (device_t dev, device_t child, \ 1765 struct bhnd_resource *r, bus_size_t offset, _type value) \ 1766 { \ 1767 BHNDB_IO_COMMON_SETUP(sizeof(_type)); \ 1768 bus_write_ ## _size (io_res, io_offset, value); \ 1769 BHNDB_IO_COMMON_TEARDOWN(); \ 1770 } 1771 1772 BHNDB_IO_READ(uint8_t, 1); 1773 BHNDB_IO_READ(uint16_t, 2); 1774 BHNDB_IO_READ(uint32_t, 4); 1775 1776 BHNDB_IO_WRITE(uint8_t, 1); 1777 BHNDB_IO_WRITE(uint16_t, 2); 1778 BHNDB_IO_WRITE(uint32_t, 4); 1779 1780 /** 1781 * Default bhndb(4) implementation of BHND_BUS_BARRIER(). 1782 */ 1783 static void 1784 bhndb_bus_barrier(device_t dev, device_t child, struct bhnd_resource *r, 1785 bus_size_t offset, bus_size_t length, int flags) 1786 { 1787 bus_size_t remain; 1788 1789 BHNDB_IO_COMMON_SETUP(length); 1790 1791 /* TODO: It's unclear whether we need a barrier implementation, 1792 * and if we do, what it needs to actually do. This may need 1793 * revisiting once we have a better idea of requirements after 1794 * porting the core drivers. */ 1795 panic("implementation incorrect"); 1796 1797 /* Use 4-byte reads where possible */ 1798 remain = length % sizeof(uint32_t); 1799 for (bus_size_t i = 0; i < (length - remain); i += 4) 1800 bus_read_4(io_res, io_offset + offset + i); 1801 1802 /* Use 1 byte reads for the remainder */ 1803 for (bus_size_t i = 0; i < remain; i++) 1804 bus_read_1(io_res, io_offset + offset + length + i); 1805 1806 BHNDB_IO_COMMON_TEARDOWN(); 1807 } 1808 1809 /** 1810 * Default bhndb(4) implementation of BUS_SETUP_INTR(). 1811 */ 1812 static int 1813 bhndb_setup_intr(device_t dev, device_t child, struct resource *r, 1814 int flags, driver_filter_t filter, driver_intr_t handler, void *arg, 1815 void **cookiep) 1816 { 1817 // TODO 1818 return (EOPNOTSUPP); 1819 } 1820 1821 /** 1822 * Default bhndb(4) implementation of BUS_TEARDOWN_INTR(). 1823 */ 1824 static int 1825 bhndb_teardown_intr(device_t dev, device_t child, struct resource *r, 1826 void *cookie) 1827 { 1828 // TODO 1829 return (EOPNOTSUPP); 1830 } 1831 1832 /** 1833 * Default bhndb(4) implementation of BUS_CONFIG_INTR(). 1834 */ 1835 static int 1836 bhndb_config_intr(device_t dev, int irq, enum intr_trigger trig, 1837 enum intr_polarity pol) 1838 { 1839 // TODO 1840 return (EOPNOTSUPP); 1841 } 1842 1843 /** 1844 * Default bhndb(4) implementation of BUS_BIND_INTR(). 1845 */ 1846 static int 1847 bhndb_bind_intr(device_t dev, device_t child, struct resource *r, int cpu) 1848 { 1849 // TODO 1850 return (EOPNOTSUPP); 1851 } 1852 1853 /** 1854 * Default bhndb(4) implementation of BUS_DESCRIBE_INTR(). 1855 */ 1856 static int 1857 bhndb_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie, 1858 const char *descr) 1859 { 1860 // TODO 1861 return (EOPNOTSUPP); 1862 } 1863 1864 /** 1865 * Default bhndb(4) implementation of BUS_GET_DMA_TAG(). 1866 */ 1867 static bus_dma_tag_t 1868 bhndb_get_dma_tag(device_t dev, device_t child) 1869 { 1870 // TODO 1871 return (NULL); 1872 } 1873 1874 static device_method_t bhndb_methods[] = { 1875 /* Device interface */ \ 1876 DEVMETHOD(device_probe, bhndb_generic_probe), 1877 DEVMETHOD(device_detach, bhndb_generic_detach), 1878 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1879 DEVMETHOD(device_suspend, bhndb_generic_suspend), 1880 DEVMETHOD(device_resume, bhndb_generic_resume), 1881 1882 /* Bus interface */ 1883 DEVMETHOD(bus_probe_nomatch, bhndb_probe_nomatch), 1884 DEVMETHOD(bus_print_child, bhndb_print_child), 1885 DEVMETHOD(bus_child_pnpinfo_str, bhndb_child_pnpinfo_str), 1886 DEVMETHOD(bus_child_location_str, bhndb_child_location_str), 1887 DEVMETHOD(bus_add_child, bhndb_add_child), 1888 DEVMETHOD(bus_child_deleted, bhndb_child_deleted), 1889 1890 DEVMETHOD(bus_alloc_resource, bhndb_alloc_resource), 1891 DEVMETHOD(bus_release_resource, bhndb_release_resource), 1892 DEVMETHOD(bus_activate_resource, bhndb_activate_resource), 1893 DEVMETHOD(bus_deactivate_resource, bhndb_deactivate_resource), 1894 1895 DEVMETHOD(bus_setup_intr, bhndb_setup_intr), 1896 DEVMETHOD(bus_teardown_intr, bhndb_teardown_intr), 1897 DEVMETHOD(bus_config_intr, bhndb_config_intr), 1898 DEVMETHOD(bus_bind_intr, bhndb_bind_intr), 1899 DEVMETHOD(bus_describe_intr, bhndb_describe_intr), 1900 1901 DEVMETHOD(bus_get_dma_tag, bhndb_get_dma_tag), 1902 1903 DEVMETHOD(bus_adjust_resource, bhndb_adjust_resource), 1904 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 1905 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1906 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1907 DEVMETHOD(bus_get_resource_list, bhndb_get_resource_list), 1908 1909 DEVMETHOD(bus_read_ivar, bhndb_read_ivar), 1910 DEVMETHOD(bus_write_ivar, bhndb_write_ivar), 1911 1912 /* BHNDB interface */ 1913 DEVMETHOD(bhndb_get_chipid, bhndb_get_chipid), 1914 DEVMETHOD(bhndb_init_full_config, bhndb_generic_init_full_config), 1915 DEVMETHOD(bhndb_suspend_resource, bhndb_suspend_resource), 1916 DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource), 1917 1918 /* BHND interface */ 1919 DEVMETHOD(bhnd_bus_is_hw_disabled, bhndb_is_hw_disabled), 1920 DEVMETHOD(bhnd_bus_is_hostb_device, bhndb_is_hostb_device), 1921 DEVMETHOD(bhnd_bus_get_chipid, bhndb_get_chipid), 1922 DEVMETHOD(bhnd_bus_alloc_resource, bhndb_alloc_bhnd_resource), 1923 DEVMETHOD(bhnd_bus_release_resource, bhndb_release_bhnd_resource), 1924 DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource), 1925 DEVMETHOD(bhnd_bus_activate_resource, bhndb_deactivate_bhnd_resource), 1926 DEVMETHOD(bhnd_bus_read_1, bhndb_bus_read_1), 1927 DEVMETHOD(bhnd_bus_read_2, bhndb_bus_read_2), 1928 DEVMETHOD(bhnd_bus_read_4, bhndb_bus_read_4), 1929 DEVMETHOD(bhnd_bus_write_1, bhndb_bus_write_1), 1930 DEVMETHOD(bhnd_bus_write_2, bhndb_bus_write_2), 1931 DEVMETHOD(bhnd_bus_write_4, bhndb_bus_write_4), 1932 DEVMETHOD(bhnd_bus_barrier, bhndb_bus_barrier), 1933 1934 DEVMETHOD_END 1935 }; 1936 1937 devclass_t bhndb_devclass; 1938 1939 DEFINE_CLASS_0(bhndb, bhndb_driver, bhndb_methods, sizeof(struct bhndb_softc)); 1940 1941 MODULE_VERSION(bhndb, 1); 1942 MODULE_DEPEND(bhndb, bhnd, 1, 1, 1); 1943 MODULE_DEPEND(bhndb, bhnd_chipc, 1, 1, 1); 1944