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