xref: /freebsd/sys/dev/bhnd/bcma/bcma.c (revision 5dae51da3da0cc94d17bd67b308fad304ebec7e0)
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);
801