14ad7e9b0SAdrian Chadd /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
36e778a7eSPedro F. Giffuni *
48e35bf83SLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
58e35bf83SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation
64ad7e9b0SAdrian Chadd * All rights reserved.
74ad7e9b0SAdrian Chadd *
88e35bf83SLandon J. Fuller * Portions of this software were developed by Landon Fuller
98e35bf83SLandon J. Fuller * under sponsorship from the FreeBSD Foundation.
108e35bf83SLandon 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
3696546b75SAdrian Chadd #include <sys/param.h>
374ad7e9b0SAdrian Chadd #include <sys/bus.h>
388e35bf83SLandon J. Fuller #include <sys/refcount.h>
394ad7e9b0SAdrian Chadd #include <sys/systm.h>
404ad7e9b0SAdrian Chadd
414ad7e9b0SAdrian Chadd #include <machine/bus.h>
424ad7e9b0SAdrian Chadd #include <sys/rman.h>
434ad7e9b0SAdrian Chadd #include <machine/resource.h>
444ad7e9b0SAdrian Chadd
45d851916eSLandon J. Fuller #include <dev/bhnd/siba/sibareg.h>
46d851916eSLandon J. Fuller
474ad7e9b0SAdrian Chadd #include <dev/bhnd/cores/chipc/chipcreg.h>
484ad7e9b0SAdrian Chadd
49d567592bSAdrian Chadd #include "nvram/bhnd_nvram.h"
50d567592bSAdrian Chadd
51d567592bSAdrian Chadd #include "bhnd_chipc_if.h"
52d567592bSAdrian Chadd
53d567592bSAdrian Chadd #include "bhnd_nvram_if.h"
54d567592bSAdrian Chadd #include "bhnd_nvram_map.h"
55d567592bSAdrian Chadd
564ad7e9b0SAdrian Chadd #include "bhndreg.h"
574ad7e9b0SAdrian Chadd #include "bhndvar.h"
588e35bf83SLandon J. Fuller #include "bhnd_private.h"
598e35bf83SLandon J. Fuller
608e35bf83SLandon J. Fuller static void bhnd_service_registry_free_entry(
618e35bf83SLandon J. Fuller struct bhnd_service_entry *entry);
628e35bf83SLandon J. Fuller
638e35bf83SLandon J. Fuller static int compare_ascending_probe_order(const void *lhs, const void *rhs);
648e35bf83SLandon J. Fuller static int compare_descending_probe_order(const void *lhs,
658e35bf83SLandon J. Fuller const void *rhs);
664ad7e9b0SAdrian Chadd
674ad7e9b0SAdrian Chadd /* BHND core device description table. */
684ad7e9b0SAdrian Chadd static const struct bhnd_core_desc {
694ad7e9b0SAdrian Chadd uint16_t vendor;
704ad7e9b0SAdrian Chadd uint16_t device;
714ad7e9b0SAdrian Chadd bhnd_devclass_t class;
724ad7e9b0SAdrian Chadd const char *desc;
734ad7e9b0SAdrian Chadd } bhnd_core_descs[] = {
744ad7e9b0SAdrian Chadd #define BHND_CDESC(_mfg, _cid, _cls, _desc) \
754ad7e9b0SAdrian Chadd { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid, \
764ad7e9b0SAdrian Chadd BHND_DEVCLASS_ ## _cls, _desc }
774ad7e9b0SAdrian Chadd
784ad7e9b0SAdrian Chadd BHND_CDESC(BCM, CC, CC, "ChipCommon I/O Controller"),
794ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ILINE20, OTHER, "iLine20 HPNA"),
804ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SRAM, RAM, "SRAM"),
814ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SDRAM, RAM, "SDRAM"),
824ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PCI, PCI, "PCI Bridge"),
83f75615f2SLandon J. Fuller BHND_CDESC(BCM, MIPS, CPU, "BMIPS CPU"),
844ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ENET, ENET_MAC, "Fast Ethernet MAC"),
85a225321fSLandon J. Fuller BHND_CDESC(BCM, V90_CODEC, SOFTMODEM, "V.90 SoftModem Codec"),
86fb88110cSLandon J. Fuller BHND_CDESC(BCM, USB, USB_DUAL, "USB 1.1 Device/Host Controller"),
874ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ADSL, OTHER, "ADSL Core"),
884ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ILINE100, OTHER, "iLine100 HPNA"),
894ad7e9b0SAdrian Chadd BHND_CDESC(BCM, IPSEC, OTHER, "IPsec Accelerator"),
904ad7e9b0SAdrian Chadd BHND_CDESC(BCM, UTOPIA, OTHER, "UTOPIA ATM Core"),
914ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PCMCIA, PCCARD, "PCMCIA Bridge"),
924ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SOCRAM, RAM, "Internal Memory"),
934ad7e9b0SAdrian Chadd BHND_CDESC(BCM, MEMC, MEMC, "MEMC SDRAM Controller"),
944ad7e9b0SAdrian Chadd BHND_CDESC(BCM, OFDM, OTHER, "OFDM PHY"),
954ad7e9b0SAdrian Chadd BHND_CDESC(BCM, EXTIF, OTHER, "External Interface"),
964ad7e9b0SAdrian Chadd BHND_CDESC(BCM, D11, WLAN, "802.11 MAC/PHY/Radio"),
974ad7e9b0SAdrian Chadd BHND_CDESC(BCM, APHY, WLAN_PHY, "802.11a PHY"),
984ad7e9b0SAdrian Chadd BHND_CDESC(BCM, BPHY, WLAN_PHY, "802.11b PHY"),
994ad7e9b0SAdrian Chadd BHND_CDESC(BCM, GPHY, WLAN_PHY, "802.11g PHY"),
100f75615f2SLandon J. Fuller BHND_CDESC(BCM, MIPS33, CPU, "BMIPS33 CPU"),
101fb88110cSLandon J. Fuller BHND_CDESC(BCM, USB11H, USB_HOST, "USB 1.1 Host Controller"),
102fb88110cSLandon J. Fuller BHND_CDESC(BCM, USB11D, USB_DEV, "USB 1.1 Device Controller"),
103fb88110cSLandon J. Fuller BHND_CDESC(BCM, USB20H, USB_HOST, "USB 2.0 Host Controller"),
104fb88110cSLandon J. Fuller BHND_CDESC(BCM, USB20D, USB_DEV, "USB 2.0 Device Controller"),
1054ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SDIOH, OTHER, "SDIO Host Controller"),
1064ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ROBO, OTHER, "RoboSwitch"),
1074ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ATA100, OTHER, "Parallel ATA Controller"),
1084ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SATAXOR, OTHER, "SATA DMA/XOR Controller"),
1094ad7e9b0SAdrian Chadd BHND_CDESC(BCM, GIGETH, ENET_MAC, "Gigabit Ethernet MAC"),
1104ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PCIE, PCIE, "PCIe Bridge"),
1114ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NPHY, WLAN_PHY, "802.11n 2x2 PHY"),
1124ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SRAMC, MEMC, "SRAM Controller"),
1134ad7e9b0SAdrian Chadd BHND_CDESC(BCM, MINIMAC, OTHER, "MINI MAC/PHY"),
1144ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ARM11, CPU, "ARM1176 CPU"),
1154ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ARM7S, CPU, "ARM7TDMI-S CPU"),
1164ad7e9b0SAdrian Chadd BHND_CDESC(BCM, LPPHY, WLAN_PHY, "802.11a/b/g PHY"),
1174ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PMU, PMU, "PMU"),
1184ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SSNPHY, WLAN_PHY, "802.11n Single-Stream PHY"),
1194ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SDIOD, OTHER, "SDIO Device Core"),
1204ad7e9b0SAdrian Chadd BHND_CDESC(BCM, ARMCM3, CPU, "ARM Cortex-M3 CPU"),
1214ad7e9b0SAdrian Chadd BHND_CDESC(BCM, HTPHY, WLAN_PHY, "802.11n 4x4 PHY"),
122d342b2e9SLandon J. Fuller BHND_CDESC(MIPS,MIPS74K, CPU, "MIPS74k CPU"),
1234ad7e9b0SAdrian Chadd BHND_CDESC(BCM, GMAC, ENET_MAC, "Gigabit MAC core"),
1244ad7e9b0SAdrian Chadd BHND_CDESC(BCM, DMEMC, MEMC, "DDR1/DDR2 Memory Controller"),
1254ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PCIERC, OTHER, "PCIe Root Complex"),
1264ad7e9b0SAdrian Chadd BHND_CDESC(BCM, OCP, SOC_BRIDGE, "OCP to OCP Bridge"),
1274ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SC, OTHER, "Shared Common Core"),
1284ad7e9b0SAdrian Chadd BHND_CDESC(BCM, AHB, SOC_BRIDGE, "OCP to AHB Bridge"),
1294ad7e9b0SAdrian Chadd BHND_CDESC(BCM, SPIH, OTHER, "SPI Host Controller"),
1304ad7e9b0SAdrian Chadd BHND_CDESC(BCM, I2S, OTHER, "I2S Digital Audio Interface"),
1314ad7e9b0SAdrian Chadd BHND_CDESC(BCM, DMEMS, MEMC, "SDR/DDR1 Memory Controller"),
1324ad7e9b0SAdrian Chadd BHND_CDESC(BCM, UBUS_SHIM, OTHER, "BCM6362/UBUS WLAN SHIM"),
1334ad7e9b0SAdrian Chadd BHND_CDESC(BCM, PCIE2, PCIE, "PCIe Bridge (Gen2)"),
1344ad7e9b0SAdrian Chadd
1354ad7e9b0SAdrian Chadd BHND_CDESC(ARM, APB_BRIDGE, SOC_BRIDGE, "BP135 AMBA3 AXI to APB Bridge"),
1364ad7e9b0SAdrian Chadd BHND_CDESC(ARM, PL301, SOC_ROUTER, "PL301 AMBA3 Interconnect"),
1374ad7e9b0SAdrian Chadd BHND_CDESC(ARM, EROM, EROM, "PL366 Device Enumeration ROM"),
1384ad7e9b0SAdrian Chadd BHND_CDESC(ARM, OOB_ROUTER, OTHER, "PL367 OOB Interrupt Router"),
1394ad7e9b0SAdrian Chadd BHND_CDESC(ARM, AXI_UNMAPPED, OTHER, "Unmapped Address Ranges"),
1404ad7e9b0SAdrian Chadd
1414ad7e9b0SAdrian Chadd BHND_CDESC(BCM, 4706_CC, CC, "ChipCommon I/O Controller"),
1424ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_PCIE2, PCIE, "PCIe Bridge (Gen2)"),
1434ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_DMA, OTHER, "DMA engine"),
1444ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_SDIO, OTHER, "SDIO 3.0 Host Controller"),
145fb88110cSLandon J. Fuller BHND_CDESC(BCM, NS_USB20H, USB_HOST, "USB 2.0 Host Controller"),
146fb88110cSLandon J. Fuller BHND_CDESC(BCM, NS_USB30H, USB_HOST, "USB 3.0 Host Controller"),
1474ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_A9JTAG, OTHER, "ARM Cortex A9 JTAG Interface"),
1484ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_DDR23_MEMC, MEMC, "Denali DDR2/DD3 Memory Controller"),
1494ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_ROM, NVRAM, "System ROM"),
1504ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_NAND, NVRAM, "NAND Flash Controller"),
1514ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_QSPI, NVRAM, "QSPI Flash Controller"),
1524ad7e9b0SAdrian Chadd BHND_CDESC(BCM, NS_CC_B, CC_B, "ChipCommon B Auxiliary I/O Controller"),
1534ad7e9b0SAdrian Chadd BHND_CDESC(BCM, 4706_SOCRAM, RAM, "Internal Memory"),
1544ad7e9b0SAdrian Chadd BHND_CDESC(BCM, IHOST_ARMCA9, CPU, "ARM Cortex A9 CPU"),
1554ad7e9b0SAdrian Chadd BHND_CDESC(BCM, 4706_GMAC_CMN, ENET, "Gigabit MAC (Common)"),
1564ad7e9b0SAdrian Chadd BHND_CDESC(BCM, 4706_GMAC, ENET_MAC, "Gigabit MAC"),
1574ad7e9b0SAdrian Chadd BHND_CDESC(BCM, AMEMC, MEMC, "Denali DDR1/DDR2 Memory Controller"),
1584ad7e9b0SAdrian Chadd #undef BHND_CDESC
1594ad7e9b0SAdrian Chadd
1604ad7e9b0SAdrian Chadd /* Derived from inspection of the BCM4331 cores that provide PrimeCell
1614ad7e9b0SAdrian Chadd * IDs. Due to lack of documentation, the surmised device name/purpose
1624ad7e9b0SAdrian Chadd * provided here may be incorrect. */
1634ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_PRIMEID_EROM, BHND_DEVCLASS_OTHER,
1644ad7e9b0SAdrian Chadd "PL364 Device Enumeration ROM" },
1654ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_PRIMEID_SWRAP, BHND_DEVCLASS_OTHER,
1664ad7e9b0SAdrian Chadd "PL368 Device Management Interface" },
1674ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_PRIMEID_MWRAP, BHND_DEVCLASS_OTHER,
1684ad7e9b0SAdrian Chadd "PL369 Device Management Interface" },
1694ad7e9b0SAdrian Chadd { 0, 0, 0, NULL }
1704ad7e9b0SAdrian Chadd };
1714ad7e9b0SAdrian Chadd
1724e96bf3aSLandon J. Fuller static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[];
1734e96bf3aSLandon J. Fuller static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[];
1744e96bf3aSLandon J. Fuller
1754e96bf3aSLandon J. Fuller /**
1764e96bf3aSLandon J. Fuller * Device table entries for core-specific CLKCTL quirk lookup.
1774e96bf3aSLandon J. Fuller */
1784e96bf3aSLandon J. Fuller static const struct bhnd_device bhnd_clkctl_devices[] = {
1794e96bf3aSLandon J. Fuller BHND_DEVICE(BCM, CC, NULL, bhnd_chipc_clkctl_quirks),
1804e96bf3aSLandon J. Fuller BHND_DEVICE(BCM, PCMCIA, NULL, bhnd_pcmcia_clkctl_quirks),
1814e96bf3aSLandon J. Fuller BHND_DEVICE_END,
1824e96bf3aSLandon J. Fuller };
1834e96bf3aSLandon J. Fuller
1844e96bf3aSLandon J. Fuller /** ChipCommon CLKCTL quirks */
1854e96bf3aSLandon J. Fuller static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[] = {
1864e96bf3aSLandon J. Fuller /* HTAVAIL/ALPAVAIL are bitswapped in chipc's CLKCTL */
1874e96bf3aSLandon J. Fuller BHND_CHIP_QUIRK(4328, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
1884e96bf3aSLandon J. Fuller BHND_CHIP_QUIRK(5354, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
1894e96bf3aSLandon J. Fuller BHND_DEVICE_QUIRK_END
1904e96bf3aSLandon J. Fuller };
1914e96bf3aSLandon J. Fuller
1924e96bf3aSLandon J. Fuller /** PCMCIA CLKCTL quirks */
1934e96bf3aSLandon J. Fuller static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[] = {
1944e96bf3aSLandon J. Fuller /* HTAVAIL/ALPAVAIL are bitswapped in pcmcia's CLKCTL */
1954e96bf3aSLandon J. Fuller BHND_CHIP_QUIRK(4328, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
1964e96bf3aSLandon J. Fuller BHND_CHIP_QUIRK(5354, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
1974e96bf3aSLandon J. Fuller BHND_DEVICE_QUIRK_END
1984e96bf3aSLandon J. Fuller };
1994e96bf3aSLandon J. Fuller
2004ad7e9b0SAdrian Chadd /**
2014ad7e9b0SAdrian Chadd * Return the name for a given JEP106 manufacturer ID.
2024ad7e9b0SAdrian Chadd *
2034ad7e9b0SAdrian Chadd * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
2044ad7e9b0SAdrian Chadd * JEP106 continuation code.
2054ad7e9b0SAdrian Chadd */
2064ad7e9b0SAdrian Chadd const char *
bhnd_vendor_name(uint16_t vendor)2074ad7e9b0SAdrian Chadd bhnd_vendor_name(uint16_t vendor)
2084ad7e9b0SAdrian Chadd {
2094ad7e9b0SAdrian Chadd switch (vendor) {
2104ad7e9b0SAdrian Chadd case BHND_MFGID_ARM:
2114ad7e9b0SAdrian Chadd return "ARM";
2124ad7e9b0SAdrian Chadd case BHND_MFGID_BCM:
2134ad7e9b0SAdrian Chadd return "Broadcom";
2144ad7e9b0SAdrian Chadd case BHND_MFGID_MIPS:
2154ad7e9b0SAdrian Chadd return "MIPS";
2164ad7e9b0SAdrian Chadd default:
2174ad7e9b0SAdrian Chadd return "unknown";
2184ad7e9b0SAdrian Chadd }
2194ad7e9b0SAdrian Chadd }
2204ad7e9b0SAdrian Chadd
2214ad7e9b0SAdrian Chadd /**
2224ad7e9b0SAdrian Chadd * Return the name of a port type.
22305ed3f90SLandon J. Fuller *
22405ed3f90SLandon J. Fuller * @param port_type The port type to look up.
2254ad7e9b0SAdrian Chadd */
2264ad7e9b0SAdrian Chadd const char *
bhnd_port_type_name(bhnd_port_type port_type)2274ad7e9b0SAdrian Chadd bhnd_port_type_name(bhnd_port_type port_type)
2284ad7e9b0SAdrian Chadd {
2294ad7e9b0SAdrian Chadd switch (port_type) {
2304ad7e9b0SAdrian Chadd case BHND_PORT_DEVICE:
2314ad7e9b0SAdrian Chadd return ("device");
2324ad7e9b0SAdrian Chadd case BHND_PORT_BRIDGE:
2334ad7e9b0SAdrian Chadd return ("bridge");
2344ad7e9b0SAdrian Chadd case BHND_PORT_AGENT:
2354ad7e9b0SAdrian Chadd return ("agent");
236c2ec037fSEd Maste default:
237c2ec037fSEd Maste return "unknown";
2384ad7e9b0SAdrian Chadd }
2394ad7e9b0SAdrian Chadd }
2404ad7e9b0SAdrian Chadd
241fdedcd9fSLandon J. Fuller /**
242fdedcd9fSLandon J. Fuller * Return the name of an NVRAM source.
24305ed3f90SLandon J. Fuller *
24405ed3f90SLandon J. Fuller * @param nvram_src The NVRAM source type to look up.
245fdedcd9fSLandon J. Fuller */
246fdedcd9fSLandon J. Fuller const char *
bhnd_nvram_src_name(bhnd_nvram_src nvram_src)247fdedcd9fSLandon J. Fuller bhnd_nvram_src_name(bhnd_nvram_src nvram_src)
248fdedcd9fSLandon J. Fuller {
249fdedcd9fSLandon J. Fuller switch (nvram_src) {
250fdedcd9fSLandon J. Fuller case BHND_NVRAM_SRC_FLASH:
251fdedcd9fSLandon J. Fuller return ("flash");
252fdedcd9fSLandon J. Fuller case BHND_NVRAM_SRC_OTP:
253fdedcd9fSLandon J. Fuller return ("OTP");
254fdedcd9fSLandon J. Fuller case BHND_NVRAM_SRC_SPROM:
255fdedcd9fSLandon J. Fuller return ("SPROM");
256fdedcd9fSLandon J. Fuller case BHND_NVRAM_SRC_UNKNOWN:
257fdedcd9fSLandon J. Fuller return ("none");
258fdedcd9fSLandon J. Fuller default:
259fdedcd9fSLandon J. Fuller return ("unknown");
260fdedcd9fSLandon J. Fuller }
261fdedcd9fSLandon J. Fuller }
2624ad7e9b0SAdrian Chadd
2634ad7e9b0SAdrian Chadd static const struct bhnd_core_desc *
bhnd_find_core_desc(uint16_t vendor,uint16_t device)2644ad7e9b0SAdrian Chadd bhnd_find_core_desc(uint16_t vendor, uint16_t device)
2654ad7e9b0SAdrian Chadd {
2664ad7e9b0SAdrian Chadd for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
2674ad7e9b0SAdrian Chadd if (bhnd_core_descs[i].vendor != vendor)
2684ad7e9b0SAdrian Chadd continue;
2694ad7e9b0SAdrian Chadd
2704ad7e9b0SAdrian Chadd if (bhnd_core_descs[i].device != device)
2714ad7e9b0SAdrian Chadd continue;
2724ad7e9b0SAdrian Chadd
2734ad7e9b0SAdrian Chadd return (&bhnd_core_descs[i]);
2744ad7e9b0SAdrian Chadd }
2754ad7e9b0SAdrian Chadd
2764ad7e9b0SAdrian Chadd return (NULL);
2774ad7e9b0SAdrian Chadd }
2784ad7e9b0SAdrian Chadd
2794ad7e9b0SAdrian Chadd /**
2804ad7e9b0SAdrian Chadd * Return a human-readable name for a BHND core.
2814ad7e9b0SAdrian Chadd *
28205ed3f90SLandon J. Fuller * @param vendor The core designer's JEDEC-106 Manufacturer ID.
2834ad7e9b0SAdrian Chadd * @param device The core identifier.
2844ad7e9b0SAdrian Chadd */
2854ad7e9b0SAdrian Chadd const char *
bhnd_find_core_name(uint16_t vendor,uint16_t device)2864ad7e9b0SAdrian Chadd bhnd_find_core_name(uint16_t vendor, uint16_t device)
2874ad7e9b0SAdrian Chadd {
2884ad7e9b0SAdrian Chadd const struct bhnd_core_desc *desc;
2894ad7e9b0SAdrian Chadd
2904ad7e9b0SAdrian Chadd if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
2914ad7e9b0SAdrian Chadd return ("unknown");
2924ad7e9b0SAdrian Chadd
2934ad7e9b0SAdrian Chadd return desc->desc;
2944ad7e9b0SAdrian Chadd }
2954ad7e9b0SAdrian Chadd
2964ad7e9b0SAdrian Chadd /**
2974ad7e9b0SAdrian Chadd * Return the device class for a BHND core.
2984ad7e9b0SAdrian Chadd *
29905ed3f90SLandon J. Fuller * @param vendor The core designer's JEDEC-106 Manufacturer ID.
3004ad7e9b0SAdrian Chadd * @param device The core identifier.
3014ad7e9b0SAdrian Chadd */
3024ad7e9b0SAdrian Chadd bhnd_devclass_t
bhnd_find_core_class(uint16_t vendor,uint16_t device)3034ad7e9b0SAdrian Chadd bhnd_find_core_class(uint16_t vendor, uint16_t device)
3044ad7e9b0SAdrian Chadd {
3054ad7e9b0SAdrian Chadd const struct bhnd_core_desc *desc;
3064ad7e9b0SAdrian Chadd
3074ad7e9b0SAdrian Chadd if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
3084ad7e9b0SAdrian Chadd return (BHND_DEVCLASS_OTHER);
3094ad7e9b0SAdrian Chadd
3104ad7e9b0SAdrian Chadd return desc->class;
3114ad7e9b0SAdrian Chadd }
3124ad7e9b0SAdrian Chadd
3134ad7e9b0SAdrian Chadd /**
3144ad7e9b0SAdrian Chadd * Return a human-readable name for a BHND core.
3154ad7e9b0SAdrian Chadd *
3164ad7e9b0SAdrian Chadd * @param ci The core's info record.
3174ad7e9b0SAdrian Chadd */
3184ad7e9b0SAdrian Chadd const char *
bhnd_core_name(const struct bhnd_core_info * ci)3194ad7e9b0SAdrian Chadd bhnd_core_name(const struct bhnd_core_info *ci)
3204ad7e9b0SAdrian Chadd {
3214ad7e9b0SAdrian Chadd return bhnd_find_core_name(ci->vendor, ci->device);
3224ad7e9b0SAdrian Chadd }
3234ad7e9b0SAdrian Chadd
3244ad7e9b0SAdrian Chadd /**
3254ad7e9b0SAdrian Chadd * Return the device class for a BHND core.
3264ad7e9b0SAdrian Chadd *
3274ad7e9b0SAdrian Chadd * @param ci The core's info record.
3284ad7e9b0SAdrian Chadd */
3294ad7e9b0SAdrian Chadd bhnd_devclass_t
bhnd_core_class(const struct bhnd_core_info * ci)3304ad7e9b0SAdrian Chadd bhnd_core_class(const struct bhnd_core_info *ci)
3314ad7e9b0SAdrian Chadd {
3324ad7e9b0SAdrian Chadd return bhnd_find_core_class(ci->vendor, ci->device);
3334ad7e9b0SAdrian Chadd }
3344ad7e9b0SAdrian Chadd
3354ad7e9b0SAdrian Chadd /**
3369bb95906SLandon J. Fuller * Write a human readable name representation of the given
3379bb95906SLandon J. Fuller * BHND_CHIPID_* constant to @p buffer.
3389bb95906SLandon J. Fuller *
3399bb95906SLandon J. Fuller * @param buffer Output buffer, or NULL to compute the required size.
3409bb95906SLandon J. Fuller * @param size Capacity of @p buffer, in bytes.
3419bb95906SLandon J. Fuller * @param chip_id Chip ID to be formatted.
3429bb95906SLandon J. Fuller *
34305ed3f90SLandon J. Fuller * @return The required number of bytes on success, or a negative integer on
34405ed3f90SLandon J. Fuller * failure. No more than @p size-1 characters be written, with the @p size'th
34505ed3f90SLandon J. Fuller * set to '\0'.
3469bb95906SLandon J. Fuller *
3479bb95906SLandon J. Fuller * @sa BHND_CHIPID_MAX_NAMELEN
3489bb95906SLandon J. Fuller */
3499bb95906SLandon J. Fuller int
bhnd_format_chip_id(char * buffer,size_t size,uint16_t chip_id)3509bb95906SLandon J. Fuller bhnd_format_chip_id(char *buffer, size_t size, uint16_t chip_id)
3519bb95906SLandon J. Fuller {
3529bb95906SLandon J. Fuller /* All hex formatted IDs are within the range of 0x4000-0x9C3F (40000-1) */
3539bb95906SLandon J. Fuller if (chip_id >= 0x4000 && chip_id <= 0x9C3F)
3549bb95906SLandon J. Fuller return (snprintf(buffer, size, "BCM%hX", chip_id));
3559bb95906SLandon J. Fuller else
3569bb95906SLandon J. Fuller return (snprintf(buffer, size, "BCM%hu", chip_id));
3579bb95906SLandon J. Fuller }
3589bb95906SLandon J. Fuller
3599bb95906SLandon J. Fuller /**
36005ed3f90SLandon J. Fuller * Return a core info record populated from a bhnd-attached @p dev.
3614ad7e9b0SAdrian Chadd *
3624ad7e9b0SAdrian Chadd * @param dev A bhnd device.
36305ed3f90SLandon J. Fuller *
36405ed3f90SLandon J. Fuller * @return A core info record for @p dev.
3654ad7e9b0SAdrian Chadd */
3664ad7e9b0SAdrian Chadd struct bhnd_core_info
bhnd_get_core_info(device_t dev)3674ad7e9b0SAdrian Chadd bhnd_get_core_info(device_t dev) {
3684ad7e9b0SAdrian Chadd return (struct bhnd_core_info) {
3694ad7e9b0SAdrian Chadd .vendor = bhnd_get_vendor(dev),
3704ad7e9b0SAdrian Chadd .device = bhnd_get_device(dev),
3714ad7e9b0SAdrian Chadd .hwrev = bhnd_get_hwrev(dev),
3724ad7e9b0SAdrian Chadd .core_idx = bhnd_get_core_index(dev),
3734ad7e9b0SAdrian Chadd .unit = bhnd_get_core_unit(dev)
3744ad7e9b0SAdrian Chadd };
3754ad7e9b0SAdrian Chadd }
3764ad7e9b0SAdrian Chadd
3774ad7e9b0SAdrian Chadd /**
3788e35bf83SLandon J. Fuller * Find a @p class child device with @p unit on @p bus.
3794ad7e9b0SAdrian Chadd *
3808e35bf83SLandon J. Fuller * @param bus The bhnd-compatible bus to be searched.
3814ad7e9b0SAdrian Chadd * @param class The device class to match on.
382fdedcd9fSLandon J. Fuller * @param unit The core unit number; specify -1 to return the first match
3834ad7e9b0SAdrian Chadd * regardless of unit number.
3844ad7e9b0SAdrian Chadd *
3854ad7e9b0SAdrian Chadd * @retval device_t if a matching child device is found.
3864ad7e9b0SAdrian Chadd * @retval NULL if no matching child device is found.
3874ad7e9b0SAdrian Chadd */
3884ad7e9b0SAdrian Chadd device_t
bhnd_bus_find_child(device_t bus,bhnd_devclass_t class,int unit)3898e35bf83SLandon J. Fuller bhnd_bus_find_child(device_t bus, bhnd_devclass_t class, int unit)
3904ad7e9b0SAdrian Chadd {
3914ad7e9b0SAdrian Chadd struct bhnd_core_match md = {
3925ad9ac03SAdrian Chadd BHND_MATCH_CORE_CLASS(class),
3935ad9ac03SAdrian Chadd BHND_MATCH_CORE_UNIT(unit)
3944ad7e9b0SAdrian Chadd };
3954ad7e9b0SAdrian Chadd
3965ad9ac03SAdrian Chadd if (unit == -1)
3975ad9ac03SAdrian Chadd md.m.match.core_unit = 0;
3985ad9ac03SAdrian Chadd
3998e35bf83SLandon J. Fuller return bhnd_bus_match_child(bus, &md);
4004ad7e9b0SAdrian Chadd }
4014ad7e9b0SAdrian Chadd
4024ad7e9b0SAdrian Chadd /**
4038e35bf83SLandon J. Fuller * Find the first child device on @p bus that matches @p desc.
4044ad7e9b0SAdrian Chadd *
4058e35bf83SLandon J. Fuller * @param bus The bhnd-compatible bus to be searched.
4064ad7e9b0SAdrian Chadd * @param desc A match descriptor.
4074ad7e9b0SAdrian Chadd *
4084ad7e9b0SAdrian Chadd * @retval device_t if a matching child device is found.
4094ad7e9b0SAdrian Chadd * @retval NULL if no matching child device is found.
4104ad7e9b0SAdrian Chadd */
4114ad7e9b0SAdrian Chadd device_t
bhnd_bus_match_child(device_t bus,const struct bhnd_core_match * desc)4128e35bf83SLandon J. Fuller bhnd_bus_match_child(device_t bus, const struct bhnd_core_match *desc)
4134ad7e9b0SAdrian Chadd {
4144ad7e9b0SAdrian Chadd device_t *devlistp;
4154ad7e9b0SAdrian Chadd device_t match;
4164ad7e9b0SAdrian Chadd int devcnt;
4174ad7e9b0SAdrian Chadd int error;
4184ad7e9b0SAdrian Chadd
4198e35bf83SLandon J. Fuller error = device_get_children(bus, &devlistp, &devcnt);
4204ad7e9b0SAdrian Chadd if (error != 0)
4214ad7e9b0SAdrian Chadd return (NULL);
4224ad7e9b0SAdrian Chadd
4234ad7e9b0SAdrian Chadd match = NULL;
4244ad7e9b0SAdrian Chadd for (int i = 0; i < devcnt; i++) {
4255ad9ac03SAdrian Chadd struct bhnd_core_info ci = bhnd_get_core_info(devlistp[i]);
4265ad9ac03SAdrian Chadd
4275ad9ac03SAdrian Chadd if (bhnd_core_matches(&ci, desc)) {
4285ad9ac03SAdrian Chadd match = devlistp[i];
4294ad7e9b0SAdrian Chadd goto done;
4304ad7e9b0SAdrian Chadd }
4314ad7e9b0SAdrian Chadd }
4324ad7e9b0SAdrian Chadd
4334ad7e9b0SAdrian Chadd done:
4344ad7e9b0SAdrian Chadd free(devlistp, M_TEMP);
4354ad7e9b0SAdrian Chadd return match;
4364ad7e9b0SAdrian Chadd }
4374ad7e9b0SAdrian Chadd
4384ad7e9b0SAdrian Chadd /**
4398e35bf83SLandon J. Fuller * Retrieve an ordered list of all device instances currently connected to
4408e35bf83SLandon J. Fuller * @p bus, returning a pointer to the array in @p devlistp and the count
4418e35bf83SLandon J. Fuller * in @p ndevs.
4428e35bf83SLandon J. Fuller *
4438e35bf83SLandon J. Fuller * The memory allocated for the table must be freed via
4448e35bf83SLandon J. Fuller * bhnd_bus_free_children().
4458e35bf83SLandon J. Fuller *
4468e35bf83SLandon J. Fuller * @param bus The bhnd-compatible bus to be queried.
4478e35bf83SLandon J. Fuller * @param[out] devlist The array of devices.
4488e35bf83SLandon J. Fuller * @param[out] devcount The number of devices in @p devlistp
4498e35bf83SLandon J. Fuller * @param order The order in which devices will be returned
4508e35bf83SLandon J. Fuller * in @p devlist.
4518e35bf83SLandon J. Fuller *
4528e35bf83SLandon J. Fuller * @retval 0 success
4538e35bf83SLandon J. Fuller * @retval non-zero if an error occurs, a regular unix error code will
4548e35bf83SLandon J. Fuller * be returned.
4558e35bf83SLandon J. Fuller */
4568e35bf83SLandon J. Fuller int
bhnd_bus_get_children(device_t bus,device_t ** devlist,int * devcount,bhnd_device_order order)4578e35bf83SLandon J. Fuller bhnd_bus_get_children(device_t bus, device_t **devlist, int *devcount,
4588e35bf83SLandon J. Fuller bhnd_device_order order)
4598e35bf83SLandon J. Fuller {
4608e35bf83SLandon J. Fuller int error;
4618e35bf83SLandon J. Fuller
4628e35bf83SLandon J. Fuller /* Fetch device array */
4638e35bf83SLandon J. Fuller if ((error = device_get_children(bus, devlist, devcount)))
4648e35bf83SLandon J. Fuller return (error);
4658e35bf83SLandon J. Fuller
4668e35bf83SLandon J. Fuller /* Perform requested sorting */
4678e35bf83SLandon J. Fuller if ((error = bhnd_sort_devices(*devlist, *devcount, order))) {
4688e35bf83SLandon J. Fuller bhnd_bus_free_children(*devlist);
4698e35bf83SLandon J. Fuller return (error);
4708e35bf83SLandon J. Fuller }
4718e35bf83SLandon J. Fuller
4728e35bf83SLandon J. Fuller return (0);
4738e35bf83SLandon J. Fuller }
4748e35bf83SLandon J. Fuller
4758e35bf83SLandon J. Fuller /**
4768e35bf83SLandon J. Fuller * Free any memory allocated in a previous call to bhnd_bus_get_children().
4778e35bf83SLandon J. Fuller *
4788e35bf83SLandon J. Fuller * @param devlist The device array returned by bhnd_bus_get_children().
4798e35bf83SLandon J. Fuller */
4808e35bf83SLandon J. Fuller void
bhnd_bus_free_children(device_t * devlist)4818e35bf83SLandon J. Fuller bhnd_bus_free_children(device_t *devlist)
4828e35bf83SLandon J. Fuller {
4838e35bf83SLandon J. Fuller free(devlist, M_TEMP);
4848e35bf83SLandon J. Fuller }
4858e35bf83SLandon J. Fuller
4868e35bf83SLandon J. Fuller /**
4878e35bf83SLandon J. Fuller * Perform in-place sorting of an array of bhnd device instances.
4888e35bf83SLandon J. Fuller *
4898e35bf83SLandon J. Fuller * @param devlist An array of bhnd devices.
4908e35bf83SLandon J. Fuller * @param devcount The number of devices in @p devs.
4918e35bf83SLandon J. Fuller * @param order The sort order to be used.
49205ed3f90SLandon J. Fuller *
49305ed3f90SLandon J. Fuller * @retval 0 success
49405ed3f90SLandon J. Fuller * @retval EINVAL if the sort order is unknown.
4958e35bf83SLandon J. Fuller */
4968e35bf83SLandon J. Fuller int
bhnd_sort_devices(device_t * devlist,size_t devcount,bhnd_device_order order)4978e35bf83SLandon J. Fuller bhnd_sort_devices(device_t *devlist, size_t devcount, bhnd_device_order order)
4988e35bf83SLandon J. Fuller {
4998e35bf83SLandon J. Fuller int (*compare)(const void *, const void *);
5008e35bf83SLandon J. Fuller
5018e35bf83SLandon J. Fuller switch (order) {
5028e35bf83SLandon J. Fuller case BHND_DEVICE_ORDER_ATTACH:
5038e35bf83SLandon J. Fuller compare = compare_ascending_probe_order;
5048e35bf83SLandon J. Fuller break;
5058e35bf83SLandon J. Fuller case BHND_DEVICE_ORDER_DETACH:
5068e35bf83SLandon J. Fuller compare = compare_descending_probe_order;
5078e35bf83SLandon J. Fuller break;
5088e35bf83SLandon J. Fuller default:
5098e35bf83SLandon J. Fuller printf("unknown sort order: %d\n", order);
5108e35bf83SLandon J. Fuller return (EINVAL);
5118e35bf83SLandon J. Fuller }
5128e35bf83SLandon J. Fuller
5138e35bf83SLandon J. Fuller qsort(devlist, devcount, sizeof(*devlist), compare);
5148e35bf83SLandon J. Fuller return (0);
5158e35bf83SLandon J. Fuller }
5168e35bf83SLandon J. Fuller
5178e35bf83SLandon J. Fuller /*
5188e35bf83SLandon J. Fuller * Ascending comparison of bhnd device's probe order.
5198e35bf83SLandon J. Fuller */
5208e35bf83SLandon J. Fuller static int
compare_ascending_probe_order(const void * lhs,const void * rhs)5218e35bf83SLandon J. Fuller compare_ascending_probe_order(const void *lhs, const void *rhs)
5228e35bf83SLandon J. Fuller {
5238e35bf83SLandon J. Fuller device_t ldev, rdev;
5248e35bf83SLandon J. Fuller int lorder, rorder;
5258e35bf83SLandon J. Fuller
5268e35bf83SLandon J. Fuller ldev = (*(const device_t *) lhs);
5278e35bf83SLandon J. Fuller rdev = (*(const device_t *) rhs);
5288e35bf83SLandon J. Fuller
5298e35bf83SLandon J. Fuller lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev);
5308e35bf83SLandon J. Fuller rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev);
5318e35bf83SLandon J. Fuller
5328e35bf83SLandon J. Fuller if (lorder < rorder) {
5338e35bf83SLandon J. Fuller return (-1);
5348e35bf83SLandon J. Fuller } else if (lorder > rorder) {
5358e35bf83SLandon J. Fuller return (1);
5368e35bf83SLandon J. Fuller } else {
5378e35bf83SLandon J. Fuller return (0);
5388e35bf83SLandon J. Fuller }
5398e35bf83SLandon J. Fuller }
5408e35bf83SLandon J. Fuller
5418e35bf83SLandon J. Fuller /*
5428e35bf83SLandon J. Fuller * Descending comparison of bhnd device's probe order.
5438e35bf83SLandon J. Fuller */
5448e35bf83SLandon J. Fuller static int
compare_descending_probe_order(const void * lhs,const void * rhs)5458e35bf83SLandon J. Fuller compare_descending_probe_order(const void *lhs, const void *rhs)
5468e35bf83SLandon J. Fuller {
5478e35bf83SLandon J. Fuller return (compare_ascending_probe_order(rhs, lhs));
5488e35bf83SLandon J. Fuller }
5498e35bf83SLandon J. Fuller
5508e35bf83SLandon J. Fuller /**
5518e35bf83SLandon J. Fuller * Call device_probe_and_attach() for each of the bhnd bus device's
5528e35bf83SLandon J. Fuller * children, in bhnd attach order.
5538e35bf83SLandon J. Fuller *
5548e35bf83SLandon J. Fuller * @param bus The bhnd-compatible bus for which all children should be probed
5558e35bf83SLandon J. Fuller * and attached.
5568e35bf83SLandon J. Fuller */
5578e35bf83SLandon J. Fuller int
bhnd_bus_probe_children(device_t bus)5588e35bf83SLandon J. Fuller bhnd_bus_probe_children(device_t bus)
5598e35bf83SLandon J. Fuller {
5608e35bf83SLandon J. Fuller device_t *devs;
5618e35bf83SLandon J. Fuller int ndevs;
5628e35bf83SLandon J. Fuller int error;
5638e35bf83SLandon J. Fuller
5648e35bf83SLandon J. Fuller /* Fetch children in attach order */
5658e35bf83SLandon J. Fuller error = bhnd_bus_get_children(bus, &devs, &ndevs,
5668e35bf83SLandon J. Fuller BHND_DEVICE_ORDER_ATTACH);
5678e35bf83SLandon J. Fuller if (error)
5688e35bf83SLandon J. Fuller return (error);
5698e35bf83SLandon J. Fuller
5708e35bf83SLandon J. Fuller /* Probe and attach all children */
5718e35bf83SLandon J. Fuller for (int i = 0; i < ndevs; i++) {
5728e35bf83SLandon J. Fuller device_t child = devs[i];
5738e35bf83SLandon J. Fuller device_probe_and_attach(child);
5748e35bf83SLandon J. Fuller }
5758e35bf83SLandon J. Fuller
5768e35bf83SLandon J. Fuller bhnd_bus_free_children(devs);
5778e35bf83SLandon J. Fuller
5788e35bf83SLandon J. Fuller return (0);
5798e35bf83SLandon J. Fuller }
5808e35bf83SLandon J. Fuller
5818e35bf83SLandon J. Fuller /**
5828ef24a0dSAdrian Chadd * Walk up the bhnd device hierarchy to locate the root device
5838ef24a0dSAdrian Chadd * to which the bhndb bridge is attached.
5848ef24a0dSAdrian Chadd *
5858ef24a0dSAdrian Chadd * This can be used from within bhnd host bridge drivers to locate the
5868ef24a0dSAdrian Chadd * actual upstream host device.
5878ef24a0dSAdrian Chadd *
5888ef24a0dSAdrian Chadd * @param dev A bhnd device.
5898ef24a0dSAdrian Chadd * @param bus_class The expected bus (e.g. "pci") to which the bridge root
5908ef24a0dSAdrian Chadd * should be attached.
5918ef24a0dSAdrian Chadd *
5928ef24a0dSAdrian Chadd * @retval device_t if a matching parent device is found.
59305ed3f90SLandon J. Fuller * @retval NULL if @p dev is not attached via a bhndb bus.
59405ed3f90SLandon J. Fuller * @retval NULL if no parent device is attached via @p bus_class.
5958ef24a0dSAdrian Chadd */
5968ef24a0dSAdrian Chadd device_t
bhnd_find_bridge_root(device_t dev,devclass_t bus_class)5978ef24a0dSAdrian Chadd bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
5988ef24a0dSAdrian Chadd {
5998ef24a0dSAdrian Chadd devclass_t bhndb_class;
6008ef24a0dSAdrian Chadd device_t parent;
6018ef24a0dSAdrian Chadd
60258d83161SJohn Baldwin KASSERT(device_get_devclass(device_get_parent(dev)) ==
60358d83161SJohn Baldwin devclass_find("bhnd"),
6048ef24a0dSAdrian Chadd ("%s not a bhnd device", device_get_nameunit(dev)));
6058ef24a0dSAdrian Chadd
6068ef24a0dSAdrian Chadd bhndb_class = devclass_find("bhndb");
6078ef24a0dSAdrian Chadd
6088ef24a0dSAdrian Chadd /* Walk the device tree until we hit a bridge */
6098ef24a0dSAdrian Chadd parent = dev;
6108ef24a0dSAdrian Chadd while ((parent = device_get_parent(parent)) != NULL) {
6118ef24a0dSAdrian Chadd if (device_get_devclass(parent) == bhndb_class)
6128ef24a0dSAdrian Chadd break;
6138ef24a0dSAdrian Chadd }
6148ef24a0dSAdrian Chadd
6158ef24a0dSAdrian Chadd /* No bridge? */
6168ef24a0dSAdrian Chadd if (parent == NULL)
6178ef24a0dSAdrian Chadd return (NULL);
6188ef24a0dSAdrian Chadd
6198ef24a0dSAdrian Chadd /* Search for a parent attached to the expected bus class */
6208ef24a0dSAdrian Chadd while ((parent = device_get_parent(parent)) != NULL) {
6218ef24a0dSAdrian Chadd device_t bus;
6228ef24a0dSAdrian Chadd
6238ef24a0dSAdrian Chadd bus = device_get_parent(parent);
6248ef24a0dSAdrian Chadd if (bus != NULL && device_get_devclass(bus) == bus_class)
6258ef24a0dSAdrian Chadd return (parent);
6268ef24a0dSAdrian Chadd }
6278ef24a0dSAdrian Chadd
6288ef24a0dSAdrian Chadd /* Not found */
6298ef24a0dSAdrian Chadd return (NULL);
6308ef24a0dSAdrian Chadd }
6318ef24a0dSAdrian Chadd
6328ef24a0dSAdrian Chadd /**
6334ad7e9b0SAdrian Chadd * Find the first core in @p cores that matches @p desc.
6344ad7e9b0SAdrian Chadd *
6354ad7e9b0SAdrian Chadd * @param cores The table to search.
6364ad7e9b0SAdrian Chadd * @param num_cores The length of @p cores.
6374ad7e9b0SAdrian Chadd * @param desc A match descriptor.
6384ad7e9b0SAdrian Chadd *
6394ad7e9b0SAdrian Chadd * @retval bhnd_core_info if a matching core is found.
6404ad7e9b0SAdrian Chadd * @retval NULL if no matching core is found.
6414ad7e9b0SAdrian Chadd */
6424ad7e9b0SAdrian Chadd const struct bhnd_core_info *
bhnd_match_core(const struct bhnd_core_info * cores,u_int num_cores,const struct bhnd_core_match * desc)6434ad7e9b0SAdrian Chadd bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
6444ad7e9b0SAdrian Chadd const struct bhnd_core_match *desc)
6454ad7e9b0SAdrian Chadd {
6464ad7e9b0SAdrian Chadd for (u_int i = 0; i < num_cores; i++) {
6474ad7e9b0SAdrian Chadd if (bhnd_core_matches(&cores[i], desc))
6484ad7e9b0SAdrian Chadd return &cores[i];
6494ad7e9b0SAdrian Chadd }
6504ad7e9b0SAdrian Chadd
6514ad7e9b0SAdrian Chadd return (NULL);
6524ad7e9b0SAdrian Chadd }
6534ad7e9b0SAdrian Chadd
6544ad7e9b0SAdrian Chadd /**
6554ad7e9b0SAdrian Chadd * Find the first core in @p cores with the given @p class.
6564ad7e9b0SAdrian Chadd *
6574ad7e9b0SAdrian Chadd * @param cores The table to search.
6584ad7e9b0SAdrian Chadd * @param num_cores The length of @p cores.
65905ed3f90SLandon J. Fuller * @param class The device class to match on.
6604ad7e9b0SAdrian Chadd *
66105ed3f90SLandon J. Fuller * @retval non-NULL if a matching core is found.
6624ad7e9b0SAdrian Chadd * @retval NULL if no matching core is found.
6634ad7e9b0SAdrian Chadd */
6644ad7e9b0SAdrian Chadd const struct bhnd_core_info *
bhnd_find_core(const struct bhnd_core_info * cores,u_int num_cores,bhnd_devclass_t class)6654ad7e9b0SAdrian Chadd bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
6664ad7e9b0SAdrian Chadd bhnd_devclass_t class)
6674ad7e9b0SAdrian Chadd {
6684ad7e9b0SAdrian Chadd struct bhnd_core_match md = {
6695ad9ac03SAdrian Chadd BHND_MATCH_CORE_CLASS(class)
6704ad7e9b0SAdrian Chadd };
6714ad7e9b0SAdrian Chadd
6724ad7e9b0SAdrian Chadd return bhnd_match_core(cores, num_cores, &md);
6734ad7e9b0SAdrian Chadd }
6744ad7e9b0SAdrian Chadd
675111d7cb2SLandon J. Fuller /**
676111d7cb2SLandon J. Fuller * Create an equality match descriptor for @p core.
677111d7cb2SLandon J. Fuller *
678111d7cb2SLandon J. Fuller * @param core The core info to be matched on.
67905ed3f90SLandon J. Fuller *
68005ed3f90SLandon J. Fuller * @return an equality match descriptor for @p core.
681111d7cb2SLandon J. Fuller */
682111d7cb2SLandon J. Fuller struct bhnd_core_match
bhnd_core_get_match_desc(const struct bhnd_core_info * core)683111d7cb2SLandon J. Fuller bhnd_core_get_match_desc(const struct bhnd_core_info *core)
684111d7cb2SLandon J. Fuller {
685111d7cb2SLandon J. Fuller return ((struct bhnd_core_match) {
686111d7cb2SLandon J. Fuller BHND_MATCH_CORE_VENDOR(core->vendor),
687111d7cb2SLandon J. Fuller BHND_MATCH_CORE_ID(core->device),
688111d7cb2SLandon J. Fuller BHND_MATCH_CORE_REV(HWREV_EQ(core->hwrev)),
689111d7cb2SLandon J. Fuller BHND_MATCH_CORE_CLASS(bhnd_core_class(core)),
690111d7cb2SLandon J. Fuller BHND_MATCH_CORE_IDX(core->core_idx),
691111d7cb2SLandon J. Fuller BHND_MATCH_CORE_UNIT(core->unit)
692111d7cb2SLandon J. Fuller });
693111d7cb2SLandon J. Fuller }
694111d7cb2SLandon J. Fuller
695111d7cb2SLandon J. Fuller /**
69605ed3f90SLandon J. Fuller * Return true if the @p lhs is equal to @p rhs.
697111d7cb2SLandon J. Fuller *
698111d7cb2SLandon J. Fuller * @param lhs The first bhnd core descriptor to compare.
699111d7cb2SLandon J. Fuller * @param rhs The second bhnd core descriptor to compare.
700111d7cb2SLandon J. Fuller *
701111d7cb2SLandon J. Fuller * @retval true if @p lhs is equal to @p rhs
702111d7cb2SLandon J. Fuller * @retval false if @p lhs is not equal to @p rhs
703111d7cb2SLandon J. Fuller */
704111d7cb2SLandon J. Fuller bool
bhnd_cores_equal(const struct bhnd_core_info * lhs,const struct bhnd_core_info * rhs)705111d7cb2SLandon J. Fuller bhnd_cores_equal(const struct bhnd_core_info *lhs,
706111d7cb2SLandon J. Fuller const struct bhnd_core_info *rhs)
707111d7cb2SLandon J. Fuller {
708111d7cb2SLandon J. Fuller struct bhnd_core_match md;
709111d7cb2SLandon J. Fuller
710111d7cb2SLandon J. Fuller /* Use an equality match descriptor to perform the comparison */
711111d7cb2SLandon J. Fuller md = bhnd_core_get_match_desc(rhs);
712111d7cb2SLandon J. Fuller return (bhnd_core_matches(lhs, &md));
713111d7cb2SLandon J. Fuller }
714111d7cb2SLandon J. Fuller
7154ad7e9b0SAdrian Chadd /**
7164ad7e9b0SAdrian Chadd * Return true if the @p core matches @p desc.
7174ad7e9b0SAdrian Chadd *
7184ad7e9b0SAdrian Chadd * @param core A bhnd core descriptor.
7194ad7e9b0SAdrian Chadd * @param desc A match descriptor to compare against @p core.
7204ad7e9b0SAdrian Chadd *
72105ed3f90SLandon J. Fuller * @retval true if @p core matches @p match.
7224ad7e9b0SAdrian Chadd * @retval false if @p core does not match @p match.
7234ad7e9b0SAdrian Chadd */
7244ad7e9b0SAdrian Chadd bool
bhnd_core_matches(const struct bhnd_core_info * core,const struct bhnd_core_match * desc)7254ad7e9b0SAdrian Chadd bhnd_core_matches(const struct bhnd_core_info *core,
7264ad7e9b0SAdrian Chadd const struct bhnd_core_match *desc)
7274ad7e9b0SAdrian Chadd {
7285ad9ac03SAdrian Chadd if (desc->m.match.core_vendor && desc->core_vendor != core->vendor)
7294ad7e9b0SAdrian Chadd return (false);
7304ad7e9b0SAdrian Chadd
7315ad9ac03SAdrian Chadd if (desc->m.match.core_id && desc->core_id != core->device)
7324ad7e9b0SAdrian Chadd return (false);
7334ad7e9b0SAdrian Chadd
7345ad9ac03SAdrian Chadd if (desc->m.match.core_unit && desc->core_unit != core->unit)
7354ad7e9b0SAdrian Chadd return (false);
7364ad7e9b0SAdrian Chadd
7375ad9ac03SAdrian Chadd if (desc->m.match.core_rev &&
7385ad9ac03SAdrian Chadd !bhnd_hwrev_matches(core->hwrev, &desc->core_rev))
7394ad7e9b0SAdrian Chadd return (false);
7404ad7e9b0SAdrian Chadd
741111d7cb2SLandon J. Fuller if (desc->m.match.core_idx && desc->core_idx != core->core_idx)
742111d7cb2SLandon J. Fuller return (false);
743111d7cb2SLandon J. Fuller
7445ad9ac03SAdrian Chadd if (desc->m.match.core_class &&
7455ad9ac03SAdrian Chadd desc->core_class != bhnd_core_class(core))
7464ad7e9b0SAdrian Chadd return (false);
7474ad7e9b0SAdrian Chadd
7484ad7e9b0SAdrian Chadd return true;
7494ad7e9b0SAdrian Chadd }
7504ad7e9b0SAdrian Chadd
7514ad7e9b0SAdrian Chadd /**
752f74f1a68SAdrian Chadd * Return true if the @p chip matches @p desc.
753f74f1a68SAdrian Chadd *
754f74f1a68SAdrian Chadd * @param chip A bhnd chip identifier.
755f74f1a68SAdrian Chadd * @param desc A match descriptor to compare against @p chip.
756f74f1a68SAdrian Chadd *
75705ed3f90SLandon J. Fuller * @retval true if @p chip matches @p match.
758f74f1a68SAdrian Chadd * @retval false if @p chip does not match @p match.
759f74f1a68SAdrian Chadd */
760f74f1a68SAdrian Chadd bool
bhnd_chip_matches(const struct bhnd_chipid * chip,const struct bhnd_chip_match * desc)761f74f1a68SAdrian Chadd bhnd_chip_matches(const struct bhnd_chipid *chip,
762f74f1a68SAdrian Chadd const struct bhnd_chip_match *desc)
763f74f1a68SAdrian Chadd {
7645ad9ac03SAdrian Chadd if (desc->m.match.chip_id && chip->chip_id != desc->chip_id)
765d567592bSAdrian Chadd return (false);
766d567592bSAdrian Chadd
7675ad9ac03SAdrian Chadd if (desc->m.match.chip_pkg && chip->chip_pkg != desc->chip_pkg)
768f74f1a68SAdrian Chadd return (false);
769f74f1a68SAdrian Chadd
7705ad9ac03SAdrian Chadd if (desc->m.match.chip_rev &&
771f74f1a68SAdrian Chadd !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
772f74f1a68SAdrian Chadd return (false);
773f74f1a68SAdrian Chadd
774caeff9a3SLandon J. Fuller if (desc->m.match.chip_type && chip->chip_type != desc->chip_type)
775caeff9a3SLandon J. Fuller return (false);
776caeff9a3SLandon J. Fuller
7775ad9ac03SAdrian Chadd return (true);
7785ad9ac03SAdrian Chadd }
779d567592bSAdrian Chadd
7805ad9ac03SAdrian Chadd /**
7815ad9ac03SAdrian Chadd * Return true if the @p board matches @p desc.
7825ad9ac03SAdrian Chadd *
7835ad9ac03SAdrian Chadd * @param board The bhnd board info.
7845ad9ac03SAdrian Chadd * @param desc A match descriptor to compare against @p board.
7855ad9ac03SAdrian Chadd *
78605ed3f90SLandon J. Fuller * @retval true if @p chip matches @p match.
7875ad9ac03SAdrian Chadd * @retval false if @p chip does not match @p match.
7885ad9ac03SAdrian Chadd */
7895ad9ac03SAdrian Chadd bool
bhnd_board_matches(const struct bhnd_board_info * board,const struct bhnd_board_match * desc)7905ad9ac03SAdrian Chadd bhnd_board_matches(const struct bhnd_board_info *board,
7915ad9ac03SAdrian Chadd const struct bhnd_board_match *desc)
7925ad9ac03SAdrian Chadd {
7935ad9ac03SAdrian Chadd if (desc->m.match.board_srom_rev &&
794d567592bSAdrian Chadd !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
795d567592bSAdrian Chadd return (false);
796d567592bSAdrian Chadd
7975ad9ac03SAdrian Chadd if (desc->m.match.board_vendor &&
7985ad9ac03SAdrian Chadd board->board_vendor != desc->board_vendor)
799d567592bSAdrian Chadd return (false);
800d567592bSAdrian Chadd
8015ad9ac03SAdrian Chadd if (desc->m.match.board_type && board->board_type != desc->board_type)
802d567592bSAdrian Chadd return (false);
803d567592bSAdrian Chadd
804566ca880SLandon J. Fuller if (desc->m.match.board_devid &&
805566ca880SLandon J. Fuller board->board_devid != desc->board_devid)
806566ca880SLandon J. Fuller return (false);
807566ca880SLandon J. Fuller
8085ad9ac03SAdrian Chadd if (desc->m.match.board_rev &&
809d567592bSAdrian Chadd !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
810d567592bSAdrian Chadd return (false);
811d567592bSAdrian Chadd
812f74f1a68SAdrian Chadd return (true);
813f74f1a68SAdrian Chadd }
814f74f1a68SAdrian Chadd
815f74f1a68SAdrian Chadd /**
8164ad7e9b0SAdrian Chadd * Return true if the @p hwrev matches @p desc.
8174ad7e9b0SAdrian Chadd *
8184ad7e9b0SAdrian Chadd * @param hwrev A bhnd hardware revision.
8194ad7e9b0SAdrian Chadd * @param desc A match descriptor to compare against @p core.
8204ad7e9b0SAdrian Chadd *
82105ed3f90SLandon J. Fuller * @retval true if @p hwrev matches @p match.
8224ad7e9b0SAdrian Chadd * @retval false if @p hwrev does not match @p match.
8234ad7e9b0SAdrian Chadd */
8244ad7e9b0SAdrian Chadd bool
bhnd_hwrev_matches(uint16_t hwrev,const struct bhnd_hwrev_match * desc)8254ad7e9b0SAdrian Chadd bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
8264ad7e9b0SAdrian Chadd {
8274ad7e9b0SAdrian Chadd if (desc->start != BHND_HWREV_INVALID &&
8284ad7e9b0SAdrian Chadd desc->start > hwrev)
8294ad7e9b0SAdrian Chadd return false;
8304ad7e9b0SAdrian Chadd
8314ad7e9b0SAdrian Chadd if (desc->end != BHND_HWREV_INVALID &&
8324ad7e9b0SAdrian Chadd desc->end < hwrev)
8334ad7e9b0SAdrian Chadd return false;
8344ad7e9b0SAdrian Chadd
8354ad7e9b0SAdrian Chadd return true;
8364ad7e9b0SAdrian Chadd }
8374ad7e9b0SAdrian Chadd
8384ad7e9b0SAdrian Chadd /**
8394ad7e9b0SAdrian Chadd * Return true if the @p dev matches @p desc.
8404ad7e9b0SAdrian Chadd *
8414ad7e9b0SAdrian Chadd * @param dev A bhnd device.
8424ad7e9b0SAdrian Chadd * @param desc A match descriptor to compare against @p dev.
8434ad7e9b0SAdrian Chadd *
84405ed3f90SLandon J. Fuller * @retval true if @p dev matches @p match.
8454ad7e9b0SAdrian Chadd * @retval false if @p dev does not match @p match.
8464ad7e9b0SAdrian Chadd */
8474ad7e9b0SAdrian Chadd bool
bhnd_device_matches(device_t dev,const struct bhnd_device_match * desc)8485ad9ac03SAdrian Chadd bhnd_device_matches(device_t dev, const struct bhnd_device_match *desc)
8494ad7e9b0SAdrian Chadd {
8505ad9ac03SAdrian Chadd struct bhnd_core_info core;
8515ad9ac03SAdrian Chadd const struct bhnd_chipid *chip;
8525ad9ac03SAdrian Chadd struct bhnd_board_info board;
8535ad9ac03SAdrian Chadd device_t parent;
8545ad9ac03SAdrian Chadd int error;
8554ad7e9b0SAdrian Chadd
8565ad9ac03SAdrian Chadd /* Construct individual match descriptors */
8575ad9ac03SAdrian Chadd struct bhnd_core_match m_core = { _BHND_CORE_MATCH_COPY(desc) };
8585ad9ac03SAdrian Chadd struct bhnd_chip_match m_chip = { _BHND_CHIP_MATCH_COPY(desc) };
8595ad9ac03SAdrian Chadd struct bhnd_board_match m_board = { _BHND_BOARD_MATCH_COPY(desc) };
8605ad9ac03SAdrian Chadd
8615ad9ac03SAdrian Chadd /* Fetch and match core info */
8625ad9ac03SAdrian Chadd if (m_core.m.match_flags) {
8635ad9ac03SAdrian Chadd /* Only applicable to bhnd-attached cores */
8645ad9ac03SAdrian Chadd parent = device_get_parent(dev);
86558d83161SJohn Baldwin if (device_get_devclass(parent) != devclass_find("bhnd")) {
8665ad9ac03SAdrian Chadd device_printf(dev, "attempting to match core "
8675ad9ac03SAdrian Chadd "attributes against non-core device\n");
8685ad9ac03SAdrian Chadd return (false);
8695ad9ac03SAdrian Chadd }
8705ad9ac03SAdrian Chadd
8715ad9ac03SAdrian Chadd core = bhnd_get_core_info(dev);
8725ad9ac03SAdrian Chadd if (!bhnd_core_matches(&core, &m_core))
8735ad9ac03SAdrian Chadd return (false);
8745ad9ac03SAdrian Chadd }
8755ad9ac03SAdrian Chadd
8765ad9ac03SAdrian Chadd /* Fetch and match chip info */
8775ad9ac03SAdrian Chadd if (m_chip.m.match_flags) {
8785ad9ac03SAdrian Chadd chip = bhnd_get_chipid(dev);
8795ad9ac03SAdrian Chadd
8805ad9ac03SAdrian Chadd if (!bhnd_chip_matches(chip, &m_chip))
8815ad9ac03SAdrian Chadd return (false);
8825ad9ac03SAdrian Chadd }
8835ad9ac03SAdrian Chadd
8845ad9ac03SAdrian Chadd /* Fetch and match board info.
8855ad9ac03SAdrian Chadd *
8865ad9ac03SAdrian Chadd * This is not available until after NVRAM is up; earlier device
8875ad9ac03SAdrian Chadd * matches should not include board requirements */
8885ad9ac03SAdrian Chadd if (m_board.m.match_flags) {
8895ad9ac03SAdrian Chadd if ((error = bhnd_read_board_info(dev, &board))) {
8905ad9ac03SAdrian Chadd device_printf(dev, "failed to read required board info "
8915ad9ac03SAdrian Chadd "during device matching: %d\n", error);
8925ad9ac03SAdrian Chadd return (false);
8935ad9ac03SAdrian Chadd }
8945ad9ac03SAdrian Chadd
8955ad9ac03SAdrian Chadd if (!bhnd_board_matches(&board, &m_board))
8965ad9ac03SAdrian Chadd return (false);
8975ad9ac03SAdrian Chadd }
8985ad9ac03SAdrian Chadd
8995ad9ac03SAdrian Chadd /* All matched */
9005ad9ac03SAdrian Chadd return (true);
9014ad7e9b0SAdrian Chadd }
9024ad7e9b0SAdrian Chadd
9034ad7e9b0SAdrian Chadd /**
90436e4410aSAdrian Chadd * Search @p table for an entry matching @p dev.
90536e4410aSAdrian Chadd *
90636e4410aSAdrian Chadd * @param dev A bhnd device to match against @p table.
90736e4410aSAdrian Chadd * @param table The device table to search.
90836e4410aSAdrian Chadd * @param entry_size The @p table entry size, in bytes.
90936e4410aSAdrian Chadd *
91005ed3f90SLandon J. Fuller * @retval non-NULL the first matching device, if any.
91136e4410aSAdrian Chadd * @retval NULL if no matching device is found in @p table.
91236e4410aSAdrian Chadd */
91336e4410aSAdrian Chadd const struct bhnd_device *
bhnd_device_lookup(device_t dev,const struct bhnd_device * table,size_t entry_size)91436e4410aSAdrian Chadd bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
91536e4410aSAdrian Chadd size_t entry_size)
91636e4410aSAdrian Chadd {
91736e4410aSAdrian Chadd const struct bhnd_device *entry;
918d9352570SAdrian Chadd device_t hostb, parent;
9195ad9ac03SAdrian Chadd bhnd_attach_type attach_type;
9205ad9ac03SAdrian Chadd uint32_t dflags;
921d9352570SAdrian Chadd
922d9352570SAdrian Chadd parent = device_get_parent(dev);
9238e35bf83SLandon J. Fuller hostb = bhnd_bus_find_hostb_device(parent);
9245ad9ac03SAdrian Chadd attach_type = bhnd_get_attach_type(dev);
92536e4410aSAdrian Chadd
9265ad9ac03SAdrian Chadd for (entry = table; !BHND_DEVICE_IS_END(entry); entry =
92736e4410aSAdrian Chadd (const struct bhnd_device *) ((const char *) entry + entry_size))
92836e4410aSAdrian Chadd {
92936e4410aSAdrian Chadd /* match core info */
93036e4410aSAdrian Chadd if (!bhnd_device_matches(dev, &entry->core))
93136e4410aSAdrian Chadd continue;
93236e4410aSAdrian Chadd
93336e4410aSAdrian Chadd /* match device flags */
9345ad9ac03SAdrian Chadd dflags = entry->device_flags;
9355ad9ac03SAdrian Chadd
9365ad9ac03SAdrian Chadd /* hostb implies BHND_ATTACH_ADAPTER requirement */
9375ad9ac03SAdrian Chadd if (dflags & BHND_DF_HOSTB)
9385ad9ac03SAdrian Chadd dflags |= BHND_DF_ADAPTER;
9395ad9ac03SAdrian Chadd
9405ad9ac03SAdrian Chadd if (dflags & BHND_DF_ADAPTER)
9415ad9ac03SAdrian Chadd if (attach_type != BHND_ATTACH_ADAPTER)
9425ad9ac03SAdrian Chadd continue;
9435ad9ac03SAdrian Chadd
9445ad9ac03SAdrian Chadd if (dflags & BHND_DF_HOSTB)
945d9352570SAdrian Chadd if (dev != hostb)
94636e4410aSAdrian Chadd continue;
9475ad9ac03SAdrian Chadd
9485ad9ac03SAdrian Chadd if (dflags & BHND_DF_SOC)
9495ad9ac03SAdrian Chadd if (attach_type != BHND_ATTACH_NATIVE)
9505ad9ac03SAdrian Chadd continue;
95136e4410aSAdrian Chadd
95236e4410aSAdrian Chadd /* device found */
95336e4410aSAdrian Chadd return (entry);
95436e4410aSAdrian Chadd }
95536e4410aSAdrian Chadd
95636e4410aSAdrian Chadd /* not found */
95736e4410aSAdrian Chadd return (NULL);
95836e4410aSAdrian Chadd }
95936e4410aSAdrian Chadd
96036e4410aSAdrian Chadd /**
9615ad9ac03SAdrian Chadd * Scan the device @p table for all quirk flags applicable to @p dev.
96236e4410aSAdrian Chadd *
96336e4410aSAdrian Chadd * @param dev A bhnd device to match against @p table.
96436e4410aSAdrian Chadd * @param table The device table to search.
96505ed3f90SLandon J. Fuller * @param entry_size The @p table entry size, in bytes.
96636e4410aSAdrian Chadd *
96705ed3f90SLandon J. Fuller * @return all matching quirk flags.
96836e4410aSAdrian Chadd */
96936e4410aSAdrian Chadd uint32_t
bhnd_device_quirks(device_t dev,const struct bhnd_device * table,size_t entry_size)97036e4410aSAdrian Chadd bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
97136e4410aSAdrian Chadd size_t entry_size)
97236e4410aSAdrian Chadd {
97336e4410aSAdrian Chadd const struct bhnd_device *dent;
9745ad9ac03SAdrian Chadd const struct bhnd_device_quirk *qent, *qtable;
97536e4410aSAdrian Chadd uint32_t quirks;
97636e4410aSAdrian Chadd
9775ad9ac03SAdrian Chadd /* Locate the device entry */
9785ad9ac03SAdrian Chadd if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL)
97936e4410aSAdrian Chadd return (0);
9805ad9ac03SAdrian Chadd
9815ad9ac03SAdrian Chadd /* Quirks table is optional */
9825ad9ac03SAdrian Chadd qtable = dent->quirks_table;
9835ad9ac03SAdrian Chadd if (qtable == NULL)
9845ad9ac03SAdrian Chadd return (0);
98536e4410aSAdrian Chadd
986d567592bSAdrian Chadd /* Collect matching device quirk entries */
9875ad9ac03SAdrian Chadd quirks = 0;
98836e4410aSAdrian Chadd for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
9895ad9ac03SAdrian Chadd if (bhnd_device_matches(dev, &qent->desc))
99036e4410aSAdrian Chadd quirks |= qent->quirks;
99136e4410aSAdrian Chadd }
99236e4410aSAdrian Chadd
99336e4410aSAdrian Chadd return (quirks);
99436e4410aSAdrian Chadd }
99536e4410aSAdrian Chadd
99636e4410aSAdrian Chadd /**
9974ad7e9b0SAdrian Chadd * Allocate bhnd(4) resources defined in @p rs from a parent bus.
9984ad7e9b0SAdrian Chadd *
9994ad7e9b0SAdrian Chadd * @param dev The device requesting ownership of the resources.
10004ad7e9b0SAdrian Chadd * @param rs A standard bus resource specification. This will be updated
10014ad7e9b0SAdrian Chadd * with the allocated resource's RIDs.
10024ad7e9b0SAdrian Chadd * @param res On success, the allocated bhnd resources.
10034ad7e9b0SAdrian Chadd *
10044ad7e9b0SAdrian Chadd * @retval 0 success
10054ad7e9b0SAdrian Chadd * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
10064ad7e9b0SAdrian Chadd * all allocated resources will be released and a regular
10074ad7e9b0SAdrian Chadd * unix error code will be returned.
10084ad7e9b0SAdrian Chadd */
10094ad7e9b0SAdrian Chadd int
bhnd_alloc_resources(device_t dev,struct resource_spec * rs,struct bhnd_resource ** res)10104ad7e9b0SAdrian Chadd bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
10114ad7e9b0SAdrian Chadd struct bhnd_resource **res)
10124ad7e9b0SAdrian Chadd {
10134ad7e9b0SAdrian Chadd /* Initialize output array */
10144ad7e9b0SAdrian Chadd for (u_int i = 0; rs[i].type != -1; i++)
10154ad7e9b0SAdrian Chadd res[i] = NULL;
10164ad7e9b0SAdrian Chadd
10174ad7e9b0SAdrian Chadd for (u_int i = 0; rs[i].type != -1; i++) {
10184ad7e9b0SAdrian Chadd res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
10194ad7e9b0SAdrian Chadd rs[i].flags);
10204ad7e9b0SAdrian Chadd
10214ad7e9b0SAdrian Chadd /* Clean up all allocations on failure */
10224ad7e9b0SAdrian Chadd if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
10234ad7e9b0SAdrian Chadd bhnd_release_resources(dev, rs, res);
10244ad7e9b0SAdrian Chadd return (ENXIO);
10254ad7e9b0SAdrian Chadd }
10264ad7e9b0SAdrian Chadd }
10274ad7e9b0SAdrian Chadd
10284ad7e9b0SAdrian Chadd return (0);
102968c6ae00SEd Maste }
10304ad7e9b0SAdrian Chadd
10314ad7e9b0SAdrian Chadd /**
10324ad7e9b0SAdrian Chadd * Release bhnd(4) resources defined in @p rs from a parent bus.
10334ad7e9b0SAdrian Chadd *
10344ad7e9b0SAdrian Chadd * @param dev The device that owns the resources.
10354ad7e9b0SAdrian Chadd * @param rs A standard bus resource specification previously initialized
10364ad7e9b0SAdrian Chadd * by @p bhnd_alloc_resources.
10374ad7e9b0SAdrian Chadd * @param res The bhnd resources to be released.
10384ad7e9b0SAdrian Chadd */
10394ad7e9b0SAdrian Chadd void
bhnd_release_resources(device_t dev,const struct resource_spec * rs,struct bhnd_resource ** res)10404ad7e9b0SAdrian Chadd bhnd_release_resources(device_t dev, const struct resource_spec *rs,
10414ad7e9b0SAdrian Chadd struct bhnd_resource **res)
10424ad7e9b0SAdrian Chadd {
10434ad7e9b0SAdrian Chadd for (u_int i = 0; rs[i].type != -1; i++) {
10444ad7e9b0SAdrian Chadd if (res[i] == NULL)
10454ad7e9b0SAdrian Chadd continue;
10464ad7e9b0SAdrian Chadd
10474ad7e9b0SAdrian Chadd bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
10484ad7e9b0SAdrian Chadd res[i] = NULL;
10494ad7e9b0SAdrian Chadd }
10504ad7e9b0SAdrian Chadd }
10514ad7e9b0SAdrian Chadd
10524ad7e9b0SAdrian Chadd /**
10534e96bf3aSLandon J. Fuller * Allocate and return a new per-core PMU clock control/status (clkctl)
10544e96bf3aSLandon J. Fuller * instance for @p dev.
10554e96bf3aSLandon J. Fuller *
10564e96bf3aSLandon J. Fuller * @param dev The bhnd(4) core device mapped by @p r.
10574e96bf3aSLandon J. Fuller * @param pmu_dev The bhnd(4) PMU device, implmenting the bhnd_pmu_if
10584e96bf3aSLandon J. Fuller * interface. The caller is responsible for ensuring that
10594e96bf3aSLandon J. Fuller * this reference remains valid for the lifetime of the
10604e96bf3aSLandon J. Fuller * returned clkctl instance.
10614e96bf3aSLandon J. Fuller * @param r A resource mapping the core's clock control register
10624e96bf3aSLandon J. Fuller * (see BHND_CLK_CTL_ST). The caller is responsible for
10634e96bf3aSLandon J. Fuller * ensuring that this resource remains valid for the
10644e96bf3aSLandon J. Fuller * lifetime of the returned clkctl instance.
10654e96bf3aSLandon J. Fuller * @param offset The offset to the clock control register within @p r.
10664e96bf3aSLandon J. Fuller * @param max_latency The PMU's maximum state transition latency in
10674e96bf3aSLandon J. Fuller * microseconds; this upper bound will be used to busy-wait
10684e96bf3aSLandon J. Fuller * on PMU state transitions.
10694e96bf3aSLandon J. Fuller *
10704e96bf3aSLandon J. Fuller * @retval non-NULL success
10714e96bf3aSLandon J. Fuller * @retval NULL if allocation fails.
10724e96bf3aSLandon J. Fuller *
10734e96bf3aSLandon J. Fuller */
10744e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *
bhnd_alloc_core_clkctl(device_t dev,device_t pmu_dev,struct bhnd_resource * r,bus_size_t offset,u_int max_latency)10754e96bf3aSLandon J. Fuller bhnd_alloc_core_clkctl(device_t dev, device_t pmu_dev, struct bhnd_resource *r,
10764e96bf3aSLandon J. Fuller bus_size_t offset, u_int max_latency)
10774e96bf3aSLandon J. Fuller {
10784e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl;
10794e96bf3aSLandon J. Fuller
10804e96bf3aSLandon J. Fuller clkctl = malloc(sizeof(*clkctl), M_BHND, M_ZERO | M_NOWAIT);
10814e96bf3aSLandon J. Fuller if (clkctl == NULL)
10824e96bf3aSLandon J. Fuller return (NULL);
10834e96bf3aSLandon J. Fuller
10844e96bf3aSLandon J. Fuller clkctl->cc_dev = dev;
10854e96bf3aSLandon J. Fuller clkctl->cc_pmu_dev = pmu_dev;
10864e96bf3aSLandon J. Fuller clkctl->cc_res = r;
10874e96bf3aSLandon J. Fuller clkctl->cc_res_offset = offset;
10884e96bf3aSLandon J. Fuller clkctl->cc_max_latency = max_latency;
10894e96bf3aSLandon J. Fuller clkctl->cc_quirks = bhnd_device_quirks(dev, bhnd_clkctl_devices,
10904e96bf3aSLandon J. Fuller sizeof(bhnd_clkctl_devices[0]));
10914e96bf3aSLandon J. Fuller
10924e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK_INIT(clkctl);
10934e96bf3aSLandon J. Fuller
10944e96bf3aSLandon J. Fuller return (clkctl);
10954e96bf3aSLandon J. Fuller }
10964e96bf3aSLandon J. Fuller
10974e96bf3aSLandon J. Fuller /**
10984e96bf3aSLandon J. Fuller * Free a clkctl instance previously allocated via bhnd_alloc_core_clkctl().
10994e96bf3aSLandon J. Fuller *
11004e96bf3aSLandon J. Fuller * @param clkctl The clkctl instance to be freed.
11014e96bf3aSLandon J. Fuller */
11024e96bf3aSLandon J. Fuller void
bhnd_free_core_clkctl(struct bhnd_core_clkctl * clkctl)11034e96bf3aSLandon J. Fuller bhnd_free_core_clkctl(struct bhnd_core_clkctl *clkctl)
11044e96bf3aSLandon J. Fuller {
11054e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK_DESTROY(clkctl);
11064e96bf3aSLandon J. Fuller
11074e96bf3aSLandon J. Fuller free(clkctl, M_BHND);
11084e96bf3aSLandon J. Fuller }
11094e96bf3aSLandon J. Fuller
11104e96bf3aSLandon J. Fuller /**
11114e96bf3aSLandon J. Fuller * Wait for the per-core clock status to be equal to @p value after
11124e96bf3aSLandon J. Fuller * applying @p mask, timing out after the maximum transition latency is reached.
11134e96bf3aSLandon J. Fuller *
11144e96bf3aSLandon J. Fuller * @param clkctl Per-core clkctl state to be queryied.
11154e96bf3aSLandon J. Fuller * @param value Value to wait for.
11164e96bf3aSLandon J. Fuller * @param mask Mask to apply prior to value comparison.
11174e96bf3aSLandon J. Fuller *
11184e96bf3aSLandon J. Fuller * @retval 0 success
11194e96bf3aSLandon J. Fuller * @retval ETIMEDOUT if the PMU's maximum transition delay is reached before
11204e96bf3aSLandon J. Fuller * the clock status matches @p value and @p mask.
11214e96bf3aSLandon J. Fuller */
11224e96bf3aSLandon J. Fuller int
bhnd_core_clkctl_wait(struct bhnd_core_clkctl * clkctl,uint32_t value,uint32_t mask)11234e96bf3aSLandon J. Fuller bhnd_core_clkctl_wait(struct bhnd_core_clkctl *clkctl, uint32_t value,
11244e96bf3aSLandon J. Fuller uint32_t mask)
11254e96bf3aSLandon J. Fuller {
11264e96bf3aSLandon J. Fuller uint32_t clkst;
11274e96bf3aSLandon J. Fuller
11284e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK_ASSERT(clkctl, MA_OWNED);
11294e96bf3aSLandon J. Fuller
11304e96bf3aSLandon J. Fuller /* Bitswapped HTAVAIL/ALPAVAIL work-around */
11314e96bf3aSLandon J. Fuller if (clkctl->cc_quirks & BHND_CLKCTL_QUIRK_CCS0) {
11324e96bf3aSLandon J. Fuller uint32_t fmask, fval;
11334e96bf3aSLandon J. Fuller
11344e96bf3aSLandon J. Fuller fmask = mask & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
11354e96bf3aSLandon J. Fuller fval = value & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
11364e96bf3aSLandon J. Fuller
11374e96bf3aSLandon J. Fuller if (mask & BHND_CCS_HTAVAIL)
11384e96bf3aSLandon J. Fuller fmask |= BHND_CCS0_HTAVAIL;
11394e96bf3aSLandon J. Fuller if (value & BHND_CCS_HTAVAIL)
11404e96bf3aSLandon J. Fuller fval |= BHND_CCS0_HTAVAIL;
11414e96bf3aSLandon J. Fuller
11424e96bf3aSLandon J. Fuller if (mask & BHND_CCS_ALPAVAIL)
11434e96bf3aSLandon J. Fuller fmask |= BHND_CCS0_ALPAVAIL;
11444e96bf3aSLandon J. Fuller if (value & BHND_CCS_ALPAVAIL)
11454e96bf3aSLandon J. Fuller fval |= BHND_CCS0_ALPAVAIL;
11464e96bf3aSLandon J. Fuller
11474e96bf3aSLandon J. Fuller mask = fmask;
11484e96bf3aSLandon J. Fuller value = fval;
11494e96bf3aSLandon J. Fuller }
11504e96bf3aSLandon J. Fuller
11514e96bf3aSLandon J. Fuller for (u_int i = 0; i < clkctl->cc_max_latency; i += 10) {
11524e96bf3aSLandon J. Fuller clkst = bhnd_bus_read_4(clkctl->cc_res, clkctl->cc_res_offset);
11534e96bf3aSLandon J. Fuller if ((clkst & mask) == (value & mask))
11544e96bf3aSLandon J. Fuller return (0);
11554e96bf3aSLandon J. Fuller
11564e96bf3aSLandon J. Fuller DELAY(10);
11574e96bf3aSLandon J. Fuller }
11584e96bf3aSLandon J. Fuller
11594e96bf3aSLandon J. Fuller device_printf(clkctl->cc_dev, "clkst wait timeout (value=%#x, "
11604e96bf3aSLandon J. Fuller "mask=%#x)\n", value, mask);
11614e96bf3aSLandon J. Fuller
11624e96bf3aSLandon J. Fuller return (ETIMEDOUT);
11634e96bf3aSLandon J. Fuller }
11644e96bf3aSLandon J. Fuller
11654e96bf3aSLandon J. Fuller /**
11661728aef2SLandon J. Fuller * Read an NVRAM variable's NUL-terminated string value.
11671728aef2SLandon J. Fuller *
11681728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
11691728aef2SLandon J. Fuller * @param name The NVRAM variable name.
11701728aef2SLandon J. Fuller * @param[out] buf A buffer large enough to hold @p len bytes. On
11711728aef2SLandon J. Fuller * success, the NUL-terminated string value will be
11721728aef2SLandon J. Fuller * written to this buffer. This argment may be NULL if
11731728aef2SLandon J. Fuller * the value is not desired.
11741728aef2SLandon J. Fuller * @param len The maximum capacity of @p buf.
11751728aef2SLandon J. Fuller * @param[out] rlen On success, will be set to the actual size of
11761728aef2SLandon J. Fuller * the requested value (including NUL termination). This
11771728aef2SLandon J. Fuller * argment may be NULL if the size is not desired.
11781728aef2SLandon J. Fuller *
11791728aef2SLandon J. Fuller * @retval 0 success
11801728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
11811728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
11821728aef2SLandon J. Fuller * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
11831728aef2SLandon J. Fuller * small to hold the requested value.
11841728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a valid
11851728aef2SLandon J. Fuller * string representation.
11861728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow @p type.
11871728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
11881728aef2SLandon J. Fuller * error code will be returned.
11891728aef2SLandon J. Fuller */
11901728aef2SLandon J. Fuller int
bhnd_nvram_getvar_str(device_t dev,const char * name,char * buf,size_t len,size_t * rlen)11911728aef2SLandon J. Fuller bhnd_nvram_getvar_str(device_t dev, const char *name, char *buf, size_t len,
11921728aef2SLandon J. Fuller size_t *rlen)
11931728aef2SLandon J. Fuller {
11941728aef2SLandon J. Fuller size_t larg;
11951728aef2SLandon J. Fuller int error;
11961728aef2SLandon J. Fuller
11971728aef2SLandon J. Fuller larg = len;
119877cb4d3eSLandon J. Fuller error = bhnd_nvram_getvar(dev, name, buf, &larg,
119977cb4d3eSLandon J. Fuller BHND_NVRAM_TYPE_STRING);
12001728aef2SLandon J. Fuller if (rlen != NULL)
12011728aef2SLandon J. Fuller *rlen = larg;
12021728aef2SLandon J. Fuller
12031728aef2SLandon J. Fuller return (error);
12041728aef2SLandon J. Fuller }
12051728aef2SLandon J. Fuller
12061728aef2SLandon J. Fuller /**
12071728aef2SLandon J. Fuller * Read an NVRAM variable's unsigned integer value.
12081728aef2SLandon J. Fuller *
12091728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
12101728aef2SLandon J. Fuller * @param name The NVRAM variable name.
12111728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
12121728aef2SLandon J. Fuller * to this pointer.
12131728aef2SLandon J. Fuller * @param width The output integer type width (1, 2, or
12141728aef2SLandon J. Fuller * 4 bytes).
12151728aef2SLandon J. Fuller *
12161728aef2SLandon J. Fuller * @retval 0 success
12171728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
12181728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
12191728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
12201728aef2SLandon J. Fuller * a valid unsigned integer representation.
12211728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow) an
12221728aef2SLandon J. Fuller * unsigned representation of the given @p width.
12231728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
12241728aef2SLandon J. Fuller * error code will be returned.
12251728aef2SLandon J. Fuller */
12261728aef2SLandon J. Fuller int
bhnd_nvram_getvar_uint(device_t dev,const char * name,void * value,int width)12271728aef2SLandon J. Fuller bhnd_nvram_getvar_uint(device_t dev, const char *name, void *value, int width)
12281728aef2SLandon J. Fuller {
12291728aef2SLandon J. Fuller bhnd_nvram_type type;
12301728aef2SLandon J. Fuller size_t len;
12311728aef2SLandon J. Fuller
12321728aef2SLandon J. Fuller switch (width) {
12331728aef2SLandon J. Fuller case 1:
12341728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_UINT8;
12351728aef2SLandon J. Fuller break;
12361728aef2SLandon J. Fuller case 2:
12371728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_UINT16;
12381728aef2SLandon J. Fuller break;
12391728aef2SLandon J. Fuller case 4:
12401728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_UINT32;
12411728aef2SLandon J. Fuller break;
12421728aef2SLandon J. Fuller default:
12431728aef2SLandon J. Fuller device_printf(dev, "unsupported NVRAM integer width: %d\n",
12441728aef2SLandon J. Fuller width);
12451728aef2SLandon J. Fuller return (EINVAL);
12461728aef2SLandon J. Fuller }
12471728aef2SLandon J. Fuller
12481728aef2SLandon J. Fuller len = width;
12491728aef2SLandon J. Fuller return (bhnd_nvram_getvar(dev, name, value, &len, type));
12501728aef2SLandon J. Fuller }
12511728aef2SLandon J. Fuller
12521728aef2SLandon J. Fuller /**
12531728aef2SLandon J. Fuller * Read an NVRAM variable's unsigned 8-bit integer value.
12541728aef2SLandon J. Fuller *
12551728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
12561728aef2SLandon J. Fuller * @param name The NVRAM variable name.
12571728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
12581728aef2SLandon J. Fuller * to this pointer.
12591728aef2SLandon J. Fuller *
12601728aef2SLandon J. Fuller * @retval 0 success
12611728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
12621728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
12631728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
12641728aef2SLandon J. Fuller * a valid unsigned integer representation.
12651728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow) uint8_t.
12661728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
12671728aef2SLandon J. Fuller * error code will be returned.
12681728aef2SLandon J. Fuller */
12691728aef2SLandon J. Fuller int
bhnd_nvram_getvar_uint8(device_t dev,const char * name,uint8_t * value)12701728aef2SLandon J. Fuller bhnd_nvram_getvar_uint8(device_t dev, const char *name, uint8_t *value)
12711728aef2SLandon J. Fuller {
12721728aef2SLandon J. Fuller return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
12731728aef2SLandon J. Fuller }
12741728aef2SLandon J. Fuller
12751728aef2SLandon J. Fuller /**
12761728aef2SLandon J. Fuller * Read an NVRAM variable's unsigned 16-bit integer value.
12771728aef2SLandon J. Fuller *
12781728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
12791728aef2SLandon J. Fuller * @param name The NVRAM variable name.
12801728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
12811728aef2SLandon J. Fuller * to this pointer.
12821728aef2SLandon J. Fuller *
12831728aef2SLandon J. Fuller * @retval 0 success
12841728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
12851728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
12861728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
12871728aef2SLandon J. Fuller * a valid unsigned integer representation.
12881728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow)
12891728aef2SLandon J. Fuller * uint16_t.
12901728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
12911728aef2SLandon J. Fuller * error code will be returned.
12921728aef2SLandon J. Fuller */
12931728aef2SLandon J. Fuller int
bhnd_nvram_getvar_uint16(device_t dev,const char * name,uint16_t * value)12941728aef2SLandon J. Fuller bhnd_nvram_getvar_uint16(device_t dev, const char *name, uint16_t *value)
12951728aef2SLandon J. Fuller {
12961728aef2SLandon J. Fuller return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
12971728aef2SLandon J. Fuller }
12981728aef2SLandon J. Fuller
12991728aef2SLandon J. Fuller /**
13001728aef2SLandon J. Fuller * Read an NVRAM variable's unsigned 32-bit integer value.
13011728aef2SLandon J. Fuller *
13021728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
13031728aef2SLandon J. Fuller * @param name The NVRAM variable name.
13041728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
13051728aef2SLandon J. Fuller * to this pointer.
13061728aef2SLandon J. Fuller *
13071728aef2SLandon J. Fuller * @retval 0 success
13081728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
13091728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
13101728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
13111728aef2SLandon J. Fuller * a valid unsigned integer representation.
13121728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow)
13131728aef2SLandon J. Fuller * uint32_t.
13141728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
13151728aef2SLandon J. Fuller * error code will be returned.
13161728aef2SLandon J. Fuller */
13171728aef2SLandon J. Fuller int
bhnd_nvram_getvar_uint32(device_t dev,const char * name,uint32_t * value)13181728aef2SLandon J. Fuller bhnd_nvram_getvar_uint32(device_t dev, const char *name, uint32_t *value)
13191728aef2SLandon J. Fuller {
13201728aef2SLandon J. Fuller return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
13211728aef2SLandon J. Fuller }
13221728aef2SLandon J. Fuller
13231728aef2SLandon J. Fuller /**
13241728aef2SLandon J. Fuller * Read an NVRAM variable's signed integer value.
13251728aef2SLandon J. Fuller *
13261728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
13271728aef2SLandon J. Fuller * @param name The NVRAM variable name.
13281728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
13291728aef2SLandon J. Fuller * to this pointer.
13301728aef2SLandon J. Fuller * @param width The output integer type width (1, 2, or
13311728aef2SLandon J. Fuller * 4 bytes).
13321728aef2SLandon J. Fuller *
13331728aef2SLandon J. Fuller * @retval 0 success
13341728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
13351728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
13361728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
13371728aef2SLandon J. Fuller * a valid integer representation.
13381728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow) an
13391728aef2SLandon J. Fuller * signed representation of the given @p width.
13401728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
13411728aef2SLandon J. Fuller * error code will be returned.
13421728aef2SLandon J. Fuller */
13431728aef2SLandon J. Fuller int
bhnd_nvram_getvar_int(device_t dev,const char * name,void * value,int width)13441728aef2SLandon J. Fuller bhnd_nvram_getvar_int(device_t dev, const char *name, void *value, int width)
13451728aef2SLandon J. Fuller {
13461728aef2SLandon J. Fuller bhnd_nvram_type type;
13471728aef2SLandon J. Fuller size_t len;
13481728aef2SLandon J. Fuller
13491728aef2SLandon J. Fuller switch (width) {
13501728aef2SLandon J. Fuller case 1:
13511728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_INT8;
13521728aef2SLandon J. Fuller break;
13531728aef2SLandon J. Fuller case 2:
13541728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_INT16;
13551728aef2SLandon J. Fuller break;
13561728aef2SLandon J. Fuller case 4:
13571728aef2SLandon J. Fuller type = BHND_NVRAM_TYPE_INT32;
13581728aef2SLandon J. Fuller break;
13591728aef2SLandon J. Fuller default:
13601728aef2SLandon J. Fuller device_printf(dev, "unsupported NVRAM integer width: %d\n",
13611728aef2SLandon J. Fuller width);
13621728aef2SLandon J. Fuller return (EINVAL);
13631728aef2SLandon J. Fuller }
13641728aef2SLandon J. Fuller
13651728aef2SLandon J. Fuller len = width;
13661728aef2SLandon J. Fuller return (bhnd_nvram_getvar(dev, name, value, &len, type));
13671728aef2SLandon J. Fuller }
13681728aef2SLandon J. Fuller
13691728aef2SLandon J. Fuller /**
13701728aef2SLandon J. Fuller * Read an NVRAM variable's signed 8-bit integer value.
13711728aef2SLandon J. Fuller *
13721728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
13731728aef2SLandon J. Fuller * @param name The NVRAM variable name.
13741728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
13751728aef2SLandon J. Fuller * to this pointer.
13761728aef2SLandon J. Fuller *
13771728aef2SLandon J. Fuller * @retval 0 success
13781728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
13791728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
13801728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
13811728aef2SLandon J. Fuller * a valid integer representation.
13821728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow) int8_t.
13831728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
13841728aef2SLandon J. Fuller * error code will be returned.
13851728aef2SLandon J. Fuller */
13861728aef2SLandon J. Fuller int
bhnd_nvram_getvar_int8(device_t dev,const char * name,int8_t * value)13871728aef2SLandon J. Fuller bhnd_nvram_getvar_int8(device_t dev, const char *name, int8_t *value)
13881728aef2SLandon J. Fuller {
13891728aef2SLandon J. Fuller return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
13901728aef2SLandon J. Fuller }
13911728aef2SLandon J. Fuller
13921728aef2SLandon J. Fuller /**
13931728aef2SLandon J. Fuller * Read an NVRAM variable's signed 16-bit integer value.
13941728aef2SLandon J. Fuller *
13951728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
13961728aef2SLandon J. Fuller * @param name The NVRAM variable name.
13971728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
13981728aef2SLandon J. Fuller * to this pointer.
13991728aef2SLandon J. Fuller *
14001728aef2SLandon J. Fuller * @retval 0 success
14011728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
14021728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
14031728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
14041728aef2SLandon J. Fuller * a valid integer representation.
14051728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow)
14061728aef2SLandon J. Fuller * int16_t.
14071728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
14081728aef2SLandon J. Fuller * error code will be returned.
14091728aef2SLandon J. Fuller */
14101728aef2SLandon J. Fuller int
bhnd_nvram_getvar_int16(device_t dev,const char * name,int16_t * value)14111728aef2SLandon J. Fuller bhnd_nvram_getvar_int16(device_t dev, const char *name, int16_t *value)
14121728aef2SLandon J. Fuller {
14131728aef2SLandon J. Fuller return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
14141728aef2SLandon J. Fuller }
14151728aef2SLandon J. Fuller
14161728aef2SLandon J. Fuller /**
14171728aef2SLandon J. Fuller * Read an NVRAM variable's signed 32-bit integer value.
14181728aef2SLandon J. Fuller *
14191728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
14201728aef2SLandon J. Fuller * @param name The NVRAM variable name.
14211728aef2SLandon J. Fuller * @param[out] value On success, the requested value will be written
14221728aef2SLandon J. Fuller * to this pointer.
14231728aef2SLandon J. Fuller *
14241728aef2SLandon J. Fuller * @retval 0 success
14251728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
14261728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
14271728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
14281728aef2SLandon J. Fuller * a valid integer representation.
14291728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow)
14301728aef2SLandon J. Fuller * int32_t.
14311728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
14321728aef2SLandon J. Fuller * error code will be returned.
14331728aef2SLandon J. Fuller */
14341728aef2SLandon J. Fuller int
bhnd_nvram_getvar_int32(device_t dev,const char * name,int32_t * value)14351728aef2SLandon J. Fuller bhnd_nvram_getvar_int32(device_t dev, const char *name, int32_t *value)
14361728aef2SLandon J. Fuller {
14371728aef2SLandon J. Fuller return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
14381728aef2SLandon J. Fuller }
14391728aef2SLandon J. Fuller
14401728aef2SLandon J. Fuller /**
14411728aef2SLandon J. Fuller * Read an NVRAM variable's array value.
14421728aef2SLandon J. Fuller *
14431728aef2SLandon J. Fuller * @param dev A bhnd bus child device.
14441728aef2SLandon J. Fuller * @param name The NVRAM variable name.
14451728aef2SLandon J. Fuller * @param[out] buf A buffer large enough to hold @p size bytes.
14461728aef2SLandon J. Fuller * On success, the requested value will be written
14471728aef2SLandon J. Fuller * to this buffer.
14481728aef2SLandon J. Fuller * @param[in,out] size The required number of bytes to write to
14491728aef2SLandon J. Fuller * @p buf.
14501728aef2SLandon J. Fuller * @param type The desired array element data representation.
14511728aef2SLandon J. Fuller *
14521728aef2SLandon J. Fuller * @retval 0 success
14531728aef2SLandon J. Fuller * @retval ENOENT The requested variable was not found.
14541728aef2SLandon J. Fuller * @retval ENODEV No valid NVRAM source could be found.
14551728aef2SLandon J. Fuller * @retval ENXIO If less than @p size bytes are available.
14561728aef2SLandon J. Fuller * @retval ENOMEM If a buffer of @p size is too small to hold the
14571728aef2SLandon J. Fuller * requested value.
14581728aef2SLandon J. Fuller * @retval EFTYPE If the variable data cannot be coerced to a
14591728aef2SLandon J. Fuller * a valid instance of @p type.
14601728aef2SLandon J. Fuller * @retval ERANGE If value coercion would overflow (or underflow) a
14611728aef2SLandon J. Fuller * representation of @p type.
14621728aef2SLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
14631728aef2SLandon J. Fuller * error code will be returned.
14641728aef2SLandon J. Fuller */
14651728aef2SLandon J. Fuller int
bhnd_nvram_getvar_array(device_t dev,const char * name,void * buf,size_t size,bhnd_nvram_type type)14661728aef2SLandon J. Fuller bhnd_nvram_getvar_array(device_t dev, const char *name, void *buf, size_t size,
14671728aef2SLandon J. Fuller bhnd_nvram_type type)
14681728aef2SLandon J. Fuller {
14691728aef2SLandon J. Fuller size_t nbytes;
14701728aef2SLandon J. Fuller int error;
14711728aef2SLandon J. Fuller
14721728aef2SLandon J. Fuller /* Attempt read */
14731728aef2SLandon J. Fuller nbytes = size;
14741728aef2SLandon J. Fuller if ((error = bhnd_nvram_getvar(dev, name, buf, &nbytes, type)))
14751728aef2SLandon J. Fuller return (error);
14761728aef2SLandon J. Fuller
14771728aef2SLandon J. Fuller /* Verify that the expected number of bytes were fetched */
14781728aef2SLandon J. Fuller if (nbytes < size)
14791728aef2SLandon J. Fuller return (ENXIO);
14801728aef2SLandon J. Fuller
14811728aef2SLandon J. Fuller return (0);
14821728aef2SLandon J. Fuller }
14831728aef2SLandon J. Fuller
14841728aef2SLandon J. Fuller /**
14858e35bf83SLandon J. Fuller * Initialize a service provider registry.
14868e35bf83SLandon J. Fuller *
14878e35bf83SLandon J. Fuller * @param bsr The service registry to initialize.
14888e35bf83SLandon J. Fuller *
14898e35bf83SLandon J. Fuller * @retval 0 success
14908e35bf83SLandon J. Fuller * @retval non-zero if an error occurs initializing the service registry,
14918e35bf83SLandon J. Fuller * a regular unix error code will be returned.
14928e35bf83SLandon J. Fuller
14938e35bf83SLandon J. Fuller */
14948e35bf83SLandon J. Fuller int
bhnd_service_registry_init(struct bhnd_service_registry * bsr)14958e35bf83SLandon J. Fuller bhnd_service_registry_init(struct bhnd_service_registry *bsr)
14968e35bf83SLandon J. Fuller {
14978e35bf83SLandon J. Fuller STAILQ_INIT(&bsr->entries);
14988e35bf83SLandon J. Fuller mtx_init(&bsr->lock, "bhnd_service_registry lock", NULL, MTX_DEF);
14998e35bf83SLandon J. Fuller
15008e35bf83SLandon J. Fuller return (0);
15018e35bf83SLandon J. Fuller }
15028e35bf83SLandon J. Fuller
15038e35bf83SLandon J. Fuller /**
15048e35bf83SLandon J. Fuller * Release all resources held by @p bsr.
15058e35bf83SLandon J. Fuller *
15068e35bf83SLandon J. Fuller * @param bsr A service registry instance previously successfully
15078e35bf83SLandon J. Fuller * initialized via bhnd_service_registry_init().
15088e35bf83SLandon J. Fuller *
15098e35bf83SLandon J. Fuller * @retval 0 success
15108e35bf83SLandon J. Fuller * @retval EBUSY if active references to service providers registered
15118e35bf83SLandon J. Fuller * with @p bsr exist.
15128e35bf83SLandon J. Fuller */
15138e35bf83SLandon J. Fuller int
bhnd_service_registry_fini(struct bhnd_service_registry * bsr)15148e35bf83SLandon J. Fuller bhnd_service_registry_fini(struct bhnd_service_registry *bsr)
15158e35bf83SLandon J. Fuller {
15168e35bf83SLandon J. Fuller struct bhnd_service_entry *entry, *enext;
15178e35bf83SLandon J. Fuller
15188e35bf83SLandon J. Fuller /* Remove everthing we can */
15198e35bf83SLandon J. Fuller mtx_lock(&bsr->lock);
15208e35bf83SLandon J. Fuller STAILQ_FOREACH_SAFE(entry, &bsr->entries, link, enext) {
15218e35bf83SLandon J. Fuller if (entry->refs > 0)
15228e35bf83SLandon J. Fuller continue;
15238e35bf83SLandon J. Fuller
15248e35bf83SLandon J. Fuller STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry, link);
15258e35bf83SLandon J. Fuller free(entry, M_BHND);
15268e35bf83SLandon J. Fuller }
15278e35bf83SLandon J. Fuller
15288e35bf83SLandon J. Fuller if (!STAILQ_EMPTY(&bsr->entries)) {
15298e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
15308e35bf83SLandon J. Fuller return (EBUSY);
15318e35bf83SLandon J. Fuller }
15328e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
15338e35bf83SLandon J. Fuller
15348e35bf83SLandon J. Fuller mtx_destroy(&bsr->lock);
15358e35bf83SLandon J. Fuller return (0);
15368e35bf83SLandon J. Fuller }
15378e35bf83SLandon J. Fuller
15388e35bf83SLandon J. Fuller /**
15398e35bf83SLandon J. Fuller * Register a @p provider for the given @p service.
15408e35bf83SLandon J. Fuller *
15418e35bf83SLandon J. Fuller * @param bsr Service registry to be modified.
15428e35bf83SLandon J. Fuller * @param provider Service provider to register.
15438e35bf83SLandon J. Fuller * @param service Service for which @p provider will be registered.
15448e35bf83SLandon J. Fuller * @param flags Service provider flags (see BHND_SPF_*).
15458e35bf83SLandon J. Fuller *
15468e35bf83SLandon J. Fuller * @retval 0 success
15478e35bf83SLandon J. Fuller * @retval EEXIST if an entry for @p service already exists.
15488e35bf83SLandon J. Fuller * @retval EINVAL if @p service is BHND_SERVICE_ANY.
15498e35bf83SLandon J. Fuller * @retval non-zero if registering @p provider otherwise fails, a regular
15508e35bf83SLandon J. Fuller * unix error code will be returned.
15518e35bf83SLandon J. Fuller */
15528e35bf83SLandon J. Fuller int
bhnd_service_registry_add(struct bhnd_service_registry * bsr,device_t provider,bhnd_service_t service,uint32_t flags)15538e35bf83SLandon J. Fuller bhnd_service_registry_add(struct bhnd_service_registry *bsr, device_t provider,
15548e35bf83SLandon J. Fuller bhnd_service_t service, uint32_t flags)
15558e35bf83SLandon J. Fuller {
15568e35bf83SLandon J. Fuller struct bhnd_service_entry *entry;
15578e35bf83SLandon J. Fuller
15588e35bf83SLandon J. Fuller if (service == BHND_SERVICE_ANY)
15598e35bf83SLandon J. Fuller return (EINVAL);
15608e35bf83SLandon J. Fuller
15618e35bf83SLandon J. Fuller mtx_lock(&bsr->lock);
15628e35bf83SLandon J. Fuller
15638e35bf83SLandon J. Fuller /* Is a service provider already registered? */
15648e35bf83SLandon J. Fuller STAILQ_FOREACH(entry, &bsr->entries, link) {
15658e35bf83SLandon J. Fuller if (entry->service == service) {
15668e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
15678e35bf83SLandon J. Fuller return (EEXIST);
15688e35bf83SLandon J. Fuller }
15698e35bf83SLandon J. Fuller }
15708e35bf83SLandon J. Fuller
15718e35bf83SLandon J. Fuller /* Initialize and insert our new entry */
15728e35bf83SLandon J. Fuller entry = malloc(sizeof(*entry), M_BHND, M_NOWAIT);
15738e35bf83SLandon J. Fuller if (entry == NULL) {
15748e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
15758e35bf83SLandon J. Fuller return (ENOMEM);
15768e35bf83SLandon J. Fuller }
15778e35bf83SLandon J. Fuller
15788e35bf83SLandon J. Fuller entry->provider = provider;
15798e35bf83SLandon J. Fuller entry->service = service;
15808e35bf83SLandon J. Fuller entry->flags = flags;
15818e35bf83SLandon J. Fuller refcount_init(&entry->refs, 0);
15828e35bf83SLandon J. Fuller
15838e35bf83SLandon J. Fuller STAILQ_INSERT_HEAD(&bsr->entries, entry, link);
15848e35bf83SLandon J. Fuller
15858e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
15868e35bf83SLandon J. Fuller return (0);
15878e35bf83SLandon J. Fuller }
15888e35bf83SLandon J. Fuller
15898e35bf83SLandon J. Fuller /**
15908e35bf83SLandon J. Fuller * Free an unreferenced registry entry.
15918e35bf83SLandon J. Fuller *
15928e35bf83SLandon J. Fuller * @param entry The entry to be deallocated.
15938e35bf83SLandon J. Fuller */
15948e35bf83SLandon J. Fuller static void
bhnd_service_registry_free_entry(struct bhnd_service_entry * entry)15958e35bf83SLandon J. Fuller bhnd_service_registry_free_entry(struct bhnd_service_entry *entry)
15968e35bf83SLandon J. Fuller {
15978e35bf83SLandon J. Fuller KASSERT(entry->refs == 0, ("provider has active references"));
15988e35bf83SLandon J. Fuller free(entry, M_BHND);
15998e35bf83SLandon J. Fuller }
16008e35bf83SLandon J. Fuller
16018e35bf83SLandon J. Fuller /**
16028e35bf83SLandon J. Fuller * Attempt to remove the @p service provider registration for @p provider.
16038e35bf83SLandon J. Fuller *
16048e35bf83SLandon J. Fuller * @param bsr The service registry to be modified.
16058e35bf83SLandon J. Fuller * @param provider The service provider to be deregistered.
16068e35bf83SLandon J. Fuller * @param service The service for which @p provider will be deregistered,
16078e35bf83SLandon J. Fuller * or BHND_SERVICE_ANY to remove all service
16088e35bf83SLandon J. Fuller * registrations for @p provider.
16098e35bf83SLandon J. Fuller *
16108e35bf83SLandon J. Fuller * @retval 0 success
161105ed3f90SLandon J. Fuller * @retval EBUSY if active references to @p provider exist; see
16128e35bf83SLandon J. Fuller * bhnd_service_registry_retain() and
16138e35bf83SLandon J. Fuller * bhnd_service_registry_release().
16148e35bf83SLandon J. Fuller */
16158e35bf83SLandon J. Fuller int
bhnd_service_registry_remove(struct bhnd_service_registry * bsr,device_t provider,bhnd_service_t service)16168e35bf83SLandon J. Fuller bhnd_service_registry_remove(struct bhnd_service_registry *bsr,
16178e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
16188e35bf83SLandon J. Fuller {
16198e35bf83SLandon J. Fuller struct bhnd_service_entry *entry, *enext;
16208e35bf83SLandon J. Fuller
16218e35bf83SLandon J. Fuller mtx_lock(&bsr->lock);
16228e35bf83SLandon J. Fuller
16238e35bf83SLandon J. Fuller #define BHND_PROV_MATCH(_e) \
16248e35bf83SLandon J. Fuller ((_e)->provider == provider && \
16258e35bf83SLandon J. Fuller (service == BHND_SERVICE_ANY || (_e)->service == service))
16268e35bf83SLandon J. Fuller
16278e35bf83SLandon J. Fuller /* Validate matching provider entries before making any
16288e35bf83SLandon J. Fuller * modifications */
16298e35bf83SLandon J. Fuller STAILQ_FOREACH(entry, &bsr->entries, link) {
16308e35bf83SLandon J. Fuller /* Skip non-matching entries */
16318e35bf83SLandon J. Fuller if (!BHND_PROV_MATCH(entry))
16328e35bf83SLandon J. Fuller continue;
16338e35bf83SLandon J. Fuller
16348e35bf83SLandon J. Fuller /* Entry is in use? */
16358e35bf83SLandon J. Fuller if (entry->refs > 0) {
16368e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
16378e35bf83SLandon J. Fuller return (EBUSY);
16388e35bf83SLandon J. Fuller }
16398e35bf83SLandon J. Fuller }
16408e35bf83SLandon J. Fuller
16418e35bf83SLandon J. Fuller /* We can now safely remove matching entries */
16428e35bf83SLandon J. Fuller STAILQ_FOREACH_SAFE(entry, &bsr->entries, link, enext) {
16438e35bf83SLandon J. Fuller /* Skip non-matching entries */
16448e35bf83SLandon J. Fuller if (!BHND_PROV_MATCH(entry))
16458e35bf83SLandon J. Fuller continue;
16468e35bf83SLandon J. Fuller
16478e35bf83SLandon J. Fuller /* Remove from list */
16488e35bf83SLandon J. Fuller STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry, link);
16498e35bf83SLandon J. Fuller
16508e35bf83SLandon J. Fuller /* Free provider entry */
16518e35bf83SLandon J. Fuller bhnd_service_registry_free_entry(entry);
16528e35bf83SLandon J. Fuller }
16538e35bf83SLandon J. Fuller #undef BHND_PROV_MATCH
16548e35bf83SLandon J. Fuller
16558e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
16568e35bf83SLandon J. Fuller return (0);
16578e35bf83SLandon J. Fuller }
16588e35bf83SLandon J. Fuller
16598e35bf83SLandon J. Fuller /**
16608e35bf83SLandon J. Fuller * Retain and return a reference to a registered @p service provider, if any.
16618e35bf83SLandon J. Fuller *
16628e35bf83SLandon J. Fuller * @param bsr The service registry to be queried.
16638e35bf83SLandon J. Fuller * @param service The service for which a provider should be returned.
16648e35bf83SLandon J. Fuller *
16658e35bf83SLandon J. Fuller * On success, the caller assumes ownership the returned provider, and
16668e35bf83SLandon J. Fuller * is responsible for releasing this reference via
16678e35bf83SLandon J. Fuller * bhnd_service_registry_release().
16688e35bf83SLandon J. Fuller *
16698e35bf83SLandon J. Fuller * @retval device_t success
16708e35bf83SLandon J. Fuller * @retval NULL if no provider is registered for @p service.
16718e35bf83SLandon J. Fuller */
16728e35bf83SLandon J. Fuller device_t
bhnd_service_registry_retain(struct bhnd_service_registry * bsr,bhnd_service_t service)16738e35bf83SLandon J. Fuller bhnd_service_registry_retain(struct bhnd_service_registry *bsr,
16748e35bf83SLandon J. Fuller bhnd_service_t service)
16758e35bf83SLandon J. Fuller {
16768e35bf83SLandon J. Fuller struct bhnd_service_entry *entry;
16778e35bf83SLandon J. Fuller
16788e35bf83SLandon J. Fuller mtx_lock(&bsr->lock);
16798e35bf83SLandon J. Fuller STAILQ_FOREACH(entry, &bsr->entries, link) {
16808e35bf83SLandon J. Fuller if (entry->service != service)
16818e35bf83SLandon J. Fuller continue;
16828e35bf83SLandon J. Fuller
16838e35bf83SLandon J. Fuller /* With a live refcount, entry is gauranteed to remain alive
16848e35bf83SLandon J. Fuller * after we release our lock */
16858e35bf83SLandon J. Fuller refcount_acquire(&entry->refs);
16868e35bf83SLandon J. Fuller
16878e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
16888e35bf83SLandon J. Fuller return (entry->provider);
16898e35bf83SLandon J. Fuller }
16908e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
16918e35bf83SLandon J. Fuller
16928e35bf83SLandon J. Fuller /* Not found */
16938e35bf83SLandon J. Fuller return (NULL);
16948e35bf83SLandon J. Fuller }
16958e35bf83SLandon J. Fuller
16968e35bf83SLandon J. Fuller /**
16978e35bf83SLandon J. Fuller * Release a reference to a service provider previously returned by
16988e35bf83SLandon J. Fuller * bhnd_service_registry_retain().
16998e35bf83SLandon J. Fuller *
17008e35bf83SLandon J. Fuller * If this is the last reference to an inherited service provider registration
170105ed3f90SLandon J. Fuller * (see BHND_SPF_INHERITED), the registration will also be removed, and
17028e35bf83SLandon J. Fuller * true will be returned.
17038e35bf83SLandon J. Fuller *
17048e35bf83SLandon J. Fuller * @param bsr The service registry from which @p provider
17058e35bf83SLandon J. Fuller * was returned.
17068e35bf83SLandon J. Fuller * @param provider The provider to be released.
17078e35bf83SLandon J. Fuller * @param service The service for which @p provider was previously
17088e35bf83SLandon J. Fuller * retained.
17098e35bf83SLandon J. Fuller * @retval true The inherited service provider registration was removed;
17108e35bf83SLandon J. Fuller * the caller should release its own reference to the
17118e35bf83SLandon J. Fuller * provider.
17128e35bf83SLandon J. Fuller * @retval false The service provider was not inherited, or active
17138e35bf83SLandon J. Fuller * references to the provider remain.
171405ed3f90SLandon J. Fuller *
171505ed3f90SLandon J. Fuller * @see BHND_SPF_INHERITED
17168e35bf83SLandon J. Fuller */
17178e35bf83SLandon J. Fuller bool
bhnd_service_registry_release(struct bhnd_service_registry * bsr,device_t provider,bhnd_service_t service)17188e35bf83SLandon J. Fuller bhnd_service_registry_release(struct bhnd_service_registry *bsr,
17198e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
17208e35bf83SLandon J. Fuller {
17218e35bf83SLandon J. Fuller struct bhnd_service_entry *entry;
17228e35bf83SLandon J. Fuller
17238e35bf83SLandon J. Fuller /* Exclusive lock, as we need to prevent any new references to the
17248e35bf83SLandon J. Fuller * entry from being taken if it's to be removed */
17258e35bf83SLandon J. Fuller mtx_lock(&bsr->lock);
17268e35bf83SLandon J. Fuller STAILQ_FOREACH(entry, &bsr->entries, link) {
17278e35bf83SLandon J. Fuller bool removed;
17288e35bf83SLandon J. Fuller
17298e35bf83SLandon J. Fuller if (entry->provider != provider)
17308e35bf83SLandon J. Fuller continue;
17318e35bf83SLandon J. Fuller
17328e35bf83SLandon J. Fuller if (entry->service != service)
17338e35bf83SLandon J. Fuller continue;
17348e35bf83SLandon J. Fuller
17358e35bf83SLandon J. Fuller if (refcount_release(&entry->refs) &&
17368e35bf83SLandon J. Fuller (entry->flags & BHND_SPF_INHERITED))
17378e35bf83SLandon J. Fuller {
17388e35bf83SLandon J. Fuller /* If an inherited entry is no longer actively
17398e35bf83SLandon J. Fuller * referenced, remove the local registration and inform
17408e35bf83SLandon J. Fuller * the caller. */
17418e35bf83SLandon J. Fuller STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry,
17428e35bf83SLandon J. Fuller link);
17438e35bf83SLandon J. Fuller bhnd_service_registry_free_entry(entry);
17448e35bf83SLandon J. Fuller removed = true;
17458e35bf83SLandon J. Fuller } else {
17468e35bf83SLandon J. Fuller removed = false;
17478e35bf83SLandon J. Fuller }
17488e35bf83SLandon J. Fuller
17498e35bf83SLandon J. Fuller mtx_unlock(&bsr->lock);
17508e35bf83SLandon J. Fuller return (removed);
17518e35bf83SLandon J. Fuller }
17528e35bf83SLandon J. Fuller
17538e35bf83SLandon J. Fuller /* Caller owns a reference, but no such provider is registered? */
17548e35bf83SLandon J. Fuller panic("invalid service provider reference");
17558e35bf83SLandon J. Fuller }
17568e35bf83SLandon J. Fuller
17578e35bf83SLandon J. Fuller /**
175836e4410aSAdrian Chadd * Using the bhnd(4) bus-level core information and a custom core name,
175936e4410aSAdrian Chadd * populate @p dev's device description.
17604ad7e9b0SAdrian Chadd *
17614ad7e9b0SAdrian Chadd * @param dev A bhnd-bus attached device.
176205ed3f90SLandon J. Fuller * @param dev_name The core's name (e.g. "SDIO Device Core").
17634ad7e9b0SAdrian Chadd */
17644ad7e9b0SAdrian Chadd void
bhnd_set_custom_core_desc(device_t dev,const char * dev_name)176536e4410aSAdrian Chadd bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
17664ad7e9b0SAdrian Chadd {
17674ad7e9b0SAdrian Chadd const char *vendor_name;
17684ad7e9b0SAdrian Chadd
17694ad7e9b0SAdrian Chadd vendor_name = bhnd_get_vendor_name(dev);
1770*a866a40bSMark Johnston device_set_descf(dev, "%s %s, rev %hhu", vendor_name, dev_name,
17714ad7e9b0SAdrian Chadd bhnd_get_hwrev(dev));
17724ad7e9b0SAdrian Chadd }
1773386fb140SAdrian Chadd
1774386fb140SAdrian Chadd /**
177536e4410aSAdrian Chadd * Using the bhnd(4) bus-level core information, populate @p dev's device
177636e4410aSAdrian Chadd * description.
177736e4410aSAdrian Chadd *
177836e4410aSAdrian Chadd * @param dev A bhnd-bus attached device.
177936e4410aSAdrian Chadd */
178036e4410aSAdrian Chadd void
bhnd_set_default_core_desc(device_t dev)178136e4410aSAdrian Chadd bhnd_set_default_core_desc(device_t dev)
178236e4410aSAdrian Chadd {
178336e4410aSAdrian Chadd bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
178436e4410aSAdrian Chadd }
178536e4410aSAdrian Chadd
17869bb95906SLandon J. Fuller /**
17879bb95906SLandon J. Fuller * Using the bhnd @p chip_id, populate the bhnd(4) bus @p dev's device
17889bb95906SLandon J. Fuller * description.
17899bb95906SLandon J. Fuller *
17909bb95906SLandon J. Fuller * @param dev A bhnd-bus attached device.
179105ed3f90SLandon J. Fuller * @param chip_id The chip identification.
17929bb95906SLandon J. Fuller */
17939bb95906SLandon J. Fuller void
bhnd_set_default_bus_desc(device_t dev,const struct bhnd_chipid * chip_id)17949bb95906SLandon J. Fuller bhnd_set_default_bus_desc(device_t dev, const struct bhnd_chipid *chip_id)
17959bb95906SLandon J. Fuller {
17969bb95906SLandon J. Fuller const char *bus_name;
17979bb95906SLandon J. Fuller char chip_name[BHND_CHIPID_MAX_NAMELEN];
17989bb95906SLandon J. Fuller
17999bb95906SLandon J. Fuller /* Determine chip type's bus name */
18009bb95906SLandon J. Fuller switch (chip_id->chip_type) {
18019bb95906SLandon J. Fuller case BHND_CHIPTYPE_SIBA:
18029bb95906SLandon J. Fuller bus_name = "SIBA bus";
18039bb95906SLandon J. Fuller break;
18049bb95906SLandon J. Fuller case BHND_CHIPTYPE_BCMA:
18059bb95906SLandon J. Fuller case BHND_CHIPTYPE_BCMA_ALT:
18069bb95906SLandon J. Fuller bus_name = "BCMA bus";
18079bb95906SLandon J. Fuller break;
18089bb95906SLandon J. Fuller case BHND_CHIPTYPE_UBUS:
18099bb95906SLandon J. Fuller bus_name = "UBUS bus";
18109bb95906SLandon J. Fuller break;
18119bb95906SLandon J. Fuller default:
18129bb95906SLandon J. Fuller bus_name = "Unknown Type";
18139bb95906SLandon J. Fuller break;
18149bb95906SLandon J. Fuller }
18159bb95906SLandon J. Fuller
18169bb95906SLandon J. Fuller /* Format chip name */
18179bb95906SLandon J. Fuller bhnd_format_chip_id(chip_name, sizeof(chip_name),
18189bb95906SLandon J. Fuller chip_id->chip_id);
18199bb95906SLandon J. Fuller
18209bb95906SLandon J. Fuller /* Format and set device description */
1821*a866a40bSMark Johnston device_set_descf(dev, "%s %s", chip_name, bus_name);
18229bb95906SLandon J. Fuller }
18239bb95906SLandon J. Fuller
182436e4410aSAdrian Chadd /**
18258e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_REGISTER_PROVIDER().
18268e35bf83SLandon J. Fuller *
18278e35bf83SLandon J. Fuller * This implementation delegates the request to the BHND_BUS_REGISTER_PROVIDER()
18288e35bf83SLandon J. Fuller * method on the parent of @p dev. If no parent exists, the implementation
18298e35bf83SLandon J. Fuller * will return an error.
18308e35bf83SLandon J. Fuller */
18318e35bf83SLandon J. Fuller int
bhnd_bus_generic_register_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)18328e35bf83SLandon J. Fuller bhnd_bus_generic_register_provider(device_t dev, device_t child,
18338e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
18348e35bf83SLandon J. Fuller {
18358e35bf83SLandon J. Fuller device_t parent = device_get_parent(dev);
18368e35bf83SLandon J. Fuller
18378e35bf83SLandon J. Fuller if (parent != NULL) {
18388e35bf83SLandon J. Fuller return (BHND_BUS_REGISTER_PROVIDER(parent, child,
18398e35bf83SLandon J. Fuller provider, service));
18408e35bf83SLandon J. Fuller }
18418e35bf83SLandon J. Fuller
18428e35bf83SLandon J. Fuller return (ENXIO);
18438e35bf83SLandon J. Fuller }
18448e35bf83SLandon J. Fuller
18458e35bf83SLandon J. Fuller /**
18468e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_DEREGISTER_PROVIDER().
18478e35bf83SLandon J. Fuller *
18488e35bf83SLandon J. Fuller * This implementation delegates the request to the
18498e35bf83SLandon J. Fuller * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
18508e35bf83SLandon J. Fuller * exists, the implementation will panic.
18518e35bf83SLandon J. Fuller */
18528e35bf83SLandon J. Fuller int
bhnd_bus_generic_deregister_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)18538e35bf83SLandon J. Fuller bhnd_bus_generic_deregister_provider(device_t dev, device_t child,
18548e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
18558e35bf83SLandon J. Fuller {
18568e35bf83SLandon J. Fuller device_t parent = device_get_parent(dev);
18578e35bf83SLandon J. Fuller
18588e35bf83SLandon J. Fuller if (parent != NULL) {
18598e35bf83SLandon J. Fuller return (BHND_BUS_DEREGISTER_PROVIDER(parent, child,
18608e35bf83SLandon J. Fuller provider, service));
18618e35bf83SLandon J. Fuller }
18628e35bf83SLandon J. Fuller
18638e35bf83SLandon J. Fuller panic("missing BHND_BUS_DEREGISTER_PROVIDER()");
18648e35bf83SLandon J. Fuller }
18658e35bf83SLandon J. Fuller
18668e35bf83SLandon J. Fuller /**
18678e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_RETAIN_PROVIDER().
18688e35bf83SLandon J. Fuller *
18698e35bf83SLandon J. Fuller * This implementation delegates the request to the
18708e35bf83SLandon J. Fuller * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
18718e35bf83SLandon J. Fuller * exists, the implementation will return NULL.
18728e35bf83SLandon J. Fuller */
18738e35bf83SLandon J. Fuller device_t
bhnd_bus_generic_retain_provider(device_t dev,device_t child,bhnd_service_t service)18748e35bf83SLandon J. Fuller bhnd_bus_generic_retain_provider(device_t dev, device_t child,
18758e35bf83SLandon J. Fuller bhnd_service_t service)
18768e35bf83SLandon J. Fuller {
18778e35bf83SLandon J. Fuller device_t parent = device_get_parent(dev);
18788e35bf83SLandon J. Fuller
18798e35bf83SLandon J. Fuller if (parent != NULL) {
18808e35bf83SLandon J. Fuller return (BHND_BUS_RETAIN_PROVIDER(parent, child,
18818e35bf83SLandon J. Fuller service));
18828e35bf83SLandon J. Fuller }
18838e35bf83SLandon J. Fuller
18848e35bf83SLandon J. Fuller return (NULL);
18858e35bf83SLandon J. Fuller }
18868e35bf83SLandon J. Fuller
18878e35bf83SLandon J. Fuller /**
18888e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_RELEASE_PROVIDER().
18898e35bf83SLandon J. Fuller *
18908e35bf83SLandon J. Fuller * This implementation delegates the request to the
18918e35bf83SLandon J. Fuller * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
18928e35bf83SLandon J. Fuller * exists, the implementation will panic.
18938e35bf83SLandon J. Fuller */
18948e35bf83SLandon J. Fuller void
bhnd_bus_generic_release_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)18958e35bf83SLandon J. Fuller bhnd_bus_generic_release_provider(device_t dev, device_t child,
18968e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
18978e35bf83SLandon J. Fuller {
18988e35bf83SLandon J. Fuller device_t parent = device_get_parent(dev);
18998e35bf83SLandon J. Fuller
19008e35bf83SLandon J. Fuller if (parent != NULL) {
19018e35bf83SLandon J. Fuller return (BHND_BUS_RELEASE_PROVIDER(parent, child,
19028e35bf83SLandon J. Fuller provider, service));
19038e35bf83SLandon J. Fuller }
19048e35bf83SLandon J. Fuller
19058e35bf83SLandon J. Fuller panic("missing BHND_BUS_RELEASE_PROVIDER()");
19068e35bf83SLandon J. Fuller }
19078e35bf83SLandon J. Fuller
19088e35bf83SLandon J. Fuller /**
19098e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_REGISTER_PROVIDER().
19108e35bf83SLandon J. Fuller *
19118e35bf83SLandon J. Fuller * This implementation uses the bhnd_service_registry_add() function to
19128e35bf83SLandon J. Fuller * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
19138e35bf83SLandon J. Fuller * a suitable service registry to edit.
19148e35bf83SLandon J. Fuller */
19158e35bf83SLandon J. Fuller int
bhnd_bus_generic_sr_register_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)19168e35bf83SLandon J. Fuller bhnd_bus_generic_sr_register_provider(device_t dev, device_t child,
19178e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
19188e35bf83SLandon J. Fuller {
19198e35bf83SLandon J. Fuller struct bhnd_service_registry *bsr;
19208e35bf83SLandon J. Fuller
19218e35bf83SLandon J. Fuller bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
19228e35bf83SLandon J. Fuller
19238e35bf83SLandon J. Fuller KASSERT(bsr != NULL, ("NULL service registry"));
19248e35bf83SLandon J. Fuller
19258e35bf83SLandon J. Fuller return (bhnd_service_registry_add(bsr, provider, service, 0));
19268e35bf83SLandon J. Fuller }
19278e35bf83SLandon J. Fuller
19288e35bf83SLandon J. Fuller /**
19298e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_DEREGISTER_PROVIDER().
19308e35bf83SLandon J. Fuller *
19318e35bf83SLandon J. Fuller * This implementation uses the bhnd_service_registry_remove() function to
19328e35bf83SLandon J. Fuller * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
19338e35bf83SLandon J. Fuller * a suitable service registry to edit.
19348e35bf83SLandon J. Fuller */
19358e35bf83SLandon J. Fuller int
bhnd_bus_generic_sr_deregister_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)19368e35bf83SLandon J. Fuller bhnd_bus_generic_sr_deregister_provider(device_t dev, device_t child,
19378e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
19388e35bf83SLandon J. Fuller {
19398e35bf83SLandon J. Fuller struct bhnd_service_registry *bsr;
19408e35bf83SLandon J. Fuller
19418e35bf83SLandon J. Fuller bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
19428e35bf83SLandon J. Fuller
19438e35bf83SLandon J. Fuller KASSERT(bsr != NULL, ("NULL service registry"));
19448e35bf83SLandon J. Fuller
19458e35bf83SLandon J. Fuller return (bhnd_service_registry_remove(bsr, provider, service));
19468e35bf83SLandon J. Fuller }
19478e35bf83SLandon J. Fuller
19488e35bf83SLandon J. Fuller /**
19498e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_RETAIN_PROVIDER().
19508e35bf83SLandon J. Fuller *
19518e35bf83SLandon J. Fuller * This implementation uses the bhnd_service_registry_retain() function to
19528e35bf83SLandon J. Fuller * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
19538e35bf83SLandon J. Fuller * a suitable service registry.
19548e35bf83SLandon J. Fuller *
19558e35bf83SLandon J. Fuller * If a local provider for the service is not available, and a parent device is
19568e35bf83SLandon J. Fuller * available, this implementation will attempt to fetch and locally register
19578e35bf83SLandon J. Fuller * a service provider reference from the parent of @p dev.
19588e35bf83SLandon J. Fuller */
19598e35bf83SLandon J. Fuller device_t
bhnd_bus_generic_sr_retain_provider(device_t dev,device_t child,bhnd_service_t service)19608e35bf83SLandon J. Fuller bhnd_bus_generic_sr_retain_provider(device_t dev, device_t child,
19618e35bf83SLandon J. Fuller bhnd_service_t service)
19628e35bf83SLandon J. Fuller {
19638e35bf83SLandon J. Fuller struct bhnd_service_registry *bsr;
19648e35bf83SLandon J. Fuller device_t parent, provider;
19658e35bf83SLandon J. Fuller int error;
19668e35bf83SLandon J. Fuller
19678e35bf83SLandon J. Fuller bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
19688e35bf83SLandon J. Fuller KASSERT(bsr != NULL, ("NULL service registry"));
19698e35bf83SLandon J. Fuller
19708e35bf83SLandon J. Fuller /*
19718e35bf83SLandon J. Fuller * Attempt to fetch a service provider reference from either the local
19728e35bf83SLandon J. Fuller * service registry, or if not found, from our parent.
19738e35bf83SLandon J. Fuller *
19748e35bf83SLandon J. Fuller * If we fetch a provider from our parent, we register the provider
19758e35bf83SLandon J. Fuller * with the local service registry to prevent conflicting local
19768e35bf83SLandon J. Fuller * registrations from being added.
19778e35bf83SLandon J. Fuller */
19788e35bf83SLandon J. Fuller while (1) {
19798e35bf83SLandon J. Fuller /* Check the local service registry first */
19808e35bf83SLandon J. Fuller provider = bhnd_service_registry_retain(bsr, service);
19818e35bf83SLandon J. Fuller if (provider != NULL)
19828e35bf83SLandon J. Fuller return (provider);
19838e35bf83SLandon J. Fuller
19848e35bf83SLandon J. Fuller /* Otherwise, try to delegate to our parent (if any) */
19858e35bf83SLandon J. Fuller if ((parent = device_get_parent(dev)) == NULL)
19868e35bf83SLandon J. Fuller return (NULL);
19878e35bf83SLandon J. Fuller
19888e35bf83SLandon J. Fuller provider = BHND_BUS_RETAIN_PROVIDER(parent, dev, service);
19898e35bf83SLandon J. Fuller if (provider == NULL)
19908e35bf83SLandon J. Fuller return (NULL);
19918e35bf83SLandon J. Fuller
19928e35bf83SLandon J. Fuller /* Register the inherited service registration with the local
19938e35bf83SLandon J. Fuller * registry */
19948e35bf83SLandon J. Fuller error = bhnd_service_registry_add(bsr, provider, service,
19958e35bf83SLandon J. Fuller BHND_SPF_INHERITED);
19968e35bf83SLandon J. Fuller if (error) {
19978e35bf83SLandon J. Fuller BHND_BUS_RELEASE_PROVIDER(parent, dev, provider,
19988e35bf83SLandon J. Fuller service);
19998e35bf83SLandon J. Fuller if (error == EEXIST) {
20008e35bf83SLandon J. Fuller /* A valid service provider was registered
20018e35bf83SLandon J. Fuller * concurrently; retry fetching from the local
20028e35bf83SLandon J. Fuller * registry */
20038e35bf83SLandon J. Fuller continue;
20048e35bf83SLandon J. Fuller }
20058e35bf83SLandon J. Fuller
20068e35bf83SLandon J. Fuller device_printf(dev, "failed to register service "
20078e35bf83SLandon J. Fuller "provider: %d\n", error);
20088e35bf83SLandon J. Fuller return (NULL);
20098e35bf83SLandon J. Fuller }
20108e35bf83SLandon J. Fuller }
20118e35bf83SLandon J. Fuller }
20128e35bf83SLandon J. Fuller
20138e35bf83SLandon J. Fuller /**
20148e35bf83SLandon J. Fuller * Helper function for implementing BHND_BUS_RELEASE_PROVIDER().
20158e35bf83SLandon J. Fuller *
20168e35bf83SLandon J. Fuller * This implementation uses the bhnd_service_registry_release() function to
20178e35bf83SLandon J. Fuller * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
20188e35bf83SLandon J. Fuller * a suitable service registry.
20198e35bf83SLandon J. Fuller */
20208e35bf83SLandon J. Fuller void
bhnd_bus_generic_sr_release_provider(device_t dev,device_t child,device_t provider,bhnd_service_t service)20218e35bf83SLandon J. Fuller bhnd_bus_generic_sr_release_provider(device_t dev, device_t child,
20228e35bf83SLandon J. Fuller device_t provider, bhnd_service_t service)
20238e35bf83SLandon J. Fuller {
20248e35bf83SLandon J. Fuller struct bhnd_service_registry *bsr;
20258e35bf83SLandon J. Fuller
20268e35bf83SLandon J. Fuller bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
20278e35bf83SLandon J. Fuller KASSERT(bsr != NULL, ("NULL service registry"));
20288e35bf83SLandon J. Fuller
20298e35bf83SLandon J. Fuller /* Release the provider reference; if the refcount hits zero on an
20308e35bf83SLandon J. Fuller * inherited reference, true will be returned, and we need to drop
20318e35bf83SLandon J. Fuller * our own bus reference to the provider */
20328e35bf83SLandon J. Fuller if (!bhnd_service_registry_release(bsr, provider, service))
20338e35bf83SLandon J. Fuller return;
20348e35bf83SLandon J. Fuller
20358e35bf83SLandon J. Fuller /* Drop our reference to the borrowed provider */
20368e35bf83SLandon J. Fuller BHND_BUS_RELEASE_PROVIDER(device_get_parent(dev), dev, provider,
20378e35bf83SLandon J. Fuller service);
20388e35bf83SLandon J. Fuller }
20398e35bf83SLandon J. Fuller
20408e35bf83SLandon J. Fuller /**
2041386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
2042386fb140SAdrian Chadd *
2043386fb140SAdrian Chadd * If a parent device is available, this implementation delegates the
2044386fb140SAdrian Chadd * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
2045386fb140SAdrian Chadd *
2046386fb140SAdrian Chadd * If no parent device is available (i.e. on a the bus root), the hardware
2047386fb140SAdrian Chadd * is assumed to be usable and false is returned.
2048386fb140SAdrian Chadd */
2049386fb140SAdrian Chadd bool
bhnd_bus_generic_is_hw_disabled(device_t dev,device_t child)2050386fb140SAdrian Chadd bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
2051386fb140SAdrian Chadd {
2052386fb140SAdrian Chadd if (device_get_parent(dev) != NULL)
2053386fb140SAdrian Chadd return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
2054386fb140SAdrian Chadd
2055386fb140SAdrian Chadd return (false);
2056386fb140SAdrian Chadd }
2057386fb140SAdrian Chadd
2058386fb140SAdrian Chadd /**
2059386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_GET_CHIPID().
2060386fb140SAdrian Chadd *
2061386fb140SAdrian Chadd * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
2062386fb140SAdrian Chadd * method on the parent of @p dev. If no parent exists, the implementation
2063386fb140SAdrian Chadd * will panic.
2064386fb140SAdrian Chadd */
2065386fb140SAdrian Chadd const struct bhnd_chipid *
bhnd_bus_generic_get_chipid(device_t dev,device_t child)2066386fb140SAdrian Chadd bhnd_bus_generic_get_chipid(device_t dev, device_t child)
2067386fb140SAdrian Chadd {
2068386fb140SAdrian Chadd if (device_get_parent(dev) != NULL)
2069386fb140SAdrian Chadd return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
2070386fb140SAdrian Chadd
2071386fb140SAdrian Chadd panic("missing BHND_BUS_GET_CHIPID()");
2072386fb140SAdrian Chadd }
2073386fb140SAdrian Chadd
20749ed45324SLandon J. Fuller /**
20759ed45324SLandon J. Fuller * Helper function for implementing BHND_BUS_GET_DMA_TRANSLATION().
20769ed45324SLandon J. Fuller *
20779ed45324SLandon J. Fuller * If a parent device is available, this implementation delegates the
20789ed45324SLandon J. Fuller * request to the BHND_BUS_GET_DMA_TRANSLATION() method on the parent of @p dev.
20799ed45324SLandon J. Fuller *
20809ed45324SLandon J. Fuller * If no parent device is available, this implementation will panic.
20819ed45324SLandon J. Fuller */
20829ed45324SLandon J. Fuller int
bhnd_bus_generic_get_dma_translation(device_t dev,device_t child,u_int width,uint32_t flags,bus_dma_tag_t * dmat,struct bhnd_dma_translation * translation)20839ed45324SLandon J. Fuller bhnd_bus_generic_get_dma_translation(device_t dev, device_t child, u_int width,
20849ed45324SLandon J. Fuller uint32_t flags, bus_dma_tag_t *dmat,
20859ed45324SLandon J. Fuller struct bhnd_dma_translation *translation)
20869ed45324SLandon J. Fuller {
20879ed45324SLandon J. Fuller if (device_get_parent(dev) != NULL) {
20889ed45324SLandon J. Fuller return (BHND_BUS_GET_DMA_TRANSLATION(device_get_parent(dev),
20899ed45324SLandon J. Fuller child, width, flags, dmat, translation));
20909ed45324SLandon J. Fuller }
20919ed45324SLandon J. Fuller
20929ed45324SLandon J. Fuller panic("missing BHND_BUS_GET_DMA_TRANSLATION()");
20939ed45324SLandon J. Fuller }
20949ed45324SLandon J. Fuller
2095d567592bSAdrian Chadd /* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
2096d567592bSAdrian Chadd #define BHND_GV(_dest, _name) \
20971728aef2SLandon J. Fuller bhnd_nvram_getvar_uint(child, BHND_NVAR_ ## _name, &_dest, \
20981728aef2SLandon J. Fuller sizeof(_dest))
2099d567592bSAdrian Chadd
2100d567592bSAdrian Chadd #define REQ_BHND_GV(_dest, _name) do { \
2101d567592bSAdrian Chadd if ((error = BHND_GV(_dest, _name))) { \
2102d567592bSAdrian Chadd device_printf(dev, \
2103d567592bSAdrian Chadd "error reading " __STRING(_name) ": %d\n", error); \
2104d567592bSAdrian Chadd return (error); \
2105d567592bSAdrian Chadd } \
2106d567592bSAdrian Chadd } while(0)
2107d567592bSAdrian Chadd
2108d567592bSAdrian Chadd #define OPT_BHND_GV(_dest, _name, _default) do { \
2109d567592bSAdrian Chadd if ((error = BHND_GV(_dest, _name))) { \
2110d567592bSAdrian Chadd if (error != ENOENT) { \
2111d567592bSAdrian Chadd device_printf(dev, \
2112d567592bSAdrian Chadd "error reading " \
2113d567592bSAdrian Chadd __STRING(_name) ": %d\n", error); \
2114d567592bSAdrian Chadd return (error); \
2115d567592bSAdrian Chadd } \
2116d567592bSAdrian Chadd _dest = _default; \
2117d567592bSAdrian Chadd } \
2118d567592bSAdrian Chadd } while(0)
2119d567592bSAdrian Chadd
2120d567592bSAdrian Chadd /**
2121d567592bSAdrian Chadd * Helper function for implementing BHND_BUS_READ_BOARDINFO().
2122d567592bSAdrian Chadd *
2123d567592bSAdrian Chadd * This implementation populates @p info with information from NVRAM,
2124d567592bSAdrian Chadd * defaulting board_vendor and board_type fields to 0 if the
2125d567592bSAdrian Chadd * requested variables cannot be found.
2126d567592bSAdrian Chadd *
2127d567592bSAdrian Chadd * This behavior is correct for most SoCs, but must be overridden on
2128d567592bSAdrian Chadd * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
2129d567592bSAdrian Chadd * result.
2130d567592bSAdrian Chadd */
2131d567592bSAdrian Chadd int
bhnd_bus_generic_read_board_info(device_t dev,device_t child,struct bhnd_board_info * info)2132d567592bSAdrian Chadd bhnd_bus_generic_read_board_info(device_t dev, device_t child,
2133d567592bSAdrian Chadd struct bhnd_board_info *info)
2134d567592bSAdrian Chadd {
2135d567592bSAdrian Chadd int error;
2136d567592bSAdrian Chadd
2137d567592bSAdrian Chadd OPT_BHND_GV(info->board_vendor, BOARDVENDOR, 0);
2138d567592bSAdrian Chadd OPT_BHND_GV(info->board_type, BOARDTYPE, 0); /* srom >= 2 */
2139566ca880SLandon J. Fuller OPT_BHND_GV(info->board_devid, DEVID, 0); /* srom >= 8 */
2140d567592bSAdrian Chadd REQ_BHND_GV(info->board_rev, BOARDREV);
2141f90f4b65SLandon J. Fuller OPT_BHND_GV(info->board_srom_rev,SROMREV, 0); /* missing in
2142f90f4b65SLandon J. Fuller some SoC
2143f90f4b65SLandon J. Fuller NVRAM */
2144d567592bSAdrian Chadd REQ_BHND_GV(info->board_flags, BOARDFLAGS);
2145d567592bSAdrian Chadd OPT_BHND_GV(info->board_flags2, BOARDFLAGS2, 0); /* srom >= 4 */
2146d567592bSAdrian Chadd OPT_BHND_GV(info->board_flags3, BOARDFLAGS3, 0); /* srom >= 11 */
2147d567592bSAdrian Chadd
2148d567592bSAdrian Chadd return (0);
2149d567592bSAdrian Chadd }
2150d567592bSAdrian Chadd
2151d567592bSAdrian Chadd #undef BHND_GV
2152d567592bSAdrian Chadd #undef BHND_GV_REQ
2153d567592bSAdrian Chadd #undef BHND_GV_OPT
2154d567592bSAdrian Chadd
2155d567592bSAdrian Chadd /**
2156d567592bSAdrian Chadd * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
2157d567592bSAdrian Chadd *
2158fdedcd9fSLandon J. Fuller * This implementation searches @p dev for a usable NVRAM child device.
2159d567592bSAdrian Chadd *
2160d567592bSAdrian Chadd * If no usable child device is found on @p dev, the request is delegated to
2161d567592bSAdrian Chadd * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
2162d567592bSAdrian Chadd */
2163d567592bSAdrian Chadd int
bhnd_bus_generic_get_nvram_var(device_t dev,device_t child,const char * name,void * buf,size_t * size,bhnd_nvram_type type)2164d567592bSAdrian Chadd bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
21651728aef2SLandon J. Fuller void *buf, size_t *size, bhnd_nvram_type type)
2166d567592bSAdrian Chadd {
2167d567592bSAdrian Chadd device_t nvram;
2168d567592bSAdrian Chadd device_t parent;
2169d567592bSAdrian Chadd
2170d14bc723SWarner Losh bus_topo_assert();
2171fdedcd9fSLandon J. Fuller
2172fdedcd9fSLandon J. Fuller /* Look for a directly-attached NVRAM child */
2173fdedcd9fSLandon J. Fuller if ((nvram = device_find_child(dev, "bhnd_nvram", -1)) != NULL)
21741728aef2SLandon J. Fuller return BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
2175d567592bSAdrian Chadd
2176d567592bSAdrian Chadd /* Try to delegate to parent */
2177d567592bSAdrian Chadd if ((parent = device_get_parent(dev)) == NULL)
2178d567592bSAdrian Chadd return (ENODEV);
2179d567592bSAdrian Chadd
2180d567592bSAdrian Chadd return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
21811728aef2SLandon J. Fuller name, buf, size, type));
2182d567592bSAdrian Chadd }
2183d567592bSAdrian Chadd
2184386fb140SAdrian Chadd /**
2185386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
2186386fb140SAdrian Chadd *
2187386fb140SAdrian Chadd * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
2188386fb140SAdrian Chadd * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
2189386fb140SAdrian Chadd * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
2190386fb140SAdrian Chadd */
2191386fb140SAdrian Chadd struct bhnd_resource *
bhnd_bus_generic_alloc_resource(device_t dev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)2192386fb140SAdrian Chadd bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
2193386fb140SAdrian Chadd int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
2194386fb140SAdrian Chadd u_int flags)
2195386fb140SAdrian Chadd {
2196386fb140SAdrian Chadd struct bhnd_resource *br;
2197386fb140SAdrian Chadd struct resource *res;
2198386fb140SAdrian Chadd int error;
2199386fb140SAdrian Chadd
2200386fb140SAdrian Chadd br = NULL;
2201386fb140SAdrian Chadd res = NULL;
2202386fb140SAdrian Chadd
2203386fb140SAdrian Chadd /* Allocate the real bus resource (without activating it) */
2204386fb140SAdrian Chadd res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
2205386fb140SAdrian Chadd (flags & ~RF_ACTIVE));
2206386fb140SAdrian Chadd if (res == NULL)
2207386fb140SAdrian Chadd return (NULL);
2208386fb140SAdrian Chadd
2209386fb140SAdrian Chadd /* Allocate our bhnd resource wrapper. */
2210386fb140SAdrian Chadd br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
2211386fb140SAdrian Chadd if (br == NULL)
2212386fb140SAdrian Chadd goto failed;
2213386fb140SAdrian Chadd
2214386fb140SAdrian Chadd br->direct = false;
2215386fb140SAdrian Chadd br->res = res;
2216386fb140SAdrian Chadd
2217386fb140SAdrian Chadd /* Attempt activation */
2218386fb140SAdrian Chadd if (flags & RF_ACTIVE) {
2219386fb140SAdrian Chadd error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
2220386fb140SAdrian Chadd if (error)
2221386fb140SAdrian Chadd goto failed;
2222386fb140SAdrian Chadd }
2223386fb140SAdrian Chadd
2224386fb140SAdrian Chadd return (br);
2225386fb140SAdrian Chadd
2226386fb140SAdrian Chadd failed:
2227386fb140SAdrian Chadd if (res != NULL)
22289dbf5b0eSJohn Baldwin BUS_RELEASE_RESOURCE(dev, child, res);
2229386fb140SAdrian Chadd
2230386fb140SAdrian Chadd free(br, M_BHND);
2231386fb140SAdrian Chadd return (NULL);
2232386fb140SAdrian Chadd }
2233386fb140SAdrian Chadd
2234386fb140SAdrian Chadd /**
2235386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
2236386fb140SAdrian Chadd *
2237386fb140SAdrian Chadd * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
2238386fb140SAdrian Chadd * the backing resource to BUS_RELEASE_RESOURCE().
2239386fb140SAdrian Chadd */
2240386fb140SAdrian Chadd int
bhnd_bus_generic_release_resource(device_t dev,device_t child,int type,int rid,struct bhnd_resource * r)2241386fb140SAdrian Chadd bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
2242386fb140SAdrian Chadd int rid, struct bhnd_resource *r)
2243386fb140SAdrian Chadd {
2244386fb140SAdrian Chadd int error;
2245386fb140SAdrian Chadd
22469dbf5b0eSJohn Baldwin if ((error = BUS_RELEASE_RESOURCE(dev, child, r->res)))
2247386fb140SAdrian Chadd return (error);
2248386fb140SAdrian Chadd
2249386fb140SAdrian Chadd free(r, M_BHND);
2250386fb140SAdrian Chadd return (0);
2251386fb140SAdrian Chadd }
2252386fb140SAdrian Chadd
2253386fb140SAdrian Chadd /**
2254386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
2255386fb140SAdrian Chadd *
2256664a7497SLandon J. Fuller * This implementation of BHND_BUS_ACTIVATE_RESOURCE() first calls the
2257386fb140SAdrian Chadd * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
2258664a7497SLandon J. Fuller *
2259664a7497SLandon J. Fuller * If this fails, and if @p dev is the direct parent of @p child, standard
2260664a7497SLandon J. Fuller * resource activation is attempted via bus_activate_resource(). This enables
2261664a7497SLandon J. Fuller * direct use of the bhnd(4) resource APIs on devices that may not be attached
2262664a7497SLandon J. Fuller * to a parent bhnd bus or bridge.
2263386fb140SAdrian Chadd */
2264386fb140SAdrian Chadd int
bhnd_bus_generic_activate_resource(device_t dev,device_t child,int type,int rid,struct bhnd_resource * r)2265386fb140SAdrian Chadd bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
2266386fb140SAdrian Chadd int rid, struct bhnd_resource *r)
2267386fb140SAdrian Chadd {
2268664a7497SLandon J. Fuller int error;
2269664a7497SLandon J. Fuller bool passthrough;
2270386fb140SAdrian Chadd
2271664a7497SLandon J. Fuller passthrough = (device_get_parent(child) != dev);
2272664a7497SLandon J. Fuller
2273664a7497SLandon J. Fuller /* Try to delegate to the parent */
2274664a7497SLandon J. Fuller if (device_get_parent(dev) != NULL) {
2275664a7497SLandon J. Fuller error = BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
2276664a7497SLandon J. Fuller child, type, rid, r);
2277664a7497SLandon J. Fuller } else {
2278664a7497SLandon J. Fuller error = ENODEV;
2279664a7497SLandon J. Fuller }
2280664a7497SLandon J. Fuller
2281664a7497SLandon J. Fuller /* If bhnd(4) activation has failed and we're the child's direct
2282664a7497SLandon J. Fuller * parent, try falling back on standard resource activation.
2283664a7497SLandon J. Fuller */
2284664a7497SLandon J. Fuller if (error && !passthrough) {
2285664a7497SLandon J. Fuller error = bus_activate_resource(child, type, rid, r->res);
2286664a7497SLandon J. Fuller if (!error)
2287664a7497SLandon J. Fuller r->direct = true;
2288664a7497SLandon J. Fuller }
2289664a7497SLandon J. Fuller
2290664a7497SLandon J. Fuller return (error);
229168c6ae00SEd Maste }
2292386fb140SAdrian Chadd
2293386fb140SAdrian Chadd /**
2294386fb140SAdrian Chadd * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
2295386fb140SAdrian Chadd *
2296386fb140SAdrian Chadd * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
2297386fb140SAdrian Chadd * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
2298386fb140SAdrian Chadd */
2299386fb140SAdrian Chadd int
bhnd_bus_generic_deactivate_resource(device_t dev,device_t child,int type,int rid,struct bhnd_resource * r)2300386fb140SAdrian Chadd bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
2301386fb140SAdrian Chadd int type, int rid, struct bhnd_resource *r)
2302386fb140SAdrian Chadd {
2303386fb140SAdrian Chadd if (device_get_parent(dev) != NULL)
2304386fb140SAdrian Chadd return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
2305386fb140SAdrian Chadd child, type, rid, r));
2306386fb140SAdrian Chadd
2307386fb140SAdrian Chadd return (EINVAL);
230868c6ae00SEd Maste }
23092b693a88SLandon J. Fuller
2310caeff9a3SLandon J. Fuller /**
2311caeff9a3SLandon J. Fuller * Helper function for implementing BHND_BUS_GET_INTR_DOMAIN().
2312caeff9a3SLandon J. Fuller *
2313caeff9a3SLandon J. Fuller * This implementation simply returns the address of nearest bhnd(4) bus,
2314caeff9a3SLandon J. Fuller * which may be @p dev; this behavior may be incompatible with FDT/OFW targets.
2315caeff9a3SLandon J. Fuller */
2316caeff9a3SLandon J. Fuller uintptr_t
bhnd_bus_generic_get_intr_domain(device_t dev,device_t child,bool self)2317caeff9a3SLandon J. Fuller bhnd_bus_generic_get_intr_domain(device_t dev, device_t child, bool self)
2318caeff9a3SLandon J. Fuller {
2319caeff9a3SLandon J. Fuller return ((uintptr_t)dev);
2320caeff9a3SLandon J. Fuller }
2321