xref: /freebsd/sys/dev/bhnd/bhnd_subr.c (revision ce437beff1f521b5ac35ea67d0669c46b3bef27f)
1 /*-
2  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/systm.h>
36 
37 #include <machine/bus.h>
38 #include <sys/rman.h>
39 #include <machine/resource.h>
40 
41 #include <dev/bhnd/cores/chipc/chipcreg.h>
42 
43 #include "nvram/bhnd_nvram.h"
44 
45 #include "bhnd_chipc_if.h"
46 
47 #include "bhnd_nvram_if.h"
48 #include "bhnd_nvram_map.h"
49 
50 #include "bhndreg.h"
51 #include "bhndvar.h"
52 
53 /* BHND core device description table. */
54 static const struct bhnd_core_desc {
55 	uint16_t	 vendor;
56 	uint16_t	 device;
57 	bhnd_devclass_t	 class;
58 	const char	*desc;
59 } bhnd_core_descs[] = {
60 	#define	BHND_CDESC(_mfg, _cid, _cls, _desc)		\
61 	    { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,	\
62 		BHND_DEVCLASS_ ## _cls, _desc }
63 
64 	BHND_CDESC(BCM, CC,		CC,		"ChipCommon I/O Controller"),
65 	BHND_CDESC(BCM, ILINE20,	OTHER,		"iLine20 HPNA"),
66 	BHND_CDESC(BCM, SRAM,		RAM,		"SRAM"),
67 	BHND_CDESC(BCM, SDRAM,		RAM,		"SDRAM"),
68 	BHND_CDESC(BCM, PCI,		PCI,		"PCI Bridge"),
69 	BHND_CDESC(BCM, MIPS,		CPU,		"MIPS Core"),
70 	BHND_CDESC(BCM, ENET,		ENET_MAC,	"Fast Ethernet MAC"),
71 	BHND_CDESC(BCM, CODEC,		OTHER,		"V.90 Modem Codec"),
72 	BHND_CDESC(BCM, USB,		OTHER,		"USB 1.1 Device/Host Controller"),
73 	BHND_CDESC(BCM, ADSL,		OTHER,		"ADSL Core"),
74 	BHND_CDESC(BCM, ILINE100,	OTHER,		"iLine100 HPNA"),
75 	BHND_CDESC(BCM, IPSEC,		OTHER,		"IPsec Accelerator"),
76 	BHND_CDESC(BCM, UTOPIA,		OTHER,		"UTOPIA ATM Core"),
77 	BHND_CDESC(BCM, PCMCIA,		PCCARD,		"PCMCIA Bridge"),
78 	BHND_CDESC(BCM, SOCRAM,		RAM,		"Internal Memory"),
79 	BHND_CDESC(BCM, MEMC,		MEMC,		"MEMC SDRAM Controller"),
80 	BHND_CDESC(BCM, OFDM,		OTHER,		"OFDM PHY"),
81 	BHND_CDESC(BCM, EXTIF,		OTHER,		"External Interface"),
82 	BHND_CDESC(BCM, D11,		WLAN,		"802.11 MAC/PHY/Radio"),
83 	BHND_CDESC(BCM, APHY,		WLAN_PHY,	"802.11a PHY"),
84 	BHND_CDESC(BCM, BPHY,		WLAN_PHY,	"802.11b PHY"),
85 	BHND_CDESC(BCM, GPHY,		WLAN_PHY,	"802.11g PHY"),
86 	BHND_CDESC(BCM, MIPS33,		CPU,		"MIPS3302 Core"),
87 	BHND_CDESC(BCM, USB11H,		OTHER,		"USB 1.1 Host Controller"),
88 	BHND_CDESC(BCM, USB11D,		OTHER,		"USB 1.1 Device Core"),
89 	BHND_CDESC(BCM, USB20H,		OTHER,		"USB 2.0 Host Controller"),
90 	BHND_CDESC(BCM, USB20D,		OTHER,		"USB 2.0 Device Core"),
91 	BHND_CDESC(BCM, SDIOH,		OTHER,		"SDIO Host Controller"),
92 	BHND_CDESC(BCM, ROBO,		OTHER,		"RoboSwitch"),
93 	BHND_CDESC(BCM, ATA100,		OTHER,		"Parallel ATA Controller"),
94 	BHND_CDESC(BCM, SATAXOR,	OTHER,		"SATA DMA/XOR Controller"),
95 	BHND_CDESC(BCM, GIGETH,		ENET_MAC,	"Gigabit Ethernet MAC"),
96 	BHND_CDESC(BCM, PCIE,		PCIE,		"PCIe Bridge"),
97 	BHND_CDESC(BCM, NPHY,		WLAN_PHY,	"802.11n 2x2 PHY"),
98 	BHND_CDESC(BCM, SRAMC,		MEMC,		"SRAM Controller"),
99 	BHND_CDESC(BCM, MINIMAC,	OTHER,		"MINI MAC/PHY"),
100 	BHND_CDESC(BCM, ARM11,		CPU,		"ARM1176 CPU"),
101 	BHND_CDESC(BCM, ARM7S,		CPU,		"ARM7TDMI-S CPU"),
102 	BHND_CDESC(BCM, LPPHY,		WLAN_PHY,	"802.11a/b/g PHY"),
103 	BHND_CDESC(BCM, PMU,		PMU,		"PMU"),
104 	BHND_CDESC(BCM, SSNPHY,		WLAN_PHY,	"802.11n Single-Stream PHY"),
105 	BHND_CDESC(BCM, SDIOD,		OTHER,		"SDIO Device Core"),
106 	BHND_CDESC(BCM, ARMCM3,		CPU,		"ARM Cortex-M3 CPU"),
107 	BHND_CDESC(BCM, HTPHY,		WLAN_PHY,	"802.11n 4x4 PHY"),
108 	BHND_CDESC(MIPS,MIPS74K,	CPU,		"MIPS74k CPU"),
109 	BHND_CDESC(BCM, GMAC,		ENET_MAC,	"Gigabit MAC core"),
110 	BHND_CDESC(BCM, DMEMC,		MEMC,		"DDR1/DDR2 Memory Controller"),
111 	BHND_CDESC(BCM, PCIERC,		OTHER,		"PCIe Root Complex"),
112 	BHND_CDESC(BCM, OCP,		SOC_BRIDGE,	"OCP to OCP Bridge"),
113 	BHND_CDESC(BCM, SC,		OTHER,		"Shared Common Core"),
114 	BHND_CDESC(BCM, AHB,		SOC_BRIDGE,	"OCP to AHB Bridge"),
115 	BHND_CDESC(BCM, SPIH,		OTHER,		"SPI Host Controller"),
116 	BHND_CDESC(BCM, I2S,		OTHER,		"I2S Digital Audio Interface"),
117 	BHND_CDESC(BCM, DMEMS,		MEMC,		"SDR/DDR1 Memory Controller"),
118 	BHND_CDESC(BCM, UBUS_SHIM,	OTHER,		"BCM6362/UBUS WLAN SHIM"),
119 	BHND_CDESC(BCM, PCIE2,		PCIE,		"PCIe Bridge (Gen2)"),
120 
121 	BHND_CDESC(ARM, APB_BRIDGE,	SOC_BRIDGE,	"BP135 AMBA3 AXI to APB Bridge"),
122 	BHND_CDESC(ARM, PL301,		SOC_ROUTER,	"PL301 AMBA3 Interconnect"),
123 	BHND_CDESC(ARM, EROM,		EROM,		"PL366 Device Enumeration ROM"),
124 	BHND_CDESC(ARM, OOB_ROUTER,	OTHER,		"PL367 OOB Interrupt Router"),
125 	BHND_CDESC(ARM, AXI_UNMAPPED,	OTHER,		"Unmapped Address Ranges"),
126 
127 	BHND_CDESC(BCM, 4706_CC,	CC,		"ChipCommon I/O Controller"),
128 	BHND_CDESC(BCM, NS_PCIE2,	PCIE,		"PCIe Bridge (Gen2)"),
129 	BHND_CDESC(BCM, NS_DMA,		OTHER,		"DMA engine"),
130 	BHND_CDESC(BCM, NS_SDIO,	OTHER,		"SDIO 3.0 Host Controller"),
131 	BHND_CDESC(BCM, NS_USB20H,	OTHER,		"USB 2.0 Host Controller"),
132 	BHND_CDESC(BCM, NS_USB30H,	OTHER,		"USB 3.0 Host Controller"),
133 	BHND_CDESC(BCM, NS_A9JTAG,	OTHER,		"ARM Cortex A9 JTAG Interface"),
134 	BHND_CDESC(BCM, NS_DDR23_MEMC,	MEMC,		"Denali DDR2/DD3 Memory Controller"),
135 	BHND_CDESC(BCM, NS_ROM,		NVRAM,		"System ROM"),
136 	BHND_CDESC(BCM, NS_NAND,	NVRAM,		"NAND Flash Controller"),
137 	BHND_CDESC(BCM, NS_QSPI,	NVRAM,		"QSPI Flash Controller"),
138 	BHND_CDESC(BCM, NS_CC_B,	CC_B,		"ChipCommon B Auxiliary I/O Controller"),
139 	BHND_CDESC(BCM, 4706_SOCRAM,	RAM,		"Internal Memory"),
140 	BHND_CDESC(BCM, IHOST_ARMCA9,	CPU,		"ARM Cortex A9 CPU"),
141 	BHND_CDESC(BCM, 4706_GMAC_CMN,	ENET,		"Gigabit MAC (Common)"),
142 	BHND_CDESC(BCM, 4706_GMAC,	ENET_MAC,	"Gigabit MAC"),
143 	BHND_CDESC(BCM, AMEMC,		MEMC,		"Denali DDR1/DDR2 Memory Controller"),
144 #undef	BHND_CDESC
145 
146 	/* Derived from inspection of the BCM4331 cores that provide PrimeCell
147 	 * IDs. Due to lack of documentation, the surmised device name/purpose
148 	 * provided here may be incorrect. */
149 	{ BHND_MFGID_ARM,	BHND_PRIMEID_EROM,	BHND_DEVCLASS_OTHER,
150 	    "PL364 Device Enumeration ROM" },
151 	{ BHND_MFGID_ARM,	BHND_PRIMEID_SWRAP,	BHND_DEVCLASS_OTHER,
152 	    "PL368 Device Management Interface" },
153 	{ BHND_MFGID_ARM,	BHND_PRIMEID_MWRAP,	BHND_DEVCLASS_OTHER,
154 	    "PL369 Device Management Interface" },
155 
156 	{ 0, 0, 0, NULL }
157 };
158 
159 /**
160  * Return the name for a given JEP106 manufacturer ID.
161  *
162  * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
163  * JEP106 continuation code.
164  */
165 const char *
166 bhnd_vendor_name(uint16_t vendor)
167 {
168 	switch (vendor) {
169 	case BHND_MFGID_ARM:
170 		return "ARM";
171 	case BHND_MFGID_BCM:
172 		return "Broadcom";
173 	case BHND_MFGID_MIPS:
174 		return "MIPS";
175 	default:
176 		return "unknown";
177 	}
178 }
179 
180 /**
181  * Return the name of a port type.
182  */
183 const char *
184 bhnd_port_type_name(bhnd_port_type port_type)
185 {
186 	switch (port_type) {
187 	case BHND_PORT_DEVICE:
188 		return ("device");
189 	case BHND_PORT_BRIDGE:
190 		return ("bridge");
191 	case BHND_PORT_AGENT:
192 		return ("agent");
193 	default:
194 		return "unknown";
195 	}
196 }
197 
198 /**
199  * Return the name of an NVRAM source.
200  */
201 const char *
202 bhnd_nvram_src_name(bhnd_nvram_src nvram_src)
203 {
204 	switch (nvram_src) {
205 	case BHND_NVRAM_SRC_FLASH:
206 		return ("flash");
207 	case BHND_NVRAM_SRC_OTP:
208 		return ("OTP");
209 	case BHND_NVRAM_SRC_SPROM:
210 		return ("SPROM");
211 	case BHND_NVRAM_SRC_UNKNOWN:
212 		return ("none");
213 	default:
214 		return ("unknown");
215 	}
216 }
217 
218 static const struct bhnd_core_desc *
219 bhnd_find_core_desc(uint16_t vendor, uint16_t device)
220 {
221 	for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
222 		if (bhnd_core_descs[i].vendor != vendor)
223 			continue;
224 
225 		if (bhnd_core_descs[i].device != device)
226 			continue;
227 
228 		return (&bhnd_core_descs[i]);
229 	}
230 
231 	return (NULL);
232 }
233 
234 /**
235  * Return a human-readable name for a BHND core.
236  *
237  * @param vendor The core designer's JEDEC-106 Manufacturer ID
238  * @param device The core identifier.
239  */
240 const char *
241 bhnd_find_core_name(uint16_t vendor, uint16_t device)
242 {
243 	const struct bhnd_core_desc *desc;
244 
245 	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
246 		return ("unknown");
247 
248 	return desc->desc;
249 }
250 
251 /**
252  * Return the device class for a BHND core.
253  *
254  * @param vendor The core designer's JEDEC-106 Manufacturer ID
255  * @param device The core identifier.
256  */
257 bhnd_devclass_t
258 bhnd_find_core_class(uint16_t vendor, uint16_t device)
259 {
260 	const struct bhnd_core_desc *desc;
261 
262 	if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
263 		return (BHND_DEVCLASS_OTHER);
264 
265 	return desc->class;
266 }
267 
268 /**
269  * Return a human-readable name for a BHND core.
270  *
271  * @param ci The core's info record.
272  */
273 const char *
274 bhnd_core_name(const struct bhnd_core_info *ci)
275 {
276 	return bhnd_find_core_name(ci->vendor, ci->device);
277 }
278 
279 /**
280  * Return the device class for a BHND core.
281  *
282  * @param ci The core's info record.
283  */
284 bhnd_devclass_t
285 bhnd_core_class(const struct bhnd_core_info *ci)
286 {
287 	return bhnd_find_core_class(ci->vendor, ci->device);
288 }
289 
290 /**
291  * Initialize a core info record with data from from a bhnd-attached @p dev.
292  *
293  * @param dev A bhnd device.
294  * @param core The record to be initialized.
295  */
296 struct bhnd_core_info
297 bhnd_get_core_info(device_t dev) {
298 	return (struct bhnd_core_info) {
299 		.vendor		= bhnd_get_vendor(dev),
300 		.device		= bhnd_get_device(dev),
301 		.hwrev		= bhnd_get_hwrev(dev),
302 		.core_idx	= bhnd_get_core_index(dev),
303 		.unit		= bhnd_get_core_unit(dev)
304 	};
305 }
306 
307 /**
308  * Find a @p class child device with @p unit on @p dev.
309  *
310  * @param parent The bhnd-compatible bus to be searched.
311  * @param class The device class to match on.
312  * @param unit The core unit number; specify -1 to return the first match
313  * regardless of unit number.
314  *
315  * @retval device_t if a matching child device is found.
316  * @retval NULL if no matching child device is found.
317  */
318 device_t
319 bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
320 {
321 	struct bhnd_core_match md = {
322 		BHND_MATCH_CORE_CLASS(class),
323 		BHND_MATCH_CORE_UNIT(unit)
324 	};
325 
326 	if (unit == -1)
327 		md.m.match.core_unit = 0;
328 
329 	return bhnd_match_child(dev, &md);
330 }
331 
332 /**
333  * Find the first child device on @p dev that matches @p desc.
334  *
335  * @param parent The bhnd-compatible bus to be searched.
336  * @param desc A match descriptor.
337  *
338  * @retval device_t if a matching child device is found.
339  * @retval NULL if no matching child device is found.
340  */
341 device_t
342 bhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
343 {
344 	device_t	*devlistp;
345 	device_t	 match;
346 	int		 devcnt;
347 	int		 error;
348 
349 	error = device_get_children(dev, &devlistp, &devcnt);
350 	if (error != 0)
351 		return (NULL);
352 
353 	match = NULL;
354 	for (int i = 0; i < devcnt; i++) {
355 		struct bhnd_core_info ci = bhnd_get_core_info(devlistp[i]);
356 
357 		if (bhnd_core_matches(&ci, desc)) {
358 			match = devlistp[i];
359 			goto done;
360 		}
361 	}
362 
363 done:
364 	free(devlistp, M_TEMP);
365 	return match;
366 }
367 
368 /**
369  * Walk up the bhnd device hierarchy to locate the root device
370  * to which the bhndb bridge is attached.
371  *
372  * This can be used from within bhnd host bridge drivers to locate the
373  * actual upstream host device.
374  *
375  * @param dev A bhnd device.
376  * @param bus_class The expected bus (e.g. "pci") to which the bridge root
377  * should be attached.
378  *
379  * @retval device_t if a matching parent device is found.
380  * @retval NULL @p dev is not attached via a bhndb bus
381  * @retval NULL no parent device is attached via @p bus_class.
382  */
383 device_t
384 bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
385 {
386 	devclass_t	bhndb_class;
387 	device_t	parent;
388 
389 	KASSERT(device_get_devclass(device_get_parent(dev)) == bhnd_devclass,
390 	   ("%s not a bhnd device", device_get_nameunit(dev)));
391 
392 	bhndb_class = devclass_find("bhndb");
393 
394 	/* Walk the device tree until we hit a bridge */
395 	parent = dev;
396 	while ((parent = device_get_parent(parent)) != NULL) {
397 		if (device_get_devclass(parent) == bhndb_class)
398 			break;
399 	}
400 
401 	/* No bridge? */
402 	if (parent == NULL)
403 		return (NULL);
404 
405 	/* Search for a parent attached to the expected bus class */
406 	while ((parent = device_get_parent(parent)) != NULL) {
407 		device_t bus;
408 
409 		bus = device_get_parent(parent);
410 		if (bus != NULL && device_get_devclass(bus) == bus_class)
411 			return (parent);
412 	}
413 
414 	/* Not found */
415 	return (NULL);
416 }
417 
418 /**
419  * Find the first core in @p cores that matches @p desc.
420  *
421  * @param cores The table to search.
422  * @param num_cores The length of @p cores.
423  * @param desc A match descriptor.
424  *
425  * @retval bhnd_core_info if a matching core is found.
426  * @retval NULL if no matching core is found.
427  */
428 const struct bhnd_core_info *
429 bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
430     const struct bhnd_core_match *desc)
431 {
432 	for (u_int i = 0; i < num_cores; i++) {
433 		if (bhnd_core_matches(&cores[i], desc))
434 			return &cores[i];
435 	}
436 
437 	return (NULL);
438 }
439 
440 
441 /**
442  * Find the first core in @p cores with the given @p class.
443  *
444  * @param cores The table to search.
445  * @param num_cores The length of @p cores.
446  * @param desc A match descriptor.
447  *
448  * @retval bhnd_core_info if a matching core is found.
449  * @retval NULL if no matching core is found.
450  */
451 const struct bhnd_core_info *
452 bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
453     bhnd_devclass_t class)
454 {
455 	struct bhnd_core_match md = {
456 		BHND_MATCH_CORE_CLASS(class)
457 	};
458 
459 	return bhnd_match_core(cores, num_cores, &md);
460 }
461 
462 /**
463  * Return true if the @p core matches @p desc.
464  *
465  * @param core A bhnd core descriptor.
466  * @param desc A match descriptor to compare against @p core.
467  *
468  * @retval true if @p core matches @p match
469  * @retval false if @p core does not match @p match.
470  */
471 bool
472 bhnd_core_matches(const struct bhnd_core_info *core,
473     const struct bhnd_core_match *desc)
474 {
475 	if (desc->m.match.core_vendor && desc->core_vendor != core->vendor)
476 		return (false);
477 
478 	if (desc->m.match.core_id && desc->core_id != core->device)
479 		return (false);
480 
481 	if (desc->m.match.core_unit && desc->core_unit != core->unit)
482 		return (false);
483 
484 	if (desc->m.match.core_rev &&
485 	    !bhnd_hwrev_matches(core->hwrev, &desc->core_rev))
486 		return (false);
487 
488 	if (desc->m.match.core_class &&
489 	    desc->core_class != bhnd_core_class(core))
490 		return (false);
491 
492 	return true;
493 }
494 
495 /**
496  * Return true if the @p chip matches @p desc.
497  *
498  * @param chip A bhnd chip identifier.
499  * @param desc A match descriptor to compare against @p chip.
500  *
501  * @retval true if @p chip matches @p match
502  * @retval false if @p chip does not match @p match.
503  */
504 bool
505 bhnd_chip_matches(const struct bhnd_chipid *chip,
506     const struct bhnd_chip_match *desc)
507 {
508 	if (desc->m.match.chip_id && chip->chip_id != desc->chip_id)
509 		return (false);
510 
511 	if (desc->m.match.chip_pkg && chip->chip_pkg != desc->chip_pkg)
512 		return (false);
513 
514 	if (desc->m.match.chip_rev &&
515 	    !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
516 		return (false);
517 
518 	return (true);
519 }
520 
521 /**
522  * Return true if the @p board matches @p desc.
523  *
524  * @param board The bhnd board info.
525  * @param desc A match descriptor to compare against @p board.
526  *
527  * @retval true if @p chip matches @p match
528  * @retval false if @p chip does not match @p match.
529  */
530 bool
531 bhnd_board_matches(const struct bhnd_board_info *board,
532     const struct bhnd_board_match *desc)
533 {
534 	if (desc->m.match.board_srom_rev &&
535 	    !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
536 		return (false);
537 
538 	if (desc->m.match.board_vendor &&
539 	    board->board_vendor != desc->board_vendor)
540 		return (false);
541 
542 	if (desc->m.match.board_type && board->board_type != desc->board_type)
543 		return (false);
544 
545 	if (desc->m.match.board_rev &&
546 	    !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
547 		return (false);
548 
549 	return (true);
550 }
551 
552 /**
553  * Return true if the @p hwrev matches @p desc.
554  *
555  * @param hwrev A bhnd hardware revision.
556  * @param desc A match descriptor to compare against @p core.
557  *
558  * @retval true if @p hwrev matches @p match
559  * @retval false if @p hwrev does not match @p match.
560  */
561 bool
562 bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
563 {
564 	if (desc->start != BHND_HWREV_INVALID &&
565 	    desc->start > hwrev)
566 		return false;
567 
568 	if (desc->end != BHND_HWREV_INVALID &&
569 	    desc->end < hwrev)
570 		return false;
571 
572 	return true;
573 }
574 
575 /**
576  * Return true if the @p dev matches @p desc.
577  *
578  * @param dev A bhnd device.
579  * @param desc A match descriptor to compare against @p dev.
580  *
581  * @retval true if @p dev matches @p match
582  * @retval false if @p dev does not match @p match.
583  */
584 bool
585 bhnd_device_matches(device_t dev, const struct bhnd_device_match *desc)
586 {
587 	struct bhnd_core_info		 core;
588 	const struct bhnd_chipid	*chip;
589 	struct bhnd_board_info		 board;
590 	device_t			 parent;
591 	int				 error;
592 
593 	/* Construct individual match descriptors */
594 	struct bhnd_core_match	m_core	= { _BHND_CORE_MATCH_COPY(desc) };
595 	struct bhnd_chip_match	m_chip	= { _BHND_CHIP_MATCH_COPY(desc) };
596 	struct bhnd_board_match	m_board	= { _BHND_BOARD_MATCH_COPY(desc) };
597 
598 	/* Fetch and match core info */
599 	if (m_core.m.match_flags) {
600 		/* Only applicable to bhnd-attached cores */
601 		parent = device_get_parent(dev);
602 		if (device_get_devclass(parent) != bhnd_devclass) {
603 			device_printf(dev, "attempting to match core "
604 			    "attributes against non-core device\n");
605 			return (false);
606 		}
607 
608 		core = bhnd_get_core_info(dev);
609 		if (!bhnd_core_matches(&core, &m_core))
610 			return (false);
611 	}
612 
613 	/* Fetch and match chip info */
614 	if (m_chip.m.match_flags) {
615 		chip = bhnd_get_chipid(dev);
616 
617 		if (!bhnd_chip_matches(chip, &m_chip))
618 			return (false);
619 	}
620 
621 	/* Fetch and match board info.
622 	 *
623 	 * This is not available until  after NVRAM is up; earlier device
624 	 * matches should not include board requirements */
625 	if (m_board.m.match_flags) {
626 		if ((error = bhnd_read_board_info(dev, &board))) {
627 			device_printf(dev, "failed to read required board info "
628 			    "during device matching: %d\n", error);
629 			return (false);
630 		}
631 
632 		if (!bhnd_board_matches(&board, &m_board))
633 			return (false);
634 	}
635 
636 	/* All matched */
637 	return (true);
638 }
639 
640 /**
641  * Search @p table for an entry matching @p dev.
642  *
643  * @param dev A bhnd device to match against @p table.
644  * @param table The device table to search.
645  * @param entry_size The @p table entry size, in bytes.
646  *
647  * @retval bhnd_device the first matching device, if any.
648  * @retval NULL if no matching device is found in @p table.
649  */
650 const struct bhnd_device *
651 bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
652     size_t entry_size)
653 {
654 	const struct bhnd_device	*entry;
655 	device_t			 hostb, parent;
656 	bhnd_attach_type		 attach_type;
657 	uint32_t			 dflags;
658 
659 	parent = device_get_parent(dev);
660 	hostb = bhnd_find_hostb_device(parent);
661 	attach_type = bhnd_get_attach_type(dev);
662 
663 	for (entry = table; !BHND_DEVICE_IS_END(entry); entry =
664 	    (const struct bhnd_device *) ((const char *) entry + entry_size))
665 	{
666 		/* match core info */
667 		if (!bhnd_device_matches(dev, &entry->core))
668 			continue;
669 
670 		/* match device flags */
671 		dflags = entry->device_flags;
672 
673 		/* hostb implies BHND_ATTACH_ADAPTER requirement */
674 		if (dflags & BHND_DF_HOSTB)
675 			dflags |= BHND_DF_ADAPTER;
676 
677 		if (dflags & BHND_DF_ADAPTER)
678 			if (attach_type != BHND_ATTACH_ADAPTER)
679 				continue;
680 
681 		if (dflags & BHND_DF_HOSTB)
682 			if (dev != hostb)
683 				continue;
684 
685 		if (dflags & BHND_DF_SOC)
686 			if (attach_type != BHND_ATTACH_NATIVE)
687 				continue;
688 
689 		/* device found */
690 		return (entry);
691 	}
692 
693 	/* not found */
694 	return (NULL);
695 }
696 
697 /**
698  * Scan the device @p table for all quirk flags applicable to @p dev.
699  *
700  * @param dev A bhnd device to match against @p table.
701  * @param table The device table to search.
702  *
703  * @return returns all matching quirk flags.
704  */
705 uint32_t
706 bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
707     size_t entry_size)
708 {
709 	const struct bhnd_device	*dent;
710 	const struct bhnd_device_quirk	*qent, *qtable;
711 	uint32_t			 quirks;
712 
713 	/* Locate the device entry */
714 	if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL)
715 		return (0);
716 
717 	/* Quirks table is optional */
718 	qtable = dent->quirks_table;
719 	if (qtable == NULL)
720 		return (0);
721 
722 	/* Collect matching device quirk entries */
723 	quirks = 0;
724 	for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
725 		if (bhnd_device_matches(dev, &qent->desc))
726 			quirks |= qent->quirks;
727 	}
728 
729 	return (quirks);
730 }
731 
732 
733 /**
734  * Allocate bhnd(4) resources defined in @p rs from a parent bus.
735  *
736  * @param dev The device requesting ownership of the resources.
737  * @param rs A standard bus resource specification. This will be updated
738  * with the allocated resource's RIDs.
739  * @param res On success, the allocated bhnd resources.
740  *
741  * @retval 0 success
742  * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
743  * 		    all allocated resources will be released and a regular
744  * 		    unix error code will be returned.
745  */
746 int
747 bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
748     struct bhnd_resource **res)
749 {
750 	/* Initialize output array */
751 	for (u_int i = 0; rs[i].type != -1; i++)
752 		res[i] = NULL;
753 
754 	for (u_int i = 0; rs[i].type != -1; i++) {
755 		res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
756 		    rs[i].flags);
757 
758 		/* Clean up all allocations on failure */
759 		if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
760 			bhnd_release_resources(dev, rs, res);
761 			return (ENXIO);
762 		}
763 	}
764 
765 	return (0);
766 };
767 
768 /**
769  * Release bhnd(4) resources defined in @p rs from a parent bus.
770  *
771  * @param dev The device that owns the resources.
772  * @param rs A standard bus resource specification previously initialized
773  * by @p bhnd_alloc_resources.
774  * @param res The bhnd resources to be released.
775  */
776 void
777 bhnd_release_resources(device_t dev, const struct resource_spec *rs,
778     struct bhnd_resource **res)
779 {
780 	for (u_int i = 0; rs[i].type != -1; i++) {
781 		if (res[i] == NULL)
782 			continue;
783 
784 		bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
785 		res[i] = NULL;
786 	}
787 }
788 
789 /**
790  * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
791  * register, returning its bhnd_chipid representation.
792  *
793  * @param idreg The CHIPC_ID register value.
794  * @param enum_addr The enumeration address to include in the result.
795  *
796  * @warning
797  * On early siba(4) devices, the ChipCommon core does not provide
798  * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
799  * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
800  * an invalid `ncores` value.
801  */
802 struct bhnd_chipid
803 bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
804 {
805 	struct bhnd_chipid result;
806 
807 	/* Fetch the basic chip info */
808 	result.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
809 	result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
810 	result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
811 	result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
812 	result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
813 
814 	result.enum_addr = enum_addr;
815 
816 	return (result);
817 }
818 
819 /**
820  * Allocate the resource defined by @p rs via @p dev, use it
821  * to read the ChipCommon ID register relative to @p chipc_offset,
822  * then release the resource.
823  *
824  * @param dev The device owning @p rs.
825  * @param rs A resource spec that encompasses the ChipCommon register block.
826  * @param chipc_offset The offset of the ChipCommon registers within @p rs.
827  * @param[out] result the chip identification data.
828  *
829  * @retval 0 success
830  * @retval non-zero if the ChipCommon identification data could not be read.
831  */
832 int
833 bhnd_read_chipid(device_t dev, struct resource_spec *rs,
834     bus_size_t chipc_offset, struct bhnd_chipid *result)
835 {
836 	struct resource			*res;
837 	uint32_t			 reg;
838 	int				 error, rid, rtype;
839 
840 	/* Allocate the ChipCommon window resource and fetch the chipid data */
841 	rid = rs->rid;
842 	rtype = rs->type;
843 	res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
844 	if (res == NULL) {
845 		device_printf(dev,
846 		    "failed to allocate bhnd chipc resource\n");
847 		return (ENXIO);
848 	}
849 
850 	/* Fetch the basic chip info */
851 	reg = bus_read_4(res, chipc_offset + CHIPC_ID);
852 	*result = bhnd_parse_chipid(reg, 0x0);
853 
854 	/* Fetch the enum base address */
855 	error = 0;
856 	switch (result->chip_type) {
857 	case BHND_CHIPTYPE_SIBA:
858 		result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
859 		break;
860 	case BHND_CHIPTYPE_BCMA:
861 	case BHND_CHIPTYPE_BCMA_ALT:
862 		result->enum_addr = bus_read_4(res, chipc_offset +
863 		    CHIPC_EROMPTR);
864 		break;
865 	case BHND_CHIPTYPE_UBUS:
866 		device_printf(dev, "unsupported ubus/bcm63xx chip type");
867 		error = ENODEV;
868 		goto cleanup;
869 	default:
870 		device_printf(dev, "unknown chip type %hhu\n",
871 		    result->chip_type);
872 		error = ENODEV;
873 		goto cleanup;
874 	}
875 
876 cleanup:
877 	/* Clean up */
878 	bus_release_resource(dev, rtype, rid, res);
879 	return (error);
880 }
881 
882 /**
883  * Read an NVRAM variable's NUL-terminated string value.
884  *
885  * @param 	dev	A bhnd bus child device.
886  * @param	name	The NVRAM variable name.
887  * @param[out]	buf	A buffer large enough to hold @p len bytes. On
888  *			success, the NUL-terminated string value will be
889  *			written to this buffer. This argment may be NULL if
890  *			the value is not desired.
891  * @param	len	The maximum capacity of @p buf.
892  * @param[out]	rlen	On success, will be set to the actual size of
893  *			the requested value (including NUL termination). This
894  *			argment may be NULL if the size is not desired.
895  *
896  * @retval 0		success
897  * @retval ENOENT	The requested variable was not found.
898  * @retval ENODEV	No valid NVRAM source could be found.
899  * @retval ENOMEM	If @p buf is non-NULL and a buffer of @p len is too
900  *			small to hold the requested value.
901  * @retval EFTYPE	If the variable data cannot be coerced to a valid
902  *			string representation.
903  * @retval ERANGE	If value coercion would overflow @p type.
904  * @retval non-zero	If reading @p name otherwise fails, a regular unix
905  *			error code will be returned.
906  */
907 int
908 bhnd_nvram_getvar_str(device_t dev, const char *name, char *buf, size_t len,
909     size_t *rlen)
910 {
911 	size_t	larg;
912 	int	error;
913 
914 	larg = len;
915 	error = bhnd_nvram_getvar(dev, name, buf, &larg, BHND_NVRAM_TYPE_CSTR);
916 	if (rlen != NULL)
917 		*rlen = larg;
918 
919 	return (error);
920 }
921 
922 /**
923  * Read an NVRAM variable's unsigned integer value.
924  *
925  * @param 		dev	A bhnd bus child device.
926  * @param		name	The NVRAM variable name.
927  * @param[out]		value	On success, the requested value will be written
928  *				to this pointer.
929  * @param		width	The output integer type width (1, 2, or
930  *				4 bytes).
931  *
932  * @retval 0		success
933  * @retval ENOENT	The requested variable was not found.
934  * @retval ENODEV	No valid NVRAM source could be found.
935  * @retval EFTYPE	If the variable data cannot be coerced to a
936  *			a valid unsigned integer representation.
937  * @retval ERANGE	If value coercion would overflow (or underflow) an
938  *			unsigned representation of the given @p width.
939  * @retval non-zero	If reading @p name otherwise fails, a regular unix
940  *			error code will be returned.
941  */
942 int
943 bhnd_nvram_getvar_uint(device_t dev, const char *name, void *value, int width)
944 {
945 	bhnd_nvram_type	type;
946 	size_t		len;
947 
948 	switch (width) {
949 	case 1:
950 		type = BHND_NVRAM_TYPE_UINT8;
951 		break;
952 	case 2:
953 		type = BHND_NVRAM_TYPE_UINT16;
954 		break;
955 	case 4:
956 		type = BHND_NVRAM_TYPE_UINT32;
957 		break;
958 	default:
959 		device_printf(dev, "unsupported NVRAM integer width: %d\n",
960 		    width);
961 		return (EINVAL);
962 	}
963 
964 	len = width;
965 	return (bhnd_nvram_getvar(dev, name, value, &len, type));
966 }
967 
968 /**
969  * Read an NVRAM variable's unsigned 8-bit integer value.
970  *
971  * @param 		dev	A bhnd bus child device.
972  * @param		name	The NVRAM variable name.
973  * @param[out]		value	On success, the requested value will be written
974  *				to this pointer.
975  *
976  * @retval 0		success
977  * @retval ENOENT	The requested variable was not found.
978  * @retval ENODEV	No valid NVRAM source could be found.
979  * @retval EFTYPE	If the variable data cannot be coerced to a
980  *			a valid unsigned integer representation.
981  * @retval ERANGE	If value coercion would overflow (or underflow) uint8_t.
982  * @retval non-zero	If reading @p name otherwise fails, a regular unix
983  *			error code will be returned.
984  */
985 int
986 bhnd_nvram_getvar_uint8(device_t dev, const char *name, uint8_t *value)
987 {
988 	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
989 }
990 
991 /**
992  * Read an NVRAM variable's unsigned 16-bit integer value.
993  *
994  * @param 		dev	A bhnd bus child device.
995  * @param		name	The NVRAM variable name.
996  * @param[out]		value	On success, the requested value will be written
997  *				to this pointer.
998  *
999  * @retval 0		success
1000  * @retval ENOENT	The requested variable was not found.
1001  * @retval ENODEV	No valid NVRAM source could be found.
1002  * @retval EFTYPE	If the variable data cannot be coerced to a
1003  *			a valid unsigned integer representation.
1004  * @retval ERANGE	If value coercion would overflow (or underflow)
1005  *			uint16_t.
1006  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1007  *			error code will be returned.
1008  */
1009 int
1010 bhnd_nvram_getvar_uint16(device_t dev, const char *name, uint16_t *value)
1011 {
1012 	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
1013 }
1014 
1015 /**
1016  * Read an NVRAM variable's unsigned 32-bit integer value.
1017  *
1018  * @param 		dev	A bhnd bus child device.
1019  * @param		name	The NVRAM variable name.
1020  * @param[out]		value	On success, the requested value will be written
1021  *				to this pointer.
1022  *
1023  * @retval 0		success
1024  * @retval ENOENT	The requested variable was not found.
1025  * @retval ENODEV	No valid NVRAM source could be found.
1026  * @retval EFTYPE	If the variable data cannot be coerced to a
1027  *			a valid unsigned integer representation.
1028  * @retval ERANGE	If value coercion would overflow (or underflow)
1029  *			uint32_t.
1030  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1031  *			error code will be returned.
1032  */
1033 int
1034 bhnd_nvram_getvar_uint32(device_t dev, const char *name, uint32_t *value)
1035 {
1036 	return (bhnd_nvram_getvar_uint(dev, name, value, sizeof(*value)));
1037 }
1038 
1039 /**
1040  * Read an NVRAM variable's signed integer value.
1041  *
1042  * @param 		dev	A bhnd bus child device.
1043  * @param		name	The NVRAM variable name.
1044  * @param[out]		value	On success, the requested value will be written
1045  *				to this pointer.
1046  * @param		width	The output integer type width (1, 2, or
1047  *				4 bytes).
1048  *
1049  * @retval 0		success
1050  * @retval ENOENT	The requested variable was not found.
1051  * @retval ENODEV	No valid NVRAM source could be found.
1052  * @retval EFTYPE	If the variable data cannot be coerced to a
1053  *			a valid integer representation.
1054  * @retval ERANGE	If value coercion would overflow (or underflow) an
1055  *			signed representation of the given @p width.
1056  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1057  *			error code will be returned.
1058  */
1059 int
1060 bhnd_nvram_getvar_int(device_t dev, const char *name, void *value, int width)
1061 {
1062 	bhnd_nvram_type	type;
1063 	size_t		len;
1064 
1065 	switch (width) {
1066 	case 1:
1067 		type = BHND_NVRAM_TYPE_INT8;
1068 		break;
1069 	case 2:
1070 		type = BHND_NVRAM_TYPE_INT16;
1071 		break;
1072 	case 4:
1073 		type = BHND_NVRAM_TYPE_INT32;
1074 		break;
1075 	default:
1076 		device_printf(dev, "unsupported NVRAM integer width: %d\n",
1077 		    width);
1078 		return (EINVAL);
1079 	}
1080 
1081 	len = width;
1082 	return (bhnd_nvram_getvar(dev, name, value, &len, type));
1083 }
1084 
1085 /**
1086  * Read an NVRAM variable's signed 8-bit integer value.
1087  *
1088  * @param 		dev	A bhnd bus child device.
1089  * @param		name	The NVRAM variable name.
1090  * @param[out]		value	On success, the requested value will be written
1091  *				to this pointer.
1092  *
1093  * @retval 0		success
1094  * @retval ENOENT	The requested variable was not found.
1095  * @retval ENODEV	No valid NVRAM source could be found.
1096  * @retval EFTYPE	If the variable data cannot be coerced to a
1097  *			a valid integer representation.
1098  * @retval ERANGE	If value coercion would overflow (or underflow) int8_t.
1099  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1100  *			error code will be returned.
1101  */
1102 int
1103 bhnd_nvram_getvar_int8(device_t dev, const char *name, int8_t *value)
1104 {
1105 	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1106 }
1107 
1108 /**
1109  * Read an NVRAM variable's signed 16-bit integer value.
1110  *
1111  * @param 		dev	A bhnd bus child device.
1112  * @param		name	The NVRAM variable name.
1113  * @param[out]		value	On success, the requested value will be written
1114  *				to this pointer.
1115  *
1116  * @retval 0		success
1117  * @retval ENOENT	The requested variable was not found.
1118  * @retval ENODEV	No valid NVRAM source could be found.
1119  * @retval EFTYPE	If the variable data cannot be coerced to a
1120  *			a valid integer representation.
1121  * @retval ERANGE	If value coercion would overflow (or underflow)
1122  *			int16_t.
1123  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1124  *			error code will be returned.
1125  */
1126 int
1127 bhnd_nvram_getvar_int16(device_t dev, const char *name, int16_t *value)
1128 {
1129 	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1130 }
1131 
1132 /**
1133  * Read an NVRAM variable's signed 32-bit integer value.
1134  *
1135  * @param 		dev	A bhnd bus child device.
1136  * @param		name	The NVRAM variable name.
1137  * @param[out]		value	On success, the requested value will be written
1138  *				to this pointer.
1139  *
1140  * @retval 0		success
1141  * @retval ENOENT	The requested variable was not found.
1142  * @retval ENODEV	No valid NVRAM source could be found.
1143  * @retval EFTYPE	If the variable data cannot be coerced to a
1144  *			a valid integer representation.
1145  * @retval ERANGE	If value coercion would overflow (or underflow)
1146  *			int32_t.
1147  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1148  *			error code will be returned.
1149  */
1150 int
1151 bhnd_nvram_getvar_int32(device_t dev, const char *name, int32_t *value)
1152 {
1153 	return (bhnd_nvram_getvar_int(dev, name, value, sizeof(*value)));
1154 }
1155 
1156 
1157 /**
1158  * Read an NVRAM variable's array value.
1159  *
1160  * @param 		dev	A bhnd bus child device.
1161  * @param		name	The NVRAM variable name.
1162  * @param[out]		buf	A buffer large enough to hold @p size bytes.
1163  *				On success, the requested value will be written
1164  *				to this buffer.
1165  * @param[in,out]	size	The required number of bytes to write to
1166  *				@p buf.
1167  * @param		type	The desired array element data representation.
1168  *
1169  * @retval 0		success
1170  * @retval ENOENT	The requested variable was not found.
1171  * @retval ENODEV	No valid NVRAM source could be found.
1172  * @retval ENXIO	If less than @p size bytes are available.
1173  * @retval ENOMEM	If a buffer of @p size is too small to hold the
1174  *			requested value.
1175  * @retval EFTYPE	If the variable data cannot be coerced to a
1176  *			a valid instance of @p type.
1177  * @retval ERANGE	If value coercion would overflow (or underflow) a
1178  *			representation of @p type.
1179  * @retval non-zero	If reading @p name otherwise fails, a regular unix
1180  *			error code will be returned.
1181  */
1182 int
1183 bhnd_nvram_getvar_array(device_t dev, const char *name, void *buf, size_t size,
1184     bhnd_nvram_type type)
1185 {
1186 	size_t	nbytes;
1187 	int	error;
1188 
1189 	/* Attempt read */
1190 	nbytes = size;
1191 	if ((error = bhnd_nvram_getvar(dev, name, buf, &nbytes, type)))
1192 		return (error);
1193 
1194 	/* Verify that the expected number of bytes were fetched */
1195 	if (nbytes < size)
1196 		return (ENXIO);
1197 
1198 	return (0);
1199 }
1200 
1201 /**
1202  * Using the bhnd(4) bus-level core information and a custom core name,
1203  * populate @p dev's device description.
1204  *
1205  * @param dev A bhnd-bus attached device.
1206  * @param dev_name The core's name (e.g. "SDIO Device Core")
1207  */
1208 void
1209 bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
1210 {
1211 	const char *vendor_name;
1212 	char *desc;
1213 
1214 	vendor_name = bhnd_get_vendor_name(dev);
1215 	asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name,
1216 	    bhnd_get_hwrev(dev));
1217 
1218 	if (desc != NULL) {
1219 		device_set_desc_copy(dev, desc);
1220 		free(desc, M_BHND);
1221 	} else {
1222 		device_set_desc(dev, dev_name);
1223 	}
1224 }
1225 
1226 /**
1227  * Using the bhnd(4) bus-level core information, populate @p dev's device
1228  * description.
1229  *
1230  * @param dev A bhnd-bus attached device.
1231  */
1232 void
1233 bhnd_set_default_core_desc(device_t dev)
1234 {
1235 	bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
1236 }
1237 
1238 /**
1239  * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
1240  *
1241  * If a parent device is available, this implementation delegates the
1242  * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
1243  *
1244  * If no parent device is available (i.e. on a the bus root), the hardware
1245  * is assumed to be usable and false is returned.
1246  */
1247 bool
1248 bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
1249 {
1250 	if (device_get_parent(dev) != NULL)
1251 		return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
1252 
1253 	return (false);
1254 }
1255 
1256 /**
1257  * Helper function for implementing BHND_BUS_GET_CHIPID().
1258  *
1259  * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
1260  * method on the parent of @p dev. If no parent exists, the implementation
1261  * will panic.
1262  */
1263 const struct bhnd_chipid *
1264 bhnd_bus_generic_get_chipid(device_t dev, device_t child)
1265 {
1266 	if (device_get_parent(dev) != NULL)
1267 		return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
1268 
1269 	panic("missing BHND_BUS_GET_CHIPID()");
1270 }
1271 
1272 /* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
1273 #define	BHND_GV(_dest, _name)	\
1274 	bhnd_nvram_getvar_uint(child, BHND_NVAR_ ## _name, &_dest,	\
1275 	    sizeof(_dest))
1276 
1277 #define	REQ_BHND_GV(_dest, _name)		do {			\
1278 	if ((error = BHND_GV(_dest, _name))) {				\
1279 		device_printf(dev,					\
1280 		    "error reading " __STRING(_name) ": %d\n", error);	\
1281 		return (error);						\
1282 	}								\
1283 } while(0)
1284 
1285 #define	OPT_BHND_GV(_dest, _name, _default)	do {			\
1286 	if ((error = BHND_GV(_dest, _name))) {				\
1287 		if (error != ENOENT) {					\
1288 			device_printf(dev,				\
1289 			    "error reading "				\
1290 			       __STRING(_name) ": %d\n", error);	\
1291 			return (error);					\
1292 		}							\
1293 		_dest = _default;					\
1294 	}								\
1295 } while(0)
1296 
1297 /**
1298  * Helper function for implementing BHND_BUS_READ_BOARDINFO().
1299  *
1300  * This implementation populates @p info with information from NVRAM,
1301  * defaulting board_vendor and board_type fields to 0 if the
1302  * requested variables cannot be found.
1303  *
1304  * This behavior is correct for most SoCs, but must be overridden on
1305  * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
1306  * result.
1307  */
1308 int
1309 bhnd_bus_generic_read_board_info(device_t dev, device_t child,
1310     struct bhnd_board_info *info)
1311 {
1312 	int	error;
1313 
1314 	OPT_BHND_GV(info->board_vendor,	BOARDVENDOR,	0);
1315 	OPT_BHND_GV(info->board_type,	BOARDTYPE,	0);	/* srom >= 2 */
1316 	REQ_BHND_GV(info->board_rev,	BOARDREV);
1317 	REQ_BHND_GV(info->board_srom_rev,SROMREV);
1318 	REQ_BHND_GV(info->board_flags,	BOARDFLAGS);
1319 	OPT_BHND_GV(info->board_flags2,	BOARDFLAGS2,	0);	/* srom >= 4 */
1320 	OPT_BHND_GV(info->board_flags3,	BOARDFLAGS3,	0);	/* srom >= 11 */
1321 
1322 	return (0);
1323 }
1324 
1325 #undef	BHND_GV
1326 #undef	BHND_GV_REQ
1327 #undef	BHND_GV_OPT
1328 
1329 /**
1330  * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
1331  *
1332  * This implementation searches @p dev for a usable NVRAM child device.
1333  *
1334  * If no usable child device is found on @p dev, the request is delegated to
1335  * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
1336  */
1337 int
1338 bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
1339     void *buf, size_t *size, bhnd_nvram_type type)
1340 {
1341 	device_t	nvram;
1342 	device_t	parent;
1343 
1344         /* Make sure we're holding Giant for newbus */
1345 	GIANT_REQUIRED;
1346 
1347 	/* Look for a directly-attached NVRAM child */
1348 	if ((nvram = device_find_child(dev, "bhnd_nvram", -1)) != NULL)
1349 		return BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
1350 
1351 	/* Try to delegate to parent */
1352 	if ((parent = device_get_parent(dev)) == NULL)
1353 		return (ENODEV);
1354 
1355 	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
1356 	    name, buf, size, type));
1357 }
1358 
1359 /**
1360  * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
1361  *
1362  * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
1363  * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
1364  * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
1365  */
1366 struct bhnd_resource *
1367 bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
1368 	int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
1369 	u_int flags)
1370 {
1371 	struct bhnd_resource	*br;
1372 	struct resource		*res;
1373 	int			 error;
1374 
1375 	br = NULL;
1376 	res = NULL;
1377 
1378 	/* Allocate the real bus resource (without activating it) */
1379 	res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
1380 	    (flags & ~RF_ACTIVE));
1381 	if (res == NULL)
1382 		return (NULL);
1383 
1384 	/* Allocate our bhnd resource wrapper. */
1385 	br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
1386 	if (br == NULL)
1387 		goto failed;
1388 
1389 	br->direct = false;
1390 	br->res = res;
1391 
1392 	/* Attempt activation */
1393 	if (flags & RF_ACTIVE) {
1394 		error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
1395 		if (error)
1396 			goto failed;
1397 	}
1398 
1399 	return (br);
1400 
1401 failed:
1402 	if (res != NULL)
1403 		BUS_RELEASE_RESOURCE(dev, child, type, *rid, res);
1404 
1405 	free(br, M_BHND);
1406 	return (NULL);
1407 }
1408 
1409 /**
1410  * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
1411  *
1412  * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
1413  * the backing resource to BUS_RELEASE_RESOURCE().
1414  */
1415 int
1416 bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
1417     int rid, struct bhnd_resource *r)
1418 {
1419 	int error;
1420 
1421 	if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res)))
1422 		return (error);
1423 
1424 	free(r, M_BHND);
1425 	return (0);
1426 }
1427 
1428 
1429 /**
1430  * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
1431  *
1432  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1433  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1434  */
1435 int
1436 bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
1437     int rid, struct bhnd_resource *r)
1438 {
1439 	/* Try to delegate to the parent */
1440 	if (device_get_parent(dev) != NULL)
1441 		return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
1442 		    child, type, rid, r));
1443 
1444 	return (EINVAL);
1445 };
1446 
1447 /**
1448  * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
1449  *
1450  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1451  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1452  */
1453 int
1454 bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
1455     int type, int rid, struct bhnd_resource *r)
1456 {
1457 	if (device_get_parent(dev) != NULL)
1458 		return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
1459 		    child, type, rid, r));
1460 
1461 	return (EINVAL);
1462 };
1463 
1464