1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 5 * Copyright (c) 2017 The FreeBSD Foundation 6 * All rights reserved. 7 * 8 * Portions of this software were developed by Landon Fuller 9 * under sponsorship from the FreeBSD Foundation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 19 * redistribution must be conditioned upon including a substantially 20 * similar Disclaimer requirement for further binary redistribution. 21 * 22 * NO WARRANTY 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 * THE POSSIBILITY OF SUCH DAMAGES. 34 */ 35 36 #include <sys/cdefs.h> 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/systm.h> 43 44 #include <machine/bus.h> 45 46 #include <dev/bhnd/cores/pmu/bhnd_pmu.h> 47 48 #include "bcma_dmp.h" 49 50 #include "bcma_eromreg.h" 51 #include "bcma_eromvar.h" 52 53 #include "bcmavar.h" 54 55 /* RID used when allocating EROM table */ 56 #define BCMA_EROM_RID 0 57 58 static bhnd_erom_class_t * 59 bcma_get_erom_class(driver_t *driver) 60 { 61 return (&bcma_erom_parser); 62 } 63 64 int 65 bcma_probe(device_t dev) 66 { 67 device_set_desc(dev, "BCMA BHND bus"); 68 return (BUS_PROBE_DEFAULT); 69 } 70 71 /** 72 * Default bcma(4) bus driver implementation of DEVICE_ATTACH(). 73 * 74 * This implementation initializes internal bcma(4) state and performs 75 * bus enumeration, and must be called by subclassing drivers in 76 * DEVICE_ATTACH() before any other bus methods. 77 */ 78 int 79 bcma_attach(device_t dev) 80 { 81 int error; 82 83 /* Enumerate children */ 84 if ((error = bcma_add_children(dev))) { 85 device_delete_children(dev); 86 return (error); 87 } 88 89 return (0); 90 } 91 92 int 93 bcma_detach(device_t dev) 94 { 95 return (bhnd_generic_detach(dev)); 96 } 97 98 static device_t 99 bcma_add_child(device_t dev, u_int order, const char *name, int unit) 100 { 101 struct bcma_devinfo *dinfo; 102 device_t child; 103 104 child = device_add_child_ordered(dev, order, name, unit); 105 if (child == NULL) 106 return (NULL); 107 108 if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) { 109 device_delete_child(dev, child); 110 return (NULL); 111 } 112 113 device_set_ivars(child, dinfo); 114 115 return (child); 116 } 117 118 static void 119 bcma_child_deleted(device_t dev, device_t child) 120 { 121 struct bcma_devinfo *dinfo; 122 123 /* Call required bhnd(4) implementation */ 124 bhnd_generic_child_deleted(dev, child); 125 126 /* Free bcma device info */ 127 if ((dinfo = device_get_ivars(child)) != NULL) 128 bcma_free_dinfo(dev, child, dinfo); 129 130 device_set_ivars(child, NULL); 131 } 132 133 static int 134 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 135 { 136 const struct bcma_devinfo *dinfo; 137 const struct bhnd_core_info *ci; 138 139 dinfo = device_get_ivars(child); 140 ci = &dinfo->corecfg->core_info; 141 142 switch (index) { 143 case BHND_IVAR_VENDOR: 144 *result = ci->vendor; 145 return (0); 146 case BHND_IVAR_DEVICE: 147 *result = ci->device; 148 return (0); 149 case BHND_IVAR_HWREV: 150 *result = ci->hwrev; 151 return (0); 152 case BHND_IVAR_DEVICE_CLASS: 153 *result = bhnd_core_class(ci); 154 return (0); 155 case BHND_IVAR_VENDOR_NAME: 156 *result = (uintptr_t) bhnd_vendor_name(ci->vendor); 157 return (0); 158 case BHND_IVAR_DEVICE_NAME: 159 *result = (uintptr_t) bhnd_core_name(ci); 160 return (0); 161 case BHND_IVAR_CORE_INDEX: 162 *result = ci->core_idx; 163 return (0); 164 case BHND_IVAR_CORE_UNIT: 165 *result = ci->unit; 166 return (0); 167 case BHND_IVAR_PMU_INFO: 168 *result = (uintptr_t) dinfo->pmu_info; 169 return (0); 170 default: 171 return (ENOENT); 172 } 173 } 174 175 static int 176 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 177 { 178 struct bcma_devinfo *dinfo; 179 180 dinfo = device_get_ivars(child); 181 182 switch (index) { 183 case BHND_IVAR_VENDOR: 184 case BHND_IVAR_DEVICE: 185 case BHND_IVAR_HWREV: 186 case BHND_IVAR_DEVICE_CLASS: 187 case BHND_IVAR_VENDOR_NAME: 188 case BHND_IVAR_DEVICE_NAME: 189 case BHND_IVAR_CORE_INDEX: 190 case BHND_IVAR_CORE_UNIT: 191 return (EINVAL); 192 case BHND_IVAR_PMU_INFO: 193 dinfo->pmu_info = (void *)value; 194 return (0); 195 default: 196 return (ENOENT); 197 } 198 } 199 200 static struct resource_list * 201 bcma_get_resource_list(device_t dev, device_t child) 202 { 203 struct bcma_devinfo *dinfo = device_get_ivars(child); 204 return (&dinfo->resources); 205 } 206 207 static int 208 bcma_read_iost(device_t dev, device_t child, uint16_t *iost) 209 { 210 uint32_t value; 211 int error; 212 213 if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4))) 214 return (error); 215 216 /* Return only the bottom 16 bits */ 217 *iost = (value & BCMA_DMP_IOST_MASK); 218 return (0); 219 } 220 221 static int 222 bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl) 223 { 224 uint32_t value; 225 int error; 226 227 if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4))) 228 return (error); 229 230 /* Return only the bottom 16 bits */ 231 *ioctl = (value & BCMA_DMP_IOCTRL_MASK); 232 return (0); 233 } 234 235 static int 236 bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask) 237 { 238 struct bcma_devinfo *dinfo; 239 struct bhnd_resource *r; 240 uint32_t ioctl; 241 242 if (device_get_parent(child) != dev) 243 return (EINVAL); 244 245 dinfo = device_get_ivars(child); 246 if ((r = dinfo->res_agent) == NULL) 247 return (ENODEV); 248 249 /* Write new value */ 250 ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); 251 ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask); 252 ioctl |= (value & mask); 253 254 bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl); 255 256 /* Perform read-back and wait for completion */ 257 bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); 258 DELAY(10); 259 260 return (0); 261 } 262 263 static bool 264 bcma_is_hw_suspended(device_t dev, device_t child) 265 { 266 uint32_t rst; 267 uint16_t ioctl; 268 int error; 269 270 /* Is core held in RESET? */ 271 error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4); 272 if (error) { 273 device_printf(child, "error reading HW reset state: %d\n", 274 error); 275 return (true); 276 } 277 278 if (rst & BCMA_DMP_RC_RESET) 279 return (true); 280 281 /* Is core clocked? */ 282 error = bhnd_read_ioctl(child, &ioctl); 283 if (error) { 284 device_printf(child, "error reading HW ioctl register: %d\n", 285 error); 286 return (true); 287 } 288 289 if (!(ioctl & BHND_IOCTL_CLK_EN)) 290 return (true); 291 292 return (false); 293 } 294 295 static int 296 bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl, 297 uint16_t reset_ioctl) 298 { 299 struct bcma_devinfo *dinfo; 300 struct bhnd_resource *r; 301 uint16_t clkflags; 302 int error; 303 304 if (device_get_parent(child) != dev) 305 return (EINVAL); 306 307 dinfo = device_get_ivars(child); 308 309 /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ 310 clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; 311 if (ioctl & clkflags) 312 return (EINVAL); 313 314 /* Can't suspend the core without access to the agent registers */ 315 if ((r = dinfo->res_agent) == NULL) 316 return (ENODEV); 317 318 /* Place core into known RESET state */ 319 if ((error = bhnd_suspend_hw(child, reset_ioctl))) 320 return (error); 321 322 /* 323 * Leaving the core in reset: 324 * - Set the caller's IOCTL flags 325 * - Enable clocks 326 * - Force clock distribution to ensure propagation throughout the 327 * core. 328 */ 329 if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX))) 330 return (error); 331 332 /* Bring the core out of reset */ 333 if ((error = bcma_dmp_write_reset(child, dinfo, 0x0))) 334 return (error); 335 336 /* Disable forced clock gating (leaving clock enabled) */ 337 error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE); 338 if (error) 339 return (error); 340 341 return (0); 342 } 343 344 static int 345 bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl) 346 { 347 struct bcma_devinfo *dinfo; 348 struct bhnd_resource *r; 349 uint16_t clkflags; 350 int error; 351 352 if (device_get_parent(child) != dev) 353 return (EINVAL); 354 355 dinfo = device_get_ivars(child); 356 357 /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ 358 clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; 359 if (ioctl & clkflags) 360 return (EINVAL); 361 362 /* Can't suspend the core without access to the agent registers */ 363 if ((r = dinfo->res_agent) == NULL) 364 return (ENODEV); 365 366 /* Wait for any pending reset operations to clear */ 367 if ((error = bcma_dmp_wait_reset(child, dinfo))) 368 return (error); 369 370 /* Put core into reset (if not already in reset) */ 371 if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET))) 372 return (error); 373 374 /* Write core flags (and clear CLK_EN/CLK_FORCE) */ 375 if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags))) 376 return (error); 377 378 return (0); 379 } 380 381 static int 382 bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value, 383 u_int width) 384 { 385 struct bcma_devinfo *dinfo; 386 struct bhnd_resource *r; 387 388 /* Must be a directly attached child core */ 389 if (device_get_parent(child) != dev) 390 return (EINVAL); 391 392 /* Fetch the agent registers */ 393 dinfo = device_get_ivars(child); 394 if ((r = dinfo->res_agent) == NULL) 395 return (ENODEV); 396 397 /* Verify bounds */ 398 if (offset > rman_get_size(r->res)) 399 return (EFAULT); 400 401 if (rman_get_size(r->res) - offset < width) 402 return (EFAULT); 403 404 switch (width) { 405 case 1: 406 *((uint8_t *)value) = bhnd_bus_read_1(r, offset); 407 return (0); 408 case 2: 409 *((uint16_t *)value) = bhnd_bus_read_2(r, offset); 410 return (0); 411 case 4: 412 *((uint32_t *)value) = bhnd_bus_read_4(r, offset); 413 return (0); 414 default: 415 return (EINVAL); 416 } 417 } 418 419 static int 420 bcma_write_config(device_t dev, device_t child, bus_size_t offset, 421 const void *value, u_int width) 422 { 423 struct bcma_devinfo *dinfo; 424 struct bhnd_resource *r; 425 426 /* Must be a directly attached child core */ 427 if (device_get_parent(child) != dev) 428 return (EINVAL); 429 430 /* Fetch the agent registers */ 431 dinfo = device_get_ivars(child); 432 if ((r = dinfo->res_agent) == NULL) 433 return (ENODEV); 434 435 /* Verify bounds */ 436 if (offset > rman_get_size(r->res)) 437 return (EFAULT); 438 439 if (rman_get_size(r->res) - offset < width) 440 return (EFAULT); 441 442 switch (width) { 443 case 1: 444 bhnd_bus_write_1(r, offset, *(const uint8_t *)value); 445 return (0); 446 case 2: 447 bhnd_bus_write_2(r, offset, *(const uint16_t *)value); 448 return (0); 449 case 4: 450 bhnd_bus_write_4(r, offset, *(const uint32_t *)value); 451 return (0); 452 default: 453 return (EINVAL); 454 } 455 } 456 457 static u_int 458 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) 459 { 460 struct bcma_devinfo *dinfo; 461 462 /* delegate non-bus-attached devices to our parent */ 463 if (device_get_parent(child) != dev) 464 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, 465 type)); 466 467 dinfo = device_get_ivars(child); 468 switch (type) { 469 case BHND_PORT_DEVICE: 470 return (dinfo->corecfg->num_dev_ports); 471 case BHND_PORT_BRIDGE: 472 return (dinfo->corecfg->num_bridge_ports); 473 case BHND_PORT_AGENT: 474 return (dinfo->corecfg->num_wrapper_ports); 475 default: 476 device_printf(dev, "%s: unknown type (%d)\n", 477 __func__, 478 type); 479 return (0); 480 } 481 } 482 483 static u_int 484 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type, 485 u_int port_num) 486 { 487 struct bcma_devinfo *dinfo; 488 struct bcma_sport_list *ports; 489 struct bcma_sport *port; 490 491 /* delegate non-bus-attached devices to our parent */ 492 if (device_get_parent(child) != dev) 493 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, 494 type, port_num)); 495 496 dinfo = device_get_ivars(child); 497 ports = bcma_corecfg_get_port_list(dinfo->corecfg, type); 498 499 STAILQ_FOREACH(port, ports, sp_link) { 500 if (port->sp_num == port_num) 501 return (port->sp_num_maps); 502 } 503 504 /* not found */ 505 return (0); 506 } 507 508 static int 509 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, 510 u_int port_num, u_int region_num) 511 { 512 struct bcma_devinfo *dinfo; 513 struct bcma_map *map; 514 struct bcma_sport_list *ports; 515 struct bcma_sport *port; 516 517 dinfo = device_get_ivars(child); 518 ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 519 520 STAILQ_FOREACH(port, ports, sp_link) { 521 if (port->sp_num != port_num) 522 continue; 523 524 STAILQ_FOREACH(map, &port->sp_maps, m_link) 525 if (map->m_region_num == region_num) 526 return map->m_rid; 527 } 528 529 return -1; 530 } 531 532 static int 533 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid, 534 bhnd_port_type *port_type, u_int *port_num, u_int *region_num) 535 { 536 struct bcma_devinfo *dinfo; 537 struct bcma_map *map; 538 struct bcma_sport_list *ports; 539 struct bcma_sport *port; 540 541 dinfo = device_get_ivars(child); 542 543 /* Ports are always memory mapped */ 544 if (type != SYS_RES_MEMORY) 545 return (EINVAL); 546 547 /* Starting with the most likely device list, search all three port 548 * lists */ 549 bhnd_port_type types[] = { 550 BHND_PORT_DEVICE, 551 BHND_PORT_AGENT, 552 BHND_PORT_BRIDGE 553 }; 554 555 for (int i = 0; i < nitems(types); i++) { 556 ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]); 557 558 STAILQ_FOREACH(port, ports, sp_link) { 559 STAILQ_FOREACH(map, &port->sp_maps, m_link) { 560 if (map->m_rid != rid) 561 continue; 562 563 *port_type = port->sp_type; 564 *port_num = port->sp_num; 565 *region_num = map->m_region_num; 566 return (0); 567 } 568 } 569 } 570 571 return (ENOENT); 572 } 573 574 static int 575 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, 576 u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) 577 { 578 struct bcma_devinfo *dinfo; 579 struct bcma_map *map; 580 struct bcma_sport_list *ports; 581 struct bcma_sport *port; 582 583 dinfo = device_get_ivars(child); 584 ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 585 586 /* Search the port list */ 587 STAILQ_FOREACH(port, ports, sp_link) { 588 if (port->sp_num != port_num) 589 continue; 590 591 STAILQ_FOREACH(map, &port->sp_maps, m_link) { 592 if (map->m_region_num != region_num) 593 continue; 594 595 /* Found! */ 596 *addr = map->m_base; 597 *size = map->m_size; 598 return (0); 599 } 600 } 601 602 return (ENOENT); 603 } 604 605 /** 606 * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT(). 607 */ 608 u_int 609 bcma_get_intr_count(device_t dev, device_t child) 610 { 611 struct bcma_devinfo *dinfo; 612 613 /* delegate non-bus-attached devices to our parent */ 614 if (device_get_parent(child) != dev) 615 return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child)); 616 617 dinfo = device_get_ivars(child); 618 return (dinfo->num_intrs); 619 } 620 621 /** 622 * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC(). 623 */ 624 int 625 bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec) 626 { 627 struct bcma_devinfo *dinfo; 628 struct bcma_intr *desc; 629 630 /* delegate non-bus-attached devices to our parent */ 631 if (device_get_parent(child) != dev) { 632 return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child, 633 intr, ivec)); 634 } 635 636 dinfo = device_get_ivars(child); 637 638 STAILQ_FOREACH(desc, &dinfo->intrs, i_link) { 639 if (desc->i_sel == intr) { 640 *ivec = desc->i_busline; 641 return (0); 642 } 643 } 644 645 /* Not found */ 646 return (ENXIO); 647 } 648 649 /** 650 * Scan the device enumeration ROM table, adding all valid discovered cores to 651 * the bus. 652 * 653 * @param bus The bcma bus. 654 */ 655 int 656 bcma_add_children(device_t bus) 657 { 658 bhnd_erom_t *erom; 659 struct bcma_erom *bcma_erom; 660 struct bhnd_erom_io *eio; 661 const struct bhnd_chipid *cid; 662 struct bcma_corecfg *corecfg; 663 struct bcma_devinfo *dinfo; 664 device_t child; 665 int error; 666 667 cid = BHND_BUS_GET_CHIPID(bus, bus); 668 corecfg = NULL; 669 670 /* Allocate our EROM parser */ 671 eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID); 672 erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio); 673 if (erom == NULL) { 674 bhnd_erom_io_fini(eio); 675 return (ENODEV); 676 } 677 678 /* Add all cores. */ 679 bcma_erom = (struct bcma_erom *)erom; 680 while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) { 681 /* Add the child device */ 682 child = BUS_ADD_CHILD(bus, 0, NULL, -1); 683 if (child == NULL) { 684 error = ENXIO; 685 goto cleanup; 686 } 687 688 /* Initialize device ivars */ 689 dinfo = device_get_ivars(child); 690 if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg))) 691 goto cleanup; 692 693 /* The dinfo instance now owns the corecfg value */ 694 corecfg = NULL; 695 696 /* If pins are floating or the hardware is otherwise 697 * unpopulated, the device shouldn't be used. */ 698 if (bhnd_is_hw_disabled(child)) 699 device_disable(child); 700 701 /* Issue bus callback for fully initialized child. */ 702 BHND_BUS_CHILD_ADDED(bus, child); 703 } 704 705 /* EOF while parsing cores is expected */ 706 if (error == ENOENT) 707 error = 0; 708 709 cleanup: 710 bhnd_erom_free(erom); 711 712 if (corecfg != NULL) 713 bcma_free_corecfg(corecfg); 714 715 if (error) 716 device_delete_children(bus); 717 718 return (error); 719 } 720 721 static device_method_t bcma_methods[] = { 722 /* Device interface */ 723 DEVMETHOD(device_probe, bcma_probe), 724 DEVMETHOD(device_attach, bcma_attach), 725 DEVMETHOD(device_detach, bcma_detach), 726 727 /* Bus interface */ 728 DEVMETHOD(bus_add_child, bcma_add_child), 729 DEVMETHOD(bus_child_deleted, bcma_child_deleted), 730 DEVMETHOD(bus_read_ivar, bcma_read_ivar), 731 DEVMETHOD(bus_write_ivar, bcma_write_ivar), 732 DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), 733 734 /* BHND interface */ 735 DEVMETHOD(bhnd_bus_get_erom_class, bcma_get_erom_class), 736 DEVMETHOD(bhnd_bus_read_ioctl, bcma_read_ioctl), 737 DEVMETHOD(bhnd_bus_write_ioctl, bcma_write_ioctl), 738 DEVMETHOD(bhnd_bus_read_iost, bcma_read_iost), 739 DEVMETHOD(bhnd_bus_is_hw_suspended, bcma_is_hw_suspended), 740 DEVMETHOD(bhnd_bus_reset_hw, bcma_reset_hw), 741 DEVMETHOD(bhnd_bus_suspend_hw, bcma_suspend_hw), 742 DEVMETHOD(bhnd_bus_read_config, bcma_read_config), 743 DEVMETHOD(bhnd_bus_write_config, bcma_write_config), 744 DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), 745 DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), 746 DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), 747 DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid), 748 DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr), 749 DEVMETHOD(bhnd_bus_get_intr_count, bcma_get_intr_count), 750 DEVMETHOD(bhnd_bus_get_intr_ivec, bcma_get_intr_ivec), 751 752 DEVMETHOD_END 753 }; 754 755 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver); 756 MODULE_VERSION(bcma, 1); 757 MODULE_DEPEND(bcma, bhnd, 1, 1, 1); 758