xref: /freebsd/sys/dev/bhnd/bcma/bcma.c (revision 9768746b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
5  * Copyright (c) 2017 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * Portions of this software were developed by Landon Fuller
9  * under sponsorship from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19  *    redistribution must be conditioned upon including a substantially
20  *    similar Disclaimer requirement for further binary redistribution.
21  *
22  * NO WARRANTY
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGES.
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/systm.h>
45 
46 #include <machine/bus.h>
47 
48 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
49 
50 #include "bcma_dmp.h"
51 
52 #include "bcma_eromreg.h"
53 #include "bcma_eromvar.h"
54 
55 #include "bcmavar.h"
56 
57 /* RID used when allocating EROM table */
58 #define	BCMA_EROM_RID	0
59 
60 static bhnd_erom_class_t *
61 bcma_get_erom_class(driver_t *driver)
62 {
63 	return (&bcma_erom_parser);
64 }
65 
66 int
67 bcma_probe(device_t dev)
68 {
69 	device_set_desc(dev, "BCMA BHND bus");
70 	return (BUS_PROBE_DEFAULT);
71 }
72 
73 /**
74  * Default bcma(4) bus driver implementation of DEVICE_ATTACH().
75  *
76  * This implementation initializes internal bcma(4) state and performs
77  * bus enumeration, and must be called by subclassing drivers in
78  * DEVICE_ATTACH() before any other bus methods.
79  */
80 int
81 bcma_attach(device_t dev)
82 {
83 	int error;
84 
85 	/* Enumerate children */
86 	if ((error = bcma_add_children(dev))) {
87 		device_delete_children(dev);
88 		return (error);
89 	}
90 
91 	return (0);
92 }
93 
94 int
95 bcma_detach(device_t dev)
96 {
97 	return (bhnd_generic_detach(dev));
98 }
99 
100 static device_t
101 bcma_add_child(device_t dev, u_int order, const char *name, int unit)
102 {
103 	struct bcma_devinfo	*dinfo;
104 	device_t		 child;
105 
106 	child = device_add_child_ordered(dev, order, name, unit);
107 	if (child == NULL)
108 		return (NULL);
109 
110 	if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) {
111 		device_delete_child(dev, child);
112 		return (NULL);
113 	}
114 
115 	device_set_ivars(child, dinfo);
116 
117 	return (child);
118 }
119 
120 static void
121 bcma_child_deleted(device_t dev, device_t child)
122 {
123 	struct bcma_devinfo	*dinfo;
124 
125 	/* Call required bhnd(4) implementation */
126 	bhnd_generic_child_deleted(dev, child);
127 
128 	/* Free bcma device info */
129 	if ((dinfo = device_get_ivars(child)) != NULL)
130 		bcma_free_dinfo(dev, child, dinfo);
131 
132 	device_set_ivars(child, NULL);
133 }
134 
135 static int
136 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
137 {
138 	const struct bcma_devinfo *dinfo;
139 	const struct bhnd_core_info *ci;
140 
141 	dinfo = device_get_ivars(child);
142 	ci = &dinfo->corecfg->core_info;
143 
144 	switch (index) {
145 	case BHND_IVAR_VENDOR:
146 		*result = ci->vendor;
147 		return (0);
148 	case BHND_IVAR_DEVICE:
149 		*result = ci->device;
150 		return (0);
151 	case BHND_IVAR_HWREV:
152 		*result = ci->hwrev;
153 		return (0);
154 	case BHND_IVAR_DEVICE_CLASS:
155 		*result = bhnd_core_class(ci);
156 		return (0);
157 	case BHND_IVAR_VENDOR_NAME:
158 		*result = (uintptr_t) bhnd_vendor_name(ci->vendor);
159 		return (0);
160 	case BHND_IVAR_DEVICE_NAME:
161 		*result = (uintptr_t) bhnd_core_name(ci);
162 		return (0);
163 	case BHND_IVAR_CORE_INDEX:
164 		*result = ci->core_idx;
165 		return (0);
166 	case BHND_IVAR_CORE_UNIT:
167 		*result = ci->unit;
168 		return (0);
169 	case BHND_IVAR_PMU_INFO:
170 		*result = (uintptr_t) dinfo->pmu_info;
171 		return (0);
172 	default:
173 		return (ENOENT);
174 	}
175 }
176 
177 static int
178 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
179 {
180 	struct bcma_devinfo *dinfo;
181 
182 	dinfo = device_get_ivars(child);
183 
184 	switch (index) {
185 	case BHND_IVAR_VENDOR:
186 	case BHND_IVAR_DEVICE:
187 	case BHND_IVAR_HWREV:
188 	case BHND_IVAR_DEVICE_CLASS:
189 	case BHND_IVAR_VENDOR_NAME:
190 	case BHND_IVAR_DEVICE_NAME:
191 	case BHND_IVAR_CORE_INDEX:
192 	case BHND_IVAR_CORE_UNIT:
193 		return (EINVAL);
194 	case BHND_IVAR_PMU_INFO:
195 		dinfo->pmu_info = (void *)value;
196 		return (0);
197 	default:
198 		return (ENOENT);
199 	}
200 }
201 
202 static struct resource_list *
203 bcma_get_resource_list(device_t dev, device_t child)
204 {
205 	struct bcma_devinfo *dinfo = device_get_ivars(child);
206 	return (&dinfo->resources);
207 }
208 
209 static int
210 bcma_read_iost(device_t dev, device_t child, uint16_t *iost)
211 {
212 	uint32_t	value;
213 	int		error;
214 
215 	if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4)))
216 		return (error);
217 
218 	/* Return only the bottom 16 bits */
219 	*iost = (value & BCMA_DMP_IOST_MASK);
220 	return (0);
221 }
222 
223 static int
224 bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
225 {
226 	uint32_t	value;
227 	int		error;
228 
229 	if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4)))
230 		return (error);
231 
232 	/* Return only the bottom 16 bits */
233 	*ioctl = (value & BCMA_DMP_IOCTRL_MASK);
234 	return (0);
235 }
236 
237 static int
238 bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
239 {
240 	struct bcma_devinfo	*dinfo;
241 	struct bhnd_resource	*r;
242 	uint32_t		 ioctl;
243 
244 	if (device_get_parent(child) != dev)
245 		return (EINVAL);
246 
247 	dinfo = device_get_ivars(child);
248 	if ((r = dinfo->res_agent) == NULL)
249 		return (ENODEV);
250 
251 	/* Write new value */
252 	ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
253 	ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask);
254 	ioctl |= (value & mask);
255 
256 	bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl);
257 
258 	/* Perform read-back and wait for completion */
259 	bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
260 	DELAY(10);
261 
262 	return (0);
263 }
264 
265 static bool
266 bcma_is_hw_suspended(device_t dev, device_t child)
267 {
268 	uint32_t	rst;
269 	uint16_t	ioctl;
270 	int		error;
271 
272 	/* Is core held in RESET? */
273 	error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4);
274 	if (error) {
275 		device_printf(child, "error reading HW reset state: %d\n",
276 		    error);
277 		return (true);
278 	}
279 
280 	if (rst & BCMA_DMP_RC_RESET)
281 		return (true);
282 
283 	/* Is core clocked? */
284 	error = bhnd_read_ioctl(child, &ioctl);
285 	if (error) {
286 		device_printf(child, "error reading HW ioctl register: %d\n",
287 		    error);
288 		return (true);
289 	}
290 
291 	if (!(ioctl & BHND_IOCTL_CLK_EN))
292 		return (true);
293 
294 	return (false);
295 }
296 
297 static int
298 bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl,
299     uint16_t reset_ioctl)
300 {
301 	struct bcma_devinfo	*dinfo;
302 	struct bhnd_resource	*r;
303 	uint16_t		 clkflags;
304 	int			 error;
305 
306 	if (device_get_parent(child) != dev)
307 		return (EINVAL);
308 
309 	dinfo = device_get_ivars(child);
310 
311 	/* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
312 	clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
313 	if (ioctl & clkflags)
314 		return (EINVAL);
315 
316 	/* Can't suspend the core without access to the agent registers */
317 	if ((r = dinfo->res_agent) == NULL)
318 		return (ENODEV);
319 
320 	/* Place core into known RESET state */
321 	if ((error = bhnd_suspend_hw(child, reset_ioctl)))
322 		return (error);
323 
324 	/*
325 	 * Leaving the core in reset:
326 	 * - Set the caller's IOCTL flags
327 	 * - Enable clocks
328 	 * - Force clock distribution to ensure propagation throughout the
329 	 *   core.
330 	 */
331 	if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX)))
332 		return (error);
333 
334 	/* Bring the core out of reset */
335 	if ((error = bcma_dmp_write_reset(child, dinfo, 0x0)))
336 		return (error);
337 
338 	/* Disable forced clock gating (leaving clock enabled) */
339 	error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE);
340 	if (error)
341 		return (error);
342 
343 	return (0);
344 }
345 
346 static int
347 bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl)
348 {
349 	struct bcma_devinfo	*dinfo;
350 	struct bhnd_resource	*r;
351 	uint16_t		 clkflags;
352 	int			 error;
353 
354 	if (device_get_parent(child) != dev)
355 		return (EINVAL);
356 
357 	dinfo = device_get_ivars(child);
358 
359 	/* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
360 	clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
361 	if (ioctl & clkflags)
362 		return (EINVAL);
363 
364 	/* Can't suspend the core without access to the agent registers */
365 	if ((r = dinfo->res_agent) == NULL)
366 		return (ENODEV);
367 
368 	/* Wait for any pending reset operations to clear */
369 	if ((error = bcma_dmp_wait_reset(child, dinfo)))
370 		return (error);
371 
372 	/* Put core into reset (if not already in reset) */
373 	if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET)))
374 		return (error);
375 
376 	/* Write core flags (and clear CLK_EN/CLK_FORCE) */
377 	if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags)))
378 		return (error);
379 
380 	return (0);
381 }
382 
383 static int
384 bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
385     u_int width)
386 {
387 	struct bcma_devinfo	*dinfo;
388 	struct bhnd_resource	*r;
389 
390 	/* Must be a directly attached child core */
391 	if (device_get_parent(child) != dev)
392 		return (EINVAL);
393 
394 	/* Fetch the agent registers */
395 	dinfo = device_get_ivars(child);
396 	if ((r = dinfo->res_agent) == NULL)
397 		return (ENODEV);
398 
399 	/* Verify bounds */
400 	if (offset > rman_get_size(r->res))
401 		return (EFAULT);
402 
403 	if (rman_get_size(r->res) - offset < width)
404 		return (EFAULT);
405 
406 	switch (width) {
407 	case 1:
408 		*((uint8_t *)value) = bhnd_bus_read_1(r, offset);
409 		return (0);
410 	case 2:
411 		*((uint16_t *)value) = bhnd_bus_read_2(r, offset);
412 		return (0);
413 	case 4:
414 		*((uint32_t *)value) = bhnd_bus_read_4(r, offset);
415 		return (0);
416 	default:
417 		return (EINVAL);
418 	}
419 }
420 
421 static int
422 bcma_write_config(device_t dev, device_t child, bus_size_t offset,
423     const void *value, u_int width)
424 {
425 	struct bcma_devinfo	*dinfo;
426 	struct bhnd_resource	*r;
427 
428 	/* Must be a directly attached child core */
429 	if (device_get_parent(child) != dev)
430 		return (EINVAL);
431 
432 	/* Fetch the agent registers */
433 	dinfo = device_get_ivars(child);
434 	if ((r = dinfo->res_agent) == NULL)
435 		return (ENODEV);
436 
437 	/* Verify bounds */
438 	if (offset > rman_get_size(r->res))
439 		return (EFAULT);
440 
441 	if (rman_get_size(r->res) - offset < width)
442 		return (EFAULT);
443 
444 	switch (width) {
445 	case 1:
446 		bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
447 		return (0);
448 	case 2:
449 		bhnd_bus_write_2(r, offset, *(const uint16_t *)value);
450 		return (0);
451 	case 4:
452 		bhnd_bus_write_4(r, offset, *(const uint32_t *)value);
453 		return (0);
454 	default:
455 		return (EINVAL);
456 	}
457 }
458 
459 static u_int
460 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
461 {
462 	struct bcma_devinfo *dinfo;
463 
464 	/* delegate non-bus-attached devices to our parent */
465 	if (device_get_parent(child) != dev)
466 		return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
467 		    type));
468 
469 	dinfo = device_get_ivars(child);
470 	switch (type) {
471 	case BHND_PORT_DEVICE:
472 		return (dinfo->corecfg->num_dev_ports);
473 	case BHND_PORT_BRIDGE:
474 		return (dinfo->corecfg->num_bridge_ports);
475 	case BHND_PORT_AGENT:
476 		return (dinfo->corecfg->num_wrapper_ports);
477 	default:
478 		device_printf(dev, "%s: unknown type (%d)\n",
479 		    __func__,
480 		    type);
481 		return (0);
482 	}
483 }
484 
485 static u_int
486 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
487     u_int port_num)
488 {
489 	struct bcma_devinfo	*dinfo;
490 	struct bcma_sport_list	*ports;
491 	struct bcma_sport	*port;
492 
493 	/* delegate non-bus-attached devices to our parent */
494 	if (device_get_parent(child) != dev)
495 		return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
496 		    type, port_num));
497 
498 	dinfo = device_get_ivars(child);
499 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
500 
501 	STAILQ_FOREACH(port, ports, sp_link) {
502 		if (port->sp_num == port_num)
503 			return (port->sp_num_maps);
504 	}
505 
506 	/* not found */
507 	return (0);
508 }
509 
510 static int
511 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
512     u_int port_num, u_int region_num)
513 {
514 	struct bcma_devinfo	*dinfo;
515 	struct bcma_map		*map;
516 	struct bcma_sport_list	*ports;
517 	struct bcma_sport	*port;
518 
519 	dinfo = device_get_ivars(child);
520 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
521 
522 	STAILQ_FOREACH(port, ports, sp_link) {
523 		if (port->sp_num != port_num)
524 			continue;
525 
526 		STAILQ_FOREACH(map, &port->sp_maps, m_link)
527 			if (map->m_region_num == region_num)
528 				return map->m_rid;
529 	}
530 
531 	return -1;
532 }
533 
534 static int
535 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
536     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
537 {
538 	struct bcma_devinfo	*dinfo;
539 	struct bcma_map		*map;
540 	struct bcma_sport_list	*ports;
541 	struct bcma_sport	*port;
542 
543 	dinfo = device_get_ivars(child);
544 
545 	/* Ports are always memory mapped */
546 	if (type != SYS_RES_MEMORY)
547 		return (EINVAL);
548 
549 	/* Starting with the most likely device list, search all three port
550 	 * lists */
551 	bhnd_port_type types[] = {
552 	    BHND_PORT_DEVICE,
553 	    BHND_PORT_AGENT,
554 	    BHND_PORT_BRIDGE
555 	};
556 
557 	for (int i = 0; i < nitems(types); i++) {
558 		ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
559 
560 		STAILQ_FOREACH(port, ports, sp_link) {
561 			STAILQ_FOREACH(map, &port->sp_maps, m_link) {
562 				if (map->m_rid != rid)
563 					continue;
564 
565 				*port_type = port->sp_type;
566 				*port_num = port->sp_num;
567 				*region_num = map->m_region_num;
568 				return (0);
569 			}
570 		}
571 	}
572 
573 	return (ENOENT);
574 }
575 
576 static int
577 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
578     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
579 {
580 	struct bcma_devinfo	*dinfo;
581 	struct bcma_map		*map;
582 	struct bcma_sport_list	*ports;
583 	struct bcma_sport	*port;
584 
585 	dinfo = device_get_ivars(child);
586 	ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
587 
588 	/* Search the port list */
589 	STAILQ_FOREACH(port, ports, sp_link) {
590 		if (port->sp_num != port_num)
591 			continue;
592 
593 		STAILQ_FOREACH(map, &port->sp_maps, m_link) {
594 			if (map->m_region_num != region_num)
595 				continue;
596 
597 			/* Found! */
598 			*addr = map->m_base;
599 			*size = map->m_size;
600 			return (0);
601 		}
602 	}
603 
604 	return (ENOENT);
605 }
606 
607 /**
608  * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
609  */
610 u_int
611 bcma_get_intr_count(device_t dev, device_t child)
612 {
613 	struct bcma_devinfo *dinfo;
614 
615 	/* delegate non-bus-attached devices to our parent */
616 	if (device_get_parent(child) != dev)
617 		return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
618 
619 	dinfo = device_get_ivars(child);
620 	return (dinfo->num_intrs);
621 }
622 
623 /**
624  * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
625  */
626 int
627 bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
628 {
629 	struct bcma_devinfo	*dinfo;
630 	struct bcma_intr	*desc;
631 
632 	/* delegate non-bus-attached devices to our parent */
633 	if (device_get_parent(child) != dev) {
634 		return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
635 		    intr, ivec));
636 	}
637 
638 	dinfo = device_get_ivars(child);
639 
640 	STAILQ_FOREACH(desc, &dinfo->intrs, i_link) {
641 		if (desc->i_sel == intr) {
642 			*ivec = desc->i_busline;
643 			return (0);
644 		}
645 	}
646 
647 	/* Not found */
648 	return (ENXIO);
649 }
650 
651 /**
652  * Scan the device enumeration ROM table, adding all valid discovered cores to
653  * the bus.
654  *
655  * @param bus The bcma bus.
656  */
657 int
658 bcma_add_children(device_t bus)
659 {
660 	bhnd_erom_t			*erom;
661 	struct bcma_erom		*bcma_erom;
662 	struct bhnd_erom_io		*eio;
663 	const struct bhnd_chipid	*cid;
664 	struct bcma_corecfg		*corecfg;
665 	struct bcma_devinfo		*dinfo;
666 	device_t			 child;
667 	int				 error;
668 
669 	cid = BHND_BUS_GET_CHIPID(bus, bus);
670 	corecfg = NULL;
671 
672 	/* Allocate our EROM parser */
673 	eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID);
674 	erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio);
675 	if (erom == NULL) {
676 		bhnd_erom_io_fini(eio);
677 		return (ENODEV);
678 	}
679 
680 	/* Add all cores. */
681 	bcma_erom = (struct bcma_erom *)erom;
682 	while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
683 		/* Add the child device */
684 		child = BUS_ADD_CHILD(bus, 0, NULL, -1);
685 		if (child == NULL) {
686 			error = ENXIO;
687 			goto cleanup;
688 		}
689 
690 		/* Initialize device ivars */
691 		dinfo = device_get_ivars(child);
692 		if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg)))
693 			goto cleanup;
694 
695 		/* The dinfo instance now owns the corecfg value */
696 		corecfg = NULL;
697 
698 		/* If pins are floating or the hardware is otherwise
699 		 * unpopulated, the device shouldn't be used. */
700 		if (bhnd_is_hw_disabled(child))
701 			device_disable(child);
702 
703 		/* Issue bus callback for fully initialized child. */
704 		BHND_BUS_CHILD_ADDED(bus, child);
705 	}
706 
707 	/* EOF while parsing cores is expected */
708 	if (error == ENOENT)
709 		error = 0;
710 
711 cleanup:
712 	bhnd_erom_free(erom);
713 
714 	if (corecfg != NULL)
715 		bcma_free_corecfg(corecfg);
716 
717 	if (error)
718 		device_delete_children(bus);
719 
720 	return (error);
721 }
722 
723 static device_method_t bcma_methods[] = {
724 	/* Device interface */
725 	DEVMETHOD(device_probe,			bcma_probe),
726 	DEVMETHOD(device_attach,		bcma_attach),
727 	DEVMETHOD(device_detach,		bcma_detach),
728 
729 	/* Bus interface */
730 	DEVMETHOD(bus_add_child,		bcma_add_child),
731 	DEVMETHOD(bus_child_deleted,		bcma_child_deleted),
732 	DEVMETHOD(bus_read_ivar,		bcma_read_ivar),
733 	DEVMETHOD(bus_write_ivar,		bcma_write_ivar),
734 	DEVMETHOD(bus_get_resource_list,	bcma_get_resource_list),
735 
736 	/* BHND interface */
737 	DEVMETHOD(bhnd_bus_get_erom_class,	bcma_get_erom_class),
738 	DEVMETHOD(bhnd_bus_read_ioctl,		bcma_read_ioctl),
739 	DEVMETHOD(bhnd_bus_write_ioctl,		bcma_write_ioctl),
740 	DEVMETHOD(bhnd_bus_read_iost,		bcma_read_iost),
741 	DEVMETHOD(bhnd_bus_is_hw_suspended,	bcma_is_hw_suspended),
742 	DEVMETHOD(bhnd_bus_reset_hw,		bcma_reset_hw),
743 	DEVMETHOD(bhnd_bus_suspend_hw,		bcma_suspend_hw),
744 	DEVMETHOD(bhnd_bus_read_config,		bcma_read_config),
745 	DEVMETHOD(bhnd_bus_write_config,	bcma_write_config),
746 	DEVMETHOD(bhnd_bus_get_port_count,	bcma_get_port_count),
747 	DEVMETHOD(bhnd_bus_get_region_count,	bcma_get_region_count),
748 	DEVMETHOD(bhnd_bus_get_port_rid,	bcma_get_port_rid),
749 	DEVMETHOD(bhnd_bus_decode_port_rid,	bcma_decode_port_rid),
750 	DEVMETHOD(bhnd_bus_get_region_addr,	bcma_get_region_addr),
751 	DEVMETHOD(bhnd_bus_get_intr_count,	bcma_get_intr_count),
752 	DEVMETHOD(bhnd_bus_get_intr_ivec,	bcma_get_intr_ivec),
753 
754 	DEVMETHOD_END
755 };
756 
757 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
758 MODULE_VERSION(bcma, 1);
759 MODULE_DEPEND(bcma, bhnd, 1, 1, 1);
760