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 * Broadcom Home Networking Division (HND) Bus Driver. 35 * 36 * The Broadcom HND family of devices consists of both SoCs and host-connected 37 * networking chipsets containing a common family of Broadcom IP cores, 38 * including an integrated MIPS and/or ARM cores. 39 * 40 * HND devices expose a nearly identical interface whether accessible over a 41 * native SoC interconnect, or when connected via a host interface such as 42 * PCIe. As a result, the majority of hardware support code should be re-usable 43 * across host drivers for HND networking chipsets, as well as FreeBSD support 44 * for Broadcom MIPS/ARM HND SoCs. 45 * 46 * Earlier HND models used the siba(4) on-chip interconnect, while later models 47 * use bcma(4); the programming model is almost entirely independent 48 * of the actual underlying interconect. 49 */ 50 51 #include <sys/param.h> 52 #include <sys/kernel.h> 53 #include <sys/bus.h> 54 #include <sys/module.h> 55 #include <sys/systm.h> 56 57 #include <machine/bus.h> 58 #include <sys/rman.h> 59 #include <machine/resource.h> 60 61 #include "bhnd.h" 62 #include "bhndvar.h" 63 64 #include "bhnd_nvram_if.h" 65 66 MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures"); 67 68 /** 69 * bhnd_generic_probe_nomatch() reporting configuration. 70 */ 71 static const struct bhnd_nomatch { 72 uint16_t vendor; /**< core designer */ 73 uint16_t device; /**< core id */ 74 bool if_verbose; /**< print when bootverbose is set. */ 75 } bhnd_nomatch_table[] = { 76 { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true }, 77 { BHND_MFGID_ARM, BHND_COREID_EROM, true }, 78 { BHND_MFGID_ARM, BHND_COREID_PL301, true }, 79 { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true }, 80 { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false }, 81 82 { BHND_MFGID_INVALID, BHND_COREID_INVALID, false } 83 }; 84 85 static device_t find_nvram_child(device_t dev); 86 87 static int compare_ascending_probe_order(const void *lhs, 88 const void *rhs); 89 static int compare_descending_probe_order(const void *lhs, 90 const void *rhs); 91 92 /** 93 * Helper function for implementing DEVICE_ATTACH(). 94 * 95 * This function can be used to implement DEVICE_ATTACH() for bhnd(4) 96 * bus implementations. It calls device_probe_and_attach() for each 97 * of the device's children, in order. 98 */ 99 int 100 bhnd_generic_attach(device_t dev) 101 { 102 device_t *devs; 103 int ndevs; 104 int error; 105 106 if (device_is_attached(dev)) 107 return (EBUSY); 108 109 if ((error = device_get_children(dev, &devs, &ndevs))) 110 return (error); 111 112 qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); 113 for (int i = 0; i < ndevs; i++) { 114 device_t child = devs[i]; 115 device_probe_and_attach(child); 116 } 117 118 free(devs, M_TEMP); 119 return (0); 120 } 121 122 /** 123 * Helper function for implementing DEVICE_DETACH(). 124 * 125 * This function can be used to implement DEVICE_DETACH() for bhnd(4) 126 * bus implementations. It calls device_detach() for each 127 * of the device's children, in reverse order, terminating if 128 * any call to device_detach() fails. 129 */ 130 int 131 bhnd_generic_detach(device_t dev) 132 { 133 device_t *devs; 134 int ndevs; 135 int error; 136 137 if (!device_is_attached(dev)) 138 return (EBUSY); 139 140 if ((error = device_get_children(dev, &devs, &ndevs))) 141 return (error); 142 143 /* Detach in the reverse of attach order */ 144 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 145 for (int i = 0; i < ndevs; i++) { 146 device_t child = devs[i]; 147 148 /* Terminate on first error */ 149 if ((error = device_detach(child))) 150 goto cleanup; 151 } 152 153 cleanup: 154 free(devs, M_TEMP); 155 return (error); 156 } 157 158 /** 159 * Helper function for implementing DEVICE_SHUTDOWN(). 160 * 161 * This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4) 162 * bus implementations. It calls device_shutdown() for each 163 * of the device's children, in reverse order, terminating if 164 * any call to device_shutdown() fails. 165 */ 166 int 167 bhnd_generic_shutdown(device_t dev) 168 { 169 device_t *devs; 170 int ndevs; 171 int error; 172 173 if (!device_is_attached(dev)) 174 return (EBUSY); 175 176 if ((error = device_get_children(dev, &devs, &ndevs))) 177 return (error); 178 179 /* Shutdown in the reverse of attach order */ 180 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 181 for (int i = 0; i < ndevs; i++) { 182 device_t child = devs[i]; 183 184 /* Terminate on first error */ 185 if ((error = device_shutdown(child))) 186 goto cleanup; 187 } 188 189 cleanup: 190 free(devs, M_TEMP); 191 return (error); 192 } 193 194 /** 195 * Helper function for implementing DEVICE_RESUME(). 196 * 197 * This function can be used to implement DEVICE_RESUME() for bhnd(4) 198 * bus implementations. It calls BUS_RESUME_CHILD() for each 199 * of the device's children, in order, terminating if 200 * any call to BUS_RESUME_CHILD() fails. 201 */ 202 int 203 bhnd_generic_resume(device_t dev) 204 { 205 device_t *devs; 206 int ndevs; 207 int error; 208 209 if (!device_is_attached(dev)) 210 return (EBUSY); 211 212 if ((error = device_get_children(dev, &devs, &ndevs))) 213 return (error); 214 215 qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); 216 for (int i = 0; i < ndevs; i++) { 217 device_t child = devs[i]; 218 219 /* Terminate on first error */ 220 if ((error = BUS_RESUME_CHILD(device_get_parent(child), child))) 221 goto cleanup; 222 } 223 224 cleanup: 225 free(devs, M_TEMP); 226 return (error); 227 } 228 229 /** 230 * Helper function for implementing DEVICE_SUSPEND(). 231 * 232 * This function can be used to implement DEVICE_SUSPEND() for bhnd(4) 233 * bus implementations. It calls BUS_SUSPEND_CHILD() for each 234 * of the device's children, in reverse order. If any call to 235 * BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and 236 * any devices that were suspended are resumed immediately by calling 237 * their BUS_RESUME_CHILD() methods. 238 */ 239 int 240 bhnd_generic_suspend(device_t dev) 241 { 242 device_t *devs; 243 int ndevs; 244 int error; 245 246 if (!device_is_attached(dev)) 247 return (EBUSY); 248 249 if ((error = device_get_children(dev, &devs, &ndevs))) 250 return (error); 251 252 /* Suspend in the reverse of attach order */ 253 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 254 for (int i = 0; i < ndevs; i++) { 255 device_t child = devs[i]; 256 error = BUS_SUSPEND_CHILD(device_get_parent(child), child); 257 258 /* On error, resume suspended devices and then terminate */ 259 if (error) { 260 for (int j = 0; j < i; j++) { 261 BUS_RESUME_CHILD(device_get_parent(devs[j]), 262 devs[j]); 263 } 264 265 goto cleanup; 266 } 267 } 268 269 cleanup: 270 free(devs, M_TEMP); 271 return (error); 272 } 273 274 /* 275 * Ascending comparison of bhnd device's probe order. 276 */ 277 static int 278 compare_ascending_probe_order(const void *lhs, const void *rhs) 279 { 280 device_t ldev, rdev; 281 int lorder, rorder; 282 283 ldev = (*(const device_t *) lhs); 284 rdev = (*(const device_t *) rhs); 285 286 lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev); 287 rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev); 288 289 if (lorder < rorder) { 290 return (-1); 291 } else if (lorder > rorder) { 292 return (1); 293 } else { 294 return (0); 295 } 296 } 297 298 /* 299 * Descending comparison of bhnd device's probe order. 300 */ 301 static int 302 compare_descending_probe_order(const void *lhs, const void *rhs) 303 { 304 return (compare_ascending_probe_order(rhs, lhs)); 305 } 306 307 /** 308 * Helper function for implementing BHND_BUS_GET_PROBE_ORDER(). 309 * 310 * This implementation determines probe ordering based on the device's class 311 * and other properties, including whether the device is serving as a host 312 * bridge. 313 */ 314 int 315 bhnd_generic_get_probe_order(device_t dev, device_t child) 316 { 317 switch (bhnd_get_class(child)) { 318 case BHND_DEVCLASS_CC: 319 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST); 320 321 case BHND_DEVCLASS_CC_B: 322 /* fall through */ 323 case BHND_DEVCLASS_PMU: 324 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY); 325 326 case BHND_DEVCLASS_SOC_ROUTER: 327 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE); 328 329 case BHND_DEVCLASS_SOC_BRIDGE: 330 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST); 331 332 case BHND_DEVCLASS_CPU: 333 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST); 334 335 case BHND_DEVCLASS_RAM: 336 /* fall through */ 337 case BHND_DEVCLASS_MEMC: 338 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY); 339 340 case BHND_DEVCLASS_NVRAM: 341 return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY); 342 343 case BHND_DEVCLASS_PCI: 344 case BHND_DEVCLASS_PCIE: 345 case BHND_DEVCLASS_PCCARD: 346 case BHND_DEVCLASS_ENET: 347 case BHND_DEVCLASS_ENET_MAC: 348 case BHND_DEVCLASS_ENET_PHY: 349 case BHND_DEVCLASS_WLAN: 350 case BHND_DEVCLASS_WLAN_MAC: 351 case BHND_DEVCLASS_WLAN_PHY: 352 case BHND_DEVCLASS_EROM: 353 case BHND_DEVCLASS_OTHER: 354 case BHND_DEVCLASS_INVALID: 355 if (bhnd_is_hostb_device(child)) 356 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); 357 358 return (BHND_PROBE_DEFAULT); 359 } 360 } 361 362 /** 363 * Helper function for implementing BHND_BUS_IS_REGION_VALID(). 364 * 365 * This implementation assumes that port and region numbers are 0-indexed and 366 * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and 367 * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall 368 * within the defined range. 369 */ 370 bool 371 bhnd_generic_is_region_valid(device_t dev, device_t child, 372 bhnd_port_type type, u_int port, u_int region) 373 { 374 if (port >= bhnd_get_port_count(child, type)) 375 return (false); 376 377 if (region >= bhnd_get_region_count(child, type, port)) 378 return (false); 379 380 return (true); 381 } 382 383 /** 384 * Find an NVRAM child device on @p dev, if any. 385 * 386 * @retval device_t An NVRAM device. 387 * @retval NULL If no NVRAM device is found. 388 */ 389 static device_t 390 find_nvram_child(device_t dev) 391 { 392 device_t chipc, nvram; 393 394 /* Look for a directly-attached NVRAM child */ 395 nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass), 396 -1); 397 if (nvram == NULL) 398 return (NULL); 399 400 /* Further checks require a bhnd(4) bus */ 401 if (device_get_devclass(dev) != bhnd_devclass) 402 return (NULL); 403 404 /* Look for a ChipCommon-attached OTP device */ 405 if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { 406 /* Recursively search the ChipCommon device */ 407 if ((nvram = find_nvram_child(chipc)) != NULL) 408 return (nvram); 409 } 410 411 /* Not found */ 412 return (NULL); 413 } 414 415 /** 416 * Helper function for implementing BHND_BUS_READ_NVRAM_VAR(). 417 * 418 * This implementation searches @p dev for a valid NVRAM device. If no NVRAM 419 * child device is found on @p dev, the request is delegated to the 420 * BHND_BUS_READ_NVRAM_VAR() method on the parent 421 * of @p dev. 422 */ 423 int 424 bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name, 425 void *buf, size_t *size) 426 { 427 device_t nvram; 428 429 /* Try to find an NVRAM device applicable to @p child */ 430 if ((nvram = find_nvram_child(dev)) == NULL) 431 return (BHND_BUS_READ_NVRAM_VAR(device_get_parent(dev), child, 432 name, buf, size)); 433 434 return BHND_NVRAM_GETVAR(nvram, name, buf, size); 435 } 436 437 /** 438 * Helper function for implementing BUS_PRINT_CHILD(). 439 * 440 * This implementation requests the device's struct resource_list via 441 * BUS_GET_RESOURCE_LIST. 442 */ 443 int 444 bhnd_generic_print_child(device_t dev, device_t child) 445 { 446 struct resource_list *rl; 447 int retval = 0; 448 449 retval += bus_print_child_header(dev, child); 450 451 rl = BUS_GET_RESOURCE_LIST(dev, child); 452 if (rl != NULL) { 453 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, 454 "%#jx"); 455 } 456 457 retval += printf(" at core %u", bhnd_get_core_index(child)); 458 459 retval += bus_print_child_domain(dev, child); 460 retval += bus_print_child_footer(dev, child); 461 462 return (retval); 463 } 464 465 /** 466 * Helper function for implementing BUS_PRINT_CHILD(). 467 * 468 * This implementation requests the device's struct resource_list via 469 * BUS_GET_RESOURCE_LIST. 470 */ 471 void 472 bhnd_generic_probe_nomatch(device_t dev, device_t child) 473 { 474 struct resource_list *rl; 475 const struct bhnd_nomatch *nm; 476 bool report; 477 478 /* Fetch reporting configuration for this device */ 479 report = true; 480 for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) { 481 if (nm->vendor != bhnd_get_vendor(child)) 482 continue; 483 484 if (nm->device != bhnd_get_device(child)) 485 continue; 486 487 report = false; 488 if (bootverbose && nm->if_verbose) 489 report = true; 490 break; 491 } 492 493 if (!report) 494 return; 495 496 /* Print the non-matched device info */ 497 device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child), 498 bhnd_get_device_name(child)); 499 500 rl = BUS_GET_RESOURCE_LIST(dev, child); 501 if (rl != NULL) 502 resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 503 504 printf(" at core %u (no driver attached)\n", 505 bhnd_get_core_index(child)); 506 } 507 508 /** 509 * Default implementation of BUS_CHILD_PNPINFO_STR(). 510 */ 511 static int 512 bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf, 513 size_t buflen) 514 { 515 if (device_get_parent(child) != dev) { 516 return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child, 517 buf, buflen)); 518 } 519 520 snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx", 521 bhnd_get_vendor(child), bhnd_get_device(child), 522 bhnd_get_hwrev(child)); 523 524 return (0); 525 } 526 527 /** 528 * Default implementation of implementing BUS_PRINT_CHILD(). 529 */ 530 static int 531 bhnd_child_location_str(device_t dev, device_t child, char *buf, 532 size_t buflen) 533 { 534 bhnd_addr_t addr; 535 bhnd_size_t size; 536 537 if (device_get_parent(child) != dev) { 538 return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, 539 buf, buflen)); 540 } 541 542 543 if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { 544 /* No device default port/region */ 545 if (buflen > 0) 546 *buf = '\0'; 547 return (0); 548 } 549 550 snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); 551 return (0); 552 } 553 554 /** 555 * Helper function for implementing BUS_SUSPEND_CHILD(). 556 * 557 * TODO: Power management 558 * 559 * If @p child is not a direct child of @p dev, suspension is delegated to 560 * the @p dev parent. 561 */ 562 int 563 bhnd_generic_suspend_child(device_t dev, device_t child) 564 { 565 if (device_get_parent(child) != dev) 566 BUS_SUSPEND_CHILD(device_get_parent(dev), child); 567 568 return bus_generic_suspend_child(dev, child); 569 } 570 571 /** 572 * Helper function for implementing BUS_RESUME_CHILD(). 573 * 574 * TODO: Power management 575 * 576 * If @p child is not a direct child of @p dev, suspension is delegated to 577 * the @p dev parent. 578 */ 579 int 580 bhnd_generic_resume_child(device_t dev, device_t child) 581 { 582 if (device_get_parent(child) != dev) 583 BUS_RESUME_CHILD(device_get_parent(dev), child); 584 585 return bus_generic_resume_child(dev, child); 586 } 587 588 /** 589 * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE(). 590 * 591 * If a parent device is available, this implementation delegates the 592 * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev. 593 * 594 * If no parent device is available (i.e. on a the bus root), false 595 * is returned. 596 */ 597 bool 598 bhnd_generic_is_hostb_device(device_t dev, device_t child) { 599 if (device_get_parent(dev) != NULL) 600 return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), 601 child)); 602 603 return (false); 604 } 605 606 /** 607 * Helper function for implementing BHND_BUS_IS_HW_DISABLED(). 608 * 609 * If a parent device is available, this implementation delegates the 610 * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev. 611 * 612 * If no parent device is available (i.e. on a the bus root), the hardware 613 * is assumed to be usable and false is returned. 614 */ 615 bool 616 bhnd_generic_is_hw_disabled(device_t dev, device_t child) 617 { 618 if (device_get_parent(dev) != NULL) 619 return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); 620 621 return (false); 622 } 623 624 /** 625 * Helper function for implementing BHND_BUS_GET_CHIPID(). 626 * 627 * This implementation delegates the request to the BHND_BUS_GET_CHIPID() 628 * method on the parent of @p dev. 629 */ 630 const struct bhnd_chipid * 631 bhnd_generic_get_chipid(device_t dev, device_t child) { 632 return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); 633 } 634 635 /** 636 * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). 637 * 638 * This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines 639 * any default values via BUS_GET_RESOURCE_LIST(), and calls 640 * BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev. 641 * 642 * If no parent device is available, the request is instead delegated to 643 * BUS_ALLOC_RESOURCE(). 644 */ 645 struct bhnd_resource * 646 bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type, 647 int *rid, rman_res_t start, rman_res_t end, rman_res_t count, 648 u_int flags) 649 { 650 struct bhnd_resource *r; 651 struct resource_list *rl; 652 struct resource_list_entry *rle; 653 bool isdefault; 654 bool passthrough; 655 656 passthrough = (device_get_parent(child) != dev); 657 isdefault = RMAN_IS_DEFAULT_RANGE(start, end); 658 659 /* the default RID must always be the first device port/region. */ 660 if (!passthrough && *rid == 0) { 661 int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0); 662 KASSERT(*rid == rid0, 663 ("rid 0 does not map to the first device port (%d)", rid0)); 664 } 665 666 /* Determine locally-known defaults before delegating the request. */ 667 if (!passthrough && isdefault) { 668 /* fetch resource list from child's bus */ 669 rl = BUS_GET_RESOURCE_LIST(dev, child); 670 if (rl == NULL) 671 return (NULL); /* no resource list */ 672 673 /* look for matching type/rid pair */ 674 rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), 675 type, *rid); 676 if (rle == NULL) 677 return (NULL); 678 679 /* set default values */ 680 start = rle->start; 681 end = rle->end; 682 count = ulmax(count, rle->count); 683 } 684 685 /* Try to delegate to our parent. */ 686 if (device_get_parent(dev) != NULL) { 687 return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 688 type, rid, start, end, count, flags)); 689 } 690 691 /* If this is the bus root, use a real bus-allocated resource */ 692 r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); 693 if (r == NULL) 694 return NULL; 695 696 /* Allocate the bus resource, marking it as 'direct' (not requiring 697 * any bus window remapping to perform I/O) */ 698 r->direct = true; 699 r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, 700 count, flags); 701 702 if (r->res == NULL) { 703 free(r, M_BHND); 704 return NULL; 705 } 706 707 return (r); 708 } 709 710 /** 711 * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). 712 * 713 * This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the 714 * BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev. 715 * 716 * If no parent device is available, the request is delegated to 717 * BUS_RELEASE_RESOURCE(). 718 */ 719 int 720 bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type, 721 int rid, struct bhnd_resource *r) 722 { 723 int error; 724 725 /* Try to delegate to the parent. */ 726 if (device_get_parent(dev) != NULL) 727 return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 728 type, rid, r)); 729 730 /* Release the resource directly */ 731 if (!r->direct) { 732 panic("bhnd indirect resource released without " 733 "bhnd parent bus"); 734 } 735 736 error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res); 737 if (error) 738 return (error); 739 740 free(r, M_BHND); 741 return (0); 742 } 743 744 /** 745 * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). 746 * 747 * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the 748 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. 749 * 750 * If no parent device is available, the request is delegated to 751 * BUS_ACTIVATE_RESOURCE(). 752 */ 753 int 754 bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type, 755 int rid, struct bhnd_resource *r) 756 { 757 /* Try to delegate to the parent */ 758 if (device_get_parent(dev) != NULL) 759 return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), 760 child, type, rid, r)); 761 762 /* Activate the resource directly */ 763 if (!r->direct) { 764 panic("bhnd indirect resource released without " 765 "bhnd parent bus"); 766 } 767 768 return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res)); 769 }; 770 771 /** 772 * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). 773 * 774 * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the 775 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. 776 * 777 * If no parent device is available, the request is delegated to 778 * BUS_DEACTIVATE_RESOURCE(). 779 */ 780 int 781 bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type, 782 int rid, struct bhnd_resource *r) 783 { 784 if (device_get_parent(dev) != NULL) 785 return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), 786 child, type, rid, r)); 787 788 /* De-activate the resource directly */ 789 if (!r->direct) { 790 panic("bhnd indirect resource released without " 791 "bhnd parent bus"); 792 } 793 794 return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res)); 795 }; 796 797 /* 798 * Delegate all indirect I/O to the parent device. When inherited by 799 * non-bridged bus implementations, resources will never be marked as 800 * indirect, and these methods should never be called. 801 */ 802 803 static uint8_t 804 bhnd_read_1(device_t dev, device_t child, struct bhnd_resource *r, 805 bus_size_t offset) 806 { 807 return (BHND_BUS_READ_1(device_get_parent(dev), child, r, offset)); 808 } 809 810 static uint16_t 811 bhnd_read_2(device_t dev, device_t child, struct bhnd_resource *r, 812 bus_size_t offset) 813 { 814 return (BHND_BUS_READ_2(device_get_parent(dev), child, r, offset)); 815 } 816 817 static uint32_t 818 bhnd_read_4(device_t dev, device_t child, struct bhnd_resource *r, 819 bus_size_t offset) 820 { 821 return (BHND_BUS_READ_4(device_get_parent(dev), child, r, offset)); 822 } 823 824 static void 825 bhnd_write_1(device_t dev, device_t child, struct bhnd_resource *r, 826 bus_size_t offset, uint8_t value) 827 { 828 BHND_BUS_WRITE_1(device_get_parent(dev), child, r, offset, value); 829 } 830 831 static void 832 bhnd_write_2(device_t dev, device_t child, struct bhnd_resource *r, 833 bus_size_t offset, uint16_t value) 834 { 835 BHND_BUS_WRITE_2(device_get_parent(dev), child, r, offset, value); 836 } 837 838 static void 839 bhnd_write_4(device_t dev, device_t child, struct bhnd_resource *r, 840 bus_size_t offset, uint32_t value) 841 { 842 BHND_BUS_WRITE_4(device_get_parent(dev), child, r, offset, value); 843 } 844 845 static void 846 bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r, 847 bus_size_t offset, bus_size_t length, int flags) 848 { 849 BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length, 850 flags); 851 } 852 853 static device_method_t bhnd_methods[] = { 854 /* Device interface */ \ 855 DEVMETHOD(device_attach, bhnd_generic_attach), 856 DEVMETHOD(device_detach, bhnd_generic_detach), 857 DEVMETHOD(device_shutdown, bhnd_generic_shutdown), 858 DEVMETHOD(device_suspend, bhnd_generic_suspend), 859 DEVMETHOD(device_resume, bhnd_generic_resume), 860 861 /* Bus interface */ 862 DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), 863 DEVMETHOD(bus_print_child, bhnd_generic_print_child), 864 DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), 865 DEVMETHOD(bus_child_location_str, bhnd_child_location_str), 866 867 DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child), 868 DEVMETHOD(bus_resume_child, bhnd_generic_resume_child), 869 870 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 871 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 872 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 873 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 874 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 875 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 876 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 877 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 878 879 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 880 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 881 DEVMETHOD(bus_config_intr, bus_generic_config_intr), 882 DEVMETHOD(bus_bind_intr, bus_generic_bind_intr), 883 DEVMETHOD(bus_describe_intr, bus_generic_describe_intr), 884 885 DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), 886 887 /* BHND interface */ 888 DEVMETHOD(bhnd_bus_alloc_resource, bhnd_generic_alloc_bhnd_resource), 889 DEVMETHOD(bhnd_bus_release_resource, bhnd_generic_release_bhnd_resource), 890 DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_activate_bhnd_resource), 891 DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_deactivate_bhnd_resource), 892 DEVMETHOD(bhnd_bus_get_chipid, bhnd_generic_get_chipid), 893 DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), 894 DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), 895 DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), 896 DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), 897 DEVMETHOD(bhnd_bus_write_1, bhnd_write_1), 898 DEVMETHOD(bhnd_bus_write_2, bhnd_write_2), 899 DEVMETHOD(bhnd_bus_write_4, bhnd_write_4), 900 DEVMETHOD(bhnd_bus_barrier, bhnd_barrier), 901 902 DEVMETHOD_END 903 }; 904 905 devclass_t bhnd_devclass; /**< bhnd bus. */ 906 devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */ 907 devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */ 908 909 DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc)); 910 MODULE_VERSION(bhnd, 1); 911