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