1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.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 /*
38 * Broadcom Home Networking Division (HND) Bus Driver.
39 *
40 * The Broadcom HND family of devices consists of both SoCs and host-connected
41 * networking chipsets containing a common family of Broadcom IP cores,
42 * including an integrated MIPS and/or ARM cores.
43 *
44 * HND devices expose a nearly identical interface whether accessible over a
45 * native SoC interconnect, or when connected via a host interface such as
46 * PCIe. As a result, the majority of hardware support code should be re-usable
47 * across host drivers for HND networking chipsets, as well as FreeBSD support
48 * for Broadcom MIPS/ARM HND SoCs.
49 *
50 * Earlier HND models used the siba(4) on-chip interconnect, while later models
51 * use bcma(4); the programming model is almost entirely independent
52 * of the actual underlying interconect.
53 */
54
55 #include <sys/param.h>
56 #include <sys/kernel.h>
57 #include <sys/bus.h>
58 #include <sys/module.h>
59 #include <sys/systm.h>
60
61 #include <machine/bus.h>
62 #include <sys/rman.h>
63 #include <machine/resource.h>
64
65 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
66
67 #include "bhnd_chipc_if.h"
68 #include "bhnd_nvram_if.h"
69
70 #include "bhnd.h"
71 #include "bhndreg.h"
72 #include "bhndvar.h"
73
74 #include "bhnd_private.h"
75
76 MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures");
77
78 /**
79 * bhnd_generic_probe_nomatch() reporting configuration.
80 */
81 static const struct bhnd_nomatch {
82 uint16_t vendor; /**< core designer */
83 uint16_t device; /**< core id */
84 bool if_verbose; /**< print when bootverbose is set. */
85 } bhnd_nomatch_table[] = {
86 { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true },
87 { BHND_MFGID_ARM, BHND_COREID_EROM, true },
88 { BHND_MFGID_ARM, BHND_COREID_PL301, true },
89 { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true },
90 { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false },
91 { BHND_MFGID_INVALID, BHND_COREID_INVALID, false }
92 };
93
94 static int bhnd_delete_children(struct bhnd_softc *sc);
95
96 /**
97 * Default bhnd(4) bus driver implementation of DEVICE_ATTACH().
98 *
99 * This implementation calls device_probe_and_attach() for each of the device's
100 * children, in bhnd probe order.
101 */
102 int
bhnd_generic_attach(device_t dev)103 bhnd_generic_attach(device_t dev)
104 {
105 struct bhnd_softc *sc;
106 int error;
107
108 if (device_is_attached(dev))
109 return (EBUSY);
110
111 sc = device_get_softc(dev);
112 sc->dev = dev;
113
114 /* Probe and attach all children */
115 if ((error = bhnd_bus_probe_children(dev))) {
116 bhnd_delete_children(sc);
117 return (error);
118 }
119
120 return (0);
121 }
122
123 /**
124 * Detach and delete all children, in reverse of their attach order.
125 */
126 static int
bhnd_delete_children(struct bhnd_softc * sc)127 bhnd_delete_children(struct bhnd_softc *sc)
128 {
129 device_t *devs;
130 int ndevs;
131 int error;
132
133 /* Fetch children in detach order */
134 error = bhnd_bus_get_children(sc->dev, &devs, &ndevs,
135 BHND_DEVICE_ORDER_DETACH);
136 if (error)
137 return (error);
138
139 /* Perform detach */
140 for (int i = 0; i < ndevs; i++) {
141 device_t child = devs[i];
142
143 /* Terminate on first error */
144 if ((error = device_delete_child(sc->dev, child)))
145 goto cleanup;
146 }
147
148 cleanup:
149 bhnd_bus_free_children(devs);
150 return (error);
151 }
152
153 /**
154 * Default bhnd(4) bus driver implementation of DEVICE_DETACH().
155 *
156 * This implementation calls device_detach() for each of the device's
157 * children, in reverse bhnd probe order, terminating if any call to
158 * device_detach() fails.
159 */
160 int
bhnd_generic_detach(device_t dev)161 bhnd_generic_detach(device_t dev)
162 {
163 struct bhnd_softc *sc;
164 int error;
165
166 if (!device_is_attached(dev))
167 return (EBUSY);
168
169 sc = device_get_softc(dev);
170
171 if ((error = bhnd_delete_children(sc)))
172 return (error);
173
174 return (0);
175 }
176
177 /**
178 * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN().
179 *
180 * This implementation calls device_shutdown() for each of the device's
181 * children, in reverse bhnd probe order, terminating if any call to
182 * device_shutdown() fails.
183 */
184 int
bhnd_generic_shutdown(device_t dev)185 bhnd_generic_shutdown(device_t dev)
186 {
187 device_t *devs;
188 int ndevs;
189 int error;
190
191 if (!device_is_attached(dev))
192 return (EBUSY);
193
194 /* Fetch children in detach order */
195 error = bhnd_bus_get_children(dev, &devs, &ndevs,
196 BHND_DEVICE_ORDER_DETACH);
197 if (error)
198 return (error);
199
200 /* Perform shutdown */
201 for (int i = 0; i < ndevs; i++) {
202 device_t child = devs[i];
203
204 /* Terminate on first error */
205 if ((error = device_shutdown(child)))
206 goto cleanup;
207 }
208
209 cleanup:
210 bhnd_bus_free_children(devs);
211 return (error);
212 }
213
214 /**
215 * Default bhnd(4) bus driver implementation of DEVICE_RESUME().
216 *
217 * This implementation calls BUS_RESUME_CHILD() for each of the device's
218 * children in bhnd probe order, terminating if any call to BUS_RESUME_CHILD()
219 * fails.
220 */
221 int
bhnd_generic_resume(device_t dev)222 bhnd_generic_resume(device_t dev)
223 {
224 device_t *devs;
225 int ndevs;
226 int error;
227
228 if (!device_is_attached(dev))
229 return (EBUSY);
230
231 /* Fetch children in attach order */
232 error = bhnd_bus_get_children(dev, &devs, &ndevs,
233 BHND_DEVICE_ORDER_ATTACH);
234 if (error)
235 return (error);
236
237 /* Perform resume */
238 for (int i = 0; i < ndevs; i++) {
239 device_t child = devs[i];
240
241 /* Terminate on first error */
242 if ((error = BUS_RESUME_CHILD(device_get_parent(child), child)))
243 goto cleanup;
244 }
245
246 cleanup:
247 bhnd_bus_free_children(devs);
248 return (error);
249 }
250
251 /**
252 * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND().
253 *
254 * This implementation calls BUS_SUSPEND_CHILD() for each of the device's
255 * children in reverse bhnd probe order. If any call to BUS_SUSPEND_CHILD()
256 * fails, the suspend operation is terminated and any devices that were
257 * suspended are resumed immediately by calling their BUS_RESUME_CHILD()
258 * methods.
259 */
260 int
bhnd_generic_suspend(device_t dev)261 bhnd_generic_suspend(device_t dev)
262 {
263 device_t *devs;
264 int ndevs;
265 int error;
266
267 if (!device_is_attached(dev))
268 return (EBUSY);
269
270 /* Fetch children in detach order */
271 error = bhnd_bus_get_children(dev, &devs, &ndevs,
272 BHND_DEVICE_ORDER_DETACH);
273 if (error)
274 return (error);
275
276 /* Perform suspend */
277 for (int i = 0; i < ndevs; i++) {
278 device_t child = devs[i];
279 error = BUS_SUSPEND_CHILD(device_get_parent(child), child);
280
281 /* On error, resume suspended devices and then terminate */
282 if (error) {
283 for (int j = 0; j < i; j++) {
284 BUS_RESUME_CHILD(device_get_parent(devs[j]),
285 devs[j]);
286 }
287
288 goto cleanup;
289 }
290 }
291
292 cleanup:
293 bhnd_bus_free_children(devs);
294 return (error);
295 }
296
297 /**
298 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_PROBE_ORDER().
299 *
300 * This implementation determines probe ordering based on the device's class
301 * and other properties, including whether the device is serving as a host
302 * bridge.
303 */
304 int
bhnd_generic_get_probe_order(device_t dev,device_t child)305 bhnd_generic_get_probe_order(device_t dev, device_t child)
306 {
307 switch (bhnd_get_class(child)) {
308 case BHND_DEVCLASS_CC:
309 /* Must be early enough to provide NVRAM access to the
310 * host bridge */
311 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_FIRST);
312
313 case BHND_DEVCLASS_CC_B:
314 /* fall through */
315 case BHND_DEVCLASS_PMU:
316 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY);
317
318 case BHND_DEVCLASS_SOC_ROUTER:
319 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE);
320
321 case BHND_DEVCLASS_SOC_BRIDGE:
322 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST);
323
324 case BHND_DEVCLASS_CPU:
325 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST);
326
327 case BHND_DEVCLASS_RAM:
328 /* fall through */
329 case BHND_DEVCLASS_MEMC:
330 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY);
331
332 case BHND_DEVCLASS_NVRAM:
333 return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY);
334
335 case BHND_DEVCLASS_PCI:
336 case BHND_DEVCLASS_PCIE:
337 case BHND_DEVCLASS_PCCARD:
338 case BHND_DEVCLASS_ENET:
339 case BHND_DEVCLASS_ENET_MAC:
340 case BHND_DEVCLASS_ENET_PHY:
341 case BHND_DEVCLASS_WLAN:
342 case BHND_DEVCLASS_WLAN_MAC:
343 case BHND_DEVCLASS_WLAN_PHY:
344 case BHND_DEVCLASS_EROM:
345 case BHND_DEVCLASS_OTHER:
346 case BHND_DEVCLASS_INVALID:
347 if (bhnd_bus_find_hostb_device(dev) == child)
348 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY);
349
350 return (BHND_PROBE_DEFAULT);
351 default:
352 return (BHND_PROBE_DEFAULT);
353 }
354 }
355
356 /**
357 * Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU().
358 */
359 int
bhnd_generic_alloc_pmu(device_t dev,device_t child)360 bhnd_generic_alloc_pmu(device_t dev, device_t child)
361 {
362 struct bhnd_softc *sc;
363 struct bhnd_resource *r;
364 struct bhnd_core_clkctl *clkctl;
365 struct resource_list *rl;
366 struct resource_list_entry *rle;
367 device_t pmu_dev;
368 bhnd_addr_t r_addr;
369 bhnd_size_t r_size;
370 bus_size_t pmu_regs;
371 u_int max_latency;
372 int error;
373
374 GIANT_REQUIRED; /* for newbus */
375
376 if (device_get_parent(child) != dev)
377 return (EINVAL);
378
379 sc = device_get_softc(dev);
380 clkctl = bhnd_get_pmu_info(child);
381 pmu_regs = BHND_CLK_CTL_ST;
382
383 /* already allocated? */
384 if (clkctl != NULL) {
385 panic("duplicate PMU allocation for %s",
386 device_get_nameunit(child));
387 }
388
389 /* Determine address+size of the core's PMU register block */
390 error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr,
391 &r_size);
392 if (error) {
393 device_printf(sc->dev, "error fetching register block info for "
394 "%s: %d\n", device_get_nameunit(child), error);
395 return (error);
396 }
397
398 if (r_size < (pmu_regs + sizeof(uint32_t))) {
399 device_printf(sc->dev, "pmu offset %#jx would overrun %s "
400 "register block\n", (uintmax_t)pmu_regs,
401 device_get_nameunit(child));
402 return (ENODEV);
403 }
404
405 /* Locate actual resource containing the core's register block */
406 if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) {
407 device_printf(dev, "NULL resource list returned for %s\n",
408 device_get_nameunit(child));
409 return (ENXIO);
410 }
411
412 if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) {
413 device_printf(dev, "cannot locate core register resource "
414 "for %s\n", device_get_nameunit(child));
415 return (ENXIO);
416 }
417
418 if (rle->res == NULL) {
419 device_printf(dev, "core register resource unallocated for "
420 "%s\n", device_get_nameunit(child));
421 return (ENXIO);
422 }
423
424 if (r_addr+pmu_regs < rman_get_start(rle->res) ||
425 r_addr+pmu_regs >= rman_get_end(rle->res))
426 {
427 device_printf(dev, "core register resource does not map PMU "
428 "registers at %#jx\n for %s\n", r_addr+pmu_regs,
429 device_get_nameunit(child));
430 return (ENXIO);
431 }
432
433 /* Adjust PMU register offset relative to the actual start address
434 * of the core's register block allocation.
435 *
436 * XXX: The saved offset will be invalid if bus_adjust_resource is
437 * used to modify the resource's start address.
438 */
439 if (rman_get_start(rle->res) > r_addr)
440 pmu_regs -= rman_get_start(rle->res) - r_addr;
441 else
442 pmu_regs -= r_addr - rman_get_start(rle->res);
443
444 /* Retain a PMU reference for the clkctl instance state */
445 pmu_dev = bhnd_retain_provider(child, BHND_SERVICE_PMU);
446 if (pmu_dev == NULL) {
447 device_printf(sc->dev, "PMU not found\n");
448 return (ENXIO);
449 }
450
451 /* Fetch the maximum transition latency from our PMU */
452 max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev);
453
454 /* Allocate a new bhnd_resource wrapping the standard resource we
455 * fetched from the resource list; we'll free this in
456 * bhnd_generic_release_pmu() */
457 r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
458 if (r == NULL) {
459 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
460 return (ENOMEM);
461 }
462
463 r->res = rle->res;
464 r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
465
466 /* Allocate the clkctl instance */
467 clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs,
468 max_latency);
469 if (clkctl == NULL) {
470 free(r, M_BHND);
471 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
472 return (ENOMEM);
473 }
474
475 bhnd_set_pmu_info(child, clkctl);
476 return (0);
477 }
478
479 /**
480 * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU().
481 */
482 int
bhnd_generic_release_pmu(device_t dev,device_t child)483 bhnd_generic_release_pmu(device_t dev, device_t child)
484 {
485 struct bhnd_softc *sc;
486 struct bhnd_core_clkctl *clkctl;
487 struct bhnd_resource *r;
488 device_t pmu_dev;
489
490 GIANT_REQUIRED; /* for newbus */
491
492 sc = device_get_softc(dev);
493
494 if (device_get_parent(child) != dev)
495 return (EINVAL);
496
497 clkctl = bhnd_get_pmu_info(child);
498 if (clkctl == NULL)
499 panic("pmu over-release for %s", device_get_nameunit(child));
500
501 /* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in
502 * RESET. Suspending a core clears clkctl automatically (and attempting
503 * to access the PMU registers in a suspended core will trigger a
504 * system livelock). */
505 if (!bhnd_is_hw_suspended(clkctl->cc_dev)) {
506 BHND_CLKCTL_LOCK(clkctl);
507
508 /* Clear all FORCE, AREQ, and ERSRC flags */
509 BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK |
510 BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
511
512 BHND_CLKCTL_UNLOCK(clkctl);
513 }
514
515 /* Clear child's PMU info reference */
516 bhnd_set_pmu_info(child, NULL);
517
518 /* Before freeing the clkctl instance, save a pointer to resources we
519 * need to clean up manually */
520 r = clkctl->cc_res;
521 pmu_dev = clkctl->cc_pmu_dev;
522
523 /* Free the clkctl instance */
524 bhnd_free_core_clkctl(clkctl);
525
526 /* Free the child's bhnd resource wrapper */
527 free(r, M_BHND);
528
529 /* Release the child's PMU provider reference */
530 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
531
532 return (0);
533 }
534
535 /**
536 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY().
537 */
538 int
bhnd_generic_get_clock_latency(device_t dev,device_t child,bhnd_clock clock,u_int * latency)539 bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
540 u_int *latency)
541 {
542 struct bhnd_core_clkctl *clkctl;
543
544 if (device_get_parent(child) != dev)
545 return (EINVAL);
546
547 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
548 panic("no active PMU allocation");
549
550 return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency));
551 }
552
553 /**
554 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ().
555 */
556 int
bhnd_generic_get_clock_freq(device_t dev,device_t child,bhnd_clock clock,u_int * freq)557 bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
558 u_int *freq)
559 {
560 struct bhnd_core_clkctl *clkctl;
561
562 if (device_get_parent(child) != dev)
563 return (EINVAL);
564
565 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
566 panic("no active PMU allocation");
567
568 return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq));
569 }
570
571 /**
572 * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK().
573 */
574 int
bhnd_generic_request_clock(device_t dev,device_t child,bhnd_clock clock)575 bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock)
576 {
577 struct bhnd_softc *sc;
578 struct bhnd_core_clkctl *clkctl;
579 uint32_t avail;
580 uint32_t req;
581 int error;
582
583 sc = device_get_softc(dev);
584
585 if (device_get_parent(child) != dev)
586 return (EINVAL);
587
588 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
589 panic("no active PMU allocation");
590
591 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
592
593 avail = 0x0;
594 req = 0x0;
595
596 switch (clock) {
597 case BHND_CLOCK_DYN:
598 break;
599 case BHND_CLOCK_ILP:
600 req |= BHND_CCS_FORCEILP;
601 break;
602 case BHND_CLOCK_ALP:
603 req |= BHND_CCS_FORCEALP;
604 avail |= BHND_CCS_ALPAVAIL;
605 break;
606 case BHND_CLOCK_HT:
607 req |= BHND_CCS_FORCEHT;
608 avail |= BHND_CCS_HTAVAIL;
609 break;
610 default:
611 device_printf(dev, "%s requested unknown clock: %#x\n",
612 device_get_nameunit(clkctl->cc_dev), clock);
613 return (ENODEV);
614 }
615
616 BHND_CLKCTL_LOCK(clkctl);
617
618 /* Issue request */
619 BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK);
620
621 /* Wait for clock availability */
622 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
623
624 BHND_CLKCTL_UNLOCK(clkctl);
625
626 return (error);
627 }
628
629 /**
630 * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS().
631 */
632 int
bhnd_generic_enable_clocks(device_t dev,device_t child,uint32_t clocks)633 bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
634 {
635 struct bhnd_softc *sc;
636 struct bhnd_core_clkctl *clkctl;
637 uint32_t avail;
638 uint32_t req;
639 int error;
640
641 sc = device_get_softc(dev);
642
643 if (device_get_parent(child) != dev)
644 return (EINVAL);
645
646 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
647 panic("no active PMU allocation");
648
649 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
650
651 sc = device_get_softc(dev);
652
653 avail = 0x0;
654 req = 0x0;
655
656 /* Build clock request flags */
657 if (clocks & BHND_CLOCK_DYN) /* nothing to enable */
658 clocks &= ~BHND_CLOCK_DYN;
659
660 if (clocks & BHND_CLOCK_ILP) /* nothing to enable */
661 clocks &= ~BHND_CLOCK_ILP;
662
663 if (clocks & BHND_CLOCK_ALP) {
664 req |= BHND_CCS_ALPAREQ;
665 avail |= BHND_CCS_ALPAVAIL;
666 clocks &= ~BHND_CLOCK_ALP;
667 }
668
669 if (clocks & BHND_CLOCK_HT) {
670 req |= BHND_CCS_HTAREQ;
671 avail |= BHND_CCS_HTAVAIL;
672 clocks &= ~BHND_CLOCK_HT;
673 }
674
675 /* Check for unknown clock values */
676 if (clocks != 0x0) {
677 device_printf(dev, "%s requested unknown clocks: %#x\n",
678 device_get_nameunit(clkctl->cc_dev), clocks);
679 return (ENODEV);
680 }
681
682 BHND_CLKCTL_LOCK(clkctl);
683
684 /* Issue request */
685 BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK);
686
687 /* Wait for clock availability */
688 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
689
690 BHND_CLKCTL_UNLOCK(clkctl);
691
692 return (error);
693 }
694
695 /**
696 * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC().
697 */
698 int
bhnd_generic_request_ext_rsrc(device_t dev,device_t child,u_int rsrc)699 bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
700 {
701 struct bhnd_softc *sc;
702 struct bhnd_core_clkctl *clkctl;
703 uint32_t req;
704 uint32_t avail;
705 int error;
706
707 sc = device_get_softc(dev);
708
709 if (device_get_parent(child) != dev)
710 return (EINVAL);
711
712 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
713 panic("no active PMU allocation");
714
715 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
716
717 sc = device_get_softc(dev);
718
719 if (rsrc > BHND_CCS_ERSRC_MAX)
720 return (EINVAL);
721
722 req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
723 avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
724
725 BHND_CLKCTL_LOCK(clkctl);
726
727 /* Write request */
728 BHND_CLKCTL_SET_4(clkctl, req, req);
729
730 /* Wait for resource availability */
731 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
732
733 BHND_CLKCTL_UNLOCK(clkctl);
734
735 return (error);
736 }
737
738 /**
739 * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC().
740 */
741 int
bhnd_generic_release_ext_rsrc(device_t dev,device_t child,u_int rsrc)742 bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
743 {
744 struct bhnd_softc *sc;
745 struct bhnd_core_clkctl *clkctl;
746 uint32_t mask;
747
748 sc = device_get_softc(dev);
749
750 if (device_get_parent(child) != dev)
751 return (EINVAL);
752
753 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
754 panic("no active PMU allocation");
755
756 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
757
758 sc = device_get_softc(dev);
759
760 if (rsrc > BHND_CCS_ERSRC_MAX)
761 return (EINVAL);
762
763 mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
764
765 /* Clear request */
766 BHND_CLKCTL_LOCK(clkctl);
767 BHND_CLKCTL_SET_4(clkctl, 0x0, mask);
768 BHND_CLKCTL_UNLOCK(clkctl);
769
770 return (0);
771 }
772
773 /**
774 * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
775 *
776 * This implementation assumes that port and region numbers are 0-indexed and
777 * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and
778 * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall
779 * within the defined range.
780 */
781 static bool
bhnd_generic_is_region_valid(device_t dev,device_t child,bhnd_port_type type,u_int port,u_int region)782 bhnd_generic_is_region_valid(device_t dev, device_t child,
783 bhnd_port_type type, u_int port, u_int region)
784 {
785 if (port >= bhnd_get_port_count(child, type))
786 return (false);
787
788 if (region >= bhnd_get_region_count(child, type, port))
789 return (false);
790
791 return (true);
792 }
793
794 /**
795 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR().
796 *
797 * This implementation searches @p dev for a registered NVRAM child device.
798 *
799 * If no NVRAM device is registered with @p dev, the request is delegated to
800 * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
801 */
802 int
bhnd_generic_get_nvram_var(device_t dev,device_t child,const char * name,void * buf,size_t * size,bhnd_nvram_type type)803 bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name,
804 void *buf, size_t *size, bhnd_nvram_type type)
805 {
806 struct bhnd_softc *sc;
807 device_t nvram, parent;
808 int error;
809
810 sc = device_get_softc(dev);
811
812 /* If a NVRAM device is available, consult it first */
813 nvram = bhnd_retain_provider(child, BHND_SERVICE_NVRAM);
814 if (nvram != NULL) {
815 error = BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
816 bhnd_release_provider(child, nvram, BHND_SERVICE_NVRAM);
817 return (error);
818 }
819
820 /* Otherwise, try to delegate to parent */
821 if ((parent = device_get_parent(dev)) == NULL)
822 return (ENODEV);
823
824 return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
825 name, buf, size, type));
826 }
827
828 /**
829 * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD().
830 *
831 * This implementation requests the device's struct resource_list via
832 * BUS_GET_RESOURCE_LIST.
833 */
834 int
bhnd_generic_print_child(device_t dev,device_t child)835 bhnd_generic_print_child(device_t dev, device_t child)
836 {
837 struct resource_list *rl;
838 int retval = 0;
839
840 retval += bus_print_child_header(dev, child);
841
842 rl = BUS_GET_RESOURCE_LIST(dev, child);
843
844 if (rl != NULL) {
845 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
846 "%#jx");
847
848 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
849 "%#jd");
850 }
851
852 retval += printf(" at core %u", bhnd_get_core_index(child));
853
854 retval += bus_print_child_domain(dev, child);
855 retval += bus_print_child_footer(dev, child);
856
857 return (retval);
858 }
859
860 /**
861 * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH().
862 *
863 * This implementation requests the device's struct resource_list via
864 * BUS_GET_RESOURCE_LIST.
865 */
866 void
bhnd_generic_probe_nomatch(device_t dev,device_t child)867 bhnd_generic_probe_nomatch(device_t dev, device_t child)
868 {
869 struct resource_list *rl;
870 const struct bhnd_nomatch *nm;
871 bool report;
872
873 /* Fetch reporting configuration for this device */
874 report = true;
875 for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) {
876 if (nm->vendor != bhnd_get_vendor(child))
877 continue;
878
879 if (nm->device != bhnd_get_device(child))
880 continue;
881
882 report = false;
883 if (bootverbose && nm->if_verbose)
884 report = true;
885 break;
886 }
887
888 if (!report)
889 return;
890
891 /* Print the non-matched device info */
892 device_printf(dev, "<%s %s, rev %hhu>", bhnd_get_vendor_name(child),
893 bhnd_get_device_name(child), bhnd_get_hwrev(child));
894
895 rl = BUS_GET_RESOURCE_LIST(dev, child);
896 if (rl != NULL) {
897 resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
898 resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd");
899 }
900
901 printf(" at core %u (no driver attached)\n",
902 bhnd_get_core_index(child));
903 }
904
905 /**
906 * Default implementation of BUS_CHILD_PNPINFO_STR().
907 */
908 static int
bhnd_child_pnpinfo_str(device_t dev,device_t child,char * buf,size_t buflen)909 bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf,
910 size_t buflen)
911 {
912 if (device_get_parent(child) != dev) {
913 return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child,
914 buf, buflen));
915 }
916
917 snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx",
918 bhnd_get_vendor(child), bhnd_get_device(child),
919 bhnd_get_hwrev(child));
920
921 return (0);
922 }
923
924 /**
925 * Default implementation of BUS_CHILD_LOCATION_STR().
926 */
927 static int
bhnd_child_location_str(device_t dev,device_t child,char * buf,size_t buflen)928 bhnd_child_location_str(device_t dev, device_t child, char *buf,
929 size_t buflen)
930 {
931 bhnd_addr_t addr;
932 bhnd_size_t size;
933
934 if (device_get_parent(child) != dev) {
935 return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child,
936 buf, buflen));
937 }
938
939 if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) {
940 /* No device default port/region */
941 if (buflen > 0)
942 *buf = '\0';
943 return (0);
944 }
945
946 snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr);
947 return (0);
948 }
949
950 /**
951 * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED().
952 *
953 * This implementation manages internal bhnd(4) state, and must be called
954 * by subclassing drivers.
955 */
956 void
bhnd_generic_child_deleted(device_t dev,device_t child)957 bhnd_generic_child_deleted(device_t dev, device_t child)
958 {
959 struct bhnd_softc *sc;
960
961 sc = device_get_softc(dev);
962
963 /* Free device info */
964 if (bhnd_get_pmu_info(child) != NULL) {
965 /* Releasing PMU requests automatically would be nice,
966 * but we can't reference per-core PMU register
967 * resource after driver detach */
968 panic("%s leaked device pmu state\n",
969 device_get_nameunit(child));
970 }
971 }
972
973 /**
974 * Helper function for implementing BUS_SUSPEND_CHILD().
975 *
976 * TODO: Power management
977 *
978 * If @p child is not a direct child of @p dev, suspension is delegated to
979 * the @p dev parent.
980 */
981 int
bhnd_generic_suspend_child(device_t dev,device_t child)982 bhnd_generic_suspend_child(device_t dev, device_t child)
983 {
984 if (device_get_parent(child) != dev)
985 BUS_SUSPEND_CHILD(device_get_parent(dev), child);
986
987 return bus_generic_suspend_child(dev, child);
988 }
989
990 /**
991 * Helper function for implementing BUS_RESUME_CHILD().
992 *
993 * TODO: Power management
994 *
995 * If @p child is not a direct child of @p dev, suspension is delegated to
996 * the @p dev parent.
997 */
998 int
bhnd_generic_resume_child(device_t dev,device_t child)999 bhnd_generic_resume_child(device_t dev, device_t child)
1000 {
1001 if (device_get_parent(child) != dev)
1002 BUS_RESUME_CHILD(device_get_parent(dev), child);
1003
1004 return bus_generic_resume_child(dev, child);
1005 }
1006
1007 /**
1008 * Default bhnd(4) bus driver implementation of BUS_SETUP_INTR().
1009 *
1010 * This implementation of BUS_SETUP_INTR() will delegate interrupt setup
1011 * to the parent of @p dev, if any.
1012 */
1013 int
bhnd_generic_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_filter_t * filter,driver_intr_t * intr,void * arg,void ** cookiep)1014 bhnd_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
1015 int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
1016 void **cookiep)
1017 {
1018 return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
1019 arg, cookiep));
1020 }
1021
1022 /*
1023 * Delegate all indirect I/O to the parent device. When inherited by
1024 * non-bridged bus implementations, resources will never be marked as
1025 * indirect, and these methods will never be called.
1026 */
1027 #define BHND_IO_READ(_type, _name, _method) \
1028 static _type \
1029 bhnd_read_ ## _name (device_t dev, device_t child, \
1030 struct bhnd_resource *r, bus_size_t offset) \
1031 { \
1032 return (BHND_BUS_READ_ ## _method( \
1033 device_get_parent(dev), child, r, offset)); \
1034 }
1035
1036 #define BHND_IO_WRITE(_type, _name, _method) \
1037 static void \
1038 bhnd_write_ ## _name (device_t dev, device_t child, \
1039 struct bhnd_resource *r, bus_size_t offset, _type value) \
1040 { \
1041 return (BHND_BUS_WRITE_ ## _method( \
1042 device_get_parent(dev), child, r, offset, \
1043 value)); \
1044 }
1045
1046 #define BHND_IO_MISC(_type, _op, _method) \
1047 static void \
1048 bhnd_ ## _op (device_t dev, device_t child, \
1049 struct bhnd_resource *r, bus_size_t offset, _type datap, \
1050 bus_size_t count) \
1051 { \
1052 BHND_BUS_ ## _method(device_get_parent(dev), child, r, \
1053 offset, datap, count); \
1054 }
1055
1056 #define BHND_IO_METHODS(_type, _size) \
1057 BHND_IO_READ(_type, _size, _size) \
1058 BHND_IO_WRITE(_type, _size, _size) \
1059 \
1060 BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size) \
1061 BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size) \
1062 \
1063 BHND_IO_MISC(_type*, read_multi_ ## _size, \
1064 READ_MULTI_ ## _size) \
1065 BHND_IO_MISC(_type*, write_multi_ ## _size, \
1066 WRITE_MULTI_ ## _size) \
1067 \
1068 BHND_IO_MISC(_type*, read_multi_stream_ ## _size, \
1069 READ_MULTI_STREAM_ ## _size) \
1070 BHND_IO_MISC(_type*, write_multi_stream_ ## _size, \
1071 WRITE_MULTI_STREAM_ ## _size) \
1072 \
1073 BHND_IO_MISC(_type, set_multi_ ## _size, SET_MULTI_ ## _size) \
1074 BHND_IO_MISC(_type, set_region_ ## _size, SET_REGION_ ## _size) \
1075 \
1076 BHND_IO_MISC(_type*, read_region_ ## _size, \
1077 READ_REGION_ ## _size) \
1078 BHND_IO_MISC(_type*, write_region_ ## _size, \
1079 WRITE_REGION_ ## _size) \
1080 \
1081 BHND_IO_MISC(_type*, read_region_stream_ ## _size, \
1082 READ_REGION_STREAM_ ## _size) \
1083 BHND_IO_MISC(_type*, write_region_stream_ ## _size, \
1084 WRITE_REGION_STREAM_ ## _size) \
1085
1086 BHND_IO_METHODS(uint8_t, 1);
1087 BHND_IO_METHODS(uint16_t, 2);
1088 BHND_IO_METHODS(uint32_t, 4);
1089
1090 static void
bhnd_barrier(device_t dev,device_t child,struct bhnd_resource * r,bus_size_t offset,bus_size_t length,int flags)1091 bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r,
1092 bus_size_t offset, bus_size_t length, int flags)
1093 {
1094 BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length,
1095 flags);
1096 }
1097
1098 static device_method_t bhnd_methods[] = {
1099 /* Device interface */ \
1100 DEVMETHOD(device_attach, bhnd_generic_attach),
1101 DEVMETHOD(device_detach, bhnd_generic_detach),
1102 DEVMETHOD(device_shutdown, bhnd_generic_shutdown),
1103 DEVMETHOD(device_suspend, bhnd_generic_suspend),
1104 DEVMETHOD(device_resume, bhnd_generic_resume),
1105
1106 /* Bus interface */
1107 DEVMETHOD(bus_child_deleted, bhnd_generic_child_deleted),
1108 DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch),
1109 DEVMETHOD(bus_print_child, bhnd_generic_print_child),
1110 DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str),
1111 DEVMETHOD(bus_child_location_str, bhnd_child_location_str),
1112
1113 DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child),
1114 DEVMETHOD(bus_resume_child, bhnd_generic_resume_child),
1115
1116 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
1117 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
1118 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
1119 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
1120 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
1121 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
1122 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1123 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1124
1125 DEVMETHOD(bus_setup_intr, bhnd_generic_setup_intr),
1126 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
1127 DEVMETHOD(bus_config_intr, bus_generic_config_intr),
1128 DEVMETHOD(bus_bind_intr, bus_generic_bind_intr),
1129 DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
1130
1131 DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag),
1132
1133 /* BHND interface */
1134 DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid),
1135 DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
1136
1137 DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
1138
1139 DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu),
1140 DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu),
1141 DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock),
1142 DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks),
1143 DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc),
1144 DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc),
1145 DEVMETHOD(bhnd_bus_get_clock_latency, bhnd_generic_get_clock_latency),
1146 DEVMETHOD(bhnd_bus_get_clock_freq, bhnd_generic_get_clock_freq),
1147
1148 DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
1149 DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var),
1150
1151 /* BHND interface (bus I/O) */
1152 DEVMETHOD(bhnd_bus_read_1, bhnd_read_1),
1153 DEVMETHOD(bhnd_bus_read_2, bhnd_read_2),
1154 DEVMETHOD(bhnd_bus_read_4, bhnd_read_4),
1155 DEVMETHOD(bhnd_bus_write_1, bhnd_write_1),
1156 DEVMETHOD(bhnd_bus_write_2, bhnd_write_2),
1157 DEVMETHOD(bhnd_bus_write_4, bhnd_write_4),
1158
1159 DEVMETHOD(bhnd_bus_read_stream_1, bhnd_read_stream_1),
1160 DEVMETHOD(bhnd_bus_read_stream_2, bhnd_read_stream_2),
1161 DEVMETHOD(bhnd_bus_read_stream_4, bhnd_read_stream_4),
1162 DEVMETHOD(bhnd_bus_write_stream_1, bhnd_write_stream_1),
1163 DEVMETHOD(bhnd_bus_write_stream_2, bhnd_write_stream_2),
1164 DEVMETHOD(bhnd_bus_write_stream_4, bhnd_write_stream_4),
1165
1166 DEVMETHOD(bhnd_bus_read_multi_1, bhnd_read_multi_1),
1167 DEVMETHOD(bhnd_bus_read_multi_2, bhnd_read_multi_2),
1168 DEVMETHOD(bhnd_bus_read_multi_4, bhnd_read_multi_4),
1169 DEVMETHOD(bhnd_bus_write_multi_1, bhnd_write_multi_1),
1170 DEVMETHOD(bhnd_bus_write_multi_2, bhnd_write_multi_2),
1171 DEVMETHOD(bhnd_bus_write_multi_4, bhnd_write_multi_4),
1172
1173 DEVMETHOD(bhnd_bus_read_multi_stream_1, bhnd_read_multi_stream_1),
1174 DEVMETHOD(bhnd_bus_read_multi_stream_2, bhnd_read_multi_stream_2),
1175 DEVMETHOD(bhnd_bus_read_multi_stream_4, bhnd_read_multi_stream_4),
1176 DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1),
1177 DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2),
1178 DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_4),
1179
1180 DEVMETHOD(bhnd_bus_set_multi_1, bhnd_set_multi_1),
1181 DEVMETHOD(bhnd_bus_set_multi_2, bhnd_set_multi_2),
1182 DEVMETHOD(bhnd_bus_set_multi_4, bhnd_set_multi_4),
1183
1184 DEVMETHOD(bhnd_bus_set_region_1, bhnd_set_region_1),
1185 DEVMETHOD(bhnd_bus_set_region_2, bhnd_set_region_2),
1186 DEVMETHOD(bhnd_bus_set_region_4, bhnd_set_region_4),
1187
1188 DEVMETHOD(bhnd_bus_read_region_1, bhnd_read_region_1),
1189 DEVMETHOD(bhnd_bus_read_region_2, bhnd_read_region_2),
1190 DEVMETHOD(bhnd_bus_read_region_4, bhnd_read_region_4),
1191 DEVMETHOD(bhnd_bus_write_region_1, bhnd_write_region_1),
1192 DEVMETHOD(bhnd_bus_write_region_2, bhnd_write_region_2),
1193 DEVMETHOD(bhnd_bus_write_region_4, bhnd_write_region_4),
1194
1195 DEVMETHOD(bhnd_bus_read_region_stream_1,bhnd_read_region_stream_1),
1196 DEVMETHOD(bhnd_bus_read_region_stream_2,bhnd_read_region_stream_2),
1197 DEVMETHOD(bhnd_bus_read_region_stream_4,bhnd_read_region_stream_4),
1198 DEVMETHOD(bhnd_bus_write_region_stream_1, bhnd_write_region_stream_1),
1199 DEVMETHOD(bhnd_bus_write_region_stream_2, bhnd_write_region_stream_2),
1200 DEVMETHOD(bhnd_bus_write_region_stream_4, bhnd_write_region_stream_4),
1201
1202 DEVMETHOD(bhnd_bus_barrier, bhnd_barrier),
1203
1204 DEVMETHOD_END
1205 };
1206
1207 devclass_t bhnd_devclass; /**< bhnd bus. */
1208 devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */
1209 devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */
1210
1211 DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc));
1212 MODULE_VERSION(bhnd, 1);
1213