1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2015-2016 Landon Fuller <[email protected]>
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 *
bcma_get_erom_class(driver_t * driver)59 bcma_get_erom_class(driver_t *driver)
60 {
61 return (&bcma_erom_parser);
62 }
63
64 int
bcma_probe(device_t dev)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
bcma_attach(device_t dev)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
bcma_detach(device_t dev)93 bcma_detach(device_t dev)
94 {
95 return (bhnd_generic_detach(dev));
96 }
97
98 static device_t
bcma_add_child(device_t dev,u_int order,const char * name,int unit)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
bcma_child_deleted(device_t dev,device_t child)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
bcma_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)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
bcma_write_ivar(device_t dev,device_t child,int index,uintptr_t value)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 *
bcma_get_resource_list(device_t dev,device_t child)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
bcma_read_iost(device_t dev,device_t child,uint16_t * iost)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
bcma_read_ioctl(device_t dev,device_t child,uint16_t * ioctl)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
bcma_write_ioctl(device_t dev,device_t child,uint16_t value,uint16_t mask)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
bcma_is_hw_suspended(device_t dev,device_t child)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
bcma_reset_hw(device_t dev,device_t child,uint16_t ioctl,uint16_t reset_ioctl)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
bcma_suspend_hw(device_t dev,device_t child,uint16_t ioctl)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
bcma_read_config(device_t dev,device_t child,bus_size_t offset,void * value,u_int width)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
bcma_write_config(device_t dev,device_t child,bus_size_t offset,const void * value,u_int width)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
bcma_get_port_count(device_t dev,device_t child,bhnd_port_type type)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
bcma_get_region_count(device_t dev,device_t child,bhnd_port_type type,u_int port_num)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
bcma_get_port_rid(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num)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
bcma_decode_port_rid(device_t dev,device_t child,int type,int rid,bhnd_port_type * port_type,u_int * port_num,u_int * region_num)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
bcma_get_region_addr(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num,bhnd_addr_t * addr,bhnd_size_t * size)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
bcma_get_intr_count(device_t dev,device_t child)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
bcma_get_intr_ivec(device_t dev,device_t child,u_int intr,u_int * ivec)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
bcma_add_children(device_t bus)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