bhnd(4): Implement common API for IOST/IOCTL register access and core reset
[freebsd.git] / sys / dev / bhnd / bcma / bcma.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/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39
40 #include <machine/bus.h>
41
42 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
43
44 #include "bcma_dmp.h"
45
46 #include "bcma_eromreg.h"
47 #include "bcma_eromvar.h"
48
49 #include "bcmavar.h"
50
51 /* RID used when allocating EROM table */
52 #define BCMA_EROM_RID   0
53
54 static bhnd_erom_class_t *
55 bcma_get_erom_class(driver_t *driver)
56 {
57         return (&bcma_erom_parser);
58 }
59
60 int
61 bcma_probe(device_t dev)
62 {
63         device_set_desc(dev, "BCMA BHND bus");
64         return (BUS_PROBE_DEFAULT);
65 }
66
67 /**
68  * Default bcma(4) bus driver implementation of DEVICE_ATTACH().
69  * 
70  * This implementation initializes internal bcma(4) state and performs
71  * bus enumeration, and must be called by subclassing drivers in
72  * DEVICE_ATTACH() before any other bus methods.
73  */
74 int
75 bcma_attach(device_t dev)
76 {
77         int error;
78
79         /* Enumerate children */
80         if ((error = bcma_add_children(dev))) {
81                 device_delete_children(dev);
82                 return (error);
83         }
84
85         return (0);
86 }
87
88 int
89 bcma_detach(device_t dev)
90 {
91         return (bhnd_generic_detach(dev));
92 }
93
94 static device_t
95 bcma_add_child(device_t dev, u_int order, const char *name, int unit)
96 {
97         struct bcma_devinfo     *dinfo;
98         device_t                 child;
99
100         child = device_add_child_ordered(dev, order, name, unit);
101         if (child == NULL)
102                 return (NULL);
103
104         if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) {
105                 device_delete_child(dev, child);
106                 return (NULL);
107         }
108
109         device_set_ivars(child, dinfo);
110
111         return (child);
112 }
113
114 static void
115 bcma_child_deleted(device_t dev, device_t child)
116 {
117         struct bhnd_softc       *sc;
118         struct bcma_devinfo     *dinfo;
119
120         sc = device_get_softc(dev);
121
122         /* Call required bhnd(4) implementation */
123         bhnd_generic_child_deleted(dev, child);
124
125         /* Free bcma device info */
126         if ((dinfo = device_get_ivars(child)) != NULL)
127                 bcma_free_dinfo(dev, dinfo);
128
129         device_set_ivars(child, NULL);
130 }
131
132 static int
133 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
134 {
135         const struct bcma_devinfo *dinfo;
136         const struct bhnd_core_info *ci;
137         
138         dinfo = device_get_ivars(child);
139         ci = &dinfo->corecfg->core_info;
140         
141         switch (index) {
142         case BHND_IVAR_VENDOR:
143                 *result = ci->vendor;
144                 return (0);
145         case BHND_IVAR_DEVICE:
146                 *result = ci->device;
147                 return (0);
148         case BHND_IVAR_HWREV:
149                 *result = ci->hwrev;
150                 return (0);
151         case BHND_IVAR_DEVICE_CLASS:
152                 *result = bhnd_core_class(ci);
153                 return (0);
154         case BHND_IVAR_VENDOR_NAME:
155                 *result = (uintptr_t) bhnd_vendor_name(ci->vendor);
156                 return (0);
157         case BHND_IVAR_DEVICE_NAME:
158                 *result = (uintptr_t) bhnd_core_name(ci);
159                 return (0);
160         case BHND_IVAR_CORE_INDEX:
161                 *result = ci->core_idx;
162                 return (0);
163         case BHND_IVAR_CORE_UNIT:
164                 *result = ci->unit;
165                 return (0);
166         case BHND_IVAR_PMU_INFO:
167                 *result = (uintptr_t) dinfo->pmu_info;
168                 return (0);
169         default:
170                 return (ENOENT);
171         }
172 }
173
174 static int
175 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
176 {
177         struct bcma_devinfo *dinfo;
178
179         dinfo = device_get_ivars(child);
180
181         switch (index) {
182         case BHND_IVAR_VENDOR:
183         case BHND_IVAR_DEVICE:
184         case BHND_IVAR_HWREV:
185         case BHND_IVAR_DEVICE_CLASS:
186         case BHND_IVAR_VENDOR_NAME:
187         case BHND_IVAR_DEVICE_NAME:
188         case BHND_IVAR_CORE_INDEX:
189         case BHND_IVAR_CORE_UNIT:
190                 return (EINVAL);
191         case BHND_IVAR_PMU_INFO:
192                 dinfo->pmu_info = (struct bhnd_core_pmu_info *) value;
193                 return (0);
194         default:
195                 return (ENOENT);
196         }
197 }
198
199 static struct resource_list *
200 bcma_get_resource_list(device_t dev, device_t child)
201 {
202         struct bcma_devinfo *dinfo = device_get_ivars(child);
203         return (&dinfo->resources);
204 }
205
206 static int
207 bcma_read_iost(device_t dev, device_t child, uint16_t *iost)
208 {
209         uint32_t        value;
210         int             error;
211
212         if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4)))
213                 return (error);
214
215         /* Return only the bottom 16 bits */
216         *iost = (value & BCMA_DMP_IOST_MASK);
217         return (0);
218 }
219
220 static int
221 bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
222 {
223         uint32_t        value;
224         int             error;
225
226         if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4)))
227                 return (error);
228
229         /* Return only the bottom 16 bits */
230         *ioctl = (value & BCMA_DMP_IOCTRL_MASK);
231         return (0);
232 }
233
234 static int
235 bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
236 {
237         struct bcma_devinfo     *dinfo;
238         struct bhnd_resource    *r;
239         uint32_t                 ioctl;
240
241         if (device_get_parent(child) != dev)
242                 return (EINVAL);
243
244         dinfo = device_get_ivars(child);
245         if ((r = dinfo->res_agent) == NULL)
246                 return (ENODEV);
247
248         /* Write new value */
249         ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
250         ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask);
251         ioctl |= (value & mask);
252
253         bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl);
254
255         /* Perform read-back and wait for completion */
256         bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
257         DELAY(10);
258
259         return (0);
260 }
261
262 static bool
263 bcma_is_hw_suspended(device_t dev, device_t child)
264 {
265         uint32_t        rst;
266         uint16_t        ioctl;
267         int             error;
268
269         /* Is core held in RESET? */
270         error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4);
271         if (error) {
272                 device_printf(child, "error reading HW reset state: %d\n",
273                     error);
274                 return (true);
275         }
276
277         if (rst & BMCA_DMP_RC_RESET)
278                 return (true);
279
280         /* Is core clocked? */
281         error = bhnd_read_ioctl(child, &ioctl);
282         if (error) {
283                 device_printf(child, "error reading HW ioctl register: %d\n",
284                     error);
285                 return (true);
286         }
287
288         if (!(ioctl & BHND_IOCTL_CLK_EN))
289                 return (true);
290
291         return (false);
292 }
293
294 static int
295 bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl)
296 {
297         struct bcma_devinfo             *dinfo;
298         struct bhnd_core_pmu_info       *pm;
299         struct bhnd_resource            *r;
300         int                              error;
301
302         if (device_get_parent(child) != dev)
303                 return (EINVAL);
304
305         dinfo = device_get_ivars(child);
306         pm = dinfo->pmu_info;
307
308         /* We require exclusive control over BHND_IOCTL_CLK_EN and
309          * BHND_IOCTL_CLK_FORCE. */
310         if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE))
311                 return (EINVAL);
312
313         /* Can't suspend the core without access to the agent registers */
314         if ((r = dinfo->res_agent) == NULL)
315                 return (ENODEV);
316
317         /* Place core into known RESET state */
318         if ((error = BHND_BUS_SUSPEND_HW(dev, child)))
319                 return (error);
320
321         /*
322          * Leaving the core in reset:
323          * - Set the caller's IOCTL flags
324          * - Enable clocks
325          * - Force clock distribution to ensure propagation throughout the
326          *   core.
327          */
328         error = bhnd_write_ioctl(child, 
329             ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE, UINT16_MAX);
330         if (error)
331                 return (error);
332
333         /* Bring the core out of reset */
334         if ((error = bcma_dmp_write_reset(child, dinfo, 0x0)))
335                 return (error);
336
337         /* Disable forced clock gating (leaving clock enabled) */
338         error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE);
339         if (error)
340                 return (error);
341
342         return (0);
343 }
344
345 static int
346 bcma_suspend_hw(device_t dev, device_t child)
347 {
348         struct bcma_devinfo             *dinfo;
349         struct bhnd_core_pmu_info       *pm;
350         struct bhnd_resource            *r;
351         uint32_t                         rst;
352         int                              error;
353
354         if (device_get_parent(child) != dev)
355                 return (EINVAL);
356
357         dinfo = device_get_ivars(child);
358         pm = dinfo->pmu_info;
359
360         /* Can't suspend the core without access to the agent registers */
361         if ((r = dinfo->res_agent) == NULL)
362                 return (ENODEV);
363
364         /* Wait for any pending reset operations to clear */
365         if ((error = bcma_dmp_wait_reset(child, dinfo)))
366                 return (error);
367
368         /* Already in reset? */
369         rst = bhnd_bus_read_4(r, BCMA_DMP_RESETCTRL);
370         if (rst & BMCA_DMP_RC_RESET)
371                 return (0);
372
373         /* Put core into reset */
374         if ((error = bcma_dmp_write_reset(child, dinfo, BMCA_DMP_RC_RESET)))
375                 return (error);
376
377         /* Clear core flags */
378         if ((error = bhnd_write_ioctl(child, 0x0, UINT16_MAX)))
379                 return (error);
380
381         /* Inform PMU that all outstanding request state should be discarded */
382         if (pm != NULL) {
383                 if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
384                         return (error);
385         }
386
387         return (0);
388 }
389
390 static int
391 bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
392     u_int width)
393 {
394         struct bcma_devinfo     *dinfo;
395         struct bhnd_resource    *r;
396
397         /* Must be a directly attached child core */
398         if (device_get_parent(child) != dev)
399                 return (EINVAL);
400
401         /* Fetch the agent registers */
402         dinfo = device_get_ivars(child);
403         if ((r = dinfo->res_agent) == NULL)
404                 return (ENODEV);
405
406         /* Verify bounds */
407         if (offset > rman_get_size(r->res))
408                 return (EFAULT);
409
410         if (rman_get_size(r->res) - offset < width)
411                 return (EFAULT);
412
413         switch (width) {
414         case 1:
415                 *((uint8_t *)value) = bhnd_bus_read_1(r, offset);
416                 return (0);
417         case 2:
418                 *((uint16_t *)value) = bhnd_bus_read_2(r, offset);
419                 return (0);
420         case 4:
421                 *((uint32_t *)value) = bhnd_bus_read_4(r, offset);
422                 return (0);
423         default:
424                 return (EINVAL);
425         }
426 }
427
428 static int
429 bcma_write_config(device_t dev, device_t child, bus_size_t offset,
430     const void *value, u_int width)
431 {
432         struct bcma_devinfo     *dinfo;
433         struct bhnd_resource    *r;
434
435         /* Must be a directly attached child core */
436         if (device_get_parent(child) != dev)
437                 return (EINVAL);
438
439         /* Fetch the agent registers */
440         dinfo = device_get_ivars(child);
441         if ((r = dinfo->res_agent) == NULL)
442                 return (ENODEV);
443
444         /* Verify bounds */
445         if (offset > rman_get_size(r->res))
446                 return (EFAULT);
447
448         if (rman_get_size(r->res) - offset < width)
449                 return (EFAULT);
450
451         switch (width) {
452         case 1:
453                 bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
454                 return (0);
455         case 2:
456                 bhnd_bus_write_2(r, offset, *(const uint16_t *)value);
457                 return (0);
458         case 4:
459                 bhnd_bus_write_4(r, offset, *(const uint32_t *)value);
460                 return (0);
461         default:
462                 return (EINVAL);
463         }
464 }
465
466 static u_int
467 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
468 {
469         struct bcma_devinfo *dinfo;
470
471         /* delegate non-bus-attached devices to our parent */
472         if (device_get_parent(child) != dev)
473                 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
474                     type));
475
476         dinfo = device_get_ivars(child);
477         switch (type) {
478         case BHND_PORT_DEVICE:
479                 return (dinfo->corecfg->num_dev_ports);
480         case BHND_PORT_BRIDGE:
481                 return (dinfo->corecfg->num_bridge_ports);
482         case BHND_PORT_AGENT:
483                 return (dinfo->corecfg->num_wrapper_ports);
484         default:
485                 device_printf(dev, "%s: unknown type (%d)\n",
486                     __func__,
487                     type);
488                 return (0);
489         }
490 }
491
492 static u_int
493 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
494     u_int port_num)
495 {
496         struct bcma_devinfo     *dinfo;
497         struct bcma_sport_list  *ports;
498         struct bcma_sport       *port;
499
500         /* delegate non-bus-attached devices to our parent */
501         if (device_get_parent(child) != dev)
502                 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
503                     type, port_num));
504
505         dinfo = device_get_ivars(child);
506         ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
507         
508         STAILQ_FOREACH(port, ports, sp_link) {
509                 if (port->sp_num == port_num)
510                         return (port->sp_num_maps);
511         }
512
513         /* not found */
514         return (0);
515 }
516
517 static int
518 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
519     u_int port_num, u_int region_num)
520 {
521         struct bcma_devinfo     *dinfo;
522         struct bcma_map         *map;
523         struct bcma_sport_list  *ports;
524         struct bcma_sport       *port;
525         
526         dinfo = device_get_ivars(child);
527         ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
528
529         STAILQ_FOREACH(port, ports, sp_link) {
530                 if (port->sp_num != port_num)
531                         continue;
532
533                 STAILQ_FOREACH(map, &port->sp_maps, m_link)
534                         if (map->m_region_num == region_num)
535                                 return map->m_rid;
536         }
537
538         return -1;
539 }
540
541 static int
542 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
543     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
544 {
545         struct bcma_devinfo     *dinfo;
546         struct bcma_map         *map;
547         struct bcma_sport_list  *ports;
548         struct bcma_sport       *port;
549
550         dinfo = device_get_ivars(child);
551
552         /* Ports are always memory mapped */
553         if (type != SYS_RES_MEMORY)
554                 return (EINVAL);
555
556         /* Starting with the most likely device list, search all three port
557          * lists */
558         bhnd_port_type types[] = {
559             BHND_PORT_DEVICE, 
560             BHND_PORT_AGENT,
561             BHND_PORT_BRIDGE
562         };
563
564         for (int i = 0; i < nitems(types); i++) {
565                 ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
566
567                 STAILQ_FOREACH(port, ports, sp_link) {
568                         STAILQ_FOREACH(map, &port->sp_maps, m_link) {
569                                 if (map->m_rid != rid)
570                                         continue;
571
572                                 *port_type = port->sp_type;
573                                 *port_num = port->sp_num;
574                                 *region_num = map->m_region_num;
575                                 return (0);
576                         }
577                 }
578         }
579
580         return (ENOENT);
581 }
582
583 static int
584 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
585     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
586 {
587         struct bcma_devinfo     *dinfo;
588         struct bcma_map         *map;
589         struct bcma_sport_list  *ports;
590         struct bcma_sport       *port;
591         
592         dinfo = device_get_ivars(child);
593         ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
594
595         /* Search the port list */
596         STAILQ_FOREACH(port, ports, sp_link) {
597                 if (port->sp_num != port_num)
598                         continue;
599
600                 STAILQ_FOREACH(map, &port->sp_maps, m_link) {
601                         if (map->m_region_num != region_num)
602                                 continue;
603
604                         /* Found! */
605                         *addr = map->m_base;
606                         *size = map->m_size;
607                         return (0);
608                 }
609         }
610
611         return (ENOENT);
612 }
613
614 /**
615  * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
616  * 
617  * This implementation consults @p child's agent register block,
618  * returning the number of interrupt output lines routed to @p child.
619  */
620 int
621 bcma_get_intr_count(device_t dev, device_t child)
622 {
623         struct bcma_devinfo     *dinfo;
624         uint32_t                 dmpcfg, oobw;
625
626         dinfo = device_get_ivars(child);
627
628         /* Agent block must be mapped */
629         if (dinfo->res_agent == NULL)
630                 return (0);
631
632         /* Agent must support OOB */
633         dmpcfg = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_CONFIG);
634         if (!BCMA_DMP_GET_FLAG(dmpcfg, BCMA_DMP_CFG_OOB))
635                 return (0);
636
637         /* Return OOB width as interrupt count */
638         oobw = bhnd_bus_read_4(dinfo->res_agent,
639             BCMA_DMP_OOB_OUTWIDTH(BCMA_OOB_BANK_INTR));
640         if (oobw > BCMA_OOB_NUM_SEL) {
641                 device_printf(dev, "ignoring invalid OOBOUTWIDTH for core %u: "
642                     "%#x\n", BCMA_DINFO_COREIDX(dinfo), oobw);
643                 return (0);
644         }
645         
646         return (oobw);
647 }
648
649 /**
650  * Default bcma(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
651  * 
652  * This implementation consults @p child's agent register block,
653  * returning the interrupt output line routed to @p child, at OOB selector
654  * @p intr.
655  */
656 int
657 bcma_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
658 {
659         struct bcma_devinfo     *dinfo;
660         uint32_t                 oobsel;
661
662         dinfo = device_get_ivars(child);
663
664         /* Interrupt ID must be valid. */
665         if (intr >= bcma_get_intr_count(dev, child))
666                 return (ENXIO);
667
668         /* Fetch OOBSEL busline value */
669         KASSERT(dinfo->res_agent != NULL, ("missing agent registers"));
670         oobsel = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_OOBSELOUT(
671             BCMA_OOB_BANK_INTR, intr));
672         *ivec = (oobsel >> BCMA_DMP_OOBSEL_SHIFT(intr)) &
673             BCMA_DMP_OOBSEL_BUSLINE_MASK;
674
675         return (0);
676 }
677
678 /**
679  * Scan the device enumeration ROM table, adding all valid discovered cores to
680  * the bus.
681  * 
682  * @param bus The bcma bus.
683  */
684 int
685 bcma_add_children(device_t bus)
686 {
687         bhnd_erom_t                     *erom;
688         struct bcma_erom                *bcma_erom;
689         const struct bhnd_chipid        *cid;
690         struct bcma_corecfg             *corecfg;
691         struct bcma_devinfo             *dinfo;
692         device_t                         child;
693         int                              error;
694
695         cid = BHND_BUS_GET_CHIPID(bus, bus);
696         corecfg = NULL;
697
698         /* Allocate our EROM parser */
699         erom = bhnd_erom_alloc(&bcma_erom_parser, cid, bus, BCMA_EROM_RID);
700         if (erom == NULL)
701                 return (ENODEV);
702
703         /* Add all cores. */
704         bcma_erom = (struct bcma_erom *)erom;
705         while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
706                 int nintr;
707
708                 /* Add the child device */
709                 child = BUS_ADD_CHILD(bus, 0, NULL, -1);
710                 if (child == NULL) {
711                         error = ENXIO;
712                         goto cleanup;
713                 }
714
715                 /* Initialize device ivars */
716                 dinfo = device_get_ivars(child);
717                 if ((error = bcma_init_dinfo(bus, dinfo, corecfg)))
718                         goto cleanup;
719
720                 /* The dinfo instance now owns the corecfg value */
721                 corecfg = NULL;
722
723                 /* Allocate device's agent registers, if any */
724                 if ((error = bcma_dinfo_alloc_agent(bus, child, dinfo)))
725                         goto cleanup;
726
727                 /* Assign interrupts */
728                 nintr = bhnd_get_intr_count(child);
729                 for (int rid = 0; rid < nintr; rid++) {
730                         error = BHND_BUS_ASSIGN_INTR(bus, child, rid);
731                         if (error) {
732                                 device_printf(bus, "failed to assign interrupt "
733                                     "%d to core %u: %d\n", rid,
734                                     BCMA_DINFO_COREIDX(dinfo), error);
735                         }
736                 }
737
738                 /* If pins are floating or the hardware is otherwise
739                  * unpopulated, the device shouldn't be used. */
740                 if (bhnd_is_hw_disabled(child))
741                         device_disable(child);
742
743                 /* Issue bus callback for fully initialized child. */
744                 BHND_BUS_CHILD_ADDED(bus, child);
745         }
746
747         /* EOF while parsing cores is expected */
748         if (error == ENOENT)
749                 error = 0;
750         
751 cleanup:
752         bhnd_erom_free(erom);
753
754         if (corecfg != NULL)
755                 bcma_free_corecfg(corecfg);
756
757         if (error)
758                 device_delete_children(bus);
759
760         return (error);
761 }
762
763
764 static device_method_t bcma_methods[] = {
765         /* Device interface */
766         DEVMETHOD(device_probe,                 bcma_probe),
767         DEVMETHOD(device_attach,                bcma_attach),
768         DEVMETHOD(device_detach,                bcma_detach),
769         
770         /* Bus interface */
771         DEVMETHOD(bus_add_child,                bcma_add_child),
772         DEVMETHOD(bus_child_deleted,            bcma_child_deleted),
773         DEVMETHOD(bus_read_ivar,                bcma_read_ivar),
774         DEVMETHOD(bus_write_ivar,               bcma_write_ivar),
775         DEVMETHOD(bus_get_resource_list,        bcma_get_resource_list),
776
777         /* BHND interface */
778         DEVMETHOD(bhnd_bus_get_erom_class,      bcma_get_erom_class),
779         DEVMETHOD(bhnd_bus_read_ioctl,          bcma_read_ioctl),
780         DEVMETHOD(bhnd_bus_write_ioctl,         bcma_write_ioctl),
781         DEVMETHOD(bhnd_bus_read_iost,           bcma_read_iost),
782         DEVMETHOD(bhnd_bus_is_hw_suspended,     bcma_is_hw_suspended),
783         DEVMETHOD(bhnd_bus_reset_hw,            bcma_reset_hw),
784         DEVMETHOD(bhnd_bus_suspend_hw,          bcma_suspend_hw),
785         DEVMETHOD(bhnd_bus_read_config,         bcma_read_config),
786         DEVMETHOD(bhnd_bus_write_config,        bcma_write_config),
787         DEVMETHOD(bhnd_bus_get_port_count,      bcma_get_port_count),
788         DEVMETHOD(bhnd_bus_get_region_count,    bcma_get_region_count),
789         DEVMETHOD(bhnd_bus_get_port_rid,        bcma_get_port_rid),
790         DEVMETHOD(bhnd_bus_decode_port_rid,     bcma_decode_port_rid),
791         DEVMETHOD(bhnd_bus_get_region_addr,     bcma_get_region_addr),
792         DEVMETHOD(bhnd_bus_get_intr_count,      bcma_get_intr_count),
793         DEVMETHOD(bhnd_bus_get_core_ivec,       bcma_get_core_ivec),
794
795         DEVMETHOD_END
796 };
797
798 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
799 MODULE_VERSION(bcma, 1);
800 MODULE_DEPEND(bcma, bhnd, 1, 1, 1);