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