]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/bhnd_subr.c
bhnd: fix build on gcc architectures
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / bhnd_subr.c
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/types.h>
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/systm.h>
37
38 #include <machine/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41
42 #include <dev/bhnd/cores/chipc/chipcreg.h>
43
44 #include "bhndreg.h"
45 #include "bhndvar.h"
46
47 /* BHND core device description table. */
48 static const struct bhnd_core_desc {
49         uint16_t         vendor;
50         uint16_t         device;
51         bhnd_devclass_t  class;
52         const char      *desc;
53 } bhnd_core_descs[] = {
54         #define BHND_CDESC(_mfg, _cid, _cls, _desc)             \
55             { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,        \
56                 BHND_DEVCLASS_ ## _cls, _desc }
57
58         BHND_CDESC(BCM, CC,             CC,             "ChipCommon I/O Controller"),
59         BHND_CDESC(BCM, ILINE20,        OTHER,          "iLine20 HPNA"),
60         BHND_CDESC(BCM, SRAM,           RAM,            "SRAM"),
61         BHND_CDESC(BCM, SDRAM,          RAM,            "SDRAM"),
62         BHND_CDESC(BCM, PCI,            PCI,            "PCI Bridge"),
63         BHND_CDESC(BCM, MIPS,           CPU,            "MIPS Core"),
64         BHND_CDESC(BCM, ENET,           ENET_MAC,       "Fast Ethernet MAC"),
65         BHND_CDESC(BCM, CODEC,          OTHER,          "V.90 Modem Codec"),
66         BHND_CDESC(BCM, USB,            OTHER,          "USB 1.1 Device/Host Controller"),
67         BHND_CDESC(BCM, ADSL,           OTHER,          "ADSL Core"),
68         BHND_CDESC(BCM, ILINE100,       OTHER,          "iLine100 HPNA"),
69         BHND_CDESC(BCM, IPSEC,          OTHER,          "IPsec Accelerator"),
70         BHND_CDESC(BCM, UTOPIA,         OTHER,          "UTOPIA ATM Core"),
71         BHND_CDESC(BCM, PCMCIA,         PCCARD,         "PCMCIA Bridge"),
72         BHND_CDESC(BCM, SOCRAM,         RAM,            "Internal Memory"),
73         BHND_CDESC(BCM, MEMC,           MEMC,           "MEMC SDRAM Controller"),
74         BHND_CDESC(BCM, OFDM,           OTHER,          "OFDM PHY"),
75         BHND_CDESC(BCM, EXTIF,          OTHER,          "External Interface"),
76         BHND_CDESC(BCM, D11,            WLAN,           "802.11 MAC/PHY/Radio"),
77         BHND_CDESC(BCM, APHY,           WLAN_PHY,       "802.11a PHY"),
78         BHND_CDESC(BCM, BPHY,           WLAN_PHY,       "802.11b PHY"),
79         BHND_CDESC(BCM, GPHY,           WLAN_PHY,       "802.11g PHY"),
80         BHND_CDESC(BCM, MIPS33,         CPU,            "MIPS 3302 Core"),
81         BHND_CDESC(BCM, USB11H,         OTHER,          "USB 1.1 Host Controller"),
82         BHND_CDESC(BCM, USB11D,         OTHER,          "USB 1.1 Device Core"),
83         BHND_CDESC(BCM, USB20H,         OTHER,          "USB 2.0 Host Controller"),
84         BHND_CDESC(BCM, USB20D,         OTHER,          "USB 2.0 Device Core"),
85         BHND_CDESC(BCM, SDIOH,          OTHER,          "SDIO Host Controller"),
86         BHND_CDESC(BCM, ROBO,           OTHER,          "RoboSwitch"),
87         BHND_CDESC(BCM, ATA100,         OTHER,          "Parallel ATA Controller"),
88         BHND_CDESC(BCM, SATAXOR,        OTHER,          "SATA DMA/XOR Controller"),
89         BHND_CDESC(BCM, GIGETH,         ENET_MAC,       "Gigabit Ethernet MAC"),
90         BHND_CDESC(BCM, PCIE,           PCIE,           "PCIe Bridge"),
91         BHND_CDESC(BCM, NPHY,           WLAN_PHY,       "802.11n 2x2 PHY"),
92         BHND_CDESC(BCM, SRAMC,          MEMC,           "SRAM Controller"),
93         BHND_CDESC(BCM, MINIMAC,        OTHER,          "MINI MAC/PHY"),
94         BHND_CDESC(BCM, ARM11,          CPU,            "ARM1176 CPU"),
95         BHND_CDESC(BCM, ARM7S,          CPU,            "ARM7TDMI-S CPU"),
96         BHND_CDESC(BCM, LPPHY,          WLAN_PHY,       "802.11a/b/g PHY"),
97         BHND_CDESC(BCM, PMU,            PMU,            "PMU"),
98         BHND_CDESC(BCM, SSNPHY,         WLAN_PHY,       "802.11n Single-Stream PHY"),
99         BHND_CDESC(BCM, SDIOD,          OTHER,          "SDIO Device Core"),
100         BHND_CDESC(BCM, ARMCM3,         CPU,            "ARM Cortex-M3 CPU"),
101         BHND_CDESC(BCM, HTPHY,          WLAN_PHY,       "802.11n 4x4 PHY"),
102         BHND_CDESC(BCM, MIPS74K,        CPU,            "MIPS74k CPU"),
103         BHND_CDESC(BCM, GMAC,           ENET_MAC,       "Gigabit MAC core"),
104         BHND_CDESC(BCM, DMEMC,          MEMC,           "DDR1/DDR2 Memory Controller"),
105         BHND_CDESC(BCM, PCIERC,         OTHER,          "PCIe Root Complex"),
106         BHND_CDESC(BCM, OCP,            SOC_BRIDGE,     "OCP to OCP Bridge"),
107         BHND_CDESC(BCM, SC,             OTHER,          "Shared Common Core"),
108         BHND_CDESC(BCM, AHB,            SOC_BRIDGE,     "OCP to AHB Bridge"),
109         BHND_CDESC(BCM, SPIH,           OTHER,          "SPI Host Controller"),
110         BHND_CDESC(BCM, I2S,            OTHER,          "I2S Digital Audio Interface"),
111         BHND_CDESC(BCM, DMEMS,          MEMC,           "SDR/DDR1 Memory Controller"),
112         BHND_CDESC(BCM, UBUS_SHIM,      OTHER,          "BCM6362/UBUS WLAN SHIM"),
113         BHND_CDESC(BCM, PCIE2,          PCIE,           "PCIe Bridge (Gen2)"),
114
115         BHND_CDESC(ARM, APB_BRIDGE,     SOC_BRIDGE,     "BP135 AMBA3 AXI to APB Bridge"),
116         BHND_CDESC(ARM, PL301,          SOC_ROUTER,     "PL301 AMBA3 Interconnect"),
117         BHND_CDESC(ARM, EROM,           EROM,           "PL366 Device Enumeration ROM"),
118         BHND_CDESC(ARM, OOB_ROUTER,     OTHER,          "PL367 OOB Interrupt Router"),
119         BHND_CDESC(ARM, AXI_UNMAPPED,   OTHER,          "Unmapped Address Ranges"),
120
121         BHND_CDESC(BCM, 4706_CC,        CC,             "ChipCommon I/O Controller"),
122         BHND_CDESC(BCM, NS_PCIE2,       PCIE,           "PCIe Bridge (Gen2)"),
123         BHND_CDESC(BCM, NS_DMA,         OTHER,          "DMA engine"),
124         BHND_CDESC(BCM, NS_SDIO,        OTHER,          "SDIO 3.0 Host Controller"),
125         BHND_CDESC(BCM, NS_USB20H,      OTHER,          "USB 2.0 Host Controller"),
126         BHND_CDESC(BCM, NS_USB30H,      OTHER,          "USB 3.0 Host Controller"),
127         BHND_CDESC(BCM, NS_A9JTAG,      OTHER,          "ARM Cortex A9 JTAG Interface"),
128         BHND_CDESC(BCM, NS_DDR23_MEMC,  MEMC,           "Denali DDR2/DD3 Memory Controller"),
129         BHND_CDESC(BCM, NS_ROM,         NVRAM,          "System ROM"),
130         BHND_CDESC(BCM, NS_NAND,        NVRAM,          "NAND Flash Controller"),
131         BHND_CDESC(BCM, NS_QSPI,        NVRAM,          "QSPI Flash Controller"),
132         BHND_CDESC(BCM, NS_CC_B,        CC_B,           "ChipCommon B Auxiliary I/O Controller"),
133         BHND_CDESC(BCM, 4706_SOCRAM,    RAM,            "Internal Memory"),
134         BHND_CDESC(BCM, IHOST_ARMCA9,   CPU,            "ARM Cortex A9 CPU"),
135         BHND_CDESC(BCM, 4706_GMAC_CMN,  ENET,           "Gigabit MAC (Common)"),
136         BHND_CDESC(BCM, 4706_GMAC,      ENET_MAC,       "Gigabit MAC"),
137         BHND_CDESC(BCM, AMEMC,          MEMC,           "Denali DDR1/DDR2 Memory Controller"),
138 #undef  BHND_CDESC
139
140         /* Derived from inspection of the BCM4331 cores that provide PrimeCell
141          * IDs. Due to lack of documentation, the surmised device name/purpose
142          * provided here may be incorrect. */
143         { BHND_MFGID_ARM,       BHND_PRIMEID_EROM,      BHND_DEVCLASS_OTHER,
144             "PL364 Device Enumeration ROM" },
145         { BHND_MFGID_ARM,       BHND_PRIMEID_SWRAP,     BHND_DEVCLASS_OTHER,
146             "PL368 Device Management Interface" },
147         { BHND_MFGID_ARM,       BHND_PRIMEID_MWRAP,     BHND_DEVCLASS_OTHER,
148             "PL369 Device Management Interface" },
149
150         { 0, 0, 0, NULL }
151 };
152
153 /**
154  * Return the name for a given JEP106 manufacturer ID.
155  * 
156  * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
157  * JEP106 continuation code.
158  */
159 const char *
160 bhnd_vendor_name(uint16_t vendor)
161 {
162         switch (vendor) {
163         case BHND_MFGID_ARM:
164                 return "ARM";
165         case BHND_MFGID_BCM:
166                 return "Broadcom";
167         case BHND_MFGID_MIPS:
168                 return "MIPS";
169         default:
170                 return "unknown";
171         }
172 }
173
174 /**
175  * Return the name of a port type.
176  */
177 const char *
178 bhnd_port_type_name(bhnd_port_type port_type)
179 {
180         switch (port_type) {
181         case BHND_PORT_DEVICE:
182                 return ("device");
183         case BHND_PORT_BRIDGE:
184                 return ("bridge");
185         case BHND_PORT_AGENT:
186                 return ("agent");
187         default:
188                 return "unknown";
189         }
190 }
191
192
193 static const struct bhnd_core_desc *
194 bhnd_find_core_desc(uint16_t vendor, uint16_t device)
195 {
196         for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
197                 if (bhnd_core_descs[i].vendor != vendor)
198                         continue;
199                 
200                 if (bhnd_core_descs[i].device != device)
201                         continue;
202                 
203                 return (&bhnd_core_descs[i]);
204         }
205         
206         return (NULL);
207 }
208
209 /**
210  * Return a human-readable name for a BHND core.
211  * 
212  * @param vendor The core designer's JEDEC-106 Manufacturer ID
213  * @param device The core identifier.
214  */
215 const char *
216 bhnd_find_core_name(uint16_t vendor, uint16_t device)
217 {
218         const struct bhnd_core_desc *desc;
219         
220         if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
221                 return ("unknown");
222
223         return desc->desc;
224 }
225
226 /**
227  * Return the device class for a BHND core.
228  * 
229  * @param vendor The core designer's JEDEC-106 Manufacturer ID
230  * @param device The core identifier.
231  */
232 bhnd_devclass_t
233 bhnd_find_core_class(uint16_t vendor, uint16_t device)
234 {
235         const struct bhnd_core_desc *desc;
236         
237         if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
238                 return (BHND_DEVCLASS_OTHER);
239
240         return desc->class;
241 }
242
243 /**
244  * Return a human-readable name for a BHND core.
245  * 
246  * @param ci The core's info record.
247  */
248 const char *
249 bhnd_core_name(const struct bhnd_core_info *ci)
250 {
251         return bhnd_find_core_name(ci->vendor, ci->device);
252 }
253
254 /**
255  * Return the device class for a BHND core.
256  * 
257  * @param ci The core's info record.
258  */
259 bhnd_devclass_t
260 bhnd_core_class(const struct bhnd_core_info *ci)
261 {
262         return bhnd_find_core_class(ci->vendor, ci->device);
263 }
264
265 /**
266  * Initialize a core info record with data from from a bhnd-attached @p dev.
267  * 
268  * @param dev A bhnd device.
269  * @param core The record to be initialized.
270  */
271 struct bhnd_core_info
272 bhnd_get_core_info(device_t dev) {
273         return (struct bhnd_core_info) {
274                 .vendor         = bhnd_get_vendor(dev),
275                 .device         = bhnd_get_device(dev),
276                 .hwrev          = bhnd_get_hwrev(dev),
277                 .core_idx       = bhnd_get_core_index(dev),
278                 .unit           = bhnd_get_core_unit(dev)
279         };
280 }
281
282 /**
283  * Find a @p class child device with @p unit on @p dev.
284  * 
285  * @param parent The bhnd-compatible bus to be searched.
286  * @param class The device class to match on.
287  * @param unit The device unit number; specify -1 to return the first match
288  * regardless of unit number.
289  * 
290  * @retval device_t if a matching child device is found.
291  * @retval NULL if no matching child device is found.
292  */
293 device_t
294 bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
295 {
296         struct bhnd_core_match md = {
297                 .vendor = BHND_MFGID_INVALID,
298                 .device = BHND_COREID_INVALID,
299                 .hwrev.start = BHND_HWREV_INVALID,
300                 .hwrev.end = BHND_HWREV_INVALID,
301                 .class = class,
302                 .unit = unit
303         };
304
305         return bhnd_match_child(dev, &md);
306 }
307
308 /**
309  * Find the first child device on @p dev that matches @p desc.
310  * 
311  * @param parent The bhnd-compatible bus to be searched.
312  * @param desc A match descriptor.
313  * 
314  * @retval device_t if a matching child device is found.
315  * @retval NULL if no matching child device is found.
316  */
317 device_t
318 bhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
319 {
320         device_t        *devlistp;
321         device_t         match;
322         int              devcnt;
323         int              error;
324
325         error = device_get_children(dev, &devlistp, &devcnt);
326         if (error != 0)
327                 return (NULL);
328
329         match = NULL;
330         for (int i = 0; i < devcnt; i++) {
331                 device_t dev = devlistp[i];
332                 if (bhnd_device_matches(dev, desc)) {
333                         match = dev;
334                         goto done;
335                 }
336         }
337
338 done:
339         free(devlistp, M_TEMP);
340         return match;
341 }
342
343 /**
344  * Find the first core in @p cores that matches @p desc.
345  * 
346  * @param cores The table to search.
347  * @param num_cores The length of @p cores.
348  * @param desc A match descriptor.
349  * 
350  * @retval bhnd_core_info if a matching core is found.
351  * @retval NULL if no matching core is found.
352  */
353 const struct bhnd_core_info *
354 bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
355     const struct bhnd_core_match *desc)
356 {
357         for (u_int i = 0; i < num_cores; i++) {
358                 if (bhnd_core_matches(&cores[i], desc))
359                         return &cores[i];
360         }
361
362         return (NULL);
363 }
364
365
366 /**
367  * Find the first core in @p cores with the given @p class.
368  * 
369  * @param cores The table to search.
370  * @param num_cores The length of @p cores.
371  * @param desc A match descriptor.
372  * 
373  * @retval bhnd_core_info if a matching core is found.
374  * @retval NULL if no matching core is found.
375  */
376 const struct bhnd_core_info *
377 bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
378     bhnd_devclass_t class)
379 {
380         struct bhnd_core_match md = {
381                 .vendor = BHND_MFGID_INVALID,
382                 .device = BHND_COREID_INVALID,
383                 .hwrev.start = BHND_HWREV_INVALID,
384                 .hwrev.end = BHND_HWREV_INVALID,
385                 .class = class,
386                 .unit = -1
387         };
388
389         return bhnd_match_core(cores, num_cores, &md);
390 }
391
392 /**
393  * Return true if the @p core matches @p desc.
394  * 
395  * @param core A bhnd core descriptor.
396  * @param desc A match descriptor to compare against @p core.
397  * 
398  * @retval true if @p core matches @p match
399  * @retval false if @p core does not match @p match.
400  */
401 bool
402 bhnd_core_matches(const struct bhnd_core_info *core,
403     const struct bhnd_core_match *desc)
404 {
405         if (desc->vendor != BHND_MFGID_INVALID &&
406             desc->vendor != core->vendor)
407                 return (false);
408
409         if (desc->device != BHND_COREID_INVALID &&
410             desc->device != core->device)
411                 return (false);
412
413         if (desc->unit != -1 && desc->unit != core->unit)
414                 return (false);
415
416         if (!bhnd_hwrev_matches(core->hwrev, &desc->hwrev))
417                 return (false);
418                 
419         if (desc->hwrev.end != BHND_HWREV_INVALID &&
420             desc->hwrev.end < core->hwrev)
421                 return (false);
422
423         if (desc->class != BHND_DEVCLASS_INVALID &&
424             desc->class != bhnd_core_class(core))
425                 return (false);
426
427         return true;
428 }
429
430 /**
431  * Return true if the @p hwrev matches @p desc.
432  * 
433  * @param hwrev A bhnd hardware revision.
434  * @param desc A match descriptor to compare against @p core.
435  * 
436  * @retval true if @p hwrev matches @p match
437  * @retval false if @p hwrev does not match @p match.
438  */
439 bool
440 bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
441 {
442         if (desc->start != BHND_HWREV_INVALID &&
443             desc->start > hwrev)
444                 return false;
445                 
446         if (desc->end != BHND_HWREV_INVALID &&
447             desc->end < hwrev)
448                 return false;
449
450         return true;
451 }
452
453 /**
454  * Return true if the @p dev matches @p desc.
455  * 
456  * @param dev A bhnd device.
457  * @param desc A match descriptor to compare against @p dev.
458  * 
459  * @retval true if @p dev matches @p match
460  * @retval false if @p dev does not match @p match.
461  */
462 bool
463 bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc)
464 {
465         struct bhnd_core_info ci = {
466                 .vendor = bhnd_get_vendor(dev),
467                 .device = bhnd_get_device(dev),
468                 .unit = bhnd_get_core_unit(dev),
469                 .hwrev = bhnd_get_hwrev(dev)
470         };
471
472         return bhnd_core_matches(&ci, desc);
473 }
474
475 /**
476  * Search @p table for an entry matching @p dev.
477  * 
478  * @param dev A bhnd device to match against @p table.
479  * @param table The device table to search.
480  * @param entry_size The @p table entry size, in bytes.
481  * 
482  * @retval bhnd_device the first matching device, if any.
483  * @retval NULL if no matching device is found in @p table.
484  */
485 const struct bhnd_device *
486 bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
487     size_t entry_size)
488 {
489         const struct bhnd_device *entry;
490
491         for (entry = table; entry->desc != NULL; entry =
492             (const struct bhnd_device *) ((const char *) entry + entry_size))
493         {
494                 /* match core info */
495                 if (!bhnd_device_matches(dev, &entry->core))
496                         continue;
497
498                 /* match device flags */
499                 if (entry->device_flags & BHND_DF_HOSTB) {
500                         if (!bhnd_is_hostb_device(dev))
501                                 continue;
502                 }
503
504                 /* device found */
505                 return (entry);
506         }
507
508         /* not found */
509         return (NULL);
510 }
511
512 /**
513  * Scan @p table for all quirk flags applicable to @p dev.
514  * 
515  * @param dev A bhnd device to match against @p table.
516  * @param table The device table to search.
517  * @param entry_size The @p table entry size, in bytes.
518  * 
519  * @return returns all matching quirk flags.
520  */
521 uint32_t
522 bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
523     size_t entry_size)
524 {
525         const struct bhnd_device        *dent;
526         const struct bhnd_device_quirk  *qtable, *qent;
527         uint32_t                         quirks;
528         uint16_t                         hwrev;
529
530         hwrev = bhnd_get_hwrev(dev);
531         quirks = 0;
532
533         /* Find the quirk table */
534         if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL) {
535                 /* This is almost certainly a (caller) implementation bug */
536                 device_printf(dev, "quirk lookup did not match any device\n");
537                 return (0);
538         }
539
540         /* Quirks aren't a mandatory field */
541         if ((qtable = dent->quirks_table) == NULL)
542                 return (0);
543
544         /* Collect matching quirk entries */
545         for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
546                 if (bhnd_hwrev_matches(hwrev, &qent->hwrev))
547                         quirks |= qent->quirks;
548         }
549
550         return (quirks);
551 }
552
553
554 /**
555  * Allocate bhnd(4) resources defined in @p rs from a parent bus.
556  * 
557  * @param dev The device requesting ownership of the resources.
558  * @param rs A standard bus resource specification. This will be updated
559  * with the allocated resource's RIDs.
560  * @param res On success, the allocated bhnd resources.
561  * 
562  * @retval 0 success
563  * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
564  *                  all allocated resources will be released and a regular
565  *                  unix error code will be returned.
566  */
567 int
568 bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
569     struct bhnd_resource **res)
570 {
571         /* Initialize output array */
572         for (u_int i = 0; rs[i].type != -1; i++)
573                 res[i] = NULL;
574
575         for (u_int i = 0; rs[i].type != -1; i++) {
576                 res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
577                     rs[i].flags);
578
579                 /* Clean up all allocations on failure */
580                 if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
581                         bhnd_release_resources(dev, rs, res);
582                         return (ENXIO);
583                 }
584         }
585
586         return (0);
587 };
588
589 /**
590  * Release bhnd(4) resources defined in @p rs from a parent bus.
591  * 
592  * @param dev The device that owns the resources.
593  * @param rs A standard bus resource specification previously initialized
594  * by @p bhnd_alloc_resources.
595  * @param res The bhnd resources to be released.
596  */
597 void
598 bhnd_release_resources(device_t dev, const struct resource_spec *rs,
599     struct bhnd_resource **res)
600 {
601         for (u_int i = 0; rs[i].type != -1; i++) {
602                 if (res[i] == NULL)
603                         continue;
604
605                 bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
606                 res[i] = NULL;
607         }
608 }
609
610 /**
611  * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
612  * register, returning its bhnd_chipid representation.
613  * 
614  * @param idreg The CHIPC_ID register value.
615  * @param enum_addr The enumeration address to include in the result.
616  *
617  * @warning
618  * On early siba(4) devices, the ChipCommon core does not provide
619  * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
620  * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
621  * an invalid `ncores` value.
622  */
623 struct bhnd_chipid
624 bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
625 {
626         struct bhnd_chipid result;
627
628         /* Fetch the basic chip info */
629         result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP);
630         result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG);
631         result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV);
632         result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS);
633         result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE);
634
635         result.enum_addr = enum_addr;
636
637         return (result);
638 }
639
640 /**
641  * Allocate the resource defined by @p rs via @p dev, use it
642  * to read the ChipCommon ID register relative to @p chipc_offset,
643  * then release the resource.
644  * 
645  * @param dev The device owning @p rs.
646  * @param rs A resource spec that encompasses the ChipCommon register block.
647  * @param chipc_offset The offset of the ChipCommon registers within @p rs.
648  * @param[out] result the chip identification data.
649  * 
650  * @retval 0 success
651  * @retval non-zero if the ChipCommon identification data could not be read.
652  */
653 int
654 bhnd_read_chipid(device_t dev, struct resource_spec *rs,
655     bus_size_t chipc_offset, struct bhnd_chipid *result)
656 {
657         struct resource                 *res;
658         uint32_t                         reg;
659         int                              error, rid, rtype;
660
661         /* Allocate the ChipCommon window resource and fetch the chipid data */
662         rid = rs->rid;
663         rtype = rs->type;
664         res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
665         if (res == NULL) {
666                 device_printf(dev,
667                     "failed to allocate bhnd chipc resource\n");
668                 return (ENXIO);
669         }
670
671         /* Fetch the basic chip info */
672         reg = bus_read_4(res, chipc_offset + CHIPC_ID);
673         *result = bhnd_parse_chipid(reg, 0x0);
674
675         /* Fetch the enum base address */
676         error = 0;
677         switch (result->chip_type) {
678         case BHND_CHIPTYPE_SIBA:
679                 result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
680                 break;
681         case BHND_CHIPTYPE_BCMA:
682         case BHND_CHIPTYPE_BCMA_ALT:
683                 result->enum_addr = bus_read_4(res, chipc_offset +
684                     CHIPC_EROMPTR);
685                 break;
686         case BHND_CHIPTYPE_UBUS:
687                 device_printf(dev, "unsupported ubus/bcm63xx chip type");
688                 error = ENODEV;
689                 goto cleanup;
690         default:
691                 device_printf(dev, "unknown chip type %hhu\n",
692                     result->chip_type);
693                 error = ENODEV;
694                 goto cleanup;
695         }
696
697 cleanup:
698         /* Clean up */
699         bus_release_resource(dev, rtype, rid, res);
700         return (error);
701 }
702
703 /**
704  * Using the bhnd(4) bus-level core information and a custom core name,
705  * populate @p dev's device description.
706  * 
707  * @param dev A bhnd-bus attached device.
708  * @param dev_name The core's name (e.g. "SDIO Device Core")
709  */
710 void
711 bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
712 {
713         const char *vendor_name;
714         char *desc;
715
716         vendor_name = bhnd_get_vendor_name(dev);
717         asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name,
718             bhnd_get_hwrev(dev));
719
720         if (desc != NULL) {
721                 device_set_desc_copy(dev, desc);
722                 free(desc, M_BHND);
723         } else {
724                 device_set_desc(dev, dev_name);
725         }
726 }
727
728 /**
729  * Using the bhnd(4) bus-level core information, populate @p dev's device
730  * description.
731  * 
732  * @param dev A bhnd-bus attached device.
733  */
734 void
735 bhnd_set_default_core_desc(device_t dev)
736 {
737         bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
738 }
739
740 /**
741  * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE().
742  * 
743  * If a parent device is available, this implementation delegates the
744  * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev.
745  * 
746  * If no parent device is available (i.e. on a the bus root), false
747  * is returned.
748  */
749 bool
750 bhnd_bus_generic_is_hostb_device(device_t dev, device_t child) {
751         if (device_get_parent(dev) != NULL)
752                 return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev),
753                     child));
754
755         return (false);
756 }
757
758 /**
759  * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
760  * 
761  * If a parent device is available, this implementation delegates the
762  * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
763  * 
764  * If no parent device is available (i.e. on a the bus root), the hardware
765  * is assumed to be usable and false is returned.
766  */
767 bool
768 bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
769 {
770         if (device_get_parent(dev) != NULL)
771                 return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
772
773         return (false);
774 }
775
776 /**
777  * Helper function for implementing BHND_BUS_GET_CHIPID().
778  * 
779  * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
780  * method on the parent of @p dev. If no parent exists, the implementation
781  * will panic.
782  */
783 const struct bhnd_chipid *
784 bhnd_bus_generic_get_chipid(device_t dev, device_t child)
785 {
786         if (device_get_parent(dev) != NULL)
787                 return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
788
789         panic("missing BHND_BUS_GET_CHIPID()");
790 }
791
792 /**
793  * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
794  * 
795  * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
796  * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
797  * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
798  */
799 struct bhnd_resource *
800 bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
801         int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
802         u_int flags)
803 {
804         struct bhnd_resource    *br;
805         struct resource         *res;
806         int                      error;
807
808         br = NULL;
809         res = NULL;
810
811         /* Allocate the real bus resource (without activating it) */
812         res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
813             (flags & ~RF_ACTIVE));
814         if (res == NULL)
815                 return (NULL);
816
817         /* Allocate our bhnd resource wrapper. */
818         br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
819         if (br == NULL)
820                 goto failed;
821         
822         br->direct = false;
823         br->res = res;
824
825         /* Attempt activation */
826         if (flags & RF_ACTIVE) {
827                 error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
828                 if (error)
829                         goto failed;
830         }
831
832         return (br);
833         
834 failed:
835         if (res != NULL)
836                 BUS_RELEASE_RESOURCE(dev, child, type, *rid, res);
837
838         free(br, M_BHND);
839         return (NULL);
840 }
841
842 /**
843  * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
844  * 
845  * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
846  * the backing resource to BUS_RELEASE_RESOURCE().
847  */
848 int
849 bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
850     int rid, struct bhnd_resource *r)
851 {
852         int error;
853
854         if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res)))
855                 return (error);
856
857         free(r, M_BHND);
858         return (0);
859 }
860
861
862 /**
863  * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
864  * 
865  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
866  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
867  */
868 int
869 bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
870     int rid, struct bhnd_resource *r)
871 {
872         /* Try to delegate to the parent */
873         if (device_get_parent(dev) != NULL)
874                 return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
875                     child, type, rid, r));
876
877         return (EINVAL);
878 };
879
880 /**
881  * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
882  * 
883  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
884  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
885  */
886 int
887 bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
888     int type, int rid, struct bhnd_resource *r)
889 {
890         if (device_get_parent(dev) != NULL)
891                 return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
892                     child, type, rid, r));
893
894         return (EINVAL);
895 };