14ad7e9b0SAdrian Chadd /*- 24ad7e9b0SAdrian Chadd * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 34ad7e9b0SAdrian Chadd * All rights reserved. 44ad7e9b0SAdrian Chadd * 54ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without 64ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions 74ad7e9b0SAdrian Chadd * are met: 84ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 94ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer, 104ad7e9b0SAdrian Chadd * without modification. 114ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 124ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 134ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially 144ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 154ad7e9b0SAdrian Chadd * 164ad7e9b0SAdrian Chadd * NO WARRANTY 174ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 204ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 214ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 224ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 234ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 244ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 254ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 264ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 274ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 284ad7e9b0SAdrian Chadd */ 294ad7e9b0SAdrian Chadd 304ad7e9b0SAdrian Chadd #include <sys/cdefs.h> 314ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$"); 324ad7e9b0SAdrian Chadd 334ad7e9b0SAdrian Chadd /* 344ad7e9b0SAdrian Chadd * Broadcom Home Networking Division (HND) Bus Driver. 354ad7e9b0SAdrian Chadd * 364ad7e9b0SAdrian Chadd * The Broadcom HND family of devices consists of both SoCs and host-connected 374ad7e9b0SAdrian Chadd * networking chipsets containing a common family of Broadcom IP cores, 384ad7e9b0SAdrian Chadd * including an integrated MIPS and/or ARM cores. 394ad7e9b0SAdrian Chadd * 404ad7e9b0SAdrian Chadd * HND devices expose a nearly identical interface whether accessible over a 414ad7e9b0SAdrian Chadd * native SoC interconnect, or when connected via a host interface such as 424ad7e9b0SAdrian Chadd * PCIe. As a result, the majority of hardware support code should be re-usable 434ad7e9b0SAdrian Chadd * across host drivers for HND networking chipsets, as well as FreeBSD support 444ad7e9b0SAdrian Chadd * for Broadcom MIPS/ARM HND SoCs. 454ad7e9b0SAdrian Chadd * 464ad7e9b0SAdrian Chadd * Earlier HND models used the siba(4) on-chip interconnect, while later models 474ad7e9b0SAdrian Chadd * use bcma(4); the programming model is almost entirely independent 484ad7e9b0SAdrian Chadd * of the actual underlying interconect. 494ad7e9b0SAdrian Chadd */ 504ad7e9b0SAdrian Chadd 514ad7e9b0SAdrian Chadd #include <sys/param.h> 524ad7e9b0SAdrian Chadd #include <sys/kernel.h> 534ad7e9b0SAdrian Chadd #include <sys/bus.h> 544ad7e9b0SAdrian Chadd #include <sys/module.h> 554ad7e9b0SAdrian Chadd #include <sys/systm.h> 564ad7e9b0SAdrian Chadd 574ad7e9b0SAdrian Chadd #include <machine/bus.h> 584ad7e9b0SAdrian Chadd #include <sys/rman.h> 594ad7e9b0SAdrian Chadd #include <machine/resource.h> 604ad7e9b0SAdrian Chadd 614ad7e9b0SAdrian Chadd #include "bhnd.h" 624ad7e9b0SAdrian Chadd #include "bhndvar.h" 634ad7e9b0SAdrian Chadd 644ad7e9b0SAdrian Chadd #include "bhnd_nvram_if.h" 654ad7e9b0SAdrian Chadd 664ad7e9b0SAdrian Chadd MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures"); 674ad7e9b0SAdrian Chadd 684ad7e9b0SAdrian Chadd /** 694ad7e9b0SAdrian Chadd * bhnd_generic_probe_nomatch() reporting configuration. 704ad7e9b0SAdrian Chadd */ 714ad7e9b0SAdrian Chadd static const struct bhnd_nomatch { 724ad7e9b0SAdrian Chadd uint16_t vendor; /**< core designer */ 734ad7e9b0SAdrian Chadd uint16_t device; /**< core id */ 744ad7e9b0SAdrian Chadd bool if_verbose; /**< print when bootverbose is set. */ 754ad7e9b0SAdrian Chadd } bhnd_nomatch_table[] = { 764ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true }, 774ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_EROM, true }, 784ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_PL301, true }, 794ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true }, 804ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false }, 814ad7e9b0SAdrian Chadd 824ad7e9b0SAdrian Chadd { BHND_MFGID_INVALID, BHND_COREID_INVALID, false } 834ad7e9b0SAdrian Chadd }; 844ad7e9b0SAdrian Chadd 854ad7e9b0SAdrian Chadd static device_t find_nvram_child(device_t dev); 864ad7e9b0SAdrian Chadd 874ad7e9b0SAdrian Chadd static int compare_ascending_probe_order(const void *lhs, 884ad7e9b0SAdrian Chadd const void *rhs); 894ad7e9b0SAdrian Chadd static int compare_descending_probe_order(const void *lhs, 904ad7e9b0SAdrian Chadd const void *rhs); 914ad7e9b0SAdrian Chadd 924ad7e9b0SAdrian Chadd /** 934ad7e9b0SAdrian Chadd * Helper function for implementing DEVICE_ATTACH(). 944ad7e9b0SAdrian Chadd * 954ad7e9b0SAdrian Chadd * This function can be used to implement DEVICE_ATTACH() for bhnd(4) 964ad7e9b0SAdrian Chadd * bus implementations. It calls device_probe_and_attach() for each 974ad7e9b0SAdrian Chadd * of the device's children, in order. 984ad7e9b0SAdrian Chadd */ 994ad7e9b0SAdrian Chadd int 1004ad7e9b0SAdrian Chadd bhnd_generic_attach(device_t dev) 1014ad7e9b0SAdrian Chadd { 1024ad7e9b0SAdrian Chadd device_t *devs; 1034ad7e9b0SAdrian Chadd int ndevs; 1044ad7e9b0SAdrian Chadd int error; 1054ad7e9b0SAdrian Chadd 1064ad7e9b0SAdrian Chadd if (device_is_attached(dev)) 1074ad7e9b0SAdrian Chadd return (EBUSY); 1084ad7e9b0SAdrian Chadd 1094ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 1104ad7e9b0SAdrian Chadd return (error); 1114ad7e9b0SAdrian Chadd 1124ad7e9b0SAdrian Chadd qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); 1134ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 1144ad7e9b0SAdrian Chadd device_t child = devs[i]; 1154ad7e9b0SAdrian Chadd device_probe_and_attach(child); 1164ad7e9b0SAdrian Chadd } 1174ad7e9b0SAdrian Chadd 1184ad7e9b0SAdrian Chadd free(devs, M_TEMP); 1194ad7e9b0SAdrian Chadd return (0); 1204ad7e9b0SAdrian Chadd } 1214ad7e9b0SAdrian Chadd 1224ad7e9b0SAdrian Chadd /** 1234ad7e9b0SAdrian Chadd * Helper function for implementing DEVICE_DETACH(). 1244ad7e9b0SAdrian Chadd * 1254ad7e9b0SAdrian Chadd * This function can be used to implement DEVICE_DETACH() for bhnd(4) 1264ad7e9b0SAdrian Chadd * bus implementations. It calls device_detach() for each 1274ad7e9b0SAdrian Chadd * of the device's children, in reverse order, terminating if 1284ad7e9b0SAdrian Chadd * any call to device_detach() fails. 1294ad7e9b0SAdrian Chadd */ 1304ad7e9b0SAdrian Chadd int 1314ad7e9b0SAdrian Chadd bhnd_generic_detach(device_t dev) 1324ad7e9b0SAdrian Chadd { 1334ad7e9b0SAdrian Chadd device_t *devs; 1344ad7e9b0SAdrian Chadd int ndevs; 1354ad7e9b0SAdrian Chadd int error; 1364ad7e9b0SAdrian Chadd 1374ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 1384ad7e9b0SAdrian Chadd return (EBUSY); 1394ad7e9b0SAdrian Chadd 1404ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 1414ad7e9b0SAdrian Chadd return (error); 1424ad7e9b0SAdrian Chadd 1434ad7e9b0SAdrian Chadd /* Detach in the reverse of attach order */ 1444ad7e9b0SAdrian Chadd qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 1454ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 1464ad7e9b0SAdrian Chadd device_t child = devs[i]; 1474ad7e9b0SAdrian Chadd 1484ad7e9b0SAdrian Chadd /* Terminate on first error */ 1494ad7e9b0SAdrian Chadd if ((error = device_detach(child))) 1504ad7e9b0SAdrian Chadd goto cleanup; 1514ad7e9b0SAdrian Chadd } 1524ad7e9b0SAdrian Chadd 1534ad7e9b0SAdrian Chadd cleanup: 1544ad7e9b0SAdrian Chadd free(devs, M_TEMP); 1554ad7e9b0SAdrian Chadd return (error); 1564ad7e9b0SAdrian Chadd } 1574ad7e9b0SAdrian Chadd 1584ad7e9b0SAdrian Chadd /** 1594ad7e9b0SAdrian Chadd * Helper function for implementing DEVICE_SHUTDOWN(). 1604ad7e9b0SAdrian Chadd * 1614ad7e9b0SAdrian Chadd * This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4) 1624ad7e9b0SAdrian Chadd * bus implementations. It calls device_shutdown() for each 1634ad7e9b0SAdrian Chadd * of the device's children, in reverse order, terminating if 1644ad7e9b0SAdrian Chadd * any call to device_shutdown() fails. 1654ad7e9b0SAdrian Chadd */ 1664ad7e9b0SAdrian Chadd int 1674ad7e9b0SAdrian Chadd bhnd_generic_shutdown(device_t dev) 1684ad7e9b0SAdrian Chadd { 1694ad7e9b0SAdrian Chadd device_t *devs; 1704ad7e9b0SAdrian Chadd int ndevs; 1714ad7e9b0SAdrian Chadd int error; 1724ad7e9b0SAdrian Chadd 1734ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 1744ad7e9b0SAdrian Chadd return (EBUSY); 1754ad7e9b0SAdrian Chadd 1764ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 1774ad7e9b0SAdrian Chadd return (error); 1784ad7e9b0SAdrian Chadd 1794ad7e9b0SAdrian Chadd /* Shutdown in the reverse of attach order */ 1804ad7e9b0SAdrian Chadd qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 1814ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 1824ad7e9b0SAdrian Chadd device_t child = devs[i]; 1834ad7e9b0SAdrian Chadd 1844ad7e9b0SAdrian Chadd /* Terminate on first error */ 1854ad7e9b0SAdrian Chadd if ((error = device_shutdown(child))) 1864ad7e9b0SAdrian Chadd goto cleanup; 1874ad7e9b0SAdrian Chadd } 1884ad7e9b0SAdrian Chadd 1894ad7e9b0SAdrian Chadd cleanup: 1904ad7e9b0SAdrian Chadd free(devs, M_TEMP); 1914ad7e9b0SAdrian Chadd return (error); 1924ad7e9b0SAdrian Chadd } 1934ad7e9b0SAdrian Chadd 1944ad7e9b0SAdrian Chadd /** 1954ad7e9b0SAdrian Chadd * Helper function for implementing DEVICE_RESUME(). 1964ad7e9b0SAdrian Chadd * 1974ad7e9b0SAdrian Chadd * This function can be used to implement DEVICE_RESUME() for bhnd(4) 1984ad7e9b0SAdrian Chadd * bus implementations. It calls BUS_RESUME_CHILD() for each 1994ad7e9b0SAdrian Chadd * of the device's children, in order, terminating if 2004ad7e9b0SAdrian Chadd * any call to BUS_RESUME_CHILD() fails. 2014ad7e9b0SAdrian Chadd */ 2024ad7e9b0SAdrian Chadd int 2034ad7e9b0SAdrian Chadd bhnd_generic_resume(device_t dev) 2044ad7e9b0SAdrian Chadd { 2054ad7e9b0SAdrian Chadd device_t *devs; 2064ad7e9b0SAdrian Chadd int ndevs; 2074ad7e9b0SAdrian Chadd int error; 2084ad7e9b0SAdrian Chadd 2094ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 2104ad7e9b0SAdrian Chadd return (EBUSY); 2114ad7e9b0SAdrian Chadd 2124ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 2134ad7e9b0SAdrian Chadd return (error); 2144ad7e9b0SAdrian Chadd 2154ad7e9b0SAdrian Chadd qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); 2164ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 2174ad7e9b0SAdrian Chadd device_t child = devs[i]; 2184ad7e9b0SAdrian Chadd 2194ad7e9b0SAdrian Chadd /* Terminate on first error */ 2204ad7e9b0SAdrian Chadd if ((error = BUS_RESUME_CHILD(device_get_parent(child), child))) 2214ad7e9b0SAdrian Chadd goto cleanup; 2224ad7e9b0SAdrian Chadd } 2234ad7e9b0SAdrian Chadd 2244ad7e9b0SAdrian Chadd cleanup: 2254ad7e9b0SAdrian Chadd free(devs, M_TEMP); 2264ad7e9b0SAdrian Chadd return (error); 2274ad7e9b0SAdrian Chadd } 2284ad7e9b0SAdrian Chadd 2294ad7e9b0SAdrian Chadd /** 2304ad7e9b0SAdrian Chadd * Helper function for implementing DEVICE_SUSPEND(). 2314ad7e9b0SAdrian Chadd * 2324ad7e9b0SAdrian Chadd * This function can be used to implement DEVICE_SUSPEND() for bhnd(4) 2334ad7e9b0SAdrian Chadd * bus implementations. It calls BUS_SUSPEND_CHILD() for each 2344ad7e9b0SAdrian Chadd * of the device's children, in reverse order. If any call to 2354ad7e9b0SAdrian Chadd * BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and 2364ad7e9b0SAdrian Chadd * any devices that were suspended are resumed immediately by calling 2374ad7e9b0SAdrian Chadd * their BUS_RESUME_CHILD() methods. 2384ad7e9b0SAdrian Chadd */ 2394ad7e9b0SAdrian Chadd int 2404ad7e9b0SAdrian Chadd bhnd_generic_suspend(device_t dev) 2414ad7e9b0SAdrian Chadd { 2424ad7e9b0SAdrian Chadd device_t *devs; 2434ad7e9b0SAdrian Chadd int ndevs; 2444ad7e9b0SAdrian Chadd int error; 2454ad7e9b0SAdrian Chadd 2464ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 2474ad7e9b0SAdrian Chadd return (EBUSY); 2484ad7e9b0SAdrian Chadd 2494ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 2504ad7e9b0SAdrian Chadd return (error); 2514ad7e9b0SAdrian Chadd 2524ad7e9b0SAdrian Chadd /* Suspend in the reverse of attach order */ 2534ad7e9b0SAdrian Chadd qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); 2544ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 2554ad7e9b0SAdrian Chadd device_t child = devs[i]; 2564ad7e9b0SAdrian Chadd error = BUS_SUSPEND_CHILD(device_get_parent(child), child); 2574ad7e9b0SAdrian Chadd 2584ad7e9b0SAdrian Chadd /* On error, resume suspended devices and then terminate */ 2594ad7e9b0SAdrian Chadd if (error) { 2604ad7e9b0SAdrian Chadd for (int j = 0; j < i; j++) { 2614ad7e9b0SAdrian Chadd BUS_RESUME_CHILD(device_get_parent(devs[j]), 2624ad7e9b0SAdrian Chadd devs[j]); 2634ad7e9b0SAdrian Chadd } 2644ad7e9b0SAdrian Chadd 2654ad7e9b0SAdrian Chadd goto cleanup; 2664ad7e9b0SAdrian Chadd } 2674ad7e9b0SAdrian Chadd } 2684ad7e9b0SAdrian Chadd 2694ad7e9b0SAdrian Chadd cleanup: 2704ad7e9b0SAdrian Chadd free(devs, M_TEMP); 2714ad7e9b0SAdrian Chadd return (error); 2724ad7e9b0SAdrian Chadd } 2734ad7e9b0SAdrian Chadd 2744ad7e9b0SAdrian Chadd /* 2754ad7e9b0SAdrian Chadd * Ascending comparison of bhnd device's probe order. 2764ad7e9b0SAdrian Chadd */ 2774ad7e9b0SAdrian Chadd static int 2784ad7e9b0SAdrian Chadd compare_ascending_probe_order(const void *lhs, const void *rhs) 2794ad7e9b0SAdrian Chadd { 2804ad7e9b0SAdrian Chadd device_t ldev, rdev; 2814ad7e9b0SAdrian Chadd int lorder, rorder; 2824ad7e9b0SAdrian Chadd 2834ad7e9b0SAdrian Chadd ldev = (*(const device_t *) lhs); 2844ad7e9b0SAdrian Chadd rdev = (*(const device_t *) rhs); 2854ad7e9b0SAdrian Chadd 2864ad7e9b0SAdrian Chadd lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev); 2874ad7e9b0SAdrian Chadd rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev); 2884ad7e9b0SAdrian Chadd 2894ad7e9b0SAdrian Chadd if (lorder < rorder) { 2904ad7e9b0SAdrian Chadd return (-1); 2914ad7e9b0SAdrian Chadd } else if (lorder > rorder) { 2924ad7e9b0SAdrian Chadd return (1); 2934ad7e9b0SAdrian Chadd } else { 2944ad7e9b0SAdrian Chadd return (0); 2954ad7e9b0SAdrian Chadd } 2964ad7e9b0SAdrian Chadd } 2974ad7e9b0SAdrian Chadd 2984ad7e9b0SAdrian Chadd /* 2994ad7e9b0SAdrian Chadd * Descending comparison of bhnd device's probe order. 3004ad7e9b0SAdrian Chadd */ 3014ad7e9b0SAdrian Chadd static int 3024ad7e9b0SAdrian Chadd compare_descending_probe_order(const void *lhs, const void *rhs) 3034ad7e9b0SAdrian Chadd { 3044ad7e9b0SAdrian Chadd return (compare_ascending_probe_order(rhs, lhs)); 3054ad7e9b0SAdrian Chadd } 3064ad7e9b0SAdrian Chadd 3074ad7e9b0SAdrian Chadd /** 3084ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_GET_PROBE_ORDER(). 3094ad7e9b0SAdrian Chadd * 3104ad7e9b0SAdrian Chadd * This implementation determines probe ordering based on the device's class 3114ad7e9b0SAdrian Chadd * and other properties, including whether the device is serving as a host 3124ad7e9b0SAdrian Chadd * bridge. 3134ad7e9b0SAdrian Chadd */ 3144ad7e9b0SAdrian Chadd int 3154ad7e9b0SAdrian Chadd bhnd_generic_get_probe_order(device_t dev, device_t child) 3164ad7e9b0SAdrian Chadd { 3174ad7e9b0SAdrian Chadd switch (bhnd_get_class(child)) { 3184ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CC: 3194ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST); 3204ad7e9b0SAdrian Chadd 3214ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CC_B: 3224ad7e9b0SAdrian Chadd /* fall through */ 3234ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PMU: 3244ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY); 3254ad7e9b0SAdrian Chadd 3264ad7e9b0SAdrian Chadd case BHND_DEVCLASS_SOC_ROUTER: 3274ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE); 3284ad7e9b0SAdrian Chadd 3294ad7e9b0SAdrian Chadd case BHND_DEVCLASS_SOC_BRIDGE: 3304ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST); 3314ad7e9b0SAdrian Chadd 3324ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CPU: 3334ad7e9b0SAdrian Chadd return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST); 3344ad7e9b0SAdrian Chadd 3354ad7e9b0SAdrian Chadd case BHND_DEVCLASS_RAM: 3364ad7e9b0SAdrian Chadd /* fall through */ 3374ad7e9b0SAdrian Chadd case BHND_DEVCLASS_MEMC: 3384ad7e9b0SAdrian Chadd return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY); 3394ad7e9b0SAdrian Chadd 3404ad7e9b0SAdrian Chadd case BHND_DEVCLASS_NVRAM: 3414ad7e9b0SAdrian Chadd return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY); 3424ad7e9b0SAdrian Chadd 3434ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCI: 3444ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCIE: 3454ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCCARD: 3464ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET: 3474ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET_MAC: 3484ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET_PHY: 3494ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN: 3504ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN_MAC: 3514ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN_PHY: 3524ad7e9b0SAdrian Chadd case BHND_DEVCLASS_EROM: 3534ad7e9b0SAdrian Chadd case BHND_DEVCLASS_OTHER: 3544ad7e9b0SAdrian Chadd case BHND_DEVCLASS_INVALID: 3554ad7e9b0SAdrian Chadd if (bhnd_is_hostb_device(child)) 3564ad7e9b0SAdrian Chadd return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); 3574ad7e9b0SAdrian Chadd 3584ad7e9b0SAdrian Chadd return (BHND_PROBE_DEFAULT); 3594ad7e9b0SAdrian Chadd } 3604ad7e9b0SAdrian Chadd } 3614ad7e9b0SAdrian Chadd 3624ad7e9b0SAdrian Chadd /** 3634ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_IS_REGION_VALID(). 3644ad7e9b0SAdrian Chadd * 3654ad7e9b0SAdrian Chadd * This implementation assumes that port and region numbers are 0-indexed and 3664ad7e9b0SAdrian Chadd * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and 3674ad7e9b0SAdrian Chadd * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall 3684ad7e9b0SAdrian Chadd * within the defined range. 3694ad7e9b0SAdrian Chadd */ 3704ad7e9b0SAdrian Chadd bool 3714ad7e9b0SAdrian Chadd bhnd_generic_is_region_valid(device_t dev, device_t child, 3724ad7e9b0SAdrian Chadd bhnd_port_type type, u_int port, u_int region) 3734ad7e9b0SAdrian Chadd { 3744ad7e9b0SAdrian Chadd if (port >= bhnd_get_port_count(child, type)) 3754ad7e9b0SAdrian Chadd return (false); 3764ad7e9b0SAdrian Chadd 3774ad7e9b0SAdrian Chadd if (region >= bhnd_get_region_count(child, type, port)) 3784ad7e9b0SAdrian Chadd return (false); 3794ad7e9b0SAdrian Chadd 3804ad7e9b0SAdrian Chadd return (true); 3814ad7e9b0SAdrian Chadd } 3824ad7e9b0SAdrian Chadd 3834ad7e9b0SAdrian Chadd /** 3844ad7e9b0SAdrian Chadd * Find an NVRAM child device on @p dev, if any. 3854ad7e9b0SAdrian Chadd * 3864ad7e9b0SAdrian Chadd * @retval device_t An NVRAM device. 3874ad7e9b0SAdrian Chadd * @retval NULL If no NVRAM device is found. 3884ad7e9b0SAdrian Chadd */ 3894ad7e9b0SAdrian Chadd static device_t 3904ad7e9b0SAdrian Chadd find_nvram_child(device_t dev) 3914ad7e9b0SAdrian Chadd { 3924ad7e9b0SAdrian Chadd device_t chipc, nvram; 3934ad7e9b0SAdrian Chadd 3944ad7e9b0SAdrian Chadd /* Look for a directly-attached NVRAM child */ 3954ad7e9b0SAdrian Chadd nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass), 3964ad7e9b0SAdrian Chadd -1); 3974ad7e9b0SAdrian Chadd if (nvram == NULL) 3984ad7e9b0SAdrian Chadd return (NULL); 3994ad7e9b0SAdrian Chadd 4004ad7e9b0SAdrian Chadd /* Further checks require a bhnd(4) bus */ 4014ad7e9b0SAdrian Chadd if (device_get_devclass(dev) != bhnd_devclass) 4024ad7e9b0SAdrian Chadd return (NULL); 4034ad7e9b0SAdrian Chadd 4044ad7e9b0SAdrian Chadd /* Look for a ChipCommon-attached OTP device */ 4054ad7e9b0SAdrian Chadd if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { 4064ad7e9b0SAdrian Chadd /* Recursively search the ChipCommon device */ 4074ad7e9b0SAdrian Chadd if ((nvram = find_nvram_child(chipc)) != NULL) 4084ad7e9b0SAdrian Chadd return (nvram); 4094ad7e9b0SAdrian Chadd } 4104ad7e9b0SAdrian Chadd 4114ad7e9b0SAdrian Chadd /* Not found */ 4124ad7e9b0SAdrian Chadd return (NULL); 4134ad7e9b0SAdrian Chadd } 4144ad7e9b0SAdrian Chadd 4154ad7e9b0SAdrian Chadd /** 4164ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_READ_NVRAM_VAR(). 4174ad7e9b0SAdrian Chadd * 4184ad7e9b0SAdrian Chadd * This implementation searches @p dev for a valid NVRAM device. If no NVRAM 4194ad7e9b0SAdrian Chadd * child device is found on @p dev, the request is delegated to the 4204ad7e9b0SAdrian Chadd * BHND_BUS_READ_NVRAM_VAR() method on the parent 4214ad7e9b0SAdrian Chadd * of @p dev. 4224ad7e9b0SAdrian Chadd */ 4234ad7e9b0SAdrian Chadd int 4244ad7e9b0SAdrian Chadd bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name, 4254ad7e9b0SAdrian Chadd void *buf, size_t *size) 4264ad7e9b0SAdrian Chadd { 4274ad7e9b0SAdrian Chadd device_t nvram; 4284ad7e9b0SAdrian Chadd 4294ad7e9b0SAdrian Chadd /* Try to find an NVRAM device applicable to @p child */ 4304ad7e9b0SAdrian Chadd if ((nvram = find_nvram_child(dev)) == NULL) 4314ad7e9b0SAdrian Chadd return (BHND_BUS_READ_NVRAM_VAR(device_get_parent(dev), child, 4324ad7e9b0SAdrian Chadd name, buf, size)); 4334ad7e9b0SAdrian Chadd 4344ad7e9b0SAdrian Chadd return BHND_NVRAM_GETVAR(nvram, name, buf, size); 4354ad7e9b0SAdrian Chadd } 4364ad7e9b0SAdrian Chadd 4374ad7e9b0SAdrian Chadd /** 4384ad7e9b0SAdrian Chadd * Helper function for implementing BUS_PRINT_CHILD(). 4394ad7e9b0SAdrian Chadd * 4404ad7e9b0SAdrian Chadd * This implementation requests the device's struct resource_list via 4414ad7e9b0SAdrian Chadd * BUS_GET_RESOURCE_LIST. 4424ad7e9b0SAdrian Chadd */ 4434ad7e9b0SAdrian Chadd int 4444ad7e9b0SAdrian Chadd bhnd_generic_print_child(device_t dev, device_t child) 4454ad7e9b0SAdrian Chadd { 4464ad7e9b0SAdrian Chadd struct resource_list *rl; 4474ad7e9b0SAdrian Chadd int retval = 0; 4484ad7e9b0SAdrian Chadd 4494ad7e9b0SAdrian Chadd retval += bus_print_child_header(dev, child); 4504ad7e9b0SAdrian Chadd 4514ad7e9b0SAdrian Chadd rl = BUS_GET_RESOURCE_LIST(dev, child); 4524ad7e9b0SAdrian Chadd if (rl != NULL) { 4534ad7e9b0SAdrian Chadd retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, 454*f8fd3fb5SJustin Hibbits "%#jx"); 4554ad7e9b0SAdrian Chadd } 4564ad7e9b0SAdrian Chadd 4574ad7e9b0SAdrian Chadd retval += printf(" at core %u", bhnd_get_core_index(child)); 4584ad7e9b0SAdrian Chadd 4594ad7e9b0SAdrian Chadd retval += bus_print_child_domain(dev, child); 4604ad7e9b0SAdrian Chadd retval += bus_print_child_footer(dev, child); 4614ad7e9b0SAdrian Chadd 4624ad7e9b0SAdrian Chadd return (retval); 4634ad7e9b0SAdrian Chadd } 4644ad7e9b0SAdrian Chadd 4654ad7e9b0SAdrian Chadd /** 4664ad7e9b0SAdrian Chadd * Helper function for implementing BUS_PRINT_CHILD(). 4674ad7e9b0SAdrian Chadd * 4684ad7e9b0SAdrian Chadd * This implementation requests the device's struct resource_list via 4694ad7e9b0SAdrian Chadd * BUS_GET_RESOURCE_LIST. 4704ad7e9b0SAdrian Chadd */ 4714ad7e9b0SAdrian Chadd void 4724ad7e9b0SAdrian Chadd bhnd_generic_probe_nomatch(device_t dev, device_t child) 4734ad7e9b0SAdrian Chadd { 4744ad7e9b0SAdrian Chadd struct resource_list *rl; 4754ad7e9b0SAdrian Chadd const struct bhnd_nomatch *nm; 4764ad7e9b0SAdrian Chadd bool report; 4774ad7e9b0SAdrian Chadd 4784ad7e9b0SAdrian Chadd /* Fetch reporting configuration for this device */ 4794ad7e9b0SAdrian Chadd report = true; 4804ad7e9b0SAdrian Chadd for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) { 4814ad7e9b0SAdrian Chadd if (nm->vendor != bhnd_get_vendor(child)) 4824ad7e9b0SAdrian Chadd continue; 4834ad7e9b0SAdrian Chadd 4844ad7e9b0SAdrian Chadd if (nm->device != bhnd_get_device(child)) 4854ad7e9b0SAdrian Chadd continue; 4864ad7e9b0SAdrian Chadd 4874ad7e9b0SAdrian Chadd report = false; 4884ad7e9b0SAdrian Chadd if (bootverbose && nm->if_verbose) 4894ad7e9b0SAdrian Chadd report = true; 4904ad7e9b0SAdrian Chadd break; 4914ad7e9b0SAdrian Chadd } 4924ad7e9b0SAdrian Chadd 4934ad7e9b0SAdrian Chadd if (!report) 4944ad7e9b0SAdrian Chadd return; 4954ad7e9b0SAdrian Chadd 4964ad7e9b0SAdrian Chadd /* Print the non-matched device info */ 4974ad7e9b0SAdrian Chadd device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child), 4984ad7e9b0SAdrian Chadd bhnd_get_device_name(child)); 4994ad7e9b0SAdrian Chadd 5004ad7e9b0SAdrian Chadd rl = BUS_GET_RESOURCE_LIST(dev, child); 5014ad7e9b0SAdrian Chadd if (rl != NULL) 502*f8fd3fb5SJustin Hibbits resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 5034ad7e9b0SAdrian Chadd 5044ad7e9b0SAdrian Chadd printf(" at core %u (no driver attached)\n", 5054ad7e9b0SAdrian Chadd bhnd_get_core_index(child)); 5064ad7e9b0SAdrian Chadd } 5074ad7e9b0SAdrian Chadd 5084ad7e9b0SAdrian Chadd /** 5094ad7e9b0SAdrian Chadd * Default implementation of BUS_CHILD_PNPINFO_STR(). 5104ad7e9b0SAdrian Chadd */ 5114ad7e9b0SAdrian Chadd static int 5124ad7e9b0SAdrian Chadd bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf, 5134ad7e9b0SAdrian Chadd size_t buflen) 5144ad7e9b0SAdrian Chadd { 5154ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) { 5164ad7e9b0SAdrian Chadd return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child, 5174ad7e9b0SAdrian Chadd buf, buflen)); 5184ad7e9b0SAdrian Chadd } 5194ad7e9b0SAdrian Chadd 5204ad7e9b0SAdrian Chadd snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx", 5214ad7e9b0SAdrian Chadd bhnd_get_vendor(child), bhnd_get_device(child), 5224ad7e9b0SAdrian Chadd bhnd_get_hwrev(child)); 5234ad7e9b0SAdrian Chadd 5244ad7e9b0SAdrian Chadd return (0); 5254ad7e9b0SAdrian Chadd } 5264ad7e9b0SAdrian Chadd 5274ad7e9b0SAdrian Chadd /** 5284ad7e9b0SAdrian Chadd * Default implementation of implementing BUS_PRINT_CHILD(). 5294ad7e9b0SAdrian Chadd */ 5304ad7e9b0SAdrian Chadd static int 5314ad7e9b0SAdrian Chadd bhnd_child_location_str(device_t dev, device_t child, char *buf, 5324ad7e9b0SAdrian Chadd size_t buflen) 5334ad7e9b0SAdrian Chadd { 5344ad7e9b0SAdrian Chadd bhnd_addr_t addr; 5354ad7e9b0SAdrian Chadd bhnd_size_t size; 5364ad7e9b0SAdrian Chadd 5374ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) { 5384ad7e9b0SAdrian Chadd return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, 5394ad7e9b0SAdrian Chadd buf, buflen)); 5404ad7e9b0SAdrian Chadd } 5414ad7e9b0SAdrian Chadd 5424ad7e9b0SAdrian Chadd 5434ad7e9b0SAdrian Chadd if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { 5444ad7e9b0SAdrian Chadd /* No device default port/region */ 5454ad7e9b0SAdrian Chadd if (buflen > 0) 5464ad7e9b0SAdrian Chadd *buf = '\0'; 5474ad7e9b0SAdrian Chadd return (0); 5484ad7e9b0SAdrian Chadd } 5494ad7e9b0SAdrian Chadd 5504ad7e9b0SAdrian Chadd snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); 5514ad7e9b0SAdrian Chadd return (0); 5524ad7e9b0SAdrian Chadd } 5534ad7e9b0SAdrian Chadd 5544ad7e9b0SAdrian Chadd /** 5554ad7e9b0SAdrian Chadd * Helper function for implementing BUS_SUSPEND_CHILD(). 5564ad7e9b0SAdrian Chadd * 5574ad7e9b0SAdrian Chadd * TODO: Power management 5584ad7e9b0SAdrian Chadd * 5594ad7e9b0SAdrian Chadd * If @p child is not a direct child of @p dev, suspension is delegated to 5604ad7e9b0SAdrian Chadd * the @p dev parent. 5614ad7e9b0SAdrian Chadd */ 5624ad7e9b0SAdrian Chadd int 5634ad7e9b0SAdrian Chadd bhnd_generic_suspend_child(device_t dev, device_t child) 5644ad7e9b0SAdrian Chadd { 5654ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 5664ad7e9b0SAdrian Chadd BUS_SUSPEND_CHILD(device_get_parent(dev), child); 5674ad7e9b0SAdrian Chadd 5684ad7e9b0SAdrian Chadd return bus_generic_suspend_child(dev, child); 5694ad7e9b0SAdrian Chadd } 5704ad7e9b0SAdrian Chadd 5714ad7e9b0SAdrian Chadd /** 5724ad7e9b0SAdrian Chadd * Helper function for implementing BUS_RESUME_CHILD(). 5734ad7e9b0SAdrian Chadd * 5744ad7e9b0SAdrian Chadd * TODO: Power management 5754ad7e9b0SAdrian Chadd * 5764ad7e9b0SAdrian Chadd * If @p child is not a direct child of @p dev, suspension is delegated to 5774ad7e9b0SAdrian Chadd * the @p dev parent. 5784ad7e9b0SAdrian Chadd */ 5794ad7e9b0SAdrian Chadd int 5804ad7e9b0SAdrian Chadd bhnd_generic_resume_child(device_t dev, device_t child) 5814ad7e9b0SAdrian Chadd { 5824ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 5834ad7e9b0SAdrian Chadd BUS_RESUME_CHILD(device_get_parent(dev), child); 5844ad7e9b0SAdrian Chadd 5854ad7e9b0SAdrian Chadd return bus_generic_resume_child(dev, child); 5864ad7e9b0SAdrian Chadd } 5874ad7e9b0SAdrian Chadd 5884ad7e9b0SAdrian Chadd /** 5894ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE(). 5904ad7e9b0SAdrian Chadd * 5914ad7e9b0SAdrian Chadd * If a parent device is available, this implementation delegates the 5924ad7e9b0SAdrian Chadd * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev. 5934ad7e9b0SAdrian Chadd * 5944ad7e9b0SAdrian Chadd * If no parent device is available (i.e. on a the bus root), false 5954ad7e9b0SAdrian Chadd * is returned. 5964ad7e9b0SAdrian Chadd */ 5974ad7e9b0SAdrian Chadd bool 5984ad7e9b0SAdrian Chadd bhnd_generic_is_hostb_device(device_t dev, device_t child) { 5994ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) 6004ad7e9b0SAdrian Chadd return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), 6014ad7e9b0SAdrian Chadd child)); 6024ad7e9b0SAdrian Chadd 6034ad7e9b0SAdrian Chadd return (false); 6044ad7e9b0SAdrian Chadd } 6054ad7e9b0SAdrian Chadd 6064ad7e9b0SAdrian Chadd /** 6074ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_IS_HW_DISABLED(). 6084ad7e9b0SAdrian Chadd * 6094ad7e9b0SAdrian Chadd * If a parent device is available, this implementation delegates the 6104ad7e9b0SAdrian Chadd * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev. 6114ad7e9b0SAdrian Chadd * 6124ad7e9b0SAdrian Chadd * If no parent device is available (i.e. on a the bus root), the hardware 6134ad7e9b0SAdrian Chadd * is assumed to be usable and false is returned. 6144ad7e9b0SAdrian Chadd */ 6154ad7e9b0SAdrian Chadd bool 6164ad7e9b0SAdrian Chadd bhnd_generic_is_hw_disabled(device_t dev, device_t child) 6174ad7e9b0SAdrian Chadd { 6184ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) 6194ad7e9b0SAdrian Chadd return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); 6204ad7e9b0SAdrian Chadd 6214ad7e9b0SAdrian Chadd return (false); 6224ad7e9b0SAdrian Chadd } 6234ad7e9b0SAdrian Chadd 6244ad7e9b0SAdrian Chadd /** 6254ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_GET_CHIPID(). 6264ad7e9b0SAdrian Chadd * 6274ad7e9b0SAdrian Chadd * This implementation delegates the request to the BHND_BUS_GET_CHIPID() 6284ad7e9b0SAdrian Chadd * method on the parent of @p dev. 6294ad7e9b0SAdrian Chadd */ 6304ad7e9b0SAdrian Chadd const struct bhnd_chipid * 6314ad7e9b0SAdrian Chadd bhnd_generic_get_chipid(device_t dev, device_t child) { 6324ad7e9b0SAdrian Chadd return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); 6334ad7e9b0SAdrian Chadd } 6344ad7e9b0SAdrian Chadd 6354ad7e9b0SAdrian Chadd /** 6364ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). 6374ad7e9b0SAdrian Chadd * 6384ad7e9b0SAdrian Chadd * This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines 6394ad7e9b0SAdrian Chadd * any default values via BUS_GET_RESOURCE_LIST(), and calls 6404ad7e9b0SAdrian Chadd * BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev. 6414ad7e9b0SAdrian Chadd * 6424ad7e9b0SAdrian Chadd * If no parent device is available, the request is instead delegated to 6434ad7e9b0SAdrian Chadd * BUS_ALLOC_RESOURCE(). 6444ad7e9b0SAdrian Chadd */ 6454ad7e9b0SAdrian Chadd struct bhnd_resource * 6464ad7e9b0SAdrian Chadd bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type, 6474ad7e9b0SAdrian Chadd int *rid, rman_res_t start, rman_res_t end, rman_res_t count, 6484ad7e9b0SAdrian Chadd u_int flags) 6494ad7e9b0SAdrian Chadd { 6504ad7e9b0SAdrian Chadd struct bhnd_resource *r; 6514ad7e9b0SAdrian Chadd struct resource_list *rl; 6524ad7e9b0SAdrian Chadd struct resource_list_entry *rle; 6534ad7e9b0SAdrian Chadd bool isdefault; 6544ad7e9b0SAdrian Chadd bool passthrough; 6554ad7e9b0SAdrian Chadd 6564ad7e9b0SAdrian Chadd passthrough = (device_get_parent(child) != dev); 65782ed3cb0SJustin Hibbits isdefault = RMAN_IS_DEFAULT_RANGE(start, end); 6584ad7e9b0SAdrian Chadd 6594ad7e9b0SAdrian Chadd /* the default RID must always be the first device port/region. */ 6604ad7e9b0SAdrian Chadd if (!passthrough && *rid == 0) { 6614ad7e9b0SAdrian Chadd int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0); 6624ad7e9b0SAdrian Chadd KASSERT(*rid == rid0, 6634ad7e9b0SAdrian Chadd ("rid 0 does not map to the first device port (%d)", rid0)); 6644ad7e9b0SAdrian Chadd } 6654ad7e9b0SAdrian Chadd 6664ad7e9b0SAdrian Chadd /* Determine locally-known defaults before delegating the request. */ 6674ad7e9b0SAdrian Chadd if (!passthrough && isdefault) { 6684ad7e9b0SAdrian Chadd /* fetch resource list from child's bus */ 6694ad7e9b0SAdrian Chadd rl = BUS_GET_RESOURCE_LIST(dev, child); 6704ad7e9b0SAdrian Chadd if (rl == NULL) 6714ad7e9b0SAdrian Chadd return (NULL); /* no resource list */ 6724ad7e9b0SAdrian Chadd 6734ad7e9b0SAdrian Chadd /* look for matching type/rid pair */ 6744ad7e9b0SAdrian Chadd rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), 6754ad7e9b0SAdrian Chadd type, *rid); 6764ad7e9b0SAdrian Chadd if (rle == NULL) 6774ad7e9b0SAdrian Chadd return (NULL); 6784ad7e9b0SAdrian Chadd 6794ad7e9b0SAdrian Chadd /* set default values */ 6804ad7e9b0SAdrian Chadd start = rle->start; 6814ad7e9b0SAdrian Chadd end = rle->end; 6824ad7e9b0SAdrian Chadd count = ulmax(count, rle->count); 6834ad7e9b0SAdrian Chadd } 6844ad7e9b0SAdrian Chadd 6854ad7e9b0SAdrian Chadd /* Try to delegate to our parent. */ 6864ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) { 6874ad7e9b0SAdrian Chadd return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 6884ad7e9b0SAdrian Chadd type, rid, start, end, count, flags)); 6894ad7e9b0SAdrian Chadd } 6904ad7e9b0SAdrian Chadd 6914ad7e9b0SAdrian Chadd /* If this is the bus root, use a real bus-allocated resource */ 6924ad7e9b0SAdrian Chadd r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); 6934ad7e9b0SAdrian Chadd if (r == NULL) 6944ad7e9b0SAdrian Chadd return NULL; 6954ad7e9b0SAdrian Chadd 6964ad7e9b0SAdrian Chadd /* Allocate the bus resource, marking it as 'direct' (not requiring 6974ad7e9b0SAdrian Chadd * any bus window remapping to perform I/O) */ 6984ad7e9b0SAdrian Chadd r->direct = true; 6994ad7e9b0SAdrian Chadd r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, 7004ad7e9b0SAdrian Chadd count, flags); 7014ad7e9b0SAdrian Chadd 7024ad7e9b0SAdrian Chadd if (r->res == NULL) { 7034ad7e9b0SAdrian Chadd free(r, M_BHND); 7044ad7e9b0SAdrian Chadd return NULL; 7054ad7e9b0SAdrian Chadd } 7064ad7e9b0SAdrian Chadd 7074ad7e9b0SAdrian Chadd return (r); 7084ad7e9b0SAdrian Chadd } 7094ad7e9b0SAdrian Chadd 7104ad7e9b0SAdrian Chadd /** 7114ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). 7124ad7e9b0SAdrian Chadd * 7134ad7e9b0SAdrian Chadd * This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the 7144ad7e9b0SAdrian Chadd * BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev. 7154ad7e9b0SAdrian Chadd * 7164ad7e9b0SAdrian Chadd * If no parent device is available, the request is delegated to 7174ad7e9b0SAdrian Chadd * BUS_RELEASE_RESOURCE(). 7184ad7e9b0SAdrian Chadd */ 7194ad7e9b0SAdrian Chadd int 7204ad7e9b0SAdrian Chadd bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type, 7214ad7e9b0SAdrian Chadd int rid, struct bhnd_resource *r) 7224ad7e9b0SAdrian Chadd { 7234ad7e9b0SAdrian Chadd int error; 7244ad7e9b0SAdrian Chadd 7254ad7e9b0SAdrian Chadd /* Try to delegate to the parent. */ 7264ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) 7274ad7e9b0SAdrian Chadd return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 7284ad7e9b0SAdrian Chadd type, rid, r)); 7294ad7e9b0SAdrian Chadd 7304ad7e9b0SAdrian Chadd /* Release the resource directly */ 7314ad7e9b0SAdrian Chadd if (!r->direct) { 7324ad7e9b0SAdrian Chadd panic("bhnd indirect resource released without " 7334ad7e9b0SAdrian Chadd "bhnd parent bus"); 7344ad7e9b0SAdrian Chadd } 7354ad7e9b0SAdrian Chadd 7364ad7e9b0SAdrian Chadd error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res); 7374ad7e9b0SAdrian Chadd if (error) 7384ad7e9b0SAdrian Chadd return (error); 7394ad7e9b0SAdrian Chadd 7404ad7e9b0SAdrian Chadd free(r, M_BHND); 7414ad7e9b0SAdrian Chadd return (0); 7424ad7e9b0SAdrian Chadd } 7434ad7e9b0SAdrian Chadd 7444ad7e9b0SAdrian Chadd /** 7454ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). 7464ad7e9b0SAdrian Chadd * 7474ad7e9b0SAdrian Chadd * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the 7484ad7e9b0SAdrian Chadd * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. 7494ad7e9b0SAdrian Chadd * 7504ad7e9b0SAdrian Chadd * If no parent device is available, the request is delegated to 7514ad7e9b0SAdrian Chadd * BUS_ACTIVATE_RESOURCE(). 7524ad7e9b0SAdrian Chadd */ 7534ad7e9b0SAdrian Chadd int 7544ad7e9b0SAdrian Chadd bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type, 7554ad7e9b0SAdrian Chadd int rid, struct bhnd_resource *r) 7564ad7e9b0SAdrian Chadd { 7574ad7e9b0SAdrian Chadd /* Try to delegate to the parent */ 7584ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) 7594ad7e9b0SAdrian Chadd return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), 7604ad7e9b0SAdrian Chadd child, type, rid, r)); 7614ad7e9b0SAdrian Chadd 7624ad7e9b0SAdrian Chadd /* Activate the resource directly */ 7634ad7e9b0SAdrian Chadd if (!r->direct) { 7644ad7e9b0SAdrian Chadd panic("bhnd indirect resource released without " 7654ad7e9b0SAdrian Chadd "bhnd parent bus"); 7664ad7e9b0SAdrian Chadd } 7674ad7e9b0SAdrian Chadd 7684ad7e9b0SAdrian Chadd return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res)); 7694ad7e9b0SAdrian Chadd }; 7704ad7e9b0SAdrian Chadd 7714ad7e9b0SAdrian Chadd /** 7724ad7e9b0SAdrian Chadd * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). 7734ad7e9b0SAdrian Chadd * 7744ad7e9b0SAdrian Chadd * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the 7754ad7e9b0SAdrian Chadd * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. 7764ad7e9b0SAdrian Chadd * 7774ad7e9b0SAdrian Chadd * If no parent device is available, the request is delegated to 7784ad7e9b0SAdrian Chadd * BUS_DEACTIVATE_RESOURCE(). 7794ad7e9b0SAdrian Chadd */ 7804ad7e9b0SAdrian Chadd int 7814ad7e9b0SAdrian Chadd bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type, 7824ad7e9b0SAdrian Chadd int rid, struct bhnd_resource *r) 7834ad7e9b0SAdrian Chadd { 7844ad7e9b0SAdrian Chadd if (device_get_parent(dev) != NULL) 7854ad7e9b0SAdrian Chadd return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), 7864ad7e9b0SAdrian Chadd child, type, rid, r)); 7874ad7e9b0SAdrian Chadd 7884ad7e9b0SAdrian Chadd /* De-activate the resource directly */ 7894ad7e9b0SAdrian Chadd if (!r->direct) { 7904ad7e9b0SAdrian Chadd panic("bhnd indirect resource released without " 7914ad7e9b0SAdrian Chadd "bhnd parent bus"); 7924ad7e9b0SAdrian Chadd } 7934ad7e9b0SAdrian Chadd 7944ad7e9b0SAdrian Chadd return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res)); 7954ad7e9b0SAdrian Chadd }; 7964ad7e9b0SAdrian Chadd 7974ad7e9b0SAdrian Chadd /* 7984ad7e9b0SAdrian Chadd * Delegate all indirect I/O to the parent device. When inherited by 7994ad7e9b0SAdrian Chadd * non-bridged bus implementations, resources will never be marked as 8004ad7e9b0SAdrian Chadd * indirect, and these methods should never be called. 8014ad7e9b0SAdrian Chadd */ 8024ad7e9b0SAdrian Chadd 8034ad7e9b0SAdrian Chadd static uint8_t 8044ad7e9b0SAdrian Chadd bhnd_read_1(device_t dev, device_t child, struct bhnd_resource *r, 8054ad7e9b0SAdrian Chadd bus_size_t offset) 8064ad7e9b0SAdrian Chadd { 8074ad7e9b0SAdrian Chadd return (BHND_BUS_READ_1(device_get_parent(dev), child, r, offset)); 8084ad7e9b0SAdrian Chadd } 8094ad7e9b0SAdrian Chadd 8104ad7e9b0SAdrian Chadd static uint16_t 8114ad7e9b0SAdrian Chadd bhnd_read_2(device_t dev, device_t child, struct bhnd_resource *r, 8124ad7e9b0SAdrian Chadd bus_size_t offset) 8134ad7e9b0SAdrian Chadd { 8144ad7e9b0SAdrian Chadd return (BHND_BUS_READ_2(device_get_parent(dev), child, r, offset)); 8154ad7e9b0SAdrian Chadd } 8164ad7e9b0SAdrian Chadd 8174ad7e9b0SAdrian Chadd static uint32_t 8184ad7e9b0SAdrian Chadd bhnd_read_4(device_t dev, device_t child, struct bhnd_resource *r, 8194ad7e9b0SAdrian Chadd bus_size_t offset) 8204ad7e9b0SAdrian Chadd { 8214ad7e9b0SAdrian Chadd return (BHND_BUS_READ_4(device_get_parent(dev), child, r, offset)); 8224ad7e9b0SAdrian Chadd } 8234ad7e9b0SAdrian Chadd 8244ad7e9b0SAdrian Chadd static void 8254ad7e9b0SAdrian Chadd bhnd_write_1(device_t dev, device_t child, struct bhnd_resource *r, 8264ad7e9b0SAdrian Chadd bus_size_t offset, uint8_t value) 8274ad7e9b0SAdrian Chadd { 8284ad7e9b0SAdrian Chadd BHND_BUS_WRITE_1(device_get_parent(dev), child, r, offset, value); 8294ad7e9b0SAdrian Chadd } 8304ad7e9b0SAdrian Chadd 8314ad7e9b0SAdrian Chadd static void 8324ad7e9b0SAdrian Chadd bhnd_write_2(device_t dev, device_t child, struct bhnd_resource *r, 8334ad7e9b0SAdrian Chadd bus_size_t offset, uint16_t value) 8344ad7e9b0SAdrian Chadd { 8354ad7e9b0SAdrian Chadd BHND_BUS_WRITE_2(device_get_parent(dev), child, r, offset, value); 8364ad7e9b0SAdrian Chadd } 8374ad7e9b0SAdrian Chadd 8384ad7e9b0SAdrian Chadd static void 8394ad7e9b0SAdrian Chadd bhnd_write_4(device_t dev, device_t child, struct bhnd_resource *r, 8404ad7e9b0SAdrian Chadd bus_size_t offset, uint32_t value) 8414ad7e9b0SAdrian Chadd { 8424ad7e9b0SAdrian Chadd BHND_BUS_WRITE_4(device_get_parent(dev), child, r, offset, value); 8434ad7e9b0SAdrian Chadd } 8444ad7e9b0SAdrian Chadd 8454ad7e9b0SAdrian Chadd static void 8464ad7e9b0SAdrian Chadd bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r, 8474ad7e9b0SAdrian Chadd bus_size_t offset, bus_size_t length, int flags) 8484ad7e9b0SAdrian Chadd { 8494ad7e9b0SAdrian Chadd BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length, 8504ad7e9b0SAdrian Chadd flags); 8514ad7e9b0SAdrian Chadd } 8524ad7e9b0SAdrian Chadd 8534ad7e9b0SAdrian Chadd static device_method_t bhnd_methods[] = { 8544ad7e9b0SAdrian Chadd /* Device interface */ \ 8554ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bhnd_generic_attach), 8564ad7e9b0SAdrian Chadd DEVMETHOD(device_detach, bhnd_generic_detach), 8574ad7e9b0SAdrian Chadd DEVMETHOD(device_shutdown, bhnd_generic_shutdown), 8584ad7e9b0SAdrian Chadd DEVMETHOD(device_suspend, bhnd_generic_suspend), 8594ad7e9b0SAdrian Chadd DEVMETHOD(device_resume, bhnd_generic_resume), 8604ad7e9b0SAdrian Chadd 8614ad7e9b0SAdrian Chadd /* Bus interface */ 8624ad7e9b0SAdrian Chadd DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), 8634ad7e9b0SAdrian Chadd DEVMETHOD(bus_print_child, bhnd_generic_print_child), 8644ad7e9b0SAdrian Chadd DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), 8654ad7e9b0SAdrian Chadd DEVMETHOD(bus_child_location_str, bhnd_child_location_str), 8664ad7e9b0SAdrian Chadd 8674ad7e9b0SAdrian Chadd DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child), 8684ad7e9b0SAdrian Chadd DEVMETHOD(bus_resume_child, bhnd_generic_resume_child), 8694ad7e9b0SAdrian Chadd 8704ad7e9b0SAdrian Chadd DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 8714ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 8724ad7e9b0SAdrian Chadd DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 8734ad7e9b0SAdrian Chadd DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 8744ad7e9b0SAdrian Chadd DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 8754ad7e9b0SAdrian Chadd DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 8764ad7e9b0SAdrian Chadd DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 8774ad7e9b0SAdrian Chadd DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 8784ad7e9b0SAdrian Chadd 8794ad7e9b0SAdrian Chadd DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 8804ad7e9b0SAdrian Chadd DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 8814ad7e9b0SAdrian Chadd DEVMETHOD(bus_config_intr, bus_generic_config_intr), 8824ad7e9b0SAdrian Chadd DEVMETHOD(bus_bind_intr, bus_generic_bind_intr), 8834ad7e9b0SAdrian Chadd DEVMETHOD(bus_describe_intr, bus_generic_describe_intr), 8844ad7e9b0SAdrian Chadd 8854ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), 8864ad7e9b0SAdrian Chadd 8874ad7e9b0SAdrian Chadd /* BHND interface */ 8884ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_alloc_resource, bhnd_generic_alloc_bhnd_resource), 8894ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_release_resource, bhnd_generic_release_bhnd_resource), 8904ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_activate_bhnd_resource), 8914ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_deactivate_bhnd_resource), 8924ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_chipid, bhnd_generic_get_chipid), 8934ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), 8944ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), 8954ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), 8964ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), 8974ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_1, bhnd_write_1), 8984ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_2, bhnd_write_2), 8994ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_4, bhnd_write_4), 9004ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_barrier, bhnd_barrier), 9014ad7e9b0SAdrian Chadd 9024ad7e9b0SAdrian Chadd DEVMETHOD_END 9034ad7e9b0SAdrian Chadd }; 9044ad7e9b0SAdrian Chadd 9054ad7e9b0SAdrian Chadd devclass_t bhnd_devclass; /**< bhnd bus. */ 9064ad7e9b0SAdrian Chadd devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */ 9074ad7e9b0SAdrian Chadd devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */ 9084ad7e9b0SAdrian Chadd 9094ad7e9b0SAdrian Chadd DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc)); 9104ad7e9b0SAdrian Chadd MODULE_VERSION(bhnd, 1); 911