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