]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/bhnd_subr.c
[bhnd] Normalize bhnd(4) device matching API
[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 "nvram/bhnd_nvram.h"
45
46 #include "bhnd_chipc_if.h"
47
48 #include "bhnd_nvram_if.h"
49 #include "bhnd_nvram_map.h"
50
51 #include "bhndreg.h"
52 #include "bhndvar.h"
53
54 static device_t         find_nvram_child(device_t dev);
55
56 /* BHND core device description table. */
57 static const struct bhnd_core_desc {
58         uint16_t         vendor;
59         uint16_t         device;
60         bhnd_devclass_t  class;
61         const char      *desc;
62 } bhnd_core_descs[] = {
63         #define BHND_CDESC(_mfg, _cid, _cls, _desc)             \
64             { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid,        \
65                 BHND_DEVCLASS_ ## _cls, _desc }
66
67         BHND_CDESC(BCM, CC,             CC,             "ChipCommon I/O Controller"),
68         BHND_CDESC(BCM, ILINE20,        OTHER,          "iLine20 HPNA"),
69         BHND_CDESC(BCM, SRAM,           RAM,            "SRAM"),
70         BHND_CDESC(BCM, SDRAM,          RAM,            "SDRAM"),
71         BHND_CDESC(BCM, PCI,            PCI,            "PCI Bridge"),
72         BHND_CDESC(BCM, MIPS,           CPU,            "MIPS Core"),
73         BHND_CDESC(BCM, ENET,           ENET_MAC,       "Fast Ethernet MAC"),
74         BHND_CDESC(BCM, CODEC,          OTHER,          "V.90 Modem Codec"),
75         BHND_CDESC(BCM, USB,            OTHER,          "USB 1.1 Device/Host Controller"),
76         BHND_CDESC(BCM, ADSL,           OTHER,          "ADSL Core"),
77         BHND_CDESC(BCM, ILINE100,       OTHER,          "iLine100 HPNA"),
78         BHND_CDESC(BCM, IPSEC,          OTHER,          "IPsec Accelerator"),
79         BHND_CDESC(BCM, UTOPIA,         OTHER,          "UTOPIA ATM Core"),
80         BHND_CDESC(BCM, PCMCIA,         PCCARD,         "PCMCIA Bridge"),
81         BHND_CDESC(BCM, SOCRAM,         RAM,            "Internal Memory"),
82         BHND_CDESC(BCM, MEMC,           MEMC,           "MEMC SDRAM Controller"),
83         BHND_CDESC(BCM, OFDM,           OTHER,          "OFDM PHY"),
84         BHND_CDESC(BCM, EXTIF,          OTHER,          "External Interface"),
85         BHND_CDESC(BCM, D11,            WLAN,           "802.11 MAC/PHY/Radio"),
86         BHND_CDESC(BCM, APHY,           WLAN_PHY,       "802.11a PHY"),
87         BHND_CDESC(BCM, BPHY,           WLAN_PHY,       "802.11b PHY"),
88         BHND_CDESC(BCM, GPHY,           WLAN_PHY,       "802.11g PHY"),
89         BHND_CDESC(BCM, MIPS33,         CPU,            "MIPS 3302 Core"),
90         BHND_CDESC(BCM, USB11H,         OTHER,          "USB 1.1 Host Controller"),
91         BHND_CDESC(BCM, USB11D,         OTHER,          "USB 1.1 Device Core"),
92         BHND_CDESC(BCM, USB20H,         OTHER,          "USB 2.0 Host Controller"),
93         BHND_CDESC(BCM, USB20D,         OTHER,          "USB 2.0 Device Core"),
94         BHND_CDESC(BCM, SDIOH,          OTHER,          "SDIO Host Controller"),
95         BHND_CDESC(BCM, ROBO,           OTHER,          "RoboSwitch"),
96         BHND_CDESC(BCM, ATA100,         OTHER,          "Parallel ATA Controller"),
97         BHND_CDESC(BCM, SATAXOR,        OTHER,          "SATA DMA/XOR Controller"),
98         BHND_CDESC(BCM, GIGETH,         ENET_MAC,       "Gigabit Ethernet MAC"),
99         BHND_CDESC(BCM, PCIE,           PCIE,           "PCIe Bridge"),
100         BHND_CDESC(BCM, NPHY,           WLAN_PHY,       "802.11n 2x2 PHY"),
101         BHND_CDESC(BCM, SRAMC,          MEMC,           "SRAM Controller"),
102         BHND_CDESC(BCM, MINIMAC,        OTHER,          "MINI MAC/PHY"),
103         BHND_CDESC(BCM, ARM11,          CPU,            "ARM1176 CPU"),
104         BHND_CDESC(BCM, ARM7S,          CPU,            "ARM7TDMI-S CPU"),
105         BHND_CDESC(BCM, LPPHY,          WLAN_PHY,       "802.11a/b/g PHY"),
106         BHND_CDESC(BCM, PMU,            PMU,            "PMU"),
107         BHND_CDESC(BCM, SSNPHY,         WLAN_PHY,       "802.11n Single-Stream PHY"),
108         BHND_CDESC(BCM, SDIOD,          OTHER,          "SDIO Device Core"),
109         BHND_CDESC(BCM, ARMCM3,         CPU,            "ARM Cortex-M3 CPU"),
110         BHND_CDESC(BCM, HTPHY,          WLAN_PHY,       "802.11n 4x4 PHY"),
111         BHND_CDESC(BCM, MIPS74K,        CPU,            "MIPS74k CPU"),
112         BHND_CDESC(BCM, GMAC,           ENET_MAC,       "Gigabit MAC core"),
113         BHND_CDESC(BCM, DMEMC,          MEMC,           "DDR1/DDR2 Memory Controller"),
114         BHND_CDESC(BCM, PCIERC,         OTHER,          "PCIe Root Complex"),
115         BHND_CDESC(BCM, OCP,            SOC_BRIDGE,     "OCP to OCP Bridge"),
116         BHND_CDESC(BCM, SC,             OTHER,          "Shared Common Core"),
117         BHND_CDESC(BCM, AHB,            SOC_BRIDGE,     "OCP to AHB Bridge"),
118         BHND_CDESC(BCM, SPIH,           OTHER,          "SPI Host Controller"),
119         BHND_CDESC(BCM, I2S,            OTHER,          "I2S Digital Audio Interface"),
120         BHND_CDESC(BCM, DMEMS,          MEMC,           "SDR/DDR1 Memory Controller"),
121         BHND_CDESC(BCM, UBUS_SHIM,      OTHER,          "BCM6362/UBUS WLAN SHIM"),
122         BHND_CDESC(BCM, PCIE2,          PCIE,           "PCIe Bridge (Gen2)"),
123
124         BHND_CDESC(ARM, APB_BRIDGE,     SOC_BRIDGE,     "BP135 AMBA3 AXI to APB Bridge"),
125         BHND_CDESC(ARM, PL301,          SOC_ROUTER,     "PL301 AMBA3 Interconnect"),
126         BHND_CDESC(ARM, EROM,           EROM,           "PL366 Device Enumeration ROM"),
127         BHND_CDESC(ARM, OOB_ROUTER,     OTHER,          "PL367 OOB Interrupt Router"),
128         BHND_CDESC(ARM, AXI_UNMAPPED,   OTHER,          "Unmapped Address Ranges"),
129
130         BHND_CDESC(BCM, 4706_CC,        CC,             "ChipCommon I/O Controller"),
131         BHND_CDESC(BCM, NS_PCIE2,       PCIE,           "PCIe Bridge (Gen2)"),
132         BHND_CDESC(BCM, NS_DMA,         OTHER,          "DMA engine"),
133         BHND_CDESC(BCM, NS_SDIO,        OTHER,          "SDIO 3.0 Host Controller"),
134         BHND_CDESC(BCM, NS_USB20H,      OTHER,          "USB 2.0 Host Controller"),
135         BHND_CDESC(BCM, NS_USB30H,      OTHER,          "USB 3.0 Host Controller"),
136         BHND_CDESC(BCM, NS_A9JTAG,      OTHER,          "ARM Cortex A9 JTAG Interface"),
137         BHND_CDESC(BCM, NS_DDR23_MEMC,  MEMC,           "Denali DDR2/DD3 Memory Controller"),
138         BHND_CDESC(BCM, NS_ROM,         NVRAM,          "System ROM"),
139         BHND_CDESC(BCM, NS_NAND,        NVRAM,          "NAND Flash Controller"),
140         BHND_CDESC(BCM, NS_QSPI,        NVRAM,          "QSPI Flash Controller"),
141         BHND_CDESC(BCM, NS_CC_B,        CC_B,           "ChipCommon B Auxiliary I/O Controller"),
142         BHND_CDESC(BCM, 4706_SOCRAM,    RAM,            "Internal Memory"),
143         BHND_CDESC(BCM, IHOST_ARMCA9,   CPU,            "ARM Cortex A9 CPU"),
144         BHND_CDESC(BCM, 4706_GMAC_CMN,  ENET,           "Gigabit MAC (Common)"),
145         BHND_CDESC(BCM, 4706_GMAC,      ENET_MAC,       "Gigabit MAC"),
146         BHND_CDESC(BCM, AMEMC,          MEMC,           "Denali DDR1/DDR2 Memory Controller"),
147 #undef  BHND_CDESC
148
149         /* Derived from inspection of the BCM4331 cores that provide PrimeCell
150          * IDs. Due to lack of documentation, the surmised device name/purpose
151          * provided here may be incorrect. */
152         { BHND_MFGID_ARM,       BHND_PRIMEID_EROM,      BHND_DEVCLASS_OTHER,
153             "PL364 Device Enumeration ROM" },
154         { BHND_MFGID_ARM,       BHND_PRIMEID_SWRAP,     BHND_DEVCLASS_OTHER,
155             "PL368 Device Management Interface" },
156         { BHND_MFGID_ARM,       BHND_PRIMEID_MWRAP,     BHND_DEVCLASS_OTHER,
157             "PL369 Device Management Interface" },
158
159         { 0, 0, 0, NULL }
160 };
161
162 /**
163  * Return the name for a given JEP106 manufacturer ID.
164  * 
165  * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
166  * JEP106 continuation code.
167  */
168 const char *
169 bhnd_vendor_name(uint16_t vendor)
170 {
171         switch (vendor) {
172         case BHND_MFGID_ARM:
173                 return "ARM";
174         case BHND_MFGID_BCM:
175                 return "Broadcom";
176         case BHND_MFGID_MIPS:
177                 return "MIPS";
178         default:
179                 return "unknown";
180         }
181 }
182
183 /**
184  * Return the name of a port type.
185  */
186 const char *
187 bhnd_port_type_name(bhnd_port_type port_type)
188 {
189         switch (port_type) {
190         case BHND_PORT_DEVICE:
191                 return ("device");
192         case BHND_PORT_BRIDGE:
193                 return ("bridge");
194         case BHND_PORT_AGENT:
195                 return ("agent");
196         default:
197                 return "unknown";
198         }
199 }
200
201
202 static const struct bhnd_core_desc *
203 bhnd_find_core_desc(uint16_t vendor, uint16_t device)
204 {
205         for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
206                 if (bhnd_core_descs[i].vendor != vendor)
207                         continue;
208                 
209                 if (bhnd_core_descs[i].device != device)
210                         continue;
211                 
212                 return (&bhnd_core_descs[i]);
213         }
214         
215         return (NULL);
216 }
217
218 /**
219  * Return a human-readable name for a BHND core.
220  * 
221  * @param vendor The core designer's JEDEC-106 Manufacturer ID
222  * @param device The core identifier.
223  */
224 const char *
225 bhnd_find_core_name(uint16_t vendor, uint16_t device)
226 {
227         const struct bhnd_core_desc *desc;
228         
229         if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
230                 return ("unknown");
231
232         return desc->desc;
233 }
234
235 /**
236  * Return the device class for a BHND core.
237  * 
238  * @param vendor The core designer's JEDEC-106 Manufacturer ID
239  * @param device The core identifier.
240  */
241 bhnd_devclass_t
242 bhnd_find_core_class(uint16_t vendor, uint16_t device)
243 {
244         const struct bhnd_core_desc *desc;
245         
246         if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
247                 return (BHND_DEVCLASS_OTHER);
248
249         return desc->class;
250 }
251
252 /**
253  * Return a human-readable name for a BHND core.
254  * 
255  * @param ci The core's info record.
256  */
257 const char *
258 bhnd_core_name(const struct bhnd_core_info *ci)
259 {
260         return bhnd_find_core_name(ci->vendor, ci->device);
261 }
262
263 /**
264  * Return the device class for a BHND core.
265  * 
266  * @param ci The core's info record.
267  */
268 bhnd_devclass_t
269 bhnd_core_class(const struct bhnd_core_info *ci)
270 {
271         return bhnd_find_core_class(ci->vendor, ci->device);
272 }
273
274 /**
275  * Initialize a core info record with data from from a bhnd-attached @p dev.
276  * 
277  * @param dev A bhnd device.
278  * @param core The record to be initialized.
279  */
280 struct bhnd_core_info
281 bhnd_get_core_info(device_t dev) {
282         return (struct bhnd_core_info) {
283                 .vendor         = bhnd_get_vendor(dev),
284                 .device         = bhnd_get_device(dev),
285                 .hwrev          = bhnd_get_hwrev(dev),
286                 .core_idx       = bhnd_get_core_index(dev),
287                 .unit           = bhnd_get_core_unit(dev)
288         };
289 }
290
291 /**
292  * Find a @p class child device with @p unit on @p dev.
293  * 
294  * @param parent The bhnd-compatible bus to be searched.
295  * @param class The device class to match on.
296  * @param unit The device unit number; specify -1 to return the first match
297  * regardless of unit number.
298  * 
299  * @retval device_t if a matching child device is found.
300  * @retval NULL if no matching child device is found.
301  */
302 device_t
303 bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
304 {
305         struct bhnd_core_match md = {
306                 BHND_MATCH_CORE_CLASS(class),
307                 BHND_MATCH_CORE_UNIT(unit)
308         };
309
310         if (unit == -1)
311                 md.m.match.core_unit = 0;
312
313         return bhnd_match_child(dev, &md);
314 }
315
316 /**
317  * Find the first child device on @p dev that matches @p desc.
318  * 
319  * @param parent The bhnd-compatible bus to be searched.
320  * @param desc A match descriptor.
321  * 
322  * @retval device_t if a matching child device is found.
323  * @retval NULL if no matching child device is found.
324  */
325 device_t
326 bhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
327 {
328         device_t        *devlistp;
329         device_t         match;
330         int              devcnt;
331         int              error;
332
333         error = device_get_children(dev, &devlistp, &devcnt);
334         if (error != 0)
335                 return (NULL);
336
337         match = NULL;
338         for (int i = 0; i < devcnt; i++) {
339                 struct bhnd_core_info ci = bhnd_get_core_info(devlistp[i]);
340
341                 if (bhnd_core_matches(&ci, desc)) {
342                         match = devlistp[i];
343                         goto done;
344                 }
345         }
346
347 done:
348         free(devlistp, M_TEMP);
349         return match;
350 }
351
352 /**
353  * Walk up the bhnd device hierarchy to locate the root device
354  * to which the bhndb bridge is attached.
355  * 
356  * This can be used from within bhnd host bridge drivers to locate the
357  * actual upstream host device.
358  * 
359  * @param dev A bhnd device.
360  * @param bus_class The expected bus (e.g. "pci") to which the bridge root
361  * should be attached.
362  * 
363  * @retval device_t if a matching parent device is found.
364  * @retval NULL @p dev is not attached via a bhndb bus
365  * @retval NULL no parent device is attached via @p bus_class.
366  */
367 device_t
368 bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
369 {
370         devclass_t      bhndb_class;
371         device_t        parent;
372
373         KASSERT(device_get_devclass(device_get_parent(dev)) == bhnd_devclass,
374            ("%s not a bhnd device", device_get_nameunit(dev)));
375
376         bhndb_class = devclass_find("bhndb");
377
378         /* Walk the device tree until we hit a bridge */
379         parent = dev;
380         while ((parent = device_get_parent(parent)) != NULL) {
381                 if (device_get_devclass(parent) == bhndb_class)
382                         break;
383         }
384
385         /* No bridge? */
386         if (parent == NULL)
387                 return (NULL);
388
389         /* Search for a parent attached to the expected bus class */
390         while ((parent = device_get_parent(parent)) != NULL) {
391                 device_t bus;
392
393                 bus = device_get_parent(parent);
394                 if (bus != NULL && device_get_devclass(bus) == bus_class)
395                         return (parent);
396         }
397
398         /* Not found */
399         return (NULL);
400 }
401
402 /**
403  * Find the first core in @p cores that matches @p desc.
404  * 
405  * @param cores The table to search.
406  * @param num_cores The length of @p cores.
407  * @param desc A match descriptor.
408  * 
409  * @retval bhnd_core_info if a matching core is found.
410  * @retval NULL if no matching core is found.
411  */
412 const struct bhnd_core_info *
413 bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
414     const struct bhnd_core_match *desc)
415 {
416         for (u_int i = 0; i < num_cores; i++) {
417                 if (bhnd_core_matches(&cores[i], desc))
418                         return &cores[i];
419         }
420
421         return (NULL);
422 }
423
424
425 /**
426  * Find the first core in @p cores with the given @p class.
427  * 
428  * @param cores The table to search.
429  * @param num_cores The length of @p cores.
430  * @param desc A match descriptor.
431  * 
432  * @retval bhnd_core_info if a matching core is found.
433  * @retval NULL if no matching core is found.
434  */
435 const struct bhnd_core_info *
436 bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
437     bhnd_devclass_t class)
438 {
439         struct bhnd_core_match md = {
440                 BHND_MATCH_CORE_CLASS(class)
441         };
442
443         return bhnd_match_core(cores, num_cores, &md);
444 }
445
446 /**
447  * Return true if the @p core matches @p desc.
448  * 
449  * @param core A bhnd core descriptor.
450  * @param desc A match descriptor to compare against @p core.
451  * 
452  * @retval true if @p core matches @p match
453  * @retval false if @p core does not match @p match.
454  */
455 bool
456 bhnd_core_matches(const struct bhnd_core_info *core,
457     const struct bhnd_core_match *desc)
458 {
459         if (desc->m.match.core_vendor && desc->core_vendor != core->vendor)
460                 return (false);
461
462         if (desc->m.match.core_id && desc->core_id != core->device)
463                 return (false);
464
465         if (desc->m.match.core_unit && desc->core_unit != core->unit)
466                 return (false);
467
468         if (desc->m.match.core_rev && 
469             !bhnd_hwrev_matches(core->hwrev, &desc->core_rev))
470                 return (false);
471
472         if (desc->m.match.core_class &&
473             desc->core_class != bhnd_core_class(core))
474                 return (false);
475
476         return true;
477 }
478
479 /**
480  * Return true if the @p chip matches @p desc.
481  * 
482  * @param chip A bhnd chip identifier.
483  * @param desc A match descriptor to compare against @p chip.
484  * 
485  * @retval true if @p chip matches @p match
486  * @retval false if @p chip does not match @p match.
487  */
488 bool
489 bhnd_chip_matches(const struct bhnd_chipid *chip,
490     const struct bhnd_chip_match *desc)
491 {
492         if (desc->m.match.chip_id && chip->chip_id != desc->chip_id)
493                 return (false);
494
495         if (desc->m.match.chip_pkg && chip->chip_pkg != desc->chip_pkg)
496                 return (false);
497
498         if (desc->m.match.chip_rev &&
499             !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
500                 return (false);
501
502         return (true);
503 }
504
505 /**
506  * Return true if the @p board matches @p desc.
507  * 
508  * @param board The bhnd board info.
509  * @param desc A match descriptor to compare against @p board.
510  * 
511  * @retval true if @p chip matches @p match
512  * @retval false if @p chip does not match @p match.
513  */
514 bool
515 bhnd_board_matches(const struct bhnd_board_info *board,
516     const struct bhnd_board_match *desc)
517 {
518         if (desc->m.match.board_srom_rev &&
519             !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
520                 return (false);
521
522         if (desc->m.match.board_vendor &&
523             board->board_vendor != desc->board_vendor)
524                 return (false);
525
526         if (desc->m.match.board_type && board->board_type != desc->board_type)
527                 return (false);
528
529         if (desc->m.match.board_rev &&
530             !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
531                 return (false);
532
533         return (true);
534 }
535
536 /**
537  * Return true if the @p hwrev matches @p desc.
538  * 
539  * @param hwrev A bhnd hardware revision.
540  * @param desc A match descriptor to compare against @p core.
541  * 
542  * @retval true if @p hwrev matches @p match
543  * @retval false if @p hwrev does not match @p match.
544  */
545 bool
546 bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
547 {
548         if (desc->start != BHND_HWREV_INVALID &&
549             desc->start > hwrev)
550                 return false;
551                 
552         if (desc->end != BHND_HWREV_INVALID &&
553             desc->end < hwrev)
554                 return false;
555
556         return true;
557 }
558
559 /**
560  * Return true if the @p dev matches @p desc.
561  * 
562  * @param dev A bhnd device.
563  * @param desc A match descriptor to compare against @p dev.
564  * 
565  * @retval true if @p dev matches @p match
566  * @retval false if @p dev does not match @p match.
567  */
568 bool
569 bhnd_device_matches(device_t dev, const struct bhnd_device_match *desc)
570 {
571         struct bhnd_core_info            core;
572         const struct bhnd_chipid        *chip;
573         struct bhnd_board_info           board;
574         device_t                         parent;
575         int                              error;
576
577         /* Construct individual match descriptors */
578         struct bhnd_core_match  m_core  = { _BHND_CORE_MATCH_COPY(desc) };
579         struct bhnd_chip_match  m_chip  = { _BHND_CHIP_MATCH_COPY(desc) };
580         struct bhnd_board_match m_board = { _BHND_BOARD_MATCH_COPY(desc) };
581
582         /* Fetch and match core info */
583         if (m_core.m.match_flags) {
584                 /* Only applicable to bhnd-attached cores */
585                 parent = device_get_parent(dev);
586                 if (device_get_devclass(parent) != bhnd_devclass) {
587                         device_printf(dev, "attempting to match core "
588                             "attributes against non-core device\n");
589                         return (false);
590                 }
591
592                 core = bhnd_get_core_info(dev);
593                 if (!bhnd_core_matches(&core, &m_core))
594                         return (false);
595         }
596
597         /* Fetch and match chip info */
598         if (m_chip.m.match_flags) {
599                 chip = bhnd_get_chipid(dev);
600
601                 if (!bhnd_chip_matches(chip, &m_chip))
602                         return (false);
603         }
604
605         /* Fetch and match board info.
606          *
607          * This is not available until  after NVRAM is up; earlier device
608          * matches should not include board requirements */
609         if (m_board.m.match_flags) {
610                 if ((error = bhnd_read_board_info(dev, &board))) {
611                         device_printf(dev, "failed to read required board info "
612                             "during device matching: %d\n", error);
613                         return (false);
614                 }
615
616                 if (!bhnd_board_matches(&board, &m_board))
617                         return (false);
618         }
619
620         /* All matched */
621         return (true);
622 }
623
624 /**
625  * Search @p table for an entry matching @p dev.
626  * 
627  * @param dev A bhnd device to match against @p table.
628  * @param table The device table to search.
629  * @param entry_size The @p table entry size, in bytes.
630  * 
631  * @retval bhnd_device the first matching device, if any.
632  * @retval NULL if no matching device is found in @p table.
633  */
634 const struct bhnd_device *
635 bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
636     size_t entry_size)
637 {
638         const struct bhnd_device        *entry;
639         device_t                         hostb, parent;
640         bhnd_attach_type                 attach_type;
641         uint32_t                         dflags;
642
643         parent = device_get_parent(dev);
644         hostb = bhnd_find_hostb_device(parent);
645         attach_type = bhnd_get_attach_type(dev);
646
647         for (entry = table; !BHND_DEVICE_IS_END(entry); entry =
648             (const struct bhnd_device *) ((const char *) entry + entry_size))
649         {
650                 /* match core info */
651                 if (!bhnd_device_matches(dev, &entry->core))
652                         continue;
653
654                 /* match device flags */
655                 dflags = entry->device_flags;
656
657                 /* hostb implies BHND_ATTACH_ADAPTER requirement */
658                 if (dflags & BHND_DF_HOSTB)
659                         dflags |= BHND_DF_ADAPTER;
660         
661                 if (dflags & BHND_DF_ADAPTER)
662                         if (attach_type != BHND_ATTACH_ADAPTER)
663                                 continue;
664
665                 if (dflags & BHND_DF_HOSTB)
666                         if (dev != hostb)
667                                 continue;
668
669                 if (dflags & BHND_DF_SOC)
670                         if (attach_type != BHND_ATTACH_NATIVE)
671                                 continue;
672
673                 /* device found */
674                 return (entry);
675         }
676
677         /* not found */
678         return (NULL);
679 }
680
681 /**
682  * Scan the device @p table for all quirk flags applicable to @p dev.
683  * 
684  * @param dev A bhnd device to match against @p table.
685  * @param table The device table to search.
686  * 
687  * @return returns all matching quirk flags.
688  */
689 uint32_t
690 bhnd_device_quirks(device_t dev, const struct bhnd_device *table,
691     size_t entry_size)
692 {
693         const struct bhnd_device        *dent;
694         const struct bhnd_device_quirk  *qent, *qtable;
695         uint32_t                         quirks;
696
697         /* Locate the device entry */
698         if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL)
699                 return (0);
700
701         /* Quirks table is optional */
702         qtable = dent->quirks_table;
703         if (qtable == NULL)
704                 return (0);
705
706         /* Collect matching device quirk entries */
707         quirks = 0;
708         for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
709                 if (bhnd_device_matches(dev, &qent->desc))
710                         quirks |= qent->quirks;
711         }
712
713         return (quirks);
714 }
715
716
717 /**
718  * Allocate bhnd(4) resources defined in @p rs from a parent bus.
719  * 
720  * @param dev The device requesting ownership of the resources.
721  * @param rs A standard bus resource specification. This will be updated
722  * with the allocated resource's RIDs.
723  * @param res On success, the allocated bhnd resources.
724  * 
725  * @retval 0 success
726  * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
727  *                  all allocated resources will be released and a regular
728  *                  unix error code will be returned.
729  */
730 int
731 bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
732     struct bhnd_resource **res)
733 {
734         /* Initialize output array */
735         for (u_int i = 0; rs[i].type != -1; i++)
736                 res[i] = NULL;
737
738         for (u_int i = 0; rs[i].type != -1; i++) {
739                 res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
740                     rs[i].flags);
741
742                 /* Clean up all allocations on failure */
743                 if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
744                         bhnd_release_resources(dev, rs, res);
745                         return (ENXIO);
746                 }
747         }
748
749         return (0);
750 };
751
752 /**
753  * Release bhnd(4) resources defined in @p rs from a parent bus.
754  * 
755  * @param dev The device that owns the resources.
756  * @param rs A standard bus resource specification previously initialized
757  * by @p bhnd_alloc_resources.
758  * @param res The bhnd resources to be released.
759  */
760 void
761 bhnd_release_resources(device_t dev, const struct resource_spec *rs,
762     struct bhnd_resource **res)
763 {
764         for (u_int i = 0; rs[i].type != -1; i++) {
765                 if (res[i] == NULL)
766                         continue;
767
768                 bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
769                 res[i] = NULL;
770         }
771 }
772
773 /**
774  * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
775  * register, returning its bhnd_chipid representation.
776  * 
777  * @param idreg The CHIPC_ID register value.
778  * @param enum_addr The enumeration address to include in the result.
779  *
780  * @warning
781  * On early siba(4) devices, the ChipCommon core does not provide
782  * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
783  * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
784  * an invalid `ncores` value.
785  */
786 struct bhnd_chipid
787 bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
788 {
789         struct bhnd_chipid result;
790
791         /* Fetch the basic chip info */
792         result.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
793         result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
794         result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
795         result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
796         result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
797
798         result.enum_addr = enum_addr;
799
800         return (result);
801 }
802
803 /**
804  * Allocate the resource defined by @p rs via @p dev, use it
805  * to read the ChipCommon ID register relative to @p chipc_offset,
806  * then release the resource.
807  * 
808  * @param dev The device owning @p rs.
809  * @param rs A resource spec that encompasses the ChipCommon register block.
810  * @param chipc_offset The offset of the ChipCommon registers within @p rs.
811  * @param[out] result the chip identification data.
812  * 
813  * @retval 0 success
814  * @retval non-zero if the ChipCommon identification data could not be read.
815  */
816 int
817 bhnd_read_chipid(device_t dev, struct resource_spec *rs,
818     bus_size_t chipc_offset, struct bhnd_chipid *result)
819 {
820         struct resource                 *res;
821         uint32_t                         reg;
822         int                              error, rid, rtype;
823
824         /* Allocate the ChipCommon window resource and fetch the chipid data */
825         rid = rs->rid;
826         rtype = rs->type;
827         res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
828         if (res == NULL) {
829                 device_printf(dev,
830                     "failed to allocate bhnd chipc resource\n");
831                 return (ENXIO);
832         }
833
834         /* Fetch the basic chip info */
835         reg = bus_read_4(res, chipc_offset + CHIPC_ID);
836         *result = bhnd_parse_chipid(reg, 0x0);
837
838         /* Fetch the enum base address */
839         error = 0;
840         switch (result->chip_type) {
841         case BHND_CHIPTYPE_SIBA:
842                 result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
843                 break;
844         case BHND_CHIPTYPE_BCMA:
845         case BHND_CHIPTYPE_BCMA_ALT:
846                 result->enum_addr = bus_read_4(res, chipc_offset +
847                     CHIPC_EROMPTR);
848                 break;
849         case BHND_CHIPTYPE_UBUS:
850                 device_printf(dev, "unsupported ubus/bcm63xx chip type");
851                 error = ENODEV;
852                 goto cleanup;
853         default:
854                 device_printf(dev, "unknown chip type %hhu\n",
855                     result->chip_type);
856                 error = ENODEV;
857                 goto cleanup;
858         }
859
860 cleanup:
861         /* Clean up */
862         bus_release_resource(dev, rtype, rid, res);
863         return (error);
864 }
865
866 /**
867  * Using the bhnd(4) bus-level core information and a custom core name,
868  * populate @p dev's device description.
869  * 
870  * @param dev A bhnd-bus attached device.
871  * @param dev_name The core's name (e.g. "SDIO Device Core")
872  */
873 void
874 bhnd_set_custom_core_desc(device_t dev, const char *dev_name)
875 {
876         const char *vendor_name;
877         char *desc;
878
879         vendor_name = bhnd_get_vendor_name(dev);
880         asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name,
881             bhnd_get_hwrev(dev));
882
883         if (desc != NULL) {
884                 device_set_desc_copy(dev, desc);
885                 free(desc, M_BHND);
886         } else {
887                 device_set_desc(dev, dev_name);
888         }
889 }
890
891 /**
892  * Using the bhnd(4) bus-level core information, populate @p dev's device
893  * description.
894  * 
895  * @param dev A bhnd-bus attached device.
896  */
897 void
898 bhnd_set_default_core_desc(device_t dev)
899 {
900         bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
901 }
902
903 /**
904  * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
905  * 
906  * If a parent device is available, this implementation delegates the
907  * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
908  * 
909  * If no parent device is available (i.e. on a the bus root), the hardware
910  * is assumed to be usable and false is returned.
911  */
912 bool
913 bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child)
914 {
915         if (device_get_parent(dev) != NULL)
916                 return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
917
918         return (false);
919 }
920
921 /**
922  * Helper function for implementing BHND_BUS_GET_CHIPID().
923  * 
924  * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
925  * method on the parent of @p dev. If no parent exists, the implementation
926  * will panic.
927  */
928 const struct bhnd_chipid *
929 bhnd_bus_generic_get_chipid(device_t dev, device_t child)
930 {
931         if (device_get_parent(dev) != NULL)
932                 return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
933
934         panic("missing BHND_BUS_GET_CHIPID()");
935 }
936
937 /* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
938 #define BHND_GV(_dest, _name)   \
939         bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest))
940
941 #define REQ_BHND_GV(_dest, _name)               do {                    \
942         if ((error = BHND_GV(_dest, _name))) {                          \
943                 device_printf(dev,                                      \
944                     "error reading " __STRING(_name) ": %d\n", error);  \
945                 return (error);                                         \
946         }                                                               \
947 } while(0)
948
949 #define OPT_BHND_GV(_dest, _name, _default)     do {                    \
950         if ((error = BHND_GV(_dest, _name))) {                          \
951                 if (error != ENOENT) {                                  \
952                         device_printf(dev,                              \
953                             "error reading "                            \
954                                __STRING(_name) ": %d\n", error);        \
955                         return (error);                                 \
956                 }                                                       \
957                 _dest = _default;                                       \
958         }                                                               \
959 } while(0)
960
961 /**
962  * Helper function for implementing BHND_BUS_READ_BOARDINFO().
963  * 
964  * This implementation populates @p info with information from NVRAM,
965  * defaulting board_vendor and board_type fields to 0 if the
966  * requested variables cannot be found.
967  * 
968  * This behavior is correct for most SoCs, but must be overridden on
969  * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
970  * result.
971  */
972 int
973 bhnd_bus_generic_read_board_info(device_t dev, device_t child,
974     struct bhnd_board_info *info)
975 {
976         int     error;
977
978         OPT_BHND_GV(info->board_vendor, BOARDVENDOR,    0);
979         OPT_BHND_GV(info->board_type,   BOARDTYPE,      0);     /* srom >= 2 */
980         REQ_BHND_GV(info->board_rev,    BOARDREV);
981         REQ_BHND_GV(info->board_srom_rev,SROMREV);
982         REQ_BHND_GV(info->board_flags,  BOARDFLAGS);
983         OPT_BHND_GV(info->board_flags2, BOARDFLAGS2,    0);     /* srom >= 4 */
984         OPT_BHND_GV(info->board_flags3, BOARDFLAGS3,    0);     /* srom >= 11 */
985
986         return (0);
987 }
988
989 #undef  BHND_GV
990 #undef  BHND_GV_REQ
991 #undef  BHND_GV_OPT
992
993
994 /**
995  * Find an NVRAM child device on @p dev, if any.
996  * 
997  * @retval device_t An NVRAM device.
998  * @retval NULL If no NVRAM device is found.
999  */
1000 static device_t
1001 find_nvram_child(device_t dev)
1002 {
1003         device_t        chipc, nvram;
1004
1005         /* Look for a directly-attached NVRAM child */
1006         nvram = device_find_child(dev, "bhnd_nvram", 0);
1007         if (nvram != NULL)
1008                 return (nvram);
1009
1010         /* Remaining checks are only applicable when searching a bhnd(4)
1011          * bus. */
1012         if (device_get_devclass(dev) != bhnd_devclass)
1013                 return (NULL);
1014
1015         /* Look for a ChipCommon-attached NVRAM device */
1016         if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
1017                 nvram = device_find_child(chipc, "bhnd_nvram", 0);
1018                 if (nvram != NULL)
1019                         return (nvram);
1020         }
1021
1022         /* Not found */
1023         return (NULL);
1024 }
1025
1026 /**
1027  * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
1028  * 
1029  * This implementation searches @p dev for a usable NVRAM child device:
1030  * - The first child device implementing the bhnd_nvram devclass is
1031  *   returned, otherwise
1032  * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an
1033  *   attached NVRAM source.
1034  * 
1035  * If no usable child device is found on @p dev, the request is delegated to
1036  * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
1037  */
1038 int
1039 bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
1040     void *buf, size_t *size)
1041 {
1042         device_t        nvram;
1043         device_t        parent;
1044
1045         /* Try to find an NVRAM device applicable to @p child */
1046         if ((nvram = find_nvram_child(dev)) != NULL)
1047                 return BHND_NVRAM_GETVAR(nvram, name, buf, size);
1048
1049         /* Try to delegate to parent */
1050         if ((parent = device_get_parent(dev)) == NULL)
1051                 return (ENODEV);
1052
1053         return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
1054             name, buf, size));
1055 }
1056
1057 /**
1058  * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
1059  * 
1060  * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation
1061  * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation
1062  * to @p dev's BHND_BUS_ACTIVATE_RESOURCE().
1063  */
1064 struct bhnd_resource *
1065 bhnd_bus_generic_alloc_resource(device_t dev, device_t child, int type,
1066         int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
1067         u_int flags)
1068 {
1069         struct bhnd_resource    *br;
1070         struct resource         *res;
1071         int                      error;
1072
1073         br = NULL;
1074         res = NULL;
1075
1076         /* Allocate the real bus resource (without activating it) */
1077         res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count,
1078             (flags & ~RF_ACTIVE));
1079         if (res == NULL)
1080                 return (NULL);
1081
1082         /* Allocate our bhnd resource wrapper. */
1083         br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
1084         if (br == NULL)
1085                 goto failed;
1086         
1087         br->direct = false;
1088         br->res = res;
1089
1090         /* Attempt activation */
1091         if (flags & RF_ACTIVE) {
1092                 error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br);
1093                 if (error)
1094                         goto failed;
1095         }
1096
1097         return (br);
1098         
1099 failed:
1100         if (res != NULL)
1101                 BUS_RELEASE_RESOURCE(dev, child, type, *rid, res);
1102
1103         free(br, M_BHND);
1104         return (NULL);
1105 }
1106
1107 /**
1108  * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
1109  * 
1110  * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of
1111  * the backing resource to BUS_RELEASE_RESOURCE().
1112  */
1113 int
1114 bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
1115     int rid, struct bhnd_resource *r)
1116 {
1117         int error;
1118
1119         if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res)))
1120                 return (error);
1121
1122         free(r, M_BHND);
1123         return (0);
1124 }
1125
1126
1127 /**
1128  * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
1129  * 
1130  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1131  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1132  */
1133 int
1134 bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
1135     int rid, struct bhnd_resource *r)
1136 {
1137         /* Try to delegate to the parent */
1138         if (device_get_parent(dev) != NULL)
1139                 return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
1140                     child, type, rid, r));
1141
1142         return (EINVAL);
1143 };
1144
1145 /**
1146  * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
1147  * 
1148  * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
1149  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
1150  */
1151 int
1152 bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
1153     int type, int rid, struct bhnd_resource *r)
1154 {
1155         if (device_get_parent(dev) != NULL)
1156                 return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
1157                     child, type, rid, r));
1158
1159         return (EINVAL);
1160 };