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