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