14ad7e9b0SAdrian Chadd /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 36e778a7eSPedro F. Giffuni * 4caeff9a3SLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 5caeff9a3SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation 64ad7e9b0SAdrian Chadd * All rights reserved. 74ad7e9b0SAdrian Chadd * 8caeff9a3SLandon J. Fuller * Portions of this software were developed by Landon Fuller 9caeff9a3SLandon J. Fuller * under sponsorship from the FreeBSD Foundation. 10caeff9a3SLandon J. Fuller * 114ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without 124ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions 134ad7e9b0SAdrian Chadd * are met: 144ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 154ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer, 164ad7e9b0SAdrian Chadd * without modification. 174ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 184ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 194ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially 204ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 214ad7e9b0SAdrian Chadd * 224ad7e9b0SAdrian Chadd * NO WARRANTY 234ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 244ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 254ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 264ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 274ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 284ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 294ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 304ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 314ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 324ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 334ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 344ad7e9b0SAdrian Chadd */ 354ad7e9b0SAdrian Chadd 364ad7e9b0SAdrian Chadd #include <sys/param.h> 374ad7e9b0SAdrian Chadd #include <sys/bus.h> 384ad7e9b0SAdrian Chadd #include <sys/kernel.h> 394ad7e9b0SAdrian Chadd #include <sys/malloc.h> 404ad7e9b0SAdrian Chadd #include <sys/module.h> 414ad7e9b0SAdrian Chadd #include <sys/systm.h> 424ad7e9b0SAdrian Chadd 434ad7e9b0SAdrian Chadd #include <machine/bus.h> 444ad7e9b0SAdrian Chadd 458a03f98aSLandon J. Fuller #include <dev/bhnd/cores/pmu/bhnd_pmu.h> 464ad7e9b0SAdrian Chadd 47824b48efSLandon J. Fuller #include "bcma_dmp.h" 48824b48efSLandon J. Fuller 494ad7e9b0SAdrian Chadd #include "bcma_eromreg.h" 504ad7e9b0SAdrian Chadd #include "bcma_eromvar.h" 51824b48efSLandon J. Fuller 528a03f98aSLandon J. Fuller #include "bcmavar.h" 534ad7e9b0SAdrian Chadd 54664a7497SLandon J. Fuller /* RID used when allocating EROM table */ 55664a7497SLandon J. Fuller #define BCMA_EROM_RID 0 56664a7497SLandon J. Fuller 57111d7cb2SLandon J. Fuller static bhnd_erom_class_t * 58111d7cb2SLandon J. Fuller bcma_get_erom_class(driver_t *driver) 59111d7cb2SLandon J. Fuller { 60111d7cb2SLandon J. Fuller return (&bcma_erom_parser); 61111d7cb2SLandon J. Fuller } 62111d7cb2SLandon J. Fuller 634ad7e9b0SAdrian Chadd int 644ad7e9b0SAdrian Chadd bcma_probe(device_t dev) 654ad7e9b0SAdrian Chadd { 664ad7e9b0SAdrian Chadd device_set_desc(dev, "BCMA BHND bus"); 674ad7e9b0SAdrian Chadd return (BUS_PROBE_DEFAULT); 684ad7e9b0SAdrian Chadd } 694ad7e9b0SAdrian Chadd 70111d7cb2SLandon J. Fuller /** 71111d7cb2SLandon J. Fuller * Default bcma(4) bus driver implementation of DEVICE_ATTACH(). 72111d7cb2SLandon J. Fuller * 73111d7cb2SLandon J. Fuller * This implementation initializes internal bcma(4) state and performs 74111d7cb2SLandon J. Fuller * bus enumeration, and must be called by subclassing drivers in 75111d7cb2SLandon J. Fuller * DEVICE_ATTACH() before any other bus methods. 76111d7cb2SLandon J. Fuller */ 774ad7e9b0SAdrian Chadd int 784ad7e9b0SAdrian Chadd bcma_attach(device_t dev) 794ad7e9b0SAdrian Chadd { 804ad7e9b0SAdrian Chadd int error; 814ad7e9b0SAdrian Chadd 82111d7cb2SLandon J. Fuller /* Enumerate children */ 83111d7cb2SLandon J. Fuller if ((error = bcma_add_children(dev))) { 844ad7e9b0SAdrian Chadd return (error); 854ad7e9b0SAdrian Chadd } 864ad7e9b0SAdrian Chadd 87111d7cb2SLandon J. Fuller return (0); 884ad7e9b0SAdrian Chadd } 894ad7e9b0SAdrian Chadd 904ad7e9b0SAdrian Chadd int 914ad7e9b0SAdrian Chadd bcma_detach(device_t dev) 924ad7e9b0SAdrian Chadd { 934ad7e9b0SAdrian Chadd return (bhnd_generic_detach(dev)); 944ad7e9b0SAdrian Chadd } 954ad7e9b0SAdrian Chadd 968a03f98aSLandon J. Fuller static device_t 978a03f98aSLandon J. Fuller bcma_add_child(device_t dev, u_int order, const char *name, int unit) 988a03f98aSLandon J. Fuller { 998a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo; 1008a03f98aSLandon J. Fuller device_t child; 1018a03f98aSLandon J. Fuller 1028a03f98aSLandon J. Fuller child = device_add_child_ordered(dev, order, name, unit); 1038a03f98aSLandon J. Fuller if (child == NULL) 1048a03f98aSLandon J. Fuller return (NULL); 1058a03f98aSLandon J. Fuller 1068a03f98aSLandon J. Fuller if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) { 1078a03f98aSLandon J. Fuller device_delete_child(dev, child); 1088a03f98aSLandon J. Fuller return (NULL); 1098a03f98aSLandon J. Fuller } 1108a03f98aSLandon J. Fuller 1118a03f98aSLandon J. Fuller device_set_ivars(child, dinfo); 1128a03f98aSLandon J. Fuller 1138a03f98aSLandon J. Fuller return (child); 1148a03f98aSLandon J. Fuller } 1158a03f98aSLandon J. Fuller 1168a03f98aSLandon J. Fuller static void 1178a03f98aSLandon J. Fuller bcma_child_deleted(device_t dev, device_t child) 1188a03f98aSLandon J. Fuller { 1198a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo; 1208a03f98aSLandon J. Fuller 1218a03f98aSLandon J. Fuller /* Call required bhnd(4) implementation */ 1228a03f98aSLandon J. Fuller bhnd_generic_child_deleted(dev, child); 1238a03f98aSLandon J. Fuller 1248a03f98aSLandon J. Fuller /* Free bcma device info */ 1258a03f98aSLandon J. Fuller if ((dinfo = device_get_ivars(child)) != NULL) 126caeff9a3SLandon J. Fuller bcma_free_dinfo(dev, child, dinfo); 1278a03f98aSLandon J. Fuller 1288a03f98aSLandon J. Fuller device_set_ivars(child, NULL); 1298a03f98aSLandon J. Fuller } 1308a03f98aSLandon J. Fuller 1314ad7e9b0SAdrian Chadd static int 1324ad7e9b0SAdrian Chadd bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 1334ad7e9b0SAdrian Chadd { 1344ad7e9b0SAdrian Chadd const struct bcma_devinfo *dinfo; 1354ad7e9b0SAdrian Chadd const struct bhnd_core_info *ci; 1364ad7e9b0SAdrian Chadd 1374ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 1384ad7e9b0SAdrian Chadd ci = &dinfo->corecfg->core_info; 1394ad7e9b0SAdrian Chadd 1404ad7e9b0SAdrian Chadd switch (index) { 1414ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR: 1424ad7e9b0SAdrian Chadd *result = ci->vendor; 1434ad7e9b0SAdrian Chadd return (0); 1444ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE: 1454ad7e9b0SAdrian Chadd *result = ci->device; 1464ad7e9b0SAdrian Chadd return (0); 1474ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV: 1484ad7e9b0SAdrian Chadd *result = ci->hwrev; 1494ad7e9b0SAdrian Chadd return (0); 1504ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS: 1514ad7e9b0SAdrian Chadd *result = bhnd_core_class(ci); 1524ad7e9b0SAdrian Chadd return (0); 1534ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME: 1544ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_vendor_name(ci->vendor); 1554ad7e9b0SAdrian Chadd return (0); 1564ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME: 1574ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_core_name(ci); 1584ad7e9b0SAdrian Chadd return (0); 1594ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX: 1604ad7e9b0SAdrian Chadd *result = ci->core_idx; 1614ad7e9b0SAdrian Chadd return (0); 1624ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT: 1634ad7e9b0SAdrian Chadd *result = ci->unit; 1644ad7e9b0SAdrian Chadd return (0); 1658a03f98aSLandon J. Fuller case BHND_IVAR_PMU_INFO: 1668a03f98aSLandon J. Fuller *result = (uintptr_t) dinfo->pmu_info; 1678a03f98aSLandon J. Fuller return (0); 1684ad7e9b0SAdrian Chadd default: 1694ad7e9b0SAdrian Chadd return (ENOENT); 1704ad7e9b0SAdrian Chadd } 1714ad7e9b0SAdrian Chadd } 1724ad7e9b0SAdrian Chadd 1734ad7e9b0SAdrian Chadd static int 1744ad7e9b0SAdrian Chadd bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 1754ad7e9b0SAdrian Chadd { 1768a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo; 1778a03f98aSLandon J. Fuller 1788a03f98aSLandon J. Fuller dinfo = device_get_ivars(child); 1798a03f98aSLandon J. Fuller 1804ad7e9b0SAdrian Chadd switch (index) { 1814ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR: 1824ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE: 1834ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV: 1844ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS: 1854ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME: 1864ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME: 1874ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX: 1884ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT: 1894ad7e9b0SAdrian Chadd return (EINVAL); 1908a03f98aSLandon J. Fuller case BHND_IVAR_PMU_INFO: 1914e96bf3aSLandon J. Fuller dinfo->pmu_info = (void *)value; 1928a03f98aSLandon J. Fuller return (0); 1934ad7e9b0SAdrian Chadd default: 1944ad7e9b0SAdrian Chadd return (ENOENT); 1954ad7e9b0SAdrian Chadd } 1964ad7e9b0SAdrian Chadd } 1974ad7e9b0SAdrian Chadd 1984ad7e9b0SAdrian Chadd static struct resource_list * 1994ad7e9b0SAdrian Chadd bcma_get_resource_list(device_t dev, device_t child) 2004ad7e9b0SAdrian Chadd { 2014ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo = device_get_ivars(child); 2024ad7e9b0SAdrian Chadd return (&dinfo->resources); 2034ad7e9b0SAdrian Chadd } 2044ad7e9b0SAdrian Chadd 2054ad7e9b0SAdrian Chadd static int 2068a03f98aSLandon J. Fuller bcma_read_iost(device_t dev, device_t child, uint16_t *iost) 2078a03f98aSLandon J. Fuller { 2088a03f98aSLandon J. Fuller uint32_t value; 2098a03f98aSLandon J. Fuller int error; 2108a03f98aSLandon J. Fuller 2118a03f98aSLandon J. Fuller if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4))) 2128a03f98aSLandon J. Fuller return (error); 2138a03f98aSLandon J. Fuller 2148a03f98aSLandon J. Fuller /* Return only the bottom 16 bits */ 2158a03f98aSLandon J. Fuller *iost = (value & BCMA_DMP_IOST_MASK); 2168a03f98aSLandon J. Fuller return (0); 2178a03f98aSLandon J. Fuller } 2188a03f98aSLandon J. Fuller 2198a03f98aSLandon J. Fuller static int 2208a03f98aSLandon J. Fuller bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl) 2218a03f98aSLandon J. Fuller { 2228a03f98aSLandon J. Fuller uint32_t value; 2238a03f98aSLandon J. Fuller int error; 2248a03f98aSLandon J. Fuller 2258a03f98aSLandon J. Fuller if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4))) 2268a03f98aSLandon J. Fuller return (error); 2278a03f98aSLandon J. Fuller 2288a03f98aSLandon J. Fuller /* Return only the bottom 16 bits */ 2298a03f98aSLandon J. Fuller *ioctl = (value & BCMA_DMP_IOCTRL_MASK); 2308a03f98aSLandon J. Fuller return (0); 2318a03f98aSLandon J. Fuller } 2328a03f98aSLandon J. Fuller 2338a03f98aSLandon J. Fuller static int 2348a03f98aSLandon J. Fuller bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask) 2354ad7e9b0SAdrian Chadd { 2364ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2378a03f98aSLandon J. Fuller struct bhnd_resource *r; 2388a03f98aSLandon J. Fuller uint32_t ioctl; 2394ad7e9b0SAdrian Chadd 2404ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 2418a03f98aSLandon J. Fuller return (EINVAL); 2424ad7e9b0SAdrian Chadd 2434ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2448a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL) 2454ad7e9b0SAdrian Chadd return (ENODEV); 2464ad7e9b0SAdrian Chadd 2478a03f98aSLandon J. Fuller /* Write new value */ 2488a03f98aSLandon J. Fuller ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); 2498a03f98aSLandon J. Fuller ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask); 2508a03f98aSLandon J. Fuller ioctl |= (value & mask); 2514ad7e9b0SAdrian Chadd 2528a03f98aSLandon J. Fuller bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl); 25331318f07SAdrian Chadd 2548a03f98aSLandon J. Fuller /* Perform read-back and wait for completion */ 2558a03f98aSLandon J. Fuller bhnd_bus_read_4(r, BCMA_DMP_IOCTRL); 25631318f07SAdrian Chadd DELAY(10); 25731318f07SAdrian Chadd 25831318f07SAdrian Chadd return (0); 2594ad7e9b0SAdrian Chadd } 2604ad7e9b0SAdrian Chadd 2618a03f98aSLandon J. Fuller static bool 2628a03f98aSLandon J. Fuller bcma_is_hw_suspended(device_t dev, device_t child) 2638a03f98aSLandon J. Fuller { 2648a03f98aSLandon J. Fuller uint32_t rst; 2658a03f98aSLandon J. Fuller uint16_t ioctl; 2668a03f98aSLandon J. Fuller int error; 2678a03f98aSLandon J. Fuller 2688a03f98aSLandon J. Fuller /* Is core held in RESET? */ 2698a03f98aSLandon J. Fuller error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4); 2708a03f98aSLandon J. Fuller if (error) { 2718a03f98aSLandon J. Fuller device_printf(child, "error reading HW reset state: %d\n", 2728a03f98aSLandon J. Fuller error); 2738a03f98aSLandon J. Fuller return (true); 2748a03f98aSLandon J. Fuller } 2758a03f98aSLandon J. Fuller 276ba3eb10dSMichael Zhilin if (rst & BCMA_DMP_RC_RESET) 2778a03f98aSLandon J. Fuller return (true); 2788a03f98aSLandon J. Fuller 2798a03f98aSLandon J. Fuller /* Is core clocked? */ 2808a03f98aSLandon J. Fuller error = bhnd_read_ioctl(child, &ioctl); 2818a03f98aSLandon J. Fuller if (error) { 2828a03f98aSLandon J. Fuller device_printf(child, "error reading HW ioctl register: %d\n", 2838a03f98aSLandon J. Fuller error); 2848a03f98aSLandon J. Fuller return (true); 2858a03f98aSLandon J. Fuller } 2868a03f98aSLandon J. Fuller 2878a03f98aSLandon J. Fuller if (!(ioctl & BHND_IOCTL_CLK_EN)) 2888a03f98aSLandon J. Fuller return (true); 2898a03f98aSLandon J. Fuller 2908a03f98aSLandon J. Fuller return (false); 2918a03f98aSLandon J. Fuller } 2928a03f98aSLandon J. Fuller 2934ad7e9b0SAdrian Chadd static int 294ac59515bSLandon J. Fuller bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl, 295ac59515bSLandon J. Fuller uint16_t reset_ioctl) 2964ad7e9b0SAdrian Chadd { 2974ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2988a03f98aSLandon J. Fuller struct bhnd_resource *r; 299ac59515bSLandon J. Fuller uint16_t clkflags; 3008a03f98aSLandon J. Fuller int error; 3014ad7e9b0SAdrian Chadd 3024ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 3038a03f98aSLandon J. Fuller return (EINVAL); 3044ad7e9b0SAdrian Chadd 3054ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 3068a03f98aSLandon J. Fuller 307ac59515bSLandon J. Fuller /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ 308ac59515bSLandon J. Fuller clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; 309ac59515bSLandon J. Fuller if (ioctl & clkflags) 3108a03f98aSLandon J. Fuller return (EINVAL); 3114ad7e9b0SAdrian Chadd 3124ad7e9b0SAdrian Chadd /* Can't suspend the core without access to the agent registers */ 3138a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL) 3144ad7e9b0SAdrian Chadd return (ENODEV); 3154ad7e9b0SAdrian Chadd 3168a03f98aSLandon J. Fuller /* Place core into known RESET state */ 317ac59515bSLandon J. Fuller if ((error = bhnd_suspend_hw(child, reset_ioctl))) 3188a03f98aSLandon J. Fuller return (error); 3194ad7e9b0SAdrian Chadd 3208a03f98aSLandon J. Fuller /* 3218a03f98aSLandon J. Fuller * Leaving the core in reset: 3228a03f98aSLandon J. Fuller * - Set the caller's IOCTL flags 3238a03f98aSLandon J. Fuller * - Enable clocks 3248a03f98aSLandon J. Fuller * - Force clock distribution to ensure propagation throughout the 3258a03f98aSLandon J. Fuller * core. 3268a03f98aSLandon J. Fuller */ 327ac59515bSLandon J. Fuller if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX))) 3288a03f98aSLandon J. Fuller return (error); 3298a03f98aSLandon J. Fuller 3308a03f98aSLandon J. Fuller /* Bring the core out of reset */ 3318a03f98aSLandon J. Fuller if ((error = bcma_dmp_write_reset(child, dinfo, 0x0))) 3328a03f98aSLandon J. Fuller return (error); 3338a03f98aSLandon J. Fuller 3348a03f98aSLandon J. Fuller /* Disable forced clock gating (leaving clock enabled) */ 3358a03f98aSLandon J. Fuller error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE); 3368a03f98aSLandon J. Fuller if (error) 3378a03f98aSLandon J. Fuller return (error); 3388a03f98aSLandon J. Fuller 3398a03f98aSLandon J. Fuller return (0); 3404ad7e9b0SAdrian Chadd } 3414ad7e9b0SAdrian Chadd 3428a03f98aSLandon J. Fuller static int 343ac59515bSLandon J. Fuller bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl) 344f90f4b65SLandon J. Fuller { 345f90f4b65SLandon J. Fuller struct bcma_devinfo *dinfo; 346f90f4b65SLandon J. Fuller struct bhnd_resource *r; 347ac59515bSLandon J. Fuller uint16_t clkflags; 3488a03f98aSLandon J. Fuller int error; 349f90f4b65SLandon J. Fuller 350f90f4b65SLandon J. Fuller if (device_get_parent(child) != dev) 3518a03f98aSLandon J. Fuller return (EINVAL); 352f90f4b65SLandon J. Fuller 353f90f4b65SLandon J. Fuller dinfo = device_get_ivars(child); 3548a03f98aSLandon J. Fuller 355ac59515bSLandon J. Fuller /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ 356ac59515bSLandon J. Fuller clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; 357ac59515bSLandon J. Fuller if (ioctl & clkflags) 358ac59515bSLandon J. Fuller return (EINVAL); 359ac59515bSLandon J. Fuller 3608a03f98aSLandon J. Fuller /* Can't suspend the core without access to the agent registers */ 361f90f4b65SLandon J. Fuller if ((r = dinfo->res_agent) == NULL) 3628a03f98aSLandon J. Fuller return (ENODEV); 363f90f4b65SLandon J. Fuller 3648a03f98aSLandon J. Fuller /* Wait for any pending reset operations to clear */ 3658a03f98aSLandon J. Fuller if ((error = bcma_dmp_wait_reset(child, dinfo))) 3668a03f98aSLandon J. Fuller return (error); 367f90f4b65SLandon J. Fuller 368ac59515bSLandon J. Fuller /* Put core into reset (if not already in reset) */ 369ba3eb10dSMichael Zhilin if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET))) 3708a03f98aSLandon J. Fuller return (error); 3718a03f98aSLandon J. Fuller 372ac59515bSLandon J. Fuller /* Write core flags (and clear CLK_EN/CLK_FORCE) */ 373ac59515bSLandon J. Fuller if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags))) 3748a03f98aSLandon J. Fuller return (error); 3758a03f98aSLandon J. Fuller 3768a03f98aSLandon J. Fuller return (0); 3778a03f98aSLandon J. Fuller } 3788a03f98aSLandon J. Fuller 3798a03f98aSLandon J. Fuller static int 3808a03f98aSLandon J. Fuller bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value, 381f90f4b65SLandon J. Fuller u_int width) 382f90f4b65SLandon J. Fuller { 383f90f4b65SLandon J. Fuller struct bcma_devinfo *dinfo; 384f90f4b65SLandon J. Fuller struct bhnd_resource *r; 385f90f4b65SLandon J. Fuller 386f90f4b65SLandon J. Fuller /* Must be a directly attached child core */ 387f90f4b65SLandon J. Fuller if (device_get_parent(child) != dev) 3888a03f98aSLandon J. Fuller return (EINVAL); 389f90f4b65SLandon J. Fuller 390f90f4b65SLandon J. Fuller /* Fetch the agent registers */ 391f90f4b65SLandon J. Fuller dinfo = device_get_ivars(child); 392f90f4b65SLandon J. Fuller if ((r = dinfo->res_agent) == NULL) 3938a03f98aSLandon J. Fuller return (ENODEV); 394f90f4b65SLandon J. Fuller 395f90f4b65SLandon J. Fuller /* Verify bounds */ 396f90f4b65SLandon J. Fuller if (offset > rman_get_size(r->res)) 3978a03f98aSLandon J. Fuller return (EFAULT); 398f90f4b65SLandon J. Fuller 399f90f4b65SLandon J. Fuller if (rman_get_size(r->res) - offset < width) 4008a03f98aSLandon J. Fuller return (EFAULT); 401f90f4b65SLandon J. Fuller 402f90f4b65SLandon J. Fuller switch (width) { 403f90f4b65SLandon J. Fuller case 1: 4048a03f98aSLandon J. Fuller *((uint8_t *)value) = bhnd_bus_read_1(r, offset); 4058a03f98aSLandon J. Fuller return (0); 406f90f4b65SLandon J. Fuller case 2: 4078a03f98aSLandon J. Fuller *((uint16_t *)value) = bhnd_bus_read_2(r, offset); 4088a03f98aSLandon J. Fuller return (0); 409f90f4b65SLandon J. Fuller case 4: 4108a03f98aSLandon J. Fuller *((uint32_t *)value) = bhnd_bus_read_4(r, offset); 4118a03f98aSLandon J. Fuller return (0); 412f90f4b65SLandon J. Fuller default: 4138a03f98aSLandon J. Fuller return (EINVAL); 4148a03f98aSLandon J. Fuller } 4158a03f98aSLandon J. Fuller } 4168a03f98aSLandon J. Fuller 4178a03f98aSLandon J. Fuller static int 4188a03f98aSLandon J. Fuller bcma_write_config(device_t dev, device_t child, bus_size_t offset, 4198a03f98aSLandon J. Fuller const void *value, u_int width) 4208a03f98aSLandon J. Fuller { 4218a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo; 4228a03f98aSLandon J. Fuller struct bhnd_resource *r; 4238a03f98aSLandon J. Fuller 4248a03f98aSLandon J. Fuller /* Must be a directly attached child core */ 4258a03f98aSLandon J. Fuller if (device_get_parent(child) != dev) 4268a03f98aSLandon J. Fuller return (EINVAL); 4278a03f98aSLandon J. Fuller 4288a03f98aSLandon J. Fuller /* Fetch the agent registers */ 4298a03f98aSLandon J. Fuller dinfo = device_get_ivars(child); 4308a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL) 4318a03f98aSLandon J. Fuller return (ENODEV); 4328a03f98aSLandon J. Fuller 4338a03f98aSLandon J. Fuller /* Verify bounds */ 4348a03f98aSLandon J. Fuller if (offset > rman_get_size(r->res)) 4358a03f98aSLandon J. Fuller return (EFAULT); 4368a03f98aSLandon J. Fuller 4378a03f98aSLandon J. Fuller if (rman_get_size(r->res) - offset < width) 4388a03f98aSLandon J. Fuller return (EFAULT); 4398a03f98aSLandon J. Fuller 4408a03f98aSLandon J. Fuller switch (width) { 4418a03f98aSLandon J. Fuller case 1: 4428a03f98aSLandon J. Fuller bhnd_bus_write_1(r, offset, *(const uint8_t *)value); 4438a03f98aSLandon J. Fuller return (0); 4448a03f98aSLandon J. Fuller case 2: 4458a03f98aSLandon J. Fuller bhnd_bus_write_2(r, offset, *(const uint16_t *)value); 4468a03f98aSLandon J. Fuller return (0); 4478a03f98aSLandon J. Fuller case 4: 4488a03f98aSLandon J. Fuller bhnd_bus_write_4(r, offset, *(const uint32_t *)value); 4498a03f98aSLandon J. Fuller return (0); 4508a03f98aSLandon J. Fuller default: 4518a03f98aSLandon J. Fuller return (EINVAL); 452f90f4b65SLandon J. Fuller } 453f90f4b65SLandon J. Fuller } 454f90f4b65SLandon J. Fuller 4554ad7e9b0SAdrian Chadd static u_int 4564ad7e9b0SAdrian Chadd bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) 4574ad7e9b0SAdrian Chadd { 4584ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 4594ad7e9b0SAdrian Chadd 4604ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */ 4614ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 4624ad7e9b0SAdrian Chadd return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, 4634ad7e9b0SAdrian Chadd type)); 4644ad7e9b0SAdrian Chadd 4654ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 4664ad7e9b0SAdrian Chadd switch (type) { 4674ad7e9b0SAdrian Chadd case BHND_PORT_DEVICE: 4684ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_dev_ports); 4694ad7e9b0SAdrian Chadd case BHND_PORT_BRIDGE: 4704ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_bridge_ports); 4714ad7e9b0SAdrian Chadd case BHND_PORT_AGENT: 4724ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_wrapper_ports); 473988fa8d0SAdrian Chadd default: 474988fa8d0SAdrian Chadd device_printf(dev, "%s: unknown type (%d)\n", 475988fa8d0SAdrian Chadd __func__, 476988fa8d0SAdrian Chadd type); 477988fa8d0SAdrian Chadd return (0); 4784ad7e9b0SAdrian Chadd } 4794ad7e9b0SAdrian Chadd } 4804ad7e9b0SAdrian Chadd 4814ad7e9b0SAdrian Chadd static u_int 4824ad7e9b0SAdrian Chadd bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type, 4834ad7e9b0SAdrian Chadd u_int port_num) 4844ad7e9b0SAdrian Chadd { 4854ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 4864ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 4874ad7e9b0SAdrian Chadd struct bcma_sport *port; 4884ad7e9b0SAdrian Chadd 4894ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */ 4904ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 4914ad7e9b0SAdrian Chadd return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, 4924ad7e9b0SAdrian Chadd type, port_num)); 4934ad7e9b0SAdrian Chadd 4944ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 4954ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, type); 4964ad7e9b0SAdrian Chadd 4974ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 4984ad7e9b0SAdrian Chadd if (port->sp_num == port_num) 4994ad7e9b0SAdrian Chadd return (port->sp_num_maps); 5004ad7e9b0SAdrian Chadd } 5014ad7e9b0SAdrian Chadd 5024ad7e9b0SAdrian Chadd /* not found */ 5034ad7e9b0SAdrian Chadd return (0); 5044ad7e9b0SAdrian Chadd } 5054ad7e9b0SAdrian Chadd 5064ad7e9b0SAdrian Chadd static int 5074ad7e9b0SAdrian Chadd bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, 5084ad7e9b0SAdrian Chadd u_int port_num, u_int region_num) 5094ad7e9b0SAdrian Chadd { 5104ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 5114ad7e9b0SAdrian Chadd struct bcma_map *map; 5124ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 5134ad7e9b0SAdrian Chadd struct bcma_sport *port; 5144ad7e9b0SAdrian Chadd 5154ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 5164ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 5174ad7e9b0SAdrian Chadd 5184ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 5194ad7e9b0SAdrian Chadd if (port->sp_num != port_num) 5204ad7e9b0SAdrian Chadd continue; 5214ad7e9b0SAdrian Chadd 5224ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) 5234ad7e9b0SAdrian Chadd if (map->m_region_num == region_num) 5244ad7e9b0SAdrian Chadd return map->m_rid; 5254ad7e9b0SAdrian Chadd } 5264ad7e9b0SAdrian Chadd 5274ad7e9b0SAdrian Chadd return -1; 5284ad7e9b0SAdrian Chadd } 5294ad7e9b0SAdrian Chadd 5304ad7e9b0SAdrian Chadd static int 5314ad7e9b0SAdrian Chadd bcma_decode_port_rid(device_t dev, device_t child, int type, int rid, 5324ad7e9b0SAdrian Chadd bhnd_port_type *port_type, u_int *port_num, u_int *region_num) 5334ad7e9b0SAdrian Chadd { 5344ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 5354ad7e9b0SAdrian Chadd struct bcma_map *map; 5364ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 5374ad7e9b0SAdrian Chadd struct bcma_sport *port; 5384ad7e9b0SAdrian Chadd 5394ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 5404ad7e9b0SAdrian Chadd 5414ad7e9b0SAdrian Chadd /* Ports are always memory mapped */ 5424ad7e9b0SAdrian Chadd if (type != SYS_RES_MEMORY) 5434ad7e9b0SAdrian Chadd return (EINVAL); 5444ad7e9b0SAdrian Chadd 5454ad7e9b0SAdrian Chadd /* Starting with the most likely device list, search all three port 5464ad7e9b0SAdrian Chadd * lists */ 5474ad7e9b0SAdrian Chadd bhnd_port_type types[] = { 5484ad7e9b0SAdrian Chadd BHND_PORT_DEVICE, 5494ad7e9b0SAdrian Chadd BHND_PORT_AGENT, 5504ad7e9b0SAdrian Chadd BHND_PORT_BRIDGE 5514ad7e9b0SAdrian Chadd }; 5524ad7e9b0SAdrian Chadd 5534ad7e9b0SAdrian Chadd for (int i = 0; i < nitems(types); i++) { 5544ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]); 5554ad7e9b0SAdrian Chadd 5564ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 5574ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) { 5584ad7e9b0SAdrian Chadd if (map->m_rid != rid) 5594ad7e9b0SAdrian Chadd continue; 5604ad7e9b0SAdrian Chadd 5614ad7e9b0SAdrian Chadd *port_type = port->sp_type; 5624ad7e9b0SAdrian Chadd *port_num = port->sp_num; 5634ad7e9b0SAdrian Chadd *region_num = map->m_region_num; 5644ad7e9b0SAdrian Chadd return (0); 5654ad7e9b0SAdrian Chadd } 5664ad7e9b0SAdrian Chadd } 5674ad7e9b0SAdrian Chadd } 5684ad7e9b0SAdrian Chadd 5694ad7e9b0SAdrian Chadd return (ENOENT); 5704ad7e9b0SAdrian Chadd } 5714ad7e9b0SAdrian Chadd 5724ad7e9b0SAdrian Chadd static int 5734ad7e9b0SAdrian Chadd bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, 5744ad7e9b0SAdrian Chadd u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) 5754ad7e9b0SAdrian Chadd { 5764ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 5774ad7e9b0SAdrian Chadd struct bcma_map *map; 5784ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 5794ad7e9b0SAdrian Chadd struct bcma_sport *port; 5804ad7e9b0SAdrian Chadd 5814ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 5824ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 5834ad7e9b0SAdrian Chadd 5844ad7e9b0SAdrian Chadd /* Search the port list */ 5854ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 5864ad7e9b0SAdrian Chadd if (port->sp_num != port_num) 5874ad7e9b0SAdrian Chadd continue; 5884ad7e9b0SAdrian Chadd 5894ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) { 5904ad7e9b0SAdrian Chadd if (map->m_region_num != region_num) 5914ad7e9b0SAdrian Chadd continue; 5924ad7e9b0SAdrian Chadd 5934ad7e9b0SAdrian Chadd /* Found! */ 5944ad7e9b0SAdrian Chadd *addr = map->m_base; 5954ad7e9b0SAdrian Chadd *size = map->m_size; 5964ad7e9b0SAdrian Chadd return (0); 5974ad7e9b0SAdrian Chadd } 5984ad7e9b0SAdrian Chadd } 5994ad7e9b0SAdrian Chadd 6004ad7e9b0SAdrian Chadd return (ENOENT); 6014ad7e9b0SAdrian Chadd } 6024ad7e9b0SAdrian Chadd 603824b48efSLandon J. Fuller /** 604824b48efSLandon J. Fuller * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT(). 605824b48efSLandon J. Fuller */ 606caeff9a3SLandon J. Fuller u_int 607824b48efSLandon J. Fuller bcma_get_intr_count(device_t dev, device_t child) 608824b48efSLandon J. Fuller { 609824b48efSLandon J. Fuller struct bcma_devinfo *dinfo; 610caeff9a3SLandon J. Fuller 611caeff9a3SLandon J. Fuller /* delegate non-bus-attached devices to our parent */ 612caeff9a3SLandon J. Fuller if (device_get_parent(child) != dev) 613caeff9a3SLandon J. Fuller return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child)); 614824b48efSLandon J. Fuller 615824b48efSLandon J. Fuller dinfo = device_get_ivars(child); 616caeff9a3SLandon J. Fuller return (dinfo->num_intrs); 617824b48efSLandon J. Fuller } 618824b48efSLandon J. Fuller 619824b48efSLandon J. Fuller /** 620caeff9a3SLandon J. Fuller * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC(). 621824b48efSLandon J. Fuller */ 622824b48efSLandon J. Fuller int 623caeff9a3SLandon J. Fuller bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec) 624824b48efSLandon J. Fuller { 625824b48efSLandon J. Fuller struct bcma_devinfo *dinfo; 626caeff9a3SLandon J. Fuller struct bcma_intr *desc; 627caeff9a3SLandon J. Fuller 628caeff9a3SLandon J. Fuller /* delegate non-bus-attached devices to our parent */ 629caeff9a3SLandon J. Fuller if (device_get_parent(child) != dev) { 630caeff9a3SLandon J. Fuller return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child, 631caeff9a3SLandon J. Fuller intr, ivec)); 632caeff9a3SLandon J. Fuller } 633824b48efSLandon J. Fuller 634824b48efSLandon J. Fuller dinfo = device_get_ivars(child); 635824b48efSLandon J. Fuller 636caeff9a3SLandon J. Fuller STAILQ_FOREACH(desc, &dinfo->intrs, i_link) { 637caeff9a3SLandon J. Fuller if (desc->i_sel == intr) { 638caeff9a3SLandon J. Fuller *ivec = desc->i_busline; 639824b48efSLandon J. Fuller return (0); 640824b48efSLandon J. Fuller } 641caeff9a3SLandon J. Fuller } 642caeff9a3SLandon J. Fuller 643caeff9a3SLandon J. Fuller /* Not found */ 644caeff9a3SLandon J. Fuller return (ENXIO); 645caeff9a3SLandon J. Fuller } 646824b48efSLandon J. Fuller 6474ad7e9b0SAdrian Chadd /** 648664a7497SLandon J. Fuller * Scan the device enumeration ROM table, adding all valid discovered cores to 6494ad7e9b0SAdrian Chadd * the bus. 6504ad7e9b0SAdrian Chadd * 6514ad7e9b0SAdrian Chadd * @param bus The bcma bus. 6524ad7e9b0SAdrian Chadd */ 6534ad7e9b0SAdrian Chadd int 654664a7497SLandon J. Fuller bcma_add_children(device_t bus) 6554ad7e9b0SAdrian Chadd { 656664a7497SLandon J. Fuller bhnd_erom_t *erom; 657664a7497SLandon J. Fuller struct bcma_erom *bcma_erom; 65889294a78SLandon J. Fuller struct bhnd_erom_io *eio; 659664a7497SLandon J. Fuller const struct bhnd_chipid *cid; 6604ad7e9b0SAdrian Chadd struct bcma_corecfg *corecfg; 6614ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 6624ad7e9b0SAdrian Chadd device_t child; 6634ad7e9b0SAdrian Chadd int error; 6644ad7e9b0SAdrian Chadd 665664a7497SLandon J. Fuller cid = BHND_BUS_GET_CHIPID(bus, bus); 6664ad7e9b0SAdrian Chadd corecfg = NULL; 6674ad7e9b0SAdrian Chadd 668664a7497SLandon J. Fuller /* Allocate our EROM parser */ 66989294a78SLandon J. Fuller eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID); 67089294a78SLandon J. Fuller erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio); 67189294a78SLandon J. Fuller if (erom == NULL) { 67289294a78SLandon J. Fuller bhnd_erom_io_fini(eio); 673664a7497SLandon J. Fuller return (ENODEV); 67489294a78SLandon J. Fuller } 6754ad7e9b0SAdrian Chadd 6764ad7e9b0SAdrian Chadd /* Add all cores. */ 677664a7497SLandon J. Fuller bcma_erom = (struct bcma_erom *)erom; 678664a7497SLandon J. Fuller while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) { 6794ad7e9b0SAdrian Chadd /* Add the child device */ 680*a05a6804SWarner Losh child = BUS_ADD_CHILD(bus, 0, NULL, DEVICE_UNIT_ANY); 6814ad7e9b0SAdrian Chadd if (child == NULL) { 6824ad7e9b0SAdrian Chadd error = ENXIO; 683111d7cb2SLandon J. Fuller goto cleanup; 6844ad7e9b0SAdrian Chadd } 6854ad7e9b0SAdrian Chadd 686688fc8c0SLandon J. Fuller /* Initialize device ivars */ 687688fc8c0SLandon J. Fuller dinfo = device_get_ivars(child); 688caeff9a3SLandon J. Fuller if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg))) 689111d7cb2SLandon J. Fuller goto cleanup; 690688fc8c0SLandon J. Fuller 691688fc8c0SLandon J. Fuller /* The dinfo instance now owns the corecfg value */ 692688fc8c0SLandon J. Fuller corecfg = NULL; 6934ad7e9b0SAdrian Chadd 6944ad7e9b0SAdrian Chadd /* If pins are floating or the hardware is otherwise 6954ad7e9b0SAdrian Chadd * unpopulated, the device shouldn't be used. */ 6964ad7e9b0SAdrian Chadd if (bhnd_is_hw_disabled(child)) 6974ad7e9b0SAdrian Chadd device_disable(child); 698f90f4b65SLandon J. Fuller 699f90f4b65SLandon J. Fuller /* Issue bus callback for fully initialized child. */ 700f90f4b65SLandon J. Fuller BHND_BUS_CHILD_ADDED(bus, child); 7014ad7e9b0SAdrian Chadd } 7024ad7e9b0SAdrian Chadd 703111d7cb2SLandon J. Fuller /* EOF while parsing cores is expected */ 7044ad7e9b0SAdrian Chadd if (error == ENOENT) 705664a7497SLandon J. Fuller error = 0; 7064ad7e9b0SAdrian Chadd 707111d7cb2SLandon J. Fuller cleanup: 708664a7497SLandon J. Fuller bhnd_erom_free(erom); 709664a7497SLandon J. Fuller 7104ad7e9b0SAdrian Chadd if (corecfg != NULL) 7114ad7e9b0SAdrian Chadd bcma_free_corecfg(corecfg); 7124ad7e9b0SAdrian Chadd 713111d7cb2SLandon J. Fuller if (error) 714111d7cb2SLandon J. Fuller device_delete_children(bus); 715111d7cb2SLandon J. Fuller 7164ad7e9b0SAdrian Chadd return (error); 7174ad7e9b0SAdrian Chadd } 7184ad7e9b0SAdrian Chadd 7194ad7e9b0SAdrian Chadd static device_method_t bcma_methods[] = { 7204ad7e9b0SAdrian Chadd /* Device interface */ 7214ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bcma_probe), 7224ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bcma_attach), 7234ad7e9b0SAdrian Chadd DEVMETHOD(device_detach, bcma_detach), 7244ad7e9b0SAdrian Chadd 7254ad7e9b0SAdrian Chadd /* Bus interface */ 7268a03f98aSLandon J. Fuller DEVMETHOD(bus_add_child, bcma_add_child), 7278a03f98aSLandon J. Fuller DEVMETHOD(bus_child_deleted, bcma_child_deleted), 7284ad7e9b0SAdrian Chadd DEVMETHOD(bus_read_ivar, bcma_read_ivar), 7294ad7e9b0SAdrian Chadd DEVMETHOD(bus_write_ivar, bcma_write_ivar), 7304ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), 7314ad7e9b0SAdrian Chadd 7324ad7e9b0SAdrian Chadd /* BHND interface */ 733111d7cb2SLandon J. Fuller DEVMETHOD(bhnd_bus_get_erom_class, bcma_get_erom_class), 7348a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_read_ioctl, bcma_read_ioctl), 7358a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_write_ioctl, bcma_write_ioctl), 7368a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_read_iost, bcma_read_iost), 7378a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_is_hw_suspended, bcma_is_hw_suspended), 7388a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_reset_hw, bcma_reset_hw), 7398a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_suspend_hw, bcma_suspend_hw), 740f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_read_config, bcma_read_config), 741f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_write_config, bcma_write_config), 7424ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), 7434ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), 7444ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), 7454ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid), 7464ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr), 747824b48efSLandon J. Fuller DEVMETHOD(bhnd_bus_get_intr_count, bcma_get_intr_count), 748caeff9a3SLandon J. Fuller DEVMETHOD(bhnd_bus_get_intr_ivec, bcma_get_intr_ivec), 7494ad7e9b0SAdrian Chadd 7504ad7e9b0SAdrian Chadd DEVMETHOD_END 7514ad7e9b0SAdrian Chadd }; 7524ad7e9b0SAdrian Chadd 7534ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver); 7544ad7e9b0SAdrian Chadd MODULE_VERSION(bcma, 1); 7554ad7e9b0SAdrian Chadd MODULE_DEPEND(bcma, bhnd, 1, 1, 1); 756