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