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