1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 *    redistribution must be conditioned upon including a substantially
20 *    similar Disclaimer requirement for further binary redistribution.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36#include <sys/param.h>
37#include <sys/bus.h>
38#include <sys/refcount.h>
39#include <sys/systm.h>
40
41#include <machine/bus.h>
42#include <sys/rman.h>
43#include <machine/resource.h>
44
45#include <dev/bhnd/siba/sibareg.h>
46
47#include <dev/bhnd/cores/chipc/chipcreg.h>
48
49#include "nvram/bhnd_nvram.h"
50
51#include "bhnd_chipc_if.h"
52
53#include "bhnd_nvram_if.h"
54#include "bhnd_nvram_map.h"
55
56#include "bhndreg.h"
57#include "bhndvar.h"
58#include "bhnd_private.h"
59
60static void	bhnd_service_registry_free_entry(
61		    struct bhnd_service_entry *entry);
62
63static int	compare_ascending_probe_order(const void *lhs, const void *rhs);
64static int	compare_descending_probe_order(const void *lhs,
65		    const void *rhs);
66
67/* BHND core device description table. */
68static const struct bhnd_core_desc {
69	uint16_t	 vendor;
70	uint16_t	 device;
71	bhnd_devclass_t	 class;
72	const char	*desc;
73} bhnd_core_descs[] = {
74	#define	BHND_CDESC(_mfg, _cid, _cls, _desc)		\
75	    { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,	\
76		BHND_DEVCLASS_ ## _cls, _desc }
77
78	BHND_CDESC(BCM, CC,		CC,		"ChipCommon I/O Controller"),
79	BHND_CDESC(BCM, ILINE20,	OTHER,		"iLine20 HPNA"),
80	BHND_CDESC(BCM, SRAM,		RAM,		"SRAM"),
81	BHND_CDESC(BCM, SDRAM,		RAM,		"SDRAM"),
82	BHND_CDESC(BCM, PCI,		PCI,		"PCI Bridge"),
83	BHND_CDESC(BCM, MIPS,		CPU,		"BMIPS CPU"),
84	BHND_CDESC(BCM, ENET,		ENET_MAC,	"Fast Ethernet MAC"),
85	BHND_CDESC(BCM, V90_CODEC,	SOFTMODEM,	"V.90 SoftModem Codec"),
86	BHND_CDESC(BCM, USB,		USB_DUAL,	"USB 1.1 Device/Host Controller"),
87	BHND_CDESC(BCM, ADSL,		OTHER,		"ADSL Core"),
88	BHND_CDESC(BCM, ILINE100,	OTHER,		"iLine100 HPNA"),
89	BHND_CDESC(BCM, IPSEC,		OTHER,		"IPsec Accelerator"),
90	BHND_CDESC(BCM, UTOPIA,		OTHER,		"UTOPIA ATM Core"),
91	BHND_CDESC(BCM, PCMCIA,		PCCARD,		"PCMCIA Bridge"),
92	BHND_CDESC(BCM, SOCRAM,		RAM,		"Internal Memory"),
93	BHND_CDESC(BCM, MEMC,		MEMC,		"MEMC SDRAM Controller"),
94	BHND_CDESC(BCM, OFDM,		OTHER,		"OFDM PHY"),
95	BHND_CDESC(BCM, EXTIF,		OTHER,		"External Interface"),
96	BHND_CDESC(BCM, D11,		WLAN,		"802.11 MAC/PHY/Radio"),
97	BHND_CDESC(BCM, APHY,		WLAN_PHY,	"802.11a PHY"),
98	BHND_CDESC(BCM, BPHY,		WLAN_PHY,	"802.11b PHY"),
99	BHND_CDESC(BCM, GPHY,		WLAN_PHY,	"802.11g PHY"),
100	BHND_CDESC(BCM, MIPS33,		CPU,		"BMIPS33 CPU"),
101	BHND_CDESC(BCM, USB11H,		USB_HOST,	"USB 1.1 Host Controller"),
102	BHND_CDESC(BCM, USB11D,		USB_DEV,	"USB 1.1 Device Controller"),
103	BHND_CDESC(BCM, USB20H,		USB_HOST,	"USB 2.0 Host Controller"),
104	BHND_CDESC(BCM, USB20D,		USB_DEV,	"USB 2.0 Device Controller"),
105	BHND_CDESC(BCM, SDIOH,		OTHER,		"SDIO Host Controller"),
106	BHND_CDESC(BCM, ROBO,		OTHER,		"RoboSwitch"),
107	BHND_CDESC(BCM, ATA100,		OTHER,		"Parallel ATA Controller"),
108	BHND_CDESC(BCM, SATAXOR,	OTHER,		"SATA DMA/XOR Controller"),
109	BHND_CDESC(BCM, GIGETH,		ENET_MAC,	"Gigabit Ethernet MAC"),
110	BHND_CDESC(BCM, PCIE,		PCIE,		"PCIe Bridge"),
111	BHND_CDESC(BCM, NPHY,		WLAN_PHY,	"802.11n 2x2 PHY"),
112	BHND_CDESC(BCM, SRAMC,		MEMC,		"SRAM Controller"),
113	BHND_CDESC(BCM, MINIMAC,	OTHER,		"MINI MAC/PHY"),
114	BHND_CDESC(BCM, ARM11,		CPU,		"ARM1176 CPU"),
115	BHND_CDESC(BCM, ARM7S,		CPU,		"ARM7TDMI-S CPU"),
116	BHND_CDESC(BCM, LPPHY,		WLAN_PHY,	"802.11a/b/g PHY"),
117	BHND_CDESC(BCM, PMU,		PMU,		"PMU"),
118	BHND_CDESC(BCM, SSNPHY,		WLAN_PHY,	"802.11n Single-Stream PHY"),
119	BHND_CDESC(BCM, SDIOD,		OTHER,		"SDIO Device Core"),
120	BHND_CDESC(BCM, ARMCM3,		CPU,		"ARM Cortex-M3 CPU"),
121	BHND_CDESC(BCM, HTPHY,		WLAN_PHY,	"802.11n 4x4 PHY"),
122	BHND_CDESC(MIPS,MIPS74K,	CPU,		"MIPS74k CPU"),
123	BHND_CDESC(BCM, GMAC,		ENET_MAC,	"Gigabit MAC core"),
124	BHND_CDESC(BCM, DMEMC,		MEMC,		"DDR1/DDR2 Memory Controller"),
125	BHND_CDESC(BCM, PCIERC,		OTHER,		"PCIe Root Complex"),
126	BHND_CDESC(BCM, OCP,		SOC_BRIDGE,	"OCP to OCP Bridge"),
127	BHND_CDESC(BCM, SC,		OTHER,		"Shared Common Core"),
128	BHND_CDESC(BCM, AHB,		SOC_BRIDGE,	"OCP to AHB Bridge"),
129	BHND_CDESC(BCM, SPIH,		OTHER,		"SPI Host Controller"),
130	BHND_CDESC(BCM, I2S,		OTHER,		"I2S Digital Audio Interface"),
131	BHND_CDESC(BCM, DMEMS,		MEMC,		"SDR/DDR1 Memory Controller"),
132	BHND_CDESC(BCM, UBUS_SHIM,	OTHER,		"BCM6362/UBUS WLAN SHIM"),
133	BHND_CDESC(BCM, PCIE2,		PCIE,		"PCIe Bridge (Gen2)"),
134
135	BHND_CDESC(ARM, APB_BRIDGE,	SOC_BRIDGE,	"BP135 AMBA3 AXI to APB Bridge"),
136	BHND_CDESC(ARM, PL301,		SOC_ROUTER,	"PL301 AMBA3 Interconnect"),
137	BHND_CDESC(ARM, EROM,		EROM,		"PL366 Device Enumeration ROM"),
138	BHND_CDESC(ARM, OOB_ROUTER,	OTHER,		"PL367 OOB Interrupt Router"),
139	BHND_CDESC(ARM, AXI_UNMAPPED,	OTHER,		"Unmapped Address Ranges"),
140
141	BHND_CDESC(BCM, 4706_CC,	CC,		"ChipCommon I/O Controller"),
142	BHND_CDESC(BCM, NS_PCIE2,	PCIE,		"PCIe Bridge (Gen2)"),
143	BHND_CDESC(BCM, NS_DMA,		OTHER,		"DMA engine"),
144	BHND_CDESC(BCM, NS_SDIO,	OTHER,		"SDIO 3.0 Host Controller"),
145	BHND_CDESC(BCM, NS_USB20H,	USB_HOST,	"USB 2.0 Host Controller"),
146	BHND_CDESC(BCM, NS_USB30H,	USB_HOST,	"USB 3.0 Host Controller"),
147	BHND_CDESC(BCM, NS_A9JTAG,	OTHER,		"ARM Cortex A9 JTAG Interface"),
148	BHND_CDESC(BCM, NS_DDR23_MEMC,	MEMC,		"Denali DDR2/DD3 Memory Controller"),
149	BHND_CDESC(BCM, NS_ROM,		NVRAM,		"System ROM"),
150	BHND_CDESC(BCM, NS_NAND,	NVRAM,		"NAND Flash Controller"),
151	BHND_CDESC(BCM, NS_QSPI,	NVRAM,		"QSPI Flash Controller"),
152	BHND_CDESC(BCM, NS_CC_B,	CC_B,		"ChipCommon B Auxiliary I/O Controller"),
153	BHND_CDESC(BCM, 4706_SOCRAM,	RAM,		"Internal Memory"),
154	BHND_CDESC(BCM, IHOST_ARMCA9,	CPU,		"ARM Cortex A9 CPU"),
155	BHND_CDESC(BCM, 4706_GMAC_CMN,	ENET,		"Gigabit MAC (Common)"),
156	BHND_CDESC(BCM, 4706_GMAC,	ENET_MAC,	"Gigabit MAC"),
157	BHND_CDESC(BCM, AMEMC,		MEMC,		"Denali DDR1/DDR2 Memory Controller"),
158#undef	BHND_CDESC
159
160	/* Derived from inspection of the BCM4331 cores that provide PrimeCell
161	 * IDs. Due to lack of documentation, the surmised device name/purpose
162	 * provided here may be incorrect. */
163	{ BHND_MFGID_ARM,	BHND_PRIMEID_EROM,	BHND_DEVCLASS_OTHER,
164	    "PL364 Device Enumeration ROM" },
165	{ BHND_MFGID_ARM,	BHND_PRIMEID_SWRAP,	BHND_DEVCLASS_OTHER,
166	    "PL368 Device Management Interface" },
167	{ BHND_MFGID_ARM,	BHND_PRIMEID_MWRAP,	BHND_DEVCLASS_OTHER,
168	    "PL369 Device Management Interface" },
169	{ 0, 0, 0, NULL }
170};
171
172static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[];
173static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[];
174
175/**
176 * Device table entries for core-specific CLKCTL quirk lookup.
177 */
178static const struct bhnd_device bhnd_clkctl_devices[] = {
179	BHND_DEVICE(BCM, CC,		NULL,	bhnd_chipc_clkctl_quirks),
180	BHND_DEVICE(BCM, PCMCIA,	NULL,	bhnd_pcmcia_clkctl_quirks),
181	BHND_DEVICE_END,
182};
183
184/** ChipCommon CLKCTL quirks */
185static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[] = {
186	/* HTAVAIL/ALPAVAIL are bitswapped in chipc's CLKCTL */
187	BHND_CHIP_QUIRK(4328,	HWREV_ANY,	BHND_CLKCTL_QUIRK_CCS0),
188	BHND_CHIP_QUIRK(5354,	HWREV_ANY,	BHND_CLKCTL_QUIRK_CCS0),
189	BHND_DEVICE_QUIRK_END
190};
191
192/** PCMCIA CLKCTL quirks */
193static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[] = {
194	/* HTAVAIL/ALPAVAIL are bitswapped in pcmcia's CLKCTL */
195	BHND_CHIP_QUIRK(4328,	HWREV_ANY,	BHND_CLKCTL_QUIRK_CCS0),
196	BHND_CHIP_QUIRK(5354,	HWREV_ANY,	BHND_CLKCTL_QUIRK_CCS0),
197	BHND_DEVICE_QUIRK_END
198};
199
200/**
201 * Return the name for a given JEP106 manufacturer ID.
202 *
203 * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
204 * JEP106 continuation code.
205 */
206const char *
207bhnd_vendor_name(uint16_t vendor)
208{
209	switch (vendor) {
210	case BHND_MFGID_ARM:
211		return "ARM";
212	case BHND_MFGID_BCM:
213		return "Broadcom";
214	case BHND_MFGID_MIPS:
215		return "MIPS";
216	default:
217		return "unknown";
218	}
219}
220
221/**
222 * Return the name of a port type.
223 *
224 * @param port_type The port type to look up.
225 */
226const char *
227bhnd_port_type_name(bhnd_port_type port_type)
228{
229	switch (port_type) {
230	case BHND_PORT_DEVICE:
231		return ("device");
232	case BHND_PORT_BRIDGE:
233		return ("bridge");
234	case BHND_PORT_AGENT:
235		return ("agent");
236	default:
237		return "unknown";
238	}
239}
240
241/**
242 * Return the name of an NVRAM source.
243 *
244 * @param nvram_src The NVRAM source type to look up.
245 */
246const char *
247bhnd_nvram_src_name(bhnd_nvram_src nvram_src)
248{
249	switch (nvram_src) {
250	case BHND_NVRAM_SRC_FLASH:
251		return ("flash");
252	case BHND_NVRAM_SRC_OTP:
253		return ("OTP");
254	case BHND_NVRAM_SRC_SPROM:
255		return ("SPROM");
256	case BHND_NVRAM_SRC_UNKNOWN:
257		return ("none");
258	default:
259		return ("unknown");
260	}
261}
262
263static const struct bhnd_core_desc *
264bhnd_find_core_desc(uint16_t vendor, uint16_t device)
265{
266	for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
267		if (bhnd_core_descs[i].vendor != vendor)
268			continue;
269
270		if (bhnd_core_descs[i].device != device)
271			continue;
272
273		return (&bhnd_core_descs[i]);
274	}
275
276	return (NULL);
277}
278
279/**
280 * Return a human-readable name for a BHND core.
281 *
282 * @param vendor The core designer's JEDEC-106 Manufacturer ID.
283 * @param device The core identifier.
284 */
285const char *
286bhnd_find_core_name(uint16_t vendor, uint16_t device)
287{
288	const struct bhnd_core_desc *desc;
289
290	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
291		return ("unknown");
292
293	return desc->desc;
294}
295
296/**
297 * Return the device class for a BHND core.
298 *
299 * @param vendor The core designer's JEDEC-106 Manufacturer ID.
300 * @param device The core identifier.
301 */
302bhnd_devclass_t
303bhnd_find_core_class(uint16_t vendor, uint16_t device)
304{
305	const struct bhnd_core_desc *desc;
306
307	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
308		return (BHND_DEVCLASS_OTHER);
309
310	return desc->class;
311}
312
313/**
314 * Return a human-readable name for a BHND core.
315 *
316 * @param ci The core's info record.
317 */
318const char *
319bhnd_core_name(const struct bhnd_core_info *ci)
320{
321	return bhnd_find_core_name(ci->vendor, ci->device);
322}
323
324/**
325 * Return the device class for a BHND core.
326 *
327 * @param ci The core's info record.
328 */
329bhnd_devclass_t
330bhnd_core_class(const struct bhnd_core_info *ci)
331{
332	return bhnd_find_core_class(ci->vendor, ci->device);
333}
334
335/**
336 * Write a human readable name representation of the given
337 * BHND_CHIPID_* constant to @p buffer.
338 *
339 * @param buffer Output buffer, or NULL to compute the required size.
340 * @param size Capacity of @p buffer, in bytes.
341 * @param chip_id Chip ID to be formatted.
342 *
343 * @return The required number of bytes on success, or a negative integer on
344 * failure. No more than @p size-1 characters be written, with the @p size'th
345 * set to '\0'.
346 *
347 * @sa BHND_CHIPID_MAX_NAMELEN
348 */
349int
350bhnd_format_chip_id(char *buffer, size_t size, uint16_t chip_id)
351{
352	/* All hex formatted IDs are within the range of 0x4000-0x9C3F (40000-1) */
353	if (chip_id >= 0x4000 && chip_id <= 0x9C3F)
354		return (snprintf(buffer, size, "BCM%hX", chip_id));
355	else
356		return (snprintf(buffer, size, "BCM%hu", chip_id));
357}
358
359/**
360 * Return a core info record populated from a bhnd-attached @p dev.
361 *
362 * @param dev A bhnd device.
363 *
364 * @return A core info record for @p dev.
365 */
366struct bhnd_core_info
367bhnd_get_core_info(device_t dev) {
368	return (struct bhnd_core_info) {
369		.vendor		= bhnd_get_vendor(dev),
370		.device		= bhnd_get_device(dev),
371		.hwrev		= bhnd_get_hwrev(dev),
372		.core_idx	= bhnd_get_core_index(dev),
373		.unit		= bhnd_get_core_unit(dev)
374	};
375}
376
377/**
378 * Find a @p class child device with @p unit on @p bus.
379 *
380 * @param bus The bhnd-compatible bus to be searched.
381 * @param class The device class to match on.
382 * @param unit The core unit number; specify -1 to return the first match
383 * regardless of unit number.
384 *
385 * @retval device_t if a matching child device is found.
386 * @retval NULL if no matching child device is found.
387 */
388device_t
389bhnd_bus_find_child(device_t bus, bhnd_devclass_t class, int unit)
390{
391	struct bhnd_core_match md = {
392		BHND_MATCH_CORE_CLASS(class),
393		BHND_MATCH_CORE_UNIT(unit)
394	};
395
396	if (unit == -1)
397		md.m.match.core_unit = 0;
398
399	return bhnd_bus_match_child(bus, &md);
400}
401
402/**
403 * Find the first child device on @p bus that matches @p desc.
404 *
405 * @param bus The bhnd-compatible bus to be searched.
406 * @param desc A match descriptor.
407 *
408 * @retval device_t if a matching child device is found.
409 * @retval NULL if no matching child device is found.
410 */
411device_t
412bhnd_bus_match_child(device_t bus, const struct bhnd_core_match *desc)
413{
414	device_t	*devlistp;
415	device_t	 match;
416	int		 devcnt;
417	int		 error;
418
419	error = device_get_children(bus, &devlistp, &devcnt);
420	if (error != 0)
421		return (NULL);
422
423	match = NULL;
424	for (int i = 0; i < devcnt; i++) {
425		struct bhnd_core_info ci = bhnd_get_core_info(devlistp[i]);
426
427		if (bhnd_core_matches(&ci, desc)) {
428			match = devlistp[i];
429			goto done;
430		}
431	}
432
433done:
434	free(devlistp, M_TEMP);
435	return match;
436}
437
438/**
439 * Retrieve an ordered list of all device instances currently connected to
440 * @p bus, returning a pointer to the array in @p devlistp and the count
441 * in @p ndevs.
442 *
443 * The memory allocated for the table must be freed via
444 * bhnd_bus_free_children().
445 *
446 * @param	bus		The bhnd-compatible bus to be queried.
447 * @param[out]	devlist		The array of devices.
448 * @param[out]	devcount	The number of devices in @p devlistp
449 * @param	order		The order in which devices will be returned
450 *				in @p devlist.
451 *
452 * @retval 0		success
453 * @retval non-zero	if an error occurs, a regular unix error code will
454 *			be returned.
455 */
456int
457bhnd_bus_get_children(device_t bus, device_t **devlist, int *devcount,
458    bhnd_device_order order)
459{
460	int error;
461
462	/* Fetch device array */
463	if ((error = device_get_children(bus, devlist, devcount)))
464		return (error);
465
466	/* Perform requested sorting */
467	if ((error = bhnd_sort_devices(*devlist, *devcount, order))) {
468		bhnd_bus_free_children(*devlist);
469		return (error);
470	}
471
472	return (0);
473}
474
475/**
476 * Free any memory allocated in a previous call to bhnd_bus_get_children().
477 *
478 * @param devlist The device array returned by bhnd_bus_get_children().
479 */
480void
481bhnd_bus_free_children(device_t *devlist)
482{
483	free(devlist, M_TEMP);
484}
485
486/**
487 * Perform in-place sorting of an array of bhnd device instances.
488 *
489 * @param devlist	An array of bhnd devices.
490 * @param devcount	The number of devices in @p devs.
491 * @param order		The sort order to be used.
492 *
493 * @retval 0		success
494 * @retval EINVAL	if the sort order is unknown.
495 */
496int
497bhnd_sort_devices(device_t *devlist, size_t devcount, bhnd_device_order order)
498{
499	int (*compare)(const void *, const void *);
500
501	switch (order) {
502	case BHND_DEVICE_ORDER_ATTACH:
503		compare = compare_ascending_probe_order;
504		break;
505	case BHND_DEVICE_ORDER_DETACH:
506		compare = compare_descending_probe_order;
507		break;
508	default:
509		printf("unknown sort order: %d\n", order);
510		return (EINVAL);
511	}
512
513	qsort(devlist, devcount, sizeof(*devlist), compare);
514	return (0);
515}
516
517/*
518 * Ascending comparison of bhnd device's probe order.
519 */
520static int
521compare_ascending_probe_order(const void *lhs, const void *rhs)
522{
523	device_t	ldev, rdev;
524	int		lorder, rorder;
525
526	ldev = (*(const device_t *) lhs);
527	rdev = (*(const device_t *) rhs);
528
529	lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev);
530	rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev);
531
532	if (lorder < rorder) {
533		return (-1);
534	} else if (lorder > rorder) {
535		return (1);
536	} else {
537		return (0);
538	}
539}
540
541/*
542 * Descending comparison of bhnd device's probe order.
543 */
544static int
545compare_descending_probe_order(const void *lhs, const void *rhs)
546{
547	return (compare_ascending_probe_order(rhs, lhs));
548}
549
550/**
551 * Call device_probe_and_attach() for each of the bhnd bus device's
552 * children, in bhnd attach order.
553 *
554 * @param bus The bhnd-compatible bus for which all children should be probed
555 * and attached.
556 */
557int
558bhnd_bus_probe_children(device_t bus)
559{
560	device_t	*devs;
561	int		 ndevs;
562	int		 error;
563
564	/* Fetch children in attach order */
565	error = bhnd_bus_get_children(bus, &devs, &ndevs,
566	    BHND_DEVICE_ORDER_ATTACH);
567	if (error)
568		return (error);
569
570	/* Probe and attach all children */
571	for (int i = 0; i < ndevs; i++) {
572		device_t child = devs[i];
573		device_probe_and_attach(child);
574	}
575
576	bhnd_bus_free_children(devs);
577
578	return (0);
579}
580
581/**
582 * Walk up the bhnd device hierarchy to locate the root device
583 * to which the bhndb bridge is attached.
584 *
585 * This can be used from within bhnd host bridge drivers to locate the
586 * actual upstream host device.
587 *
588 * @param dev A bhnd device.
589 * @param bus_class The expected bus (e.g. "pci") to which the bridge root
590 * should be attached.
591 *
592 * @retval device_t if a matching parent device is found.
593 * @retval NULL if @p dev is not attached via a bhndb bus.
594 * @retval NULL if no parent device is attached via @p bus_class.
595 */
596device_t
597bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
598{
599	devclass_t	bhndb_class;
600	device_t	parent;
601
602	KASSERT(device_get_devclass(device_get_parent(dev)) ==
603	    devclass_find("bhnd"),
604	   ("%s not a bhnd device", device_get_nameunit(dev)));
605
606	bhndb_class = devclass_find("bhndb");
607
608	/* Walk the device tree until we hit a bridge */
609	parent = dev;
610	while ((parent = device_get_parent(parent)) != NULL) {
611		if (device_get_devclass(parent) == bhndb_class)
612			break;
613	}
614
615	/* No bridge? */
616	if (parent == NULL)
617		return (NULL);
618
619	/* Search for a parent attached to the expected bus class */
620	while ((parent = device_get_parent(parent)) != NULL) {
621		device_t bus;
622
623		bus = device_get_parent(parent);
624		if (bus != NULL && device_get_devclass(bus) == bus_class)
625			return (parent);
626	}
627
628	/* Not found */
629	return (NULL);
630}
631
632/**
633 * Find the first core in @p cores that matches @p desc.
634 *
635 * @param cores The table to search.
636 * @param num_cores The length of @p cores.
637 * @param desc A match descriptor.
638 *
639 * @retval bhnd_core_info if a matching core is found.
640 * @retval NULL if no matching core is found.
641 */
642const struct bhnd_core_info *
643bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
644    const struct bhnd_core_match *desc)
645{
646	for (u_int i = 0; i < num_cores; i++) {
647		if (bhnd_core_matches(&cores[i], desc))
648			return &cores[i];
649	}
650
651	return (NULL);
652}
653
654/**
655 * Find the first core in @p cores with the given @p class.
656 *
657 * @param cores The table to search.
658 * @param num_cores The length of @p cores.
659 * @param class The device class to match on.
660 *
661 * @retval non-NULL if a matching core is found.
662 * @retval NULL if no matching core is found.
663 */
664const struct bhnd_core_info *
665bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
666    bhnd_devclass_t class)
667{
668	struct bhnd_core_match md = {
669		BHND_MATCH_CORE_CLASS(class)
670	};
671
672	return bhnd_match_core(cores, num_cores, &md);
673}
674
675/**
676 * Create an equality match descriptor for @p core.
677 *
678 * @param core The core info to be matched on.
679 *
680 * @return an equality match descriptor for @p core.
681 */
682struct bhnd_core_match
683bhnd_core_get_match_desc(const struct bhnd_core_info *core)
684{
685	return ((struct bhnd_core_match) {
686		BHND_MATCH_CORE_VENDOR(core->vendor),
687		BHND_MATCH_CORE_ID(core->device),
688		BHND_MATCH_CORE_REV(HWREV_EQ(core->hwrev)),
689		BHND_MATCH_CORE_CLASS(bhnd_core_class(core)),
690		BHND_MATCH_CORE_IDX(core->core_idx),
691		BHND_MATCH_CORE_UNIT(core->unit)
692	});
693}
694
695/**
696 * Return true if the @p lhs is equal to @p rhs.
697 *
698 * @param lhs The first bhnd core descriptor to compare.
699 * @param rhs The second bhnd core descriptor to compare.
700 *
701 * @retval true if @p lhs is equal to @p rhs
702 * @retval false if @p lhs is not equal to @p rhs
703 */
704bool
705bhnd_cores_equal(const struct bhnd_core_info *lhs,
706    const struct bhnd_core_info *rhs)
707{
708	struct bhnd_core_match md;
709
710	/* Use an equality match descriptor to perform the comparison */
711	md = bhnd_core_get_match_desc(rhs);
712	return (bhnd_core_matches(lhs, &md));
713}
714
715/**
716 * Return true if the @p core matches @p desc.
717 *
718 * @param core A bhnd core descriptor.
719 * @param desc A match descriptor to compare against @p core.
720 *
721 * @retval true if @p core matches @p match.
722 * @retval false if @p core does not match @p match.
723 */
724bool
725bhnd_core_matches(const struct bhnd_core_info *core,
726    const struct bhnd_core_match *desc)
727{
728	if (desc->m.match.core_vendor && desc->core_vendor != core->vendor)
729		return (false);
730
731	if (desc->m.match.core_id && desc->core_id != core->device)
732		return (false);
733
734	if (desc->m.match.core_unit && desc->core_unit != core->unit)
735		return (false);
736
737	if (desc->m.match.core_rev &&
738	    !bhnd_hwrev_matches(core->hwrev, &desc->core_rev))
739		return (false);
740
741	if (desc->m.match.core_idx && desc->core_idx != core->core_idx)
742		return (false);
743
744	if (desc->m.match.core_class &&
745	    desc->core_class != bhnd_core_class(core))
746		return (false);
747
748	return true;
749}
750
751/**
752 * Return true if the @p chip matches @p desc.
753 *
754 * @param chip A bhnd chip identifier.
755 * @param desc A match descriptor to compare against @p chip.
756 *
757 * @retval true if @p chip matches @p match.
758 * @retval false if @p chip does not match @p match.
759 */
760bool
761bhnd_chip_matches(const struct bhnd_chipid *chip,
762    const struct bhnd_chip_match *desc)
763{
764	if (desc->m.match.chip_id && chip->chip_id != desc->chip_id)
765		return (false);
766
767	if (desc->m.match.chip_pkg && chip->chip_pkg != desc->chip_pkg)
768		return (false);
769
770	if (desc->m.match.chip_rev &&
771	    !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
772		return (false);
773
774	if (desc->m.match.chip_type && chip->chip_type != desc->chip_type)
775		return (false);
776
777	return (true);
778}
779
780/**
781 * Return true if the @p board matches @p desc.
782 *
783 * @param board The bhnd board info.
784 * @param desc A match descriptor to compare against @p board.
785 *
786 * @retval true if @p chip matches @p match.
787 * @retval false if @p chip does not match @p match.
788 */
789bool
790bhnd_board_matches(const struct bhnd_board_info *board,
791    const struct bhnd_board_match *desc)
792{
793	if (desc->m.match.board_srom_rev &&
794	    !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
795		return (false);
796
797	if (desc->m.match.board_vendor &&
798	    board->board_vendor != desc->board_vendor)
799		return (false);
800
801	if (desc->m.match.board_type && board->board_type != desc->board_type)
802		return (false);
803
804	if (desc->m.match.board_devid &&
805	    board->board_devid != desc->board_devid)
806		return (false);
807
808	if (desc->m.match.board_rev &&
809	    !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
810		return (false);
811
812	return (true);
813}
814
815/**
816 * Return true if the @p hwrev matches @p desc.
817 *
818 * @param hwrev A bhnd hardware revision.
819 * @param desc A match descriptor to compare against @p core.
820 *
821 * @retval true if @p hwrev matches @p match.
822 * @retval false if @p hwrev does not match @p match.
823 */
824bool
825bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
826{
827	if (desc->start != BHND_HWREV_INVALID &&
828	    desc->start > hwrev)
829		return false;
830
831	if (desc->end != BHND_HWREV_INVALID &&
832	    desc->end < hwrev)
833		return false;
834
835	return true;
836}
837
838/**
839 * Return true if the @p dev matches @p desc.
840 *
841 * @param dev A bhnd device.
842 * @param desc A match descriptor to compare against @p dev.
843 *
844 * @retval true if @p dev matches @p match.
845 * @retval false if @p dev does not match @p match.
846 */
847bool
848bhnd_device_matches(device_t dev, const struct bhnd_device_match *desc)
849{
850	struct bhnd_core_info		 core;
851	const struct bhnd_chipid	*chip;
852	struct bhnd_board_info		 board;
853	device_t			 parent;
854	int				 error;
855
856	/* Construct individual match descriptors */
857	struct bhnd_core_match	m_core	= { _BHND_CORE_MATCH_COPY(desc) };
858	struct bhnd_chip_match	m_chip	= { _BHND_CHIP_MATCH_COPY(desc) };
859	struct bhnd_board_match	m_board	= { _BHND_BOARD_MATCH_COPY(desc) };
860
861	/* Fetch and match core info */
862	if (m_core.m.match_flags) {
863		/* Only applicable to bhnd-attached cores */
864		parent = device_get_parent(dev);
865		if (device_get_devclass(parent) != devclass_find("bhnd")) {
866			device_printf(dev, "attempting to match core "
867			    "attributes against non-core device\n");
868			return (false);
869		}
870
871		core = bhnd_get_core_info(dev);
872		if (!bhnd_core_matches(&core, &m_core))
873			return (false);
874	}
875
876	/* Fetch and match chip info */
877	if (m_chip.m.match_flags) {
878		chip = bhnd_get_chipid(dev);
879
880		if (!bhnd_chip_matches(chip, &m_chip))
881			return (false);
882	}
883
884	/* Fetch and match board info.
885	 *
886	 * This is not available until  after NVRAM is up; earlier device
887	 * matches should not include board requirements */
888	if (m_board.m.match_flags) {
889		if ((error = bhnd_read_board_info(dev, &board))) {
890			device_printf(dev, "failed to read required board info "
891			    "during device matching: %d\n", error);
892			return (false);
893		}
894
895		if (!bhnd_board_matches(&board, &m_board))
896			return (false);
897	}
898
899	/* All matched */
900	return (true);
901}
902
903/**
904 * Search @p table for an entry matching @p dev.
905 *
906 * @param dev A bhnd device to match against @p table.
907 * @param table The device table to search.
908 * @param entry_size The @p table entry size, in bytes.
909 *
910 * @retval non-NULL the first matching device, if any.
911 * @retval NULL if no matching device is found in @p table.
912 */
913const struct bhnd_device *
914bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
915    size_t entry_size)
916{
917	const struct bhnd_device	*entry;
918	device_t			 hostb, parent;
919	bhnd_attach_type		 attach_type;
920	uint32_t			 dflags;
921
922	parent = device_get_parent(dev);
923	hostb = bhnd_bus_find_hostb_device(parent);
924	attach_type = bhnd_get_attach_type(dev);
925
926	for (entry = table; !BHND_DEVICE_IS_END(entry); entry =
927	    (const struct bhnd_device *) ((const char *) entry + entry_size))
928	{
929		/* match core info */
930		if (!bhnd_device_matches(dev, &entry->core))
931			continue;
932
933		/* match device flags */
934		dflags = entry->device_flags;
935
936		/* hostb implies BHND_ATTACH_ADAPTER requirement */
937		if (dflags & BHND_DF_HOSTB)
938			dflags |= BHND_DF_ADAPTER;
939
940		if (dflags & BHND_DF_ADAPTER)
941			if (attach_type != BHND_ATTACH_ADAPTER)
942				continue;
943
944		if (dflags & BHND_DF_HOSTB)
945			if (dev != hostb)
946				continue;
947
948		if (dflags & BHND_DF_SOC)
949			if (attach_type != BHND_ATTACH_NATIVE)
950				continue;
951
952		/* device found */
953		return (entry);
954	}
955
956	/* not found */
957	return (NULL);
958}
959
960/**
961 * Scan the device @p table for all quirk flags applicable to @p dev.
962 *
963 * @param dev A bhnd device to match against @p table.
964 * @param table The device table to search.
965 * @param entry_size The @p table entry size, in bytes.
966 *
967 * @return all matching quirk flags.
968 */
969uint32_t
970bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
971    size_t entry_size)
972{
973	const struct bhnd_device	*dent;
974	const struct bhnd_device_quirk	*qent, *qtable;
975	uint32_t			 quirks;
976
977	/* Locate the device entry */
978	if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL)
979		return (0);
980
981	/* Quirks table is optional */
982	qtable = dent->quirks_table;
983	if (qtable == NULL)
984		return (0);
985
986	/* Collect matching device quirk entries */
987	quirks = 0;
988	for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
989		if (bhnd_device_matches(dev, &qent->desc))
990			quirks |= qent->quirks;
991	}
992
993	return (quirks);
994}
995
996/**
997 * Allocate bhnd(4) resources defined in @p rs from a parent bus.
998 *
999 * @param dev The device requesting ownership of the resources.
1000 * @param rs A standard bus resource specification. This will be updated
1001 * with the allocated resource's RIDs.
1002 * @param res On success, the allocated bhnd resources.
1003 *
1004 * @retval 0 success
1005 * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
1006 * 		    all allocated resources will be released and a regular
1007 * 		    unix error code will be returned.
1008 */
1009int
1010bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
1011    struct bhnd_resource **res)
1012{
1013	/* Initialize output array */
1014	for (u_int i = 0; rs[i].type != -1; i++)
1015		res[i] = NULL;
1016
1017	for (u_int i = 0; rs[i].type != -1; i++) {
1018		res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
1019		    rs[i].flags);
1020
1021		/* Clean up all allocations on failure */
1022		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
1023			bhnd_release_resources(dev, rs, res);
1024			return (ENXIO);
1025		}
1026	}
1027
1028	return (0);
1029}
1030
1031/**
1032 * Release bhnd(4) resources defined in @p rs from a parent bus.
1033 *
1034 * @param dev The device that owns the resources.
1035 * @param rs A standard bus resource specification previously initialized
1036 * by @p bhnd_alloc_resources.
1037 * @param res The bhnd resources to be released.
1038 */
1039void
1040bhnd_release_resources(device_t dev, const struct resource_spec *rs,
1041    struct bhnd_resource **res)
1042{
1043	for (u_int i = 0; rs[i].type != -1; i++) {
1044		if (res[i] == NULL)
1045			continue;
1046
1047		bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
1048		res[i] = NULL;
1049	}
1050}
1051
1052/**
1053 * Allocate and return a new per-core PMU clock control/status (clkctl)
1054 * instance for @p dev.
1055 *
1056 * @param dev		The bhnd(4) core device mapped by @p r.
1057 * @param pmu_dev	The bhnd(4) PMU device, implmenting the bhnd_pmu_if
1058 *			interface. The caller is responsible for ensuring that
1059 *			this reference remains valid for the lifetime of the
1060 *			returned clkctl instance.
1061 * @param r		A resource mapping the core's clock control register
1062 * 			(see BHND_CLK_CTL_ST). The caller is responsible for
1063 *			ensuring that this resource remains valid for the
1064 *			lifetime of the returned clkctl instance.
1065 * @param offset	The offset to the clock control register within @p r.
1066 * @param max_latency	The PMU's maximum state transition latency in
1067 *			microseconds; this upper bound will be used to busy-wait
1068 *			on PMU state transitions.
1069 *
1070 * @retval non-NULL	success
1071 * @retval NULL		if allocation fails.
1072 *
1073 */
1074struct bhnd_core_clkctl *
1075bhnd_alloc_core_clkctl(device_t dev, device_t pmu_dev, struct bhnd_resource *r,
1076    bus_size_t offset, u_int max_latency)
1077{
1078	struct bhnd_core_clkctl	*clkctl;
1079
1080	clkctl = malloc(sizeof(*clkctl), M_BHND, M_ZERO | M_NOWAIT);
1081	if (clkctl == NULL)
1082		return (NULL);
1083
1084	clkctl->cc_dev = dev;
1085	clkctl->cc_pmu_dev = pmu_dev;
1086	clkctl->cc_res = r;
1087	clkctl->cc_res_offset = offset;
1088	clkctl->cc_max_latency = max_latency;
1089	clkctl->cc_quirks = bhnd_device_quirks(dev, bhnd_clkctl_devices,
1090	    sizeof(bhnd_clkctl_devices[0]));
1091
1092	BHND_CLKCTL_LOCK_INIT(clkctl);
1093
1094	return (clkctl);
1095}
1096
1097/**
1098 * Free a clkctl instance previously allocated via bhnd_alloc_core_clkctl().
1099 *
1100 * @param clkctl	The clkctl instance to be freed.
1101 */
1102void
1103bhnd_free_core_clkctl(struct bhnd_core_clkctl *clkctl)
1104{
1105	BHND_CLKCTL_LOCK_DESTROY(clkctl);
1106
1107	free(clkctl, M_BHND);
1108}
1109
1110/**
1111 * Wait for the per-core clock status to be equal to @p value after
1112 * applying @p mask, timing out after the maximum transition latency is reached.
1113 *
1114 * @param clkctl	Per-core clkctl state to be queryied.
1115 * @param value		Value to wait for.
1116 * @param mask		Mask to apply prior to value comparison.
1117 *
1118 * @retval 0		success
1119 * @retval ETIMEDOUT	if the PMU's maximum transition delay is reached before
1120 *			the clock status matches @p value and @p mask.
1121 */
1122int
1123bhnd_core_clkctl_wait(struct bhnd_core_clkctl *clkctl, uint32_t value,
1124    uint32_t mask)
1125{
1126	uint32_t	clkst;
1127
1128	BHND_CLKCTL_LOCK_ASSERT(clkctl, MA_OWNED);
1129
1130	/* Bitswapped HTAVAIL/ALPAVAIL work-around */
1131	if (clkctl->cc_quirks & BHND_CLKCTL_QUIRK_CCS0) {
1132		uint32_t fmask, fval;
1133
1134		fmask = mask & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
1135		fval = value & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
1136
1137		if (mask & BHND_CCS_HTAVAIL)
1138			fmask |= BHND_CCS0_HTAVAIL;
1139		if (value & BHND_CCS_HTAVAIL)
1140			fval |= BHND_CCS0_HTAVAIL;
1141
1142		if (mask & BHND_CCS_ALPAVAIL)
1143			fmask |= BHND_CCS0_ALPAVAIL;
1144		if (value & BHND_CCS_ALPAVAIL)
1145			fval |= BHND_CCS0_ALPAVAIL;
1146
1147		mask = fmask;
1148		value = fval;
1149	}
1150
1151	for (u_int i = 0; i < clkctl->cc_max_latency; i += 10) {
1152		clkst = bhnd_bus_read_4(clkctl->cc_res, clkctl->cc_res_offset);
1153		if ((clkst & mask) == (value & mask))
1154			return (0);
1155
1156		DELAY(10);
1157	}
1158
1159	device_printf(clkctl->cc_dev, "clkst wait timeout (value=%#x, "
1160	    "mask=%#x)\n", value, mask);
1161
1162	return (ETIMEDOUT);
1163}
1164
1165/**
1166 * Read an NVRAM variable's NUL-terminated string value.
1167 *
1168 * @param 	dev	A bhnd bus child device.
1169 * @param	name	The NVRAM variable name.
1170 * @param[out]	buf	A buffer large enough to hold @p len bytes. On
1171 *			success, the NUL-terminated string value will be
1172 *			written to this buffer. This argment may be NULL if
1173 *			the value is not desired.
1174 * @param	len	The maximum capacity of @p buf.
1175 * @param[out]	rlen	On success, will be set to the actual size of
1176 *			the requested value (including NUL termination). This
1177 *			argment may be NULL if the size is not desired.
1178 *
1179 * @retval 0		success
1180 * @retval ENOENT	The requested variable was not found.
1181 * @retval ENODEV	No valid NVRAM source could be found.
1182 * @retval ENOMEM	If @p buf is non-NULL and a buffer of @p len is too
1183 *			small to hold the requested value.
1184 * @retval EFTYPE	If the variable data cannot be coerced to a valid
1185 *			string representation.
1186 * @retval ERANGE	If value coercion would overflow @p type.
1187 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1188 *			error code will be returned.
1189 */
1190int
1191bhnd_nvram_getvar_str(device_t dev, const char *name, char *buf, size_t len,
1192    size_t *rlen)
1193{
1194	size_t	larg;
1195	int	error;
1196
1197	larg = len;
1198	error = bhnd_nvram_getvar(dev, name, buf, &larg,
1199	    BHND_NVRAM_TYPE_STRING);
1200	if (rlen != NULL)
1201		*rlen = larg;
1202
1203	return (error);
1204}
1205
1206/**
1207 * Read an NVRAM variable's unsigned integer value.
1208 *
1209 * @param 		dev	A bhnd bus child device.
1210 * @param		name	The NVRAM variable name.
1211 * @param[out]		value	On success, the requested value will be written
1212 *				to this pointer.
1213 * @param		width	The output integer type width (1, 2, or
1214 *				4 bytes).
1215 *
1216 * @retval 0		success
1217 * @retval ENOENT	The requested variable was not found.
1218 * @retval ENODEV	No valid NVRAM source could be found.
1219 * @retval EFTYPE	If the variable data cannot be coerced to a
1220 *			a valid unsigned integer representation.
1221 * @retval ERANGE	If value coercion would overflow (or underflow) an
1222 *			unsigned representation of the given @p width.
1223 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1224 *			error code will be returned.
1225 */
1226int
1227bhnd_nvram_getvar_uint(device_t dev, const char *name, void *value, int width)
1228{
1229	bhnd_nvram_type	type;
1230	size_t		len;
1231
1232	switch (width) {
1233	case 1:
1234		type = BHND_NVRAM_TYPE_UINT8;
1235		break;
1236	case 2:
1237		type = BHND_NVRAM_TYPE_UINT16;
1238		break;
1239	case 4:
1240		type = BHND_NVRAM_TYPE_UINT32;
1241		break;
1242	default:
1243		device_printf(dev, "unsupported NVRAM integer width: %d\n",
1244		    width);
1245		return (EINVAL);
1246	}
1247
1248	len = width;
1249	return (bhnd_nvram_getvar(dev, name, value, &len, type));
1250}
1251
1252/**
1253 * Read an NVRAM variable's unsigned 8-bit integer value.
1254 *
1255 * @param 		dev	A bhnd bus child device.
1256 * @param		name	The NVRAM variable name.
1257 * @param[out]		value	On success, the requested value will be written
1258 *				to this pointer.
1259 *
1260 * @retval 0		success
1261 * @retval ENOENT	The requested variable was not found.
1262 * @retval ENODEV	No valid NVRAM source could be found.
1263 * @retval EFTYPE	If the variable data cannot be coerced to a
1264 *			a valid unsigned integer representation.
1265 * @retval ERANGE	If value coercion would overflow (or underflow) uint8_t.
1266 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1267 *			error code will be returned.
1268 */
1269int
1270bhnd_nvram_getvar_uint8(device_t dev, const char *name, uint8_t *value)
1271{
1272	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
1273}
1274
1275/**
1276 * Read an NVRAM variable's unsigned 16-bit integer value.
1277 *
1278 * @param 		dev	A bhnd bus child device.
1279 * @param		name	The NVRAM variable name.
1280 * @param[out]		value	On success, the requested value will be written
1281 *				to this pointer.
1282 *
1283 * @retval 0		success
1284 * @retval ENOENT	The requested variable was not found.
1285 * @retval ENODEV	No valid NVRAM source could be found.
1286 * @retval EFTYPE	If the variable data cannot be coerced to a
1287 *			a valid unsigned integer representation.
1288 * @retval ERANGE	If value coercion would overflow (or underflow)
1289 *			uint16_t.
1290 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1291 *			error code will be returned.
1292 */
1293int
1294bhnd_nvram_getvar_uint16(device_t dev, const char *name, uint16_t *value)
1295{
1296	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
1297}
1298
1299/**
1300 * Read an NVRAM variable's unsigned 32-bit integer value.
1301 *
1302 * @param 		dev	A bhnd bus child device.
1303 * @param		name	The NVRAM variable name.
1304 * @param[out]		value	On success, the requested value will be written
1305 *				to this pointer.
1306 *
1307 * @retval 0		success
1308 * @retval ENOENT	The requested variable was not found.
1309 * @retval ENODEV	No valid NVRAM source could be found.
1310 * @retval EFTYPE	If the variable data cannot be coerced to a
1311 *			a valid unsigned integer representation.
1312 * @retval ERANGE	If value coercion would overflow (or underflow)
1313 *			uint32_t.
1314 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1315 *			error code will be returned.
1316 */
1317int
1318bhnd_nvram_getvar_uint32(device_t dev, const char *name, uint32_t *value)
1319{
1320	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
1321}
1322
1323/**
1324 * Read an NVRAM variable's signed integer value.
1325 *
1326 * @param 		dev	A bhnd bus child device.
1327 * @param		name	The NVRAM variable name.
1328 * @param[out]		value	On success, the requested value will be written
1329 *				to this pointer.
1330 * @param		width	The output integer type width (1, 2, or
1331 *				4 bytes).
1332 *
1333 * @retval 0		success
1334 * @retval ENOENT	The requested variable was not found.
1335 * @retval ENODEV	No valid NVRAM source could be found.
1336 * @retval EFTYPE	If the variable data cannot be coerced to a
1337 *			a valid integer representation.
1338 * @retval ERANGE	If value coercion would overflow (or underflow) an
1339 *			signed representation of the given @p width.
1340 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1341 *			error code will be returned.
1342 */
1343int
1344bhnd_nvram_getvar_int(device_t dev, const char *name, void *value, int width)
1345{
1346	bhnd_nvram_type	type;
1347	size_t		len;
1348
1349	switch (width) {
1350	case 1:
1351		type = BHND_NVRAM_TYPE_INT8;
1352		break;
1353	case 2:
1354		type = BHND_NVRAM_TYPE_INT16;
1355		break;
1356	case 4:
1357		type = BHND_NVRAM_TYPE_INT32;
1358		break;
1359	default:
1360		device_printf(dev, "unsupported NVRAM integer width: %d\n",
1361		    width);
1362		return (EINVAL);
1363	}
1364
1365	len = width;
1366	return (bhnd_nvram_getvar(dev, name, value, &len, type));
1367}
1368
1369/**
1370 * Read an NVRAM variable's signed 8-bit integer value.
1371 *
1372 * @param 		dev	A bhnd bus child device.
1373 * @param		name	The NVRAM variable name.
1374 * @param[out]		value	On success, the requested value will be written
1375 *				to this pointer.
1376 *
1377 * @retval 0		success
1378 * @retval ENOENT	The requested variable was not found.
1379 * @retval ENODEV	No valid NVRAM source could be found.
1380 * @retval EFTYPE	If the variable data cannot be coerced to a
1381 *			a valid integer representation.
1382 * @retval ERANGE	If value coercion would overflow (or underflow) int8_t.
1383 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1384 *			error code will be returned.
1385 */
1386int
1387bhnd_nvram_getvar_int8(device_t dev, const char *name, int8_t *value)
1388{
1389	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1390}
1391
1392/**
1393 * Read an NVRAM variable's signed 16-bit integer value.
1394 *
1395 * @param 		dev	A bhnd bus child device.
1396 * @param		name	The NVRAM variable name.
1397 * @param[out]		value	On success, the requested value will be written
1398 *				to this pointer.
1399 *
1400 * @retval 0		success
1401 * @retval ENOENT	The requested variable was not found.
1402 * @retval ENODEV	No valid NVRAM source could be found.
1403 * @retval EFTYPE	If the variable data cannot be coerced to a
1404 *			a valid integer representation.
1405 * @retval ERANGE	If value coercion would overflow (or underflow)
1406 *			int16_t.
1407 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1408 *			error code will be returned.
1409 */
1410int
1411bhnd_nvram_getvar_int16(device_t dev, const char *name, int16_t *value)
1412{
1413	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1414}
1415
1416/**
1417 * Read an NVRAM variable's signed 32-bit integer value.
1418 *
1419 * @param 		dev	A bhnd bus child device.
1420 * @param		name	The NVRAM variable name.
1421 * @param[out]		value	On success, the requested value will be written
1422 *				to this pointer.
1423 *
1424 * @retval 0		success
1425 * @retval ENOENT	The requested variable was not found.
1426 * @retval ENODEV	No valid NVRAM source could be found.
1427 * @retval EFTYPE	If the variable data cannot be coerced to a
1428 *			a valid integer representation.
1429 * @retval ERANGE	If value coercion would overflow (or underflow)
1430 *			int32_t.
1431 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1432 *			error code will be returned.
1433 */
1434int
1435bhnd_nvram_getvar_int32(device_t dev, const char *name, int32_t *value)
1436{
1437	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1438}
1439
1440/**
1441 * Read an NVRAM variable's array value.
1442 *
1443 * @param 		dev	A bhnd bus child device.
1444 * @param		name	The NVRAM variable name.
1445 * @param[out]		buf	A buffer large enough to hold @p size bytes.
1446 *				On success, the requested value will be written
1447 *				to this buffer.
1448 * @param[in,out]	size	The required number of bytes to write to
1449 *				@p buf.
1450 * @param		type	The desired array element data representation.
1451 *
1452 * @retval 0		success
1453 * @retval ENOENT	The requested variable was not found.
1454 * @retval ENODEV	No valid NVRAM source could be found.
1455 * @retval ENXIO	If less than @p size bytes are available.
1456 * @retval ENOMEM	If a buffer of @p size is too small to hold the
1457 *			requested value.
1458 * @retval EFTYPE	If the variable data cannot be coerced to a
1459 *			a valid instance of @p type.
1460 * @retval ERANGE	If value coercion would overflow (or underflow) a
1461 *			representation of @p type.
1462 * @retval non-zero	If reading @p name otherwise fails, a regular unix
1463 *			error code will be returned.
1464 */
1465int
1466bhnd_nvram_getvar_array(device_t dev, const char *name, void *buf, size_t size,
1467    bhnd_nvram_type type)
1468{
1469	size_t	nbytes;
1470	int	error;
1471
1472	/* Attempt read */
1473	nbytes = size;
1474	if ((error = bhnd_nvram_getvar(dev, name, buf, &nbytes, type)))
1475		return (error);
1476
1477	/* Verify that the expected number of bytes were fetched */
1478	if (nbytes < size)
1479		return (ENXIO);
1480
1481	return (0);
1482}
1483
1484/**
1485 * Initialize a service provider registry.
1486 *
1487 * @param bsr		The service registry to initialize.
1488 *
1489 * @retval 0            success
1490 * @retval non-zero     if an error occurs initializing the service registry,
1491 *                      a regular unix error code will be returned.
1492
1493 */
1494int
1495bhnd_service_registry_init(struct bhnd_service_registry *bsr)
1496{
1497	STAILQ_INIT(&bsr->entries);
1498	mtx_init(&bsr->lock, "bhnd_service_registry lock", NULL, MTX_DEF);
1499
1500	return (0);
1501}
1502
1503/**
1504 * Release all resources held by @p bsr.
1505 *
1506 * @param bsr		A service registry instance previously successfully
1507 *			initialized via bhnd_service_registry_init().
1508 *
1509 * @retval 0		success
1510 * @retval EBUSY	if active references to service providers registered
1511 *			with @p bsr exist.
1512 */
1513int
1514bhnd_service_registry_fini(struct bhnd_service_registry *bsr)
1515{
1516	struct bhnd_service_entry *entry, *enext;
1517
1518	/* Remove everthing we can */
1519	mtx_lock(&bsr->lock);
1520	STAILQ_FOREACH_SAFE(entry, &bsr->entries, link, enext) {
1521		if (entry->refs > 0)
1522			continue;
1523
1524		STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry, link);
1525		free(entry, M_BHND);
1526	}
1527
1528	if (!STAILQ_EMPTY(&bsr->entries)) {
1529		mtx_unlock(&bsr->lock);
1530		return (EBUSY);
1531	}
1532	mtx_unlock(&bsr->lock);
1533
1534	mtx_destroy(&bsr->lock);
1535	return (0);
1536}
1537
1538/**
1539 * Register a @p provider for the given @p service.
1540 *
1541 * @param bsr		Service registry to be modified.
1542 * @param provider	Service provider to register.
1543 * @param service	Service for which @p provider will be registered.
1544 * @param flags		Service provider flags (see BHND_SPF_*).
1545 *
1546 * @retval 0		success
1547 * @retval EEXIST	if an entry for @p service already exists.
1548 * @retval EINVAL	if @p service is BHND_SERVICE_ANY.
1549 * @retval non-zero	if registering @p provider otherwise fails, a regular
1550 *			unix error code will be returned.
1551 */
1552int
1553bhnd_service_registry_add(struct bhnd_service_registry *bsr, device_t provider,
1554    bhnd_service_t service, uint32_t flags)
1555{
1556	struct bhnd_service_entry *entry;
1557
1558	if (service == BHND_SERVICE_ANY)
1559		return (EINVAL);
1560
1561	mtx_lock(&bsr->lock);
1562
1563	/* Is a service provider already registered? */
1564	STAILQ_FOREACH(entry, &bsr->entries, link) {
1565		if (entry->service == service) {
1566			mtx_unlock(&bsr->lock);
1567			return (EEXIST);
1568		}
1569	}
1570
1571	/* Initialize and insert our new entry */
1572	entry = malloc(sizeof(*entry), M_BHND, M_NOWAIT);
1573	if (entry == NULL) {
1574		mtx_unlock(&bsr->lock);
1575		return (ENOMEM);
1576	}
1577
1578	entry->provider = provider;
1579	entry->service = service;
1580	entry->flags = flags;
1581	refcount_init(&entry->refs, 0);
1582
1583	STAILQ_INSERT_HEAD(&bsr->entries, entry, link);
1584
1585	mtx_unlock(&bsr->lock);
1586	return (0);
1587}
1588
1589/**
1590 * Free an unreferenced registry entry.
1591 *
1592 * @param entry	The entry to be deallocated.
1593 */
1594static void
1595bhnd_service_registry_free_entry(struct bhnd_service_entry *entry)
1596{
1597	KASSERT(entry->refs == 0, ("provider has active references"));
1598	free(entry, M_BHND);
1599}
1600
1601/**
1602 * Attempt to remove the @p service provider registration for @p provider.
1603 *
1604 * @param bsr		The service registry to be modified.
1605 * @param provider	The service provider to be deregistered.
1606 * @param service	The service for which @p provider will be deregistered,
1607 *			or BHND_SERVICE_ANY to remove all service
1608 *			registrations for @p provider.
1609 *
1610 * @retval 0		success
1611 * @retval EBUSY	if active references to @p provider exist; see
1612 *			bhnd_service_registry_retain() and
1613 *			bhnd_service_registry_release().
1614 */
1615int
1616bhnd_service_registry_remove(struct bhnd_service_registry *bsr,
1617    device_t provider, bhnd_service_t service)
1618{
1619	struct bhnd_service_entry *entry, *enext;
1620
1621	mtx_lock(&bsr->lock);
1622
1623#define	BHND_PROV_MATCH(_e)	\
1624	((_e)->provider == provider &&	\
1625	 (service == BHND_SERVICE_ANY || (_e)->service == service))
1626
1627	/* Validate matching provider entries before making any
1628	 * modifications */
1629	STAILQ_FOREACH(entry, &bsr->entries, link) {
1630		/* Skip non-matching entries */
1631		if (!BHND_PROV_MATCH(entry))
1632			continue;
1633
1634		/* Entry is in use? */
1635		if (entry->refs > 0) {
1636			mtx_unlock(&bsr->lock);
1637			return (EBUSY);
1638		}
1639	}
1640
1641	/* We can now safely remove matching entries */
1642	STAILQ_FOREACH_SAFE(entry, &bsr->entries, link, enext) {
1643		/* Skip non-matching entries */
1644		if (!BHND_PROV_MATCH(entry))
1645			continue;
1646
1647		/* Remove from list */
1648		STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry, link);
1649
1650		/* Free provider entry */
1651		bhnd_service_registry_free_entry(entry);
1652	}
1653#undef	BHND_PROV_MATCH
1654
1655	mtx_unlock(&bsr->lock);
1656	return (0);
1657}
1658
1659/**
1660 * Retain and return a reference to a registered @p service provider, if any.
1661 *
1662 * @param bsr		The service registry to be queried.
1663 * @param service	The service for which a provider should be returned.
1664 *
1665 * On success, the caller assumes ownership the returned provider, and
1666 * is responsible for releasing this reference via
1667 * bhnd_service_registry_release().
1668 *
1669 * @retval device_t	success
1670 * @retval NULL		if no provider is registered for @p service.
1671 */
1672device_t
1673bhnd_service_registry_retain(struct bhnd_service_registry *bsr,
1674    bhnd_service_t service)
1675{
1676	struct bhnd_service_entry *entry;
1677
1678	mtx_lock(&bsr->lock);
1679	STAILQ_FOREACH(entry, &bsr->entries, link) {
1680		if (entry->service != service)
1681			continue;
1682
1683		/* With a live refcount, entry is gauranteed to remain alive
1684		 * after we release our lock */
1685		refcount_acquire(&entry->refs);
1686
1687		mtx_unlock(&bsr->lock);
1688		return (entry->provider);
1689	}
1690	mtx_unlock(&bsr->lock);
1691
1692	/* Not found */
1693	return (NULL);
1694}
1695
1696/**
1697 * Release a reference to a service provider previously returned by
1698 * bhnd_service_registry_retain().
1699 *
1700 * If this is the last reference to an inherited service provider registration
1701 * (see BHND_SPF_INHERITED), the registration will also be removed, and
1702 * true will be returned.
1703 *
1704 * @param bsr		The service registry from which @p provider
1705 *			was returned.
1706 * @param provider	The provider to be released.
1707 * @param service	The service for which @p provider was previously
1708 *			retained.
1709 * @retval true		The inherited service provider registration was removed;
1710 *			the caller should release its own reference to the
1711 *			provider.
1712 * @retval false	The service provider was not inherited, or active
1713 *			references to the provider remain.
1714 *
1715 * @see BHND_SPF_INHERITED
1716 */
1717bool
1718bhnd_service_registry_release(struct bhnd_service_registry *bsr,
1719    device_t provider, bhnd_service_t service)
1720{
1721	struct bhnd_service_entry *entry;
1722
1723	/* Exclusive lock, as we need to prevent any new references to the
1724	 * entry from being taken if it's to be removed */
1725	mtx_lock(&bsr->lock);
1726	STAILQ_FOREACH(entry, &bsr->entries, link) {
1727		bool removed;
1728
1729		if (entry->provider != provider)
1730			continue;
1731
1732		if (entry->service != service)
1733			continue;
1734
1735		if (refcount_release(&entry->refs) &&
1736		    (entry->flags & BHND_SPF_INHERITED))
1737		{
1738			/* If an inherited entry is no longer actively
1739			 * referenced, remove the local registration and inform
1740			 * the caller. */
1741			STAILQ_REMOVE(&bsr->entries, entry, bhnd_service_entry,
1742			    link);
1743			bhnd_service_registry_free_entry(entry);
1744			removed = true;
1745		} else {
1746			removed = false;
1747		}
1748
1749		mtx_unlock(&bsr->lock);
1750		return (removed);
1751	}
1752
1753	/* Caller owns a reference, but no such provider is registered? */
1754	panic("invalid service provider reference");
1755}
1756
1757/**
1758 * Using the bhnd(4) bus-level core information and a custom core name,
1759 * populate @p dev's device description.
1760 *
1761 * @param dev A bhnd-bus attached device.
1762 * @param dev_name The core's name (e.g. "SDIO Device Core").
1763 */
1764void
1765bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
1766{
1767	const char *vendor_name;
1768
1769	vendor_name = bhnd_get_vendor_name(dev);
1770	device_set_descf(dev, "%s %s, rev %hhu", vendor_name, dev_name,
1771	    bhnd_get_hwrev(dev));
1772}
1773
1774/**
1775 * Using the bhnd(4) bus-level core information, populate @p dev's device
1776 * description.
1777 *
1778 * @param dev A bhnd-bus attached device.
1779 */
1780void
1781bhnd_set_default_core_desc(device_t dev)
1782{
1783	bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
1784}
1785
1786/**
1787 * Using the bhnd @p chip_id, populate the bhnd(4) bus @p dev's device
1788 * description.
1789 *
1790 * @param dev A bhnd-bus attached device.
1791 * @param chip_id The chip identification.
1792 */
1793void
1794bhnd_set_default_bus_desc(device_t dev, const struct bhnd_chipid *chip_id)
1795{
1796	const char	*bus_name;
1797	char		 chip_name[BHND_CHIPID_MAX_NAMELEN];
1798
1799	/* Determine chip type's bus name */
1800	switch (chip_id->chip_type) {
1801	case BHND_CHIPTYPE_SIBA:
1802		bus_name = "SIBA bus";
1803		break;
1804	case BHND_CHIPTYPE_BCMA:
1805	case BHND_CHIPTYPE_BCMA_ALT:
1806		bus_name = "BCMA bus";
1807		break;
1808	case BHND_CHIPTYPE_UBUS:
1809		bus_name = "UBUS bus";
1810		break;
1811	default:
1812		bus_name = "Unknown Type";
1813		break;
1814	}
1815
1816	/* Format chip name */
1817	bhnd_format_chip_id(chip_name, sizeof(chip_name),
1818	     chip_id->chip_id);
1819
1820	/* Format and set device description */
1821	device_set_descf(dev, "%s %s", chip_name, bus_name);
1822}
1823
1824/**
1825 * Helper function for implementing BHND_BUS_REGISTER_PROVIDER().
1826 *
1827 * This implementation delegates the request to the BHND_BUS_REGISTER_PROVIDER()
1828 * method on the parent of @p dev. If no parent exists, the implementation
1829 * will return an error.
1830 */
1831int
1832bhnd_bus_generic_register_provider(device_t dev, device_t child,
1833    device_t provider, bhnd_service_t service)
1834{
1835	device_t parent = device_get_parent(dev);
1836
1837	if (parent != NULL) {
1838		return (BHND_BUS_REGISTER_PROVIDER(parent, child,
1839		    provider, service));
1840	}
1841
1842	return (ENXIO);
1843}
1844
1845/**
1846 * Helper function for implementing BHND_BUS_DEREGISTER_PROVIDER().
1847 *
1848 * This implementation delegates the request to the
1849 * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
1850 * exists, the implementation will panic.
1851 */
1852int
1853bhnd_bus_generic_deregister_provider(device_t dev, device_t child,
1854    device_t provider, bhnd_service_t service)
1855{
1856	device_t parent = device_get_parent(dev);
1857
1858	if (parent != NULL) {
1859		return (BHND_BUS_DEREGISTER_PROVIDER(parent, child,
1860		    provider, service));
1861	}
1862
1863	panic("missing BHND_BUS_DEREGISTER_PROVIDER()");
1864}
1865
1866/**
1867 * Helper function for implementing BHND_BUS_RETAIN_PROVIDER().
1868 *
1869 * This implementation delegates the request to the
1870 * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
1871 * exists, the implementation will return NULL.
1872 */
1873device_t
1874bhnd_bus_generic_retain_provider(device_t dev, device_t child,
1875    bhnd_service_t service)
1876{
1877	device_t parent = device_get_parent(dev);
1878
1879	if (parent != NULL) {
1880		return (BHND_BUS_RETAIN_PROVIDER(parent, child,
1881		    service));
1882	}
1883
1884	return (NULL);
1885}
1886
1887/**
1888 * Helper function for implementing BHND_BUS_RELEASE_PROVIDER().
1889 *
1890 * This implementation delegates the request to the
1891 * BHND_BUS_DEREGISTER_PROVIDER() method on the parent of @p dev. If no parent
1892 * exists, the implementation will panic.
1893 */
1894void
1895bhnd_bus_generic_release_provider(device_t dev, device_t child,
1896    device_t provider, bhnd_service_t service)
1897{
1898	device_t parent = device_get_parent(dev);
1899
1900	if (parent != NULL) {
1901		return (BHND_BUS_RELEASE_PROVIDER(parent, child,
1902		    provider, service));
1903	}
1904
1905	panic("missing BHND_BUS_RELEASE_PROVIDER()");
1906}
1907
1908/**
1909 * Helper function for implementing BHND_BUS_REGISTER_PROVIDER().
1910 *
1911 * This implementation uses the bhnd_service_registry_add() function to
1912 * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
1913 * a suitable service registry to edit.
1914 */
1915int
1916bhnd_bus_generic_sr_register_provider(device_t dev, device_t child,
1917    device_t provider, bhnd_service_t service)
1918{
1919	struct bhnd_service_registry *bsr;
1920
1921	bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
1922
1923	KASSERT(bsr != NULL, ("NULL service registry"));
1924
1925	return (bhnd_service_registry_add(bsr, provider, service, 0));
1926}
1927
1928/**
1929 * Helper function for implementing BHND_BUS_DEREGISTER_PROVIDER().
1930 *
1931 * This implementation uses the bhnd_service_registry_remove() function to
1932 * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
1933 * a suitable service registry to edit.
1934 */
1935int
1936bhnd_bus_generic_sr_deregister_provider(device_t dev, device_t child,
1937    device_t provider, bhnd_service_t service)
1938{
1939	struct bhnd_service_registry *bsr;
1940
1941	bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
1942
1943	KASSERT(bsr != NULL, ("NULL service registry"));
1944
1945	return (bhnd_service_registry_remove(bsr, provider, service));
1946}
1947
1948/**
1949 * Helper function for implementing BHND_BUS_RETAIN_PROVIDER().
1950 *
1951 * This implementation uses the bhnd_service_registry_retain() function to
1952 * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
1953 * a suitable service registry.
1954 *
1955 * If a local provider for the service is not available, and a parent device is
1956 * available, this implementation will attempt to fetch and locally register
1957 * a service provider reference from the parent of @p dev.
1958 */
1959device_t
1960bhnd_bus_generic_sr_retain_provider(device_t dev, device_t child,
1961    bhnd_service_t service)
1962{
1963	struct bhnd_service_registry	*bsr;
1964	device_t			 parent, provider;
1965	int				 error;
1966
1967	bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
1968	KASSERT(bsr != NULL, ("NULL service registry"));
1969
1970	/*
1971	 * Attempt to fetch a service provider reference from either the local
1972	 * service registry, or if not found, from our parent.
1973	 *
1974	 * If we fetch a provider from our parent, we register the provider
1975	 * with the local service registry to prevent conflicting local
1976	 * registrations from being added.
1977	 */
1978	while (1) {
1979		/* Check the local service registry first */
1980		provider = bhnd_service_registry_retain(bsr, service);
1981		if (provider != NULL)
1982			return (provider);
1983
1984		/* Otherwise, try to delegate to our parent (if any) */
1985		if ((parent = device_get_parent(dev)) == NULL)
1986			return (NULL);
1987
1988		provider = BHND_BUS_RETAIN_PROVIDER(parent, dev, service);
1989		if (provider == NULL)
1990			return (NULL);
1991
1992		/* Register the inherited service registration with the local
1993		 * registry */
1994		error = bhnd_service_registry_add(bsr, provider, service,
1995		    BHND_SPF_INHERITED);
1996		if (error) {
1997			BHND_BUS_RELEASE_PROVIDER(parent, dev, provider,
1998			    service);
1999			if (error == EEXIST) {
2000				/* A valid service provider was registered
2001				 * concurrently; retry fetching from the local
2002				 * registry */
2003				continue;
2004			}
2005
2006			device_printf(dev, "failed to register service "
2007			    "provider: %d\n", error);
2008			return (NULL);
2009		}
2010	}
2011}
2012
2013/**
2014 * Helper function for implementing BHND_BUS_RELEASE_PROVIDER().
2015 *
2016 * This implementation uses the bhnd_service_registry_release() function to
2017 * do most of the work. It calls BHND_BUS_GET_SERVICE_REGISTRY() to find
2018 * a suitable service registry.
2019 */
2020void
2021bhnd_bus_generic_sr_release_provider(device_t dev, device_t child,
2022    device_t provider, bhnd_service_t service)
2023{
2024	struct bhnd_service_registry	*bsr;
2025
2026	bsr = BHND_BUS_GET_SERVICE_REGISTRY(dev, child);
2027	KASSERT(bsr != NULL, ("NULL service registry"));
2028
2029	/* Release the provider reference; if the refcount hits zero on an
2030	 * inherited reference, true will be returned, and we need to drop
2031	 * our own bus reference to the provider */
2032	if (!bhnd_service_registry_release(bsr, provider, service))
2033		return;
2034
2035	/* Drop our reference to the borrowed provider */
2036	BHND_BUS_RELEASE_PROVIDER(device_get_parent(dev), dev, provider,
2037	    service);
2038}
2039
2040/**
2041 * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
2042 *
2043 * If a parent device is available, this implementation delegates the
2044 * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
2045 *
2046 * If no parent device is available (i.e. on a the bus root), the hardware
2047 * is assumed to be usable and false is returned.
2048 */
2049bool
2050bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
2051{
2052	if (device_get_parent(dev) != NULL)
2053		return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
2054
2055	return (false);
2056}
2057
2058/**
2059 * Helper function for implementing BHND_BUS_GET_CHIPID().
2060 *
2061 * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
2062 * method on the parent of @p dev. If no parent exists, the implementation
2063 * will panic.
2064 */
2065const struct bhnd_chipid *
2066bhnd_bus_generic_get_chipid(device_t dev, device_t child)
2067{
2068	if (device_get_parent(dev) != NULL)
2069		return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
2070
2071	panic("missing BHND_BUS_GET_CHIPID()");
2072}
2073
2074/**
2075 * Helper function for implementing BHND_BUS_GET_DMA_TRANSLATION().
2076 *
2077 * If a parent device is available, this implementation delegates the
2078 * request to the BHND_BUS_GET_DMA_TRANSLATION() method on the parent of @p dev.
2079 *
2080 * If no parent device is available, this implementation will panic.
2081 */
2082int
2083bhnd_bus_generic_get_dma_translation(device_t dev, device_t child, u_int width,
2084    uint32_t flags, bus_dma_tag_t *dmat,
2085    struct bhnd_dma_translation *translation)
2086{
2087	if (device_get_parent(dev) != NULL) {
2088		return (BHND_BUS_GET_DMA_TRANSLATION(device_get_parent(dev),
2089		    child, width, flags, dmat, translation));
2090	}
2091
2092	panic("missing BHND_BUS_GET_DMA_TRANSLATION()");
2093}
2094
2095/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
2096#define	BHND_GV(_dest, _name)	\
2097	bhnd_nvram_getvar_uint(child, BHND_NVAR_ ## _name, &_dest,	\
2098	    sizeof(_dest))
2099
2100#define	REQ_BHND_GV(_dest, _name)		do {			\
2101	if ((error = BHND_GV(_dest, _name))) {				\
2102		device_printf(dev,					\
2103		    "error reading " __STRING(_name) ": %d\n", error);	\
2104		return (error);						\
2105	}								\
2106} while(0)
2107
2108#define	OPT_BHND_GV(_dest, _name, _default)	do {			\
2109	if ((error = BHND_GV(_dest, _name))) {				\
2110		if (error != ENOENT) {					\
2111			device_printf(dev,				\
2112			    "error reading "				\
2113			       __STRING(_name) ": %d\n", error);	\
2114			return (error);					\
2115		}							\
2116		_dest = _default;					\
2117	}								\
2118} while(0)
2119
2120/**
2121 * Helper function for implementing BHND_BUS_READ_BOARDINFO().
2122 *
2123 * This implementation populates @p info with information from NVRAM,
2124 * defaulting board_vendor and board_type fields to 0 if the
2125 * requested variables cannot be found.
2126 *
2127 * This behavior is correct for most SoCs, but must be overridden on
2128 * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
2129 * result.
2130 */
2131int
2132bhnd_bus_generic_read_board_info(device_t dev, device_t child,
2133    struct bhnd_board_info *info)
2134{
2135	int	error;
2136
2137	OPT_BHND_GV(info->board_vendor,	BOARDVENDOR,	0);
2138	OPT_BHND_GV(info->board_type,	BOARDTYPE,	0);	/* srom >= 2 */
2139	OPT_BHND_GV(info->board_devid,	DEVID,		0);	/* srom >= 8 */
2140	REQ_BHND_GV(info->board_rev,	BOARDREV);
2141	OPT_BHND_GV(info->board_srom_rev,SROMREV,	0);	/* missing in
2142								   some SoC
2143								   NVRAM */
2144	REQ_BHND_GV(info->board_flags,	BOARDFLAGS);
2145	OPT_BHND_GV(info->board_flags2,	BOARDFLAGS2,	0);	/* srom >= 4 */
2146	OPT_BHND_GV(info->board_flags3,	BOARDFLAGS3,	0);	/* srom >= 11 */
2147
2148	return (0);
2149}
2150
2151#undef	BHND_GV
2152#undef	BHND_GV_REQ
2153#undef	BHND_GV_OPT
2154
2155/**
2156 * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
2157 *
2158 * This implementation searches @p dev for a usable NVRAM child device.
2159 *
2160 * If no usable child device is found on @p dev, the request is delegated to
2161 * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
2162 */
2163int
2164bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
2165    void *buf, size_t *size, bhnd_nvram_type type)
2166{
2167	device_t	nvram;
2168	device_t	parent;
2169
2170	bus_topo_assert();
2171
2172	/* Look for a directly-attached NVRAM child */
2173	if ((nvram = device_find_child(dev, "bhnd_nvram", -1)) != NULL)
2174		return BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
2175
2176	/* Try to delegate to parent */
2177	if ((parent = device_get_parent(dev)) == NULL)
2178		return (ENODEV);
2179
2180	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
2181	    name, buf, size, type));
2182}
2183
2184/**
2185 * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
2186 *
2187 * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
2188 * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
2189 * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
2190 */
2191struct bhnd_resource *
2192bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
2193	int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
2194	u_int flags)
2195{
2196	struct bhnd_resource	*br;
2197	struct resource		*res;
2198	int			 error;
2199
2200	br = NULL;
2201	res = NULL;
2202
2203	/* Allocate the real bus resource (without activating it) */
2204	res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
2205	    (flags & ~RF_ACTIVE));
2206	if (res == NULL)
2207		return (NULL);
2208
2209	/* Allocate our bhnd resource wrapper. */
2210	br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
2211	if (br == NULL)
2212		goto failed;
2213
2214	br->direct = false;
2215	br->res = res;
2216
2217	/* Attempt activation */
2218	if (flags & RF_ACTIVE) {
2219		error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
2220		if (error)
2221			goto failed;
2222	}
2223
2224	return (br);
2225
2226failed:
2227	if (res != NULL)
2228		BUS_RELEASE_RESOURCE(dev, child, res);
2229
2230	free(br, M_BHND);
2231	return (NULL);
2232}
2233
2234/**
2235 * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
2236 *
2237 * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
2238 * the backing resource to BUS_RELEASE_RESOURCE().
2239 */
2240int
2241bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
2242    int rid, struct bhnd_resource *r)
2243{
2244	int error;
2245
2246	if ((error = BUS_RELEASE_RESOURCE(dev, child, r->res)))
2247		return (error);
2248
2249	free(r, M_BHND);
2250	return (0);
2251}
2252
2253/**
2254 * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
2255 *
2256 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() first calls the
2257 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
2258 *
2259 * If this fails, and if @p dev is the direct parent of @p child, standard
2260 * resource activation is attempted via bus_activate_resource(). This enables
2261 * direct use of the bhnd(4) resource APIs on devices that may not be attached
2262 * to a parent bhnd bus or bridge.
2263 */
2264int
2265bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
2266    int rid, struct bhnd_resource *r)
2267{
2268	int	error;
2269	bool	passthrough;
2270
2271	passthrough = (device_get_parent(child) != dev);
2272
2273	/* Try to delegate to the parent */
2274	if (device_get_parent(dev) != NULL) {
2275		error = BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
2276		    child, type, rid, r);
2277	} else {
2278		error = ENODEV;
2279	}
2280
2281	/* If bhnd(4) activation has failed and we're the child's direct
2282	 * parent, try falling back on standard resource activation.
2283	 */
2284	if (error && !passthrough) {
2285		error = bus_activate_resource(child, type, rid, r->res);
2286		if (!error)
2287			r->direct = true;
2288	}
2289
2290	return (error);
2291}
2292
2293/**
2294 * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
2295 *
2296 * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
2297 * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
2298 */
2299int
2300bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
2301    int type, int rid, struct bhnd_resource *r)
2302{
2303	if (device_get_parent(dev) != NULL)
2304		return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
2305		    child, type, rid, r));
2306
2307	return (EINVAL);
2308}
2309
2310/**
2311 * Helper function for implementing BHND_BUS_GET_INTR_DOMAIN().
2312 *
2313 * This implementation simply returns the address of nearest bhnd(4) bus,
2314 * which may be @p dev; this behavior may be incompatible with FDT/OFW targets.
2315 */
2316uintptr_t
2317bhnd_bus_generic_get_intr_domain(device_t dev, device_t child, bool self)
2318{
2319	return ((uintptr_t)dev);
2320}
2321