121 * children, in reverse bhnd probe order, terminating if any call to 122 * device_detach() fails. 123 */ 124int 125bhnd_generic_detach(device_t dev) 126{ 127 device_t *devs; 128 int ndevs; 129 int error; 130 131 if (!device_is_attached(dev)) 132 return (EBUSY); 133 134 if ((error = device_get_children(dev, &devs, &ndevs))) 135 return (error); 136 137 /* Detach in the reverse of attach order */ 138 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 139 for (int i = 0; i < ndevs; i++) { 140 device_t child = devs[i]; 141 142 /* Terminate on first error */ 143 if ((error = device_detach(child))) 144 goto cleanup; 145 } 146 147cleanup: 148 free(devs, M_TEMP); 149 return (error); 150} 151 152/** 153 * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN(). 154 * 155 * This implementation calls device_shutdown() for each of the device's 156 * children, in reverse bhnd probe order, terminating if any call to 157 * device_shutdown() fails. 158 */ 159int 160bhnd_generic_shutdown(device_t dev) 161{ 162 device_t *devs; 163 int ndevs; 164 int error; 165 166 if (!device_is_attached(dev)) 167 return (EBUSY); 168 169 if ((error = device_get_children(dev, &devs, &ndevs))) 170 return (error); 171 172 /* Shutdown in the reverse of attach order */ 173 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 174 for (int i = 0; i < ndevs; i++) { 175 device_t child = devs[i]; 176 177 /* Terminate on first error */ 178 if ((error = device_shutdown(child))) 179 goto cleanup; 180 } 181 182cleanup: 183 free(devs, M_TEMP); 184 return (error); 185} 186 187/** 188 * Default bhnd(4) bus driver implementation of DEVICE_RESUME(). 189 * 190 * This implementation calls BUS_RESUME_CHILD() for each of the device's 191 * children in bhnd probe order, terminating if any call to BUS_RESUME_CHILD() 192 * fails. 193 */ 194int 195bhnd_generic_resume(device_t dev) 196{ 197 device_t *devs; 198 int ndevs; 199 int error; 200 201 if (!device_is_attached(dev)) 202 return (EBUSY); 203 204 if ((error = device_get_children(dev, &devs, &ndevs))) 205 return (error); 206 207 qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); 208 for (int i = 0; i < ndevs; i++) { 209 device_t child = devs[i]; 210 211 /* Terminate on first error */ 212 if ((error = BUS_RESUME_CHILD(device_get_parent(child), child))) 213 goto cleanup; 214 } 215 216cleanup: 217 free(devs, M_TEMP); 218 return (error); 219} 220 221/** 222 * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND(). 223 * 224 * This implementation calls BUS_SUSPEND_CHILD() for each of the device's 225 * children in reverse bhnd probe order. If any call to BUS_SUSPEND_CHILD() 226 * fails, the suspend operation is terminated and any devices that were 227 * suspended are resumed immediately by calling their BUS_RESUME_CHILD() 228 * methods. 229 */ 230int 231bhnd_generic_suspend(device_t dev) 232{ 233 device_t *devs; 234 int ndevs; 235 int error; 236 237 if (!device_is_attached(dev)) 238 return (EBUSY); 239 240 if ((error = device_get_children(dev, &devs, &ndevs))) 241 return (error); 242 243 /* Suspend in the reverse of attach order */ 244 qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 245 for (int i = 0; i < ndevs; i++) { 246 device_t child = devs[i]; 247 error = BUS_SUSPEND_CHILD(device_get_parent(child), child); 248 249 /* On error, resume suspended devices and then terminate */ 250 if (error) { 251 for (int j = 0; j < i; j++) { 252 BUS_RESUME_CHILD(device_get_parent(devs[j]), 253 devs[j]); 254 } 255 256 goto cleanup; 257 } 258 } 259 260cleanup: 261 free(devs, M_TEMP); 262 return (error); 263} 264 265/* 266 * Ascending comparison of bhnd device's probe order. 267 */ 268static int 269compare_ascending_probe_order(const void *lhs, const void *rhs) 270{ 271 device_t ldev, rdev; 272 int lorder, rorder; 273 274 ldev = (*(const device_t *) lhs); 275 rdev = (*(const device_t *) rhs); 276 277 lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev); 278 rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev); 279 280 if (lorder < rorder) { 281 return (-1); 282 } else if (lorder > rorder) { 283 return (1); 284 } else { 285 return (0); 286 } 287} 288 289/* 290 * Descending comparison of bhnd device's probe order. 291 */ 292static int 293compare_descending_probe_order(const void *lhs, const void *rhs) 294{ 295 return (compare_ascending_probe_order(rhs, lhs)); 296} 297 298/** 299 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_PROBE_ORDER(). 300 * 301 * This implementation determines probe ordering based on the device's class 302 * and other properties, including whether the device is serving as a host 303 * bridge. 304 */ 305int 306bhnd_generic_get_probe_order(device_t dev, device_t child) 307{ 308 switch (bhnd_get_class(child)) { 309 case BHND_DEVCLASS_CC: 310 /* Must be early enough to provide NVRAM access to the 311 * host bridge */ 312 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_FIRST); 313 314 case BHND_DEVCLASS_CC_B: 315 /* fall through */ 316 case BHND_DEVCLASS_PMU: 317 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY); 318 319 case BHND_DEVCLASS_SOC_ROUTER: 320 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE); 321 322 case BHND_DEVCLASS_SOC_BRIDGE: 323 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST); 324 325 case BHND_DEVCLASS_CPU: 326 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST); 327 328 case BHND_DEVCLASS_RAM: 329 /* fall through */ 330 case BHND_DEVCLASS_MEMC: 331 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY); 332 333 case BHND_DEVCLASS_NVRAM: 334 return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY); 335 336 case BHND_DEVCLASS_PCI: 337 case BHND_DEVCLASS_PCIE: 338 case BHND_DEVCLASS_PCCARD: 339 case BHND_DEVCLASS_ENET: 340 case BHND_DEVCLASS_ENET_MAC: 341 case BHND_DEVCLASS_ENET_PHY: 342 case BHND_DEVCLASS_WLAN: 343 case BHND_DEVCLASS_WLAN_MAC: 344 case BHND_DEVCLASS_WLAN_PHY: 345 case BHND_DEVCLASS_EROM: 346 case BHND_DEVCLASS_OTHER: 347 case BHND_DEVCLASS_INVALID: 348 if (bhnd_find_hostb_device(dev) == child) 349 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); 350 351 return (BHND_PROBE_DEFAULT); 352 default: 353 return (BHND_PROBE_DEFAULT); 354 } 355} 356 357/** 358 * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID(). 359 * 360 * This implementation assumes that port and region numbers are 0-indexed and 361 * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and 362 * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall 363 * within the defined range. 364 */ 365static bool 366bhnd_generic_is_region_valid(device_t dev, device_t child, 367 bhnd_port_type type, u_int port, u_int region) 368{ 369 if (port >= bhnd_get_port_count(child, type)) 370 return (false); 371 372 if (region >= bhnd_get_region_count(child, type, port)) 373 return (false); 374 375 return (true); 376} 377 378/** 379 * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD(). 380 * 381 * This implementation requests the device's struct resource_list via 382 * BUS_GET_RESOURCE_LIST. 383 */ 384int 385bhnd_generic_print_child(device_t dev, device_t child) 386{ 387 struct resource_list *rl; 388 int retval = 0; 389 390 retval += bus_print_child_header(dev, child); 391 392 rl = BUS_GET_RESOURCE_LIST(dev, child); 393 if (rl != NULL) { 394 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, 395 "%#jx"); 396 } 397 398 retval += printf(" at core %u", bhnd_get_core_index(child)); 399 400 retval += bus_print_child_domain(dev, child); 401 retval += bus_print_child_footer(dev, child); 402 403 return (retval); 404} 405 406/** 407 * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH(). 408 * 409 * This implementation requests the device's struct resource_list via 410 * BUS_GET_RESOURCE_LIST. 411 */ 412void 413bhnd_generic_probe_nomatch(device_t dev, device_t child) 414{ 415 struct resource_list *rl; 416 const struct bhnd_nomatch *nm; 417 bool report; 418 419 /* Fetch reporting configuration for this device */ 420 report = true; 421 for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) { 422 if (nm->vendor != bhnd_get_vendor(child)) 423 continue; 424 425 if (nm->device != bhnd_get_device(child)) 426 continue; 427 428 report = false; 429 if (bootverbose && nm->if_verbose) 430 report = true; 431 break; 432 } 433 434 if (!report) 435 return; 436 437 /* Print the non-matched device info */ 438 device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child), 439 bhnd_get_device_name(child)); 440 441 rl = BUS_GET_RESOURCE_LIST(dev, child); 442 if (rl != NULL) 443 resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 444 445 printf(" at core %u (no driver attached)\n", 446 bhnd_get_core_index(child)); 447} 448 449/** 450 * Default implementation of BUS_CHILD_PNPINFO_STR(). 451 */ 452static int 453bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf, 454 size_t buflen) 455{ 456 if (device_get_parent(child) != dev) { 457 return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child, 458 buf, buflen)); 459 } 460 461 snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx", 462 bhnd_get_vendor(child), bhnd_get_device(child), 463 bhnd_get_hwrev(child)); 464 465 return (0); 466} 467 468/** 469 * Default implementation of BUS_CHILD_LOCATION_STR(). 470 */ 471static int 472bhnd_child_location_str(device_t dev, device_t child, char *buf, 473 size_t buflen) 474{ 475 bhnd_addr_t addr; 476 bhnd_size_t size; 477 478 if (device_get_parent(child) != dev) { 479 return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, 480 buf, buflen)); 481 } 482 483 484 if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { 485 /* No device default port/region */ 486 if (buflen > 0) 487 *buf = '\0'; 488 return (0); 489 } 490 491 snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); 492 return (0); 493} 494 495/** 496 * Helper function for implementing BUS_SUSPEND_CHILD(). 497 * 498 * TODO: Power management 499 * 500 * If @p child is not a direct child of @p dev, suspension is delegated to 501 * the @p dev parent. 502 */ 503int 504bhnd_generic_suspend_child(device_t dev, device_t child) 505{ 506 if (device_get_parent(child) != dev) 507 BUS_SUSPEND_CHILD(device_get_parent(dev), child); 508 509 return bus_generic_suspend_child(dev, child); 510} 511 512/** 513 * Helper function for implementing BUS_RESUME_CHILD(). 514 * 515 * TODO: Power management 516 * 517 * If @p child is not a direct child of @p dev, suspension is delegated to 518 * the @p dev parent. 519 */ 520int 521bhnd_generic_resume_child(device_t dev, device_t child) 522{ 523 if (device_get_parent(child) != dev) 524 BUS_RESUME_CHILD(device_get_parent(dev), child); 525 526 return bus_generic_resume_child(dev, child); 527} 528 529/* 530 * Delegate all indirect I/O to the parent device. When inherited by 531 * non-bridged bus implementations, resources will never be marked as 532 * indirect, and these methods should never be called. 533 */ 534#define BHND_IO_READ(_type, _name, _method) \ 535static _type \ 536bhnd_read_ ## _name (device_t dev, device_t child, \ 537 struct bhnd_resource *r, bus_size_t offset) \ 538{ \ 539 return (BHND_BUS_READ_ ## _method( \ 540 device_get_parent(dev), child, r, offset)); \ 541} 542 543#define BHND_IO_WRITE(_type, _name, _method) \ 544static void \ 545bhnd_write_ ## _name (device_t dev, device_t child, \ 546 struct bhnd_resource *r, bus_size_t offset, _type value) \ 547{ \ 548 return (BHND_BUS_WRITE_ ## _method( \ 549 device_get_parent(dev), child, r, offset, \ 550 value)); \ 551} 552 553#define BHND_IO_MULTI(_type, _rw, _name, _method) \ 554static void \ 555bhnd_ ## _rw ## _multi_ ## _name (device_t dev, device_t child, \ 556 struct bhnd_resource *r, bus_size_t offset, _type *datap, \ 557 bus_size_t count) \ 558{ \ 559 BHND_BUS_ ## _method(device_get_parent(dev), child, r, \ 560 offset, datap, count); \ 561} 562 563#define BHND_IO_METHODS(_type, _size) \ 564 BHND_IO_READ(_type, _size, _size) \ 565 BHND_IO_WRITE(_type, _size, _size) \ 566 \ 567 BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size) \ 568 BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size) \ 569 \ 570 BHND_IO_MULTI(_type, read, _size, READ_MULTI_ ## _size) \ 571 BHND_IO_MULTI(_type, write, _size, WRITE_MULTI_ ## _size) \ 572 \ 573 BHND_IO_MULTI(_type, read, stream_ ## _size, \ 574 READ_MULTI_STREAM_ ## _size) \ 575 BHND_IO_MULTI(_type, write, stream_ ## _size, \ 576 WRITE_MULTI_STREAM_ ## _size) \ 577 578BHND_IO_METHODS(uint8_t, 1); 579BHND_IO_METHODS(uint16_t, 2); 580BHND_IO_METHODS(uint32_t, 4); 581 582static void 583bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r, 584 bus_size_t offset, bus_size_t length, int flags) 585{ 586 BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length, 587 flags); 588} 589 590static device_method_t bhnd_methods[] = { 591 /* Device interface */ \ 592 DEVMETHOD(device_attach, bhnd_generic_attach), 593 DEVMETHOD(device_detach, bhnd_generic_detach), 594 DEVMETHOD(device_shutdown, bhnd_generic_shutdown), 595 DEVMETHOD(device_suspend, bhnd_generic_suspend), 596 DEVMETHOD(device_resume, bhnd_generic_resume), 597 598 /* Bus interface */ 599 DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), 600 DEVMETHOD(bus_print_child, bhnd_generic_print_child), 601 DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), 602 DEVMETHOD(bus_child_location_str, bhnd_child_location_str), 603 604 DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child), 605 DEVMETHOD(bus_resume_child, bhnd_generic_resume_child), 606 607 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 608 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 609 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 610 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 611 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 612 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 613 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 614 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 615 616 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 617 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 618 DEVMETHOD(bus_config_intr, bus_generic_config_intr), 619 DEVMETHOD(bus_bind_intr, bus_generic_bind_intr), 620 DEVMETHOD(bus_describe_intr, bus_generic_describe_intr), 621 622 DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), 623 624 /* BHND interface */ 625 DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid), 626 DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), 627 DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), 628 DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), 629 DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var), 630 DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), 631 DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), 632 DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), 633 DEVMETHOD(bhnd_bus_write_1, bhnd_write_1), 634 DEVMETHOD(bhnd_bus_write_2, bhnd_write_2), 635 DEVMETHOD(bhnd_bus_write_4, bhnd_write_4), 636 DEVMETHOD(bhnd_bus_read_stream_1, bhnd_read_stream_1), 637 DEVMETHOD(bhnd_bus_read_stream_2, bhnd_read_stream_2), 638 DEVMETHOD(bhnd_bus_read_stream_4, bhnd_read_stream_4), 639 DEVMETHOD(bhnd_bus_write_stream_1, bhnd_write_stream_1), 640 DEVMETHOD(bhnd_bus_write_stream_2, bhnd_write_stream_2), 641 DEVMETHOD(bhnd_bus_write_stream_4, bhnd_write_stream_4), 642 643 DEVMETHOD(bhnd_bus_read_multi_1, bhnd_read_multi_1), 644 DEVMETHOD(bhnd_bus_read_multi_2, bhnd_read_multi_2), 645 DEVMETHOD(bhnd_bus_read_multi_4, bhnd_read_multi_4), 646 DEVMETHOD(bhnd_bus_write_multi_1, bhnd_write_multi_1), 647 DEVMETHOD(bhnd_bus_write_multi_2, bhnd_write_multi_2), 648 DEVMETHOD(bhnd_bus_write_multi_4, bhnd_write_multi_4), 649 650 DEVMETHOD(bhnd_bus_read_multi_stream_1, bhnd_read_multi_stream_1), 651 DEVMETHOD(bhnd_bus_read_multi_stream_2, bhnd_read_multi_stream_2), 652 DEVMETHOD(bhnd_bus_read_multi_stream_4, bhnd_read_multi_stream_4), 653 DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1), 654 DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2), 655 DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_4), 656 657 DEVMETHOD(bhnd_bus_barrier, bhnd_barrier), 658 659 DEVMETHOD_END 660}; 661 662devclass_t bhnd_devclass; /**< bhnd bus. */ 663devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */ 664devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */ 665 666DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc)); 667MODULE_VERSION(bhnd, 1);
|