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 *
bcma_get_erom_class(driver_t * driver)58 bcma_get_erom_class(driver_t *driver)
59 {
60 return (&bcma_erom_parser);
61 }
62
63 int
bcma_probe(device_t dev)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
bcma_attach(device_t dev)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
bcma_detach(device_t dev)91 bcma_detach(device_t dev)
92 {
93 return (bhnd_generic_detach(dev));
94 }
95
96 static device_t
bcma_add_child(device_t dev,u_int order,const char * name,int unit)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
bcma_child_deleted(device_t dev,device_t child)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
bcma_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)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
bcma_write_ivar(device_t dev,device_t child,int index,uintptr_t value)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 *
bcma_get_resource_list(device_t dev,device_t child)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
bcma_read_iost(device_t dev,device_t child,uint16_t * iost)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
bcma_read_ioctl(device_t dev,device_t child,uint16_t * ioctl)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
bcma_write_ioctl(device_t dev,device_t child,uint16_t value,uint16_t mask)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
bcma_is_hw_suspended(device_t dev,device_t child)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
bcma_reset_hw(device_t dev,device_t child,uint16_t ioctl,uint16_t reset_ioctl)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
bcma_suspend_hw(device_t dev,device_t child,uint16_t ioctl)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
bcma_read_config(device_t dev,device_t child,bus_size_t offset,void * value,u_int width)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
bcma_write_config(device_t dev,device_t child,bus_size_t offset,const void * value,u_int width)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
bcma_get_port_count(device_t dev,device_t child,bhnd_port_type type)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
bcma_get_region_count(device_t dev,device_t child,bhnd_port_type type,u_int port_num)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
bcma_get_port_rid(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num)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
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)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
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)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
bcma_get_intr_count(device_t dev,device_t child)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
bcma_get_intr_ivec(device_t dev,device_t child,u_int intr,u_int * ivec)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
bcma_add_children(device_t bus)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