Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bhnd/bhndb/bhndb.c
39536 views
1
/*-
2
* Copyright (c) 2015-2016 Landon Fuller <[email protected]>
3
* Copyright (c) 2017 The FreeBSD Foundation
4
* All rights reserved.
5
*
6
* Portions of this software were developed by Landon Fuller
7
* under sponsorship from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer,
14
* without modification.
15
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
16
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17
* redistribution must be conditioned upon including a substantially
18
* similar Disclaimer requirement for further binary redistribution.
19
*
20
* NO WARRANTY
21
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31
* THE POSSIBILITY OF SUCH DAMAGES.
32
*/
33
34
#include <sys/cdefs.h>
35
/*
36
* Abstract BHND Bridge Device Driver
37
*
38
* Provides generic support for bridging from a parent bus (such as PCI) to
39
* a BHND-compatible bus (e.g. bcma or siba).
40
*/
41
42
#include <sys/param.h>
43
#include <sys/kernel.h>
44
#include <sys/bus.h>
45
#include <sys/module.h>
46
#include <sys/sbuf.h>
47
#include <sys/systm.h>
48
49
#include <machine/bus.h>
50
#include <sys/rman.h>
51
#include <machine/resource.h>
52
53
#include <dev/bhnd/bhndvar.h>
54
#include <dev/bhnd/bhndreg.h>
55
56
#include <dev/bhnd/bhnd_erom.h>
57
58
#include <dev/bhnd/cores/chipc/chipcreg.h>
59
#include <dev/bhnd/nvram/bhnd_nvram.h>
60
61
#include "bhnd_chipc_if.h"
62
#include "bhnd_nvram_if.h"
63
64
#include "bhndbvar.h"
65
#include "bhndb_bus_if.h"
66
#include "bhndb_hwdata.h"
67
#include "bhndb_private.h"
68
69
/* Debugging flags */
70
static u_long bhndb_debug = 0;
71
TUNABLE_ULONG("hw.bhndb.debug", &bhndb_debug);
72
73
enum {
74
BHNDB_DEBUG_PRIO = 1 << 0,
75
};
76
77
#define BHNDB_DEBUG(_type) (BHNDB_DEBUG_ ## _type & bhndb_debug)
78
79
static bool bhndb_hw_matches(struct bhndb_softc *sc,
80
struct bhnd_core_info *cores, u_int ncores,
81
const struct bhndb_hw *hw);
82
83
static int bhndb_init_region_cfg(struct bhndb_softc *sc,
84
bhnd_erom_t *erom,
85
struct bhndb_resources *r,
86
struct bhnd_core_info *cores, u_int ncores,
87
const struct bhndb_hw_priority *table);
88
89
static int bhndb_find_hwspec(struct bhndb_softc *sc,
90
struct bhnd_core_info *cores, u_int ncores,
91
const struct bhndb_hw **hw);
92
93
bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc,
94
device_t child);
95
96
static struct rman *bhndb_get_rman(struct bhndb_softc *sc,
97
device_t child, int type);
98
99
static int bhndb_init_child_resource(struct resource *r,
100
struct resource *parent,
101
bhnd_size_t offset,
102
bhnd_size_t size);
103
104
static int bhndb_activate_static_region(
105
struct bhndb_softc *sc,
106
struct bhndb_region *region,
107
device_t child, struct resource *r);
108
109
static int bhndb_try_activate_resource(
110
struct bhndb_softc *sc, device_t child,
111
struct resource *r, bool *indirect);
112
113
static inline struct bhndb_dw_alloc *bhndb_io_resource(struct bhndb_softc *sc,
114
bus_addr_t addr, bus_size_t size,
115
bus_size_t *offset, bool *stolen,
116
bus_addr_t *restore);
117
118
/**
119
* Default bhndb(4) implementation of DEVICE_PROBE().
120
*
121
* This function provides the default bhndb implementation of DEVICE_PROBE(),
122
* and is compatible with bhndb(4) bridges attached via bhndb_attach_bridge().
123
*/
124
int
125
bhndb_generic_probe(device_t dev)
126
{
127
return (BUS_PROBE_NOWILDCARD);
128
}
129
130
static void
131
bhndb_probe_nomatch(device_t dev, device_t child)
132
{
133
const char *name;
134
135
name = device_get_name(child);
136
if (name == NULL)
137
name = "unknown device";
138
139
device_printf(dev, "<%s> (no driver attached)\n", name);
140
}
141
142
static int
143
bhndb_print_child(device_t dev, device_t child)
144
{
145
struct resource_list *rl;
146
int retval = 0;
147
148
retval += bus_print_child_header(dev, child);
149
150
rl = BUS_GET_RESOURCE_LIST(dev, child);
151
if (rl != NULL) {
152
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
153
"%#jx");
154
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
155
"%jd");
156
}
157
158
retval += bus_print_child_domain(dev, child);
159
retval += bus_print_child_footer(dev, child);
160
161
return (retval);
162
}
163
164
static int
165
bhndb_child_location(device_t dev, device_t child, struct sbuf *sb)
166
{
167
struct bhndb_softc *sc;
168
169
sc = device_get_softc(dev);
170
171
sbuf_printf(sb, "base=0x%llx",
172
(unsigned long long) sc->chipid.enum_addr);
173
return (0);
174
}
175
176
/**
177
* Return true if @p cores matches the @p hw specification.
178
*
179
* @param sc BHNDB device state.
180
* @param cores A device table to match against.
181
* @param ncores The number of cores in @p cores.
182
* @param hw The hardware description to be matched against.
183
*/
184
static bool
185
bhndb_hw_matches(struct bhndb_softc *sc, struct bhnd_core_info *cores,
186
u_int ncores, const struct bhndb_hw *hw)
187
{
188
for (u_int i = 0; i < hw->num_hw_reqs; i++) {
189
const struct bhnd_core_match *match;
190
bool found;
191
192
match = &hw->hw_reqs[i];
193
found = false;
194
195
for (u_int d = 0; d < ncores; d++) {
196
struct bhnd_core_info *core = &cores[d];
197
198
if (BHNDB_IS_CORE_DISABLED(sc->dev, sc->bus_dev, core))
199
continue;
200
201
if (!bhnd_core_matches(core, match))
202
continue;
203
204
found = true;
205
break;
206
}
207
208
if (!found)
209
return (false);
210
}
211
212
return (true);
213
}
214
215
/**
216
* Initialize the region maps and priority configuration in @p br using
217
* the priority @p table and the set of cores enumerated by @p erom.
218
*
219
* @param sc The bhndb device state.
220
* @param br The resource state to be configured.
221
* @param erom EROM parser used to enumerate @p cores.
222
* @param cores All cores enumerated on the bridged bhnd bus.
223
* @param ncores The length of @p cores.
224
* @param table Hardware priority table to be used to determine the relative
225
* priorities of per-core port resources.
226
*/
227
static int
228
bhndb_init_region_cfg(struct bhndb_softc *sc, bhnd_erom_t *erom,
229
struct bhndb_resources *br, struct bhnd_core_info *cores, u_int ncores,
230
const struct bhndb_hw_priority *table)
231
{
232
const struct bhndb_hw_priority *hp;
233
bhnd_addr_t addr;
234
bhnd_size_t size;
235
size_t prio_low, prio_default, prio_high;
236
int error;
237
238
/* The number of port regions per priority band that must be accessible
239
* via dynamic register windows */
240
prio_low = 0;
241
prio_default = 0;
242
prio_high = 0;
243
244
/*
245
* Register bridge regions covering all statically mapped ports.
246
*/
247
for (u_int i = 0; i < ncores; i++) {
248
const struct bhndb_regwin *regw;
249
struct bhnd_core_info *core;
250
struct bhnd_core_match md;
251
252
core = &cores[i];
253
md = bhnd_core_get_match_desc(core);
254
255
for (regw = br->cfg->register_windows;
256
regw->win_type != BHNDB_REGWIN_T_INVALID; regw++)
257
{
258
const struct bhndb_port_priority *pp;
259
uint32_t alloc_flags;
260
261
/* Only core windows are supported */
262
if (regw->win_type != BHNDB_REGWIN_T_CORE)
263
continue;
264
265
/* Skip non-matching cores. */
266
if (!bhndb_regwin_match_core(regw, core))
267
continue;
268
269
/* Fetch the base address of the mapped port */
270
error = bhnd_erom_lookup_core_addr(erom, &md,
271
regw->d.core.port_type,
272
regw->d.core.port,
273
regw->d.core.region,
274
NULL,
275
&addr,
276
&size);
277
if (error) {
278
/* Skip non-applicable register windows */
279
if (error == ENOENT)
280
continue;
281
282
return (error);
283
}
284
285
/*
286
* Apply the register window's region offset, if any.
287
*/
288
if (regw->d.core.offset > size) {
289
device_printf(sc->dev, "invalid register "
290
"window offset %#jx for region %#jx+%#jx\n",
291
regw->d.core.offset, addr, size);
292
return (EINVAL);
293
}
294
295
addr += regw->d.core.offset;
296
297
/*
298
* Always defer to the register window's size.
299
*
300
* If the port size is smaller than the window size,
301
* this ensures that we fully utilize register windows
302
* larger than the referenced port.
303
*
304
* If the port size is larger than the window size, this
305
* ensures that we do not directly map the allocations
306
* within the region to a too-small window.
307
*/
308
size = regw->win_size;
309
310
/* Fetch allocation flags from the corresponding port
311
* priority entry, if any */
312
pp = bhndb_hw_priorty_find_port(table, core,
313
regw->d.core.port_type, regw->d.core.port,
314
regw->d.core.region);
315
if (pp != NULL) {
316
alloc_flags = pp->alloc_flags;
317
} else {
318
alloc_flags = 0;
319
}
320
321
/*
322
* Add to the bus region list.
323
*
324
* The window priority for a statically mapped region is
325
* always HIGH.
326
*/
327
error = bhndb_add_resource_region(br, addr, size,
328
BHNDB_PRIORITY_HIGH, alloc_flags, regw);
329
if (error)
330
return (error);
331
}
332
}
333
334
/*
335
* Perform priority accounting and register bridge regions for all
336
* ports defined in the priority table
337
*/
338
for (u_int i = 0; i < ncores; i++) {
339
struct bhnd_core_info *core;
340
struct bhnd_core_match md;
341
342
core = &cores[i];
343
md = bhnd_core_get_match_desc(core);
344
345
/*
346
* Skip priority accounting for cores that ...
347
*/
348
349
/* ... do not require bridge resources */
350
if (BHNDB_IS_CORE_DISABLED(sc->dev, sc->bus_dev, core))
351
continue;
352
353
/* ... do not have a priority table entry */
354
hp = bhndb_hw_priority_find_core(table, core);
355
if (hp == NULL)
356
continue;
357
358
/* ... are explicitly disabled in the priority table. */
359
if (hp->priority == BHNDB_PRIORITY_NONE)
360
continue;
361
362
/* Determine the number of dynamic windows required and
363
* register their bus_region entries. */
364
for (u_int i = 0; i < hp->num_ports; i++) {
365
const struct bhndb_port_priority *pp;
366
367
pp = &hp->ports[i];
368
369
/* Fetch the address+size of the mapped port. */
370
error = bhnd_erom_lookup_core_addr(erom, &md,
371
pp->type, pp->port, pp->region,
372
NULL, &addr, &size);
373
if (error) {
374
/* Skip ports not defined on this device */
375
if (error == ENOENT)
376
continue;
377
378
return (error);
379
}
380
381
/* Skip ports with an existing static mapping */
382
if (bhndb_has_static_region_mapping(br, addr, size))
383
continue;
384
385
/* Define a dynamic region for this port */
386
error = bhndb_add_resource_region(br, addr, size,
387
pp->priority, pp->alloc_flags, NULL);
388
if (error)
389
return (error);
390
391
/* Update port mapping counts */
392
switch (pp->priority) {
393
case BHNDB_PRIORITY_NONE:
394
break;
395
case BHNDB_PRIORITY_LOW:
396
prio_low++;
397
break;
398
case BHNDB_PRIORITY_DEFAULT:
399
prio_default++;
400
break;
401
case BHNDB_PRIORITY_HIGH:
402
prio_high++;
403
break;
404
}
405
}
406
}
407
408
/* Determine the minimum priority at which we'll allocate direct
409
* register windows from our dynamic pool */
410
size_t prio_total = prio_low + prio_default + prio_high;
411
if (prio_total <= br->dwa_count) {
412
/* low+default+high priority regions get windows */
413
br->min_prio = BHNDB_PRIORITY_LOW;
414
415
} else if (prio_default + prio_high <= br->dwa_count) {
416
/* default+high priority regions get windows */
417
br->min_prio = BHNDB_PRIORITY_DEFAULT;
418
419
} else {
420
/* high priority regions get windows */
421
br->min_prio = BHNDB_PRIORITY_HIGH;
422
}
423
424
if (BHNDB_DEBUG(PRIO)) {
425
struct bhndb_region *region;
426
const char *direct_msg, *type_msg;
427
bhndb_priority_t prio, prio_min;
428
uint32_t flags;
429
430
prio_min = br->min_prio;
431
device_printf(sc->dev, "min_prio: %d\n", prio_min);
432
433
STAILQ_FOREACH(region, &br->bus_regions, link) {
434
prio = region->priority;
435
flags = region->alloc_flags;
436
437
direct_msg = prio >= prio_min ? "direct" : "indirect";
438
type_msg = region->static_regwin ? "static" : "dynamic";
439
440
device_printf(sc->dev, "region 0x%llx+0x%llx priority "
441
"%u %s/%s",
442
(unsigned long long) region->addr,
443
(unsigned long long) region->size,
444
region->priority,
445
direct_msg, type_msg);
446
447
if (flags & BHNDB_ALLOC_FULFILL_ON_OVERCOMMIT)
448
printf(" [overcommit]\n");
449
else
450
printf("\n");
451
}
452
}
453
454
return (0);
455
}
456
457
/**
458
* Find a hardware specification for @p dev.
459
*
460
* @param sc The bhndb device state.
461
* @param cores All cores enumerated on the bridged bhnd bus.
462
* @param ncores The length of @p cores.
463
* @param[out] hw On success, the matched hardware specification.
464
* with @p dev.
465
*
466
* @retval 0 success
467
* @retval non-zero if an error occurs fetching device info for comparison.
468
*/
469
static int
470
bhndb_find_hwspec(struct bhndb_softc *sc, struct bhnd_core_info *cores,
471
u_int ncores, const struct bhndb_hw **hw)
472
{
473
const struct bhndb_hw *next, *hw_table;
474
475
/* Search for the first matching hardware config. */
476
hw_table = BHNDB_BUS_GET_HARDWARE_TABLE(sc->parent_dev, sc->dev);
477
for (next = hw_table; next->hw_reqs != NULL; next++) {
478
if (!bhndb_hw_matches(sc, cores, ncores, next))
479
continue;
480
481
/* Found */
482
*hw = next;
483
return (0);
484
}
485
486
return (ENOENT);
487
}
488
489
/**
490
* Helper function that must be called by subclass bhndb(4) drivers
491
* when implementing DEVICE_ATTACH() before calling any bhnd(4) or bhndb(4)
492
* APIs on the bridge device.
493
*
494
* This function will add a bridged bhnd(4) child device with a device order of
495
* BHND_PROBE_BUS. Any subclass bhndb(4) driver may use the BHND_PROBE_*
496
* priority bands to add additional devices that will be attached in
497
* their preferred order relative to the bridged bhnd(4) bus.
498
*
499
* @param dev The bridge device to attach.
500
* @param cid The bridged device's chip identification.
501
* @param cores The bridged device's core table.
502
* @param ncores The number of cores in @p cores.
503
* @param bridge_core Core info for the bhnd(4) core serving as the host
504
* bridge.
505
* @param erom_class An erom parser class that may be used to parse
506
* the bridged device's device enumeration table.
507
*/
508
int
509
bhndb_attach(device_t dev, struct bhnd_chipid *cid,
510
struct bhnd_core_info *cores, u_int ncores,
511
struct bhnd_core_info *bridge_core, bhnd_erom_class_t *erom_class)
512
{
513
struct bhndb_devinfo *dinfo;
514
struct bhndb_softc *sc;
515
const struct bhndb_hw *hw;
516
const struct bhndb_hwcfg *hwcfg;
517
const struct bhndb_hw_priority *hwprio;
518
struct bhnd_erom_io *eio;
519
bhnd_erom_t *erom;
520
int error;
521
522
sc = device_get_softc(dev);
523
sc->dev = dev;
524
sc->parent_dev = device_get_parent(dev);
525
sc->bridge_core = *bridge_core;
526
sc->chipid = *cid;
527
528
if ((error = bhnd_service_registry_init(&sc->services)))
529
return (error);
530
531
BHNDB_LOCK_INIT(sc);
532
533
erom = NULL;
534
535
/* Find a matching bridge hardware configuration */
536
if ((error = bhndb_find_hwspec(sc, cores, ncores, &hw))) {
537
device_printf(sc->dev, "unable to identify device, "
538
" using generic bridge resource definitions\n");
539
540
hwcfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, dev);
541
hw = NULL;
542
} else {
543
hwcfg = hw->cfg;
544
}
545
546
if (hw != NULL && (bootverbose || BHNDB_DEBUG(PRIO))) {
547
device_printf(sc->dev, "%s resource configuration\n", hw->name);
548
}
549
550
/* Allocate bridge resource state using the discovered hardware
551
* configuration */
552
sc->bus_res = bhndb_alloc_resources(sc->dev, sc->parent_dev, hwcfg);
553
if (sc->bus_res == NULL) {
554
device_printf(sc->dev, "failed to allocate bridge resource "
555
"state\n");
556
error = ENOMEM;
557
goto failed;
558
}
559
560
/* Add our bridged bus device */
561
sc->bus_dev = BUS_ADD_CHILD(dev, BHND_PROBE_BUS, "bhnd", DEVICE_UNIT_ANY);
562
if (sc->bus_dev == NULL) {
563
error = ENXIO;
564
goto failed;
565
}
566
567
dinfo = device_get_ivars(sc->bus_dev);
568
dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED;
569
570
/* We can now use bhndb to perform bridging of SYS_RES_MEMORY resources;
571
* we use this to instantiate an erom parser instance */
572
eio = bhnd_erom_iores_new(sc->bus_dev, 0);
573
if ((erom = bhnd_erom_alloc(erom_class, cid, eio)) == NULL) {
574
bhnd_erom_io_fini(eio);
575
error = ENXIO;
576
goto failed;
577
}
578
579
/* Populate our resource priority configuration */
580
hwprio = BHNDB_BUS_GET_HARDWARE_PRIO(sc->parent_dev, sc->dev);
581
error = bhndb_init_region_cfg(sc, erom, sc->bus_res, cores, ncores,
582
hwprio);
583
if (error) {
584
device_printf(sc->dev, "failed to initialize resource "
585
"priority configuration: %d\n", error);
586
goto failed;
587
}
588
589
/* Free our erom instance */
590
bhnd_erom_free(erom);
591
erom = NULL;
592
593
return (0);
594
595
failed:
596
BHNDB_LOCK_DESTROY(sc);
597
598
if (sc->bus_res != NULL)
599
bhndb_free_resources(sc->bus_res);
600
601
if (erom != NULL)
602
bhnd_erom_free(erom);
603
604
bhnd_service_registry_fini(&sc->services);
605
606
return (error);
607
}
608
609
/**
610
* Default bhndb(4) implementation of DEVICE_DETACH().
611
*
612
* This function detaches any child devices, and if successful, releases all
613
* resources held by the bridge device.
614
*/
615
int
616
bhndb_generic_detach(device_t dev)
617
{
618
struct bhndb_softc *sc;
619
int error;
620
621
sc = device_get_softc(dev);
622
623
/* Detach children */
624
if ((error = bus_generic_detach(dev)))
625
return (error);
626
627
/* Clean up our service registry */
628
if ((error = bhnd_service_registry_fini(&sc->services)))
629
return (error);
630
631
/* Clean up our driver state. */
632
bhndb_free_resources(sc->bus_res);
633
634
BHNDB_LOCK_DESTROY(sc);
635
636
return (0);
637
}
638
639
/**
640
* Default bhndb(4) implementation of DEVICE_SUSPEND().
641
*
642
* This function calls bus_generic_suspend() (or implements equivalent
643
* behavior).
644
*/
645
int
646
bhndb_generic_suspend(device_t dev)
647
{
648
return (bus_generic_suspend(dev));
649
}
650
651
/**
652
* Default bhndb(4) implementation of DEVICE_RESUME().
653
*
654
* This function calls bus_generic_resume() (or implements equivalent
655
* behavior).
656
*/
657
int
658
bhndb_generic_resume(device_t dev)
659
{
660
struct bhndb_softc *sc;
661
struct bhndb_resources *bus_res;
662
struct bhndb_dw_alloc *dwa;
663
int error;
664
665
sc = device_get_softc(dev);
666
bus_res = sc->bus_res;
667
668
/* Guarantee that all in-use dynamic register windows are mapped to
669
* their previously configured target address. */
670
BHNDB_LOCK(sc);
671
error = 0;
672
for (size_t i = 0; i < bus_res->dwa_count; i++) {
673
dwa = &bus_res->dw_alloc[i];
674
675
/* Skip regions that were not previously used */
676
if (bhndb_dw_is_free(bus_res, dwa) && dwa->target == 0x0)
677
continue;
678
679
/* Otherwise, ensure the register window is correct before
680
* any children attempt MMIO */
681
error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target);
682
if (error)
683
break;
684
}
685
BHNDB_UNLOCK(sc);
686
687
/* Error restoring hardware state; children cannot be safely resumed */
688
if (error) {
689
device_printf(dev, "Unable to restore hardware configuration; "
690
"cannot resume: %d\n", error);
691
return (error);
692
}
693
694
return (bus_generic_resume(dev));
695
}
696
697
/**
698
* Default implementation of BHNDB_SUSPEND_RESOURCE.
699
*/
700
static void
701
bhndb_suspend_resource(device_t dev, device_t child, int type,
702
struct resource *r)
703
{
704
struct bhndb_softc *sc;
705
struct bhndb_dw_alloc *dwa;
706
707
sc = device_get_softc(dev);
708
709
/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
710
if (type != SYS_RES_MEMORY)
711
return;
712
713
BHNDB_LOCK(sc);
714
dwa = bhndb_dw_find_resource(sc->bus_res, r);
715
if (dwa == NULL) {
716
BHNDB_UNLOCK(sc);
717
return;
718
}
719
720
if (BHNDB_DEBUG(PRIO))
721
device_printf(child, "suspend resource type=%d 0x%jx+0x%jx\n",
722
type, rman_get_start(r), rman_get_size(r));
723
724
/* Release the resource's window reference */
725
bhndb_dw_release(sc->bus_res, dwa, r);
726
BHNDB_UNLOCK(sc);
727
}
728
729
/**
730
* Default implementation of BHNDB_RESUME_RESOURCE.
731
*/
732
static int
733
bhndb_resume_resource(device_t dev, device_t child, int type,
734
struct resource *r)
735
{
736
struct bhndb_softc *sc;
737
738
sc = device_get_softc(dev);
739
740
/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
741
if (type != SYS_RES_MEMORY)
742
return (0);
743
744
/* Inactive resources don't require reallocation of bridge resources */
745
if (!(rman_get_flags(r) & RF_ACTIVE))
746
return (0);
747
748
if (BHNDB_DEBUG(PRIO))
749
device_printf(child, "resume resource type=%d 0x%jx+0x%jx\n",
750
type, rman_get_start(r), rman_get_size(r));
751
752
return (bhndb_try_activate_resource(sc, rman_get_device(r), r, NULL));
753
}
754
755
/**
756
* Default bhndb(4) implementation of BUS_READ_IVAR().
757
*/
758
static int
759
bhndb_read_ivar(device_t dev, device_t child, int index,
760
uintptr_t *result)
761
{
762
return (ENOENT);
763
}
764
765
/**
766
* Default bhndb(4) implementation of BUS_WRITE_IVAR().
767
*/
768
static int
769
bhndb_write_ivar(device_t dev, device_t child, int index,
770
uintptr_t value)
771
{
772
return (ENOENT);
773
}
774
775
/**
776
* Return the address space for the given @p child device.
777
*/
778
bhndb_addrspace
779
bhndb_get_addrspace(struct bhndb_softc *sc, device_t child)
780
{
781
struct bhndb_devinfo *dinfo;
782
device_t imd_dev;
783
784
/* Find the directly attached parent of the requesting device */
785
imd_dev = child;
786
while (imd_dev != NULL && device_get_parent(imd_dev) != sc->dev)
787
imd_dev = device_get_parent(imd_dev);
788
789
if (imd_dev == NULL)
790
panic("bhndb address space request for non-child device %s\n",
791
device_get_nameunit(child));
792
793
dinfo = device_get_ivars(imd_dev);
794
return (dinfo->addrspace);
795
}
796
797
/**
798
* Return the rman instance for a given resource @p type, if any.
799
*
800
* @param sc The bhndb device state.
801
* @param child The requesting child.
802
* @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...)
803
*/
804
static struct rman *
805
bhndb_get_rman(struct bhndb_softc *sc, device_t child, int type)
806
{
807
switch (bhndb_get_addrspace(sc, child)) {
808
case BHNDB_ADDRSPACE_NATIVE:
809
switch (type) {
810
case SYS_RES_MEMORY:
811
return (&sc->bus_res->ht_mem_rman);
812
case SYS_RES_IRQ:
813
return (NULL);
814
default:
815
return (NULL);
816
}
817
818
case BHNDB_ADDRSPACE_BRIDGED:
819
switch (type) {
820
case SYS_RES_MEMORY:
821
return (&sc->bus_res->br_mem_rman);
822
case SYS_RES_IRQ:
823
return (&sc->bus_res->br_irq_rman);
824
default:
825
return (NULL);
826
}
827
}
828
829
/* Quieten gcc */
830
return (NULL);
831
}
832
833
/**
834
* Default implementation of BUS_ADD_CHILD()
835
*/
836
static device_t
837
bhndb_add_child(device_t dev, u_int order, const char *name, int unit)
838
{
839
struct bhndb_devinfo *dinfo;
840
device_t child;
841
842
child = device_add_child_ordered(dev, order, name, unit);
843
if (child == NULL)
844
return (NULL);
845
846
dinfo = malloc(sizeof(struct bhndb_devinfo), M_BHND, M_NOWAIT);
847
if (dinfo == NULL) {
848
device_delete_child(dev, child);
849
return (NULL);
850
}
851
852
dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE;
853
resource_list_init(&dinfo->resources);
854
855
device_set_ivars(child, dinfo);
856
857
return (child);
858
}
859
860
/**
861
* Default implementation of BUS_CHILD_DELETED().
862
*/
863
static void
864
bhndb_child_deleted(device_t dev, device_t child)
865
{
866
struct bhndb_devinfo *dinfo = device_get_ivars(child);
867
if (dinfo != NULL) {
868
resource_list_free(&dinfo->resources);
869
free(dinfo, M_BHND);
870
}
871
872
device_set_ivars(child, NULL);
873
}
874
875
/**
876
* Default implementation of BHNDB_GET_CHIPID().
877
*/
878
static const struct bhnd_chipid *
879
bhndb_get_chipid(device_t dev, device_t child)
880
{
881
struct bhndb_softc *sc = device_get_softc(dev);
882
return (&sc->chipid);
883
}
884
885
/**
886
* Default implementation of BHNDB_IS_CORE_DISABLED().
887
*/
888
static bool
889
bhndb_is_core_disabled(device_t dev, device_t child,
890
struct bhnd_core_info *core)
891
{
892
struct bhndb_softc *sc;
893
894
sc = device_get_softc(dev);
895
896
/* Try to defer to the bhndb bus parent */
897
if (BHNDB_BUS_IS_CORE_DISABLED(sc->parent_dev, dev, core))
898
return (true);
899
900
/* Otherwise, we treat bridge-capable cores as unpopulated if they're
901
* not the configured host bridge */
902
if (BHND_DEVCLASS_SUPPORTS_HOSTB(bhnd_core_class(core)))
903
return (!bhnd_cores_equal(core, &sc->bridge_core));
904
905
/* Assume the core is populated */
906
return (false);
907
}
908
909
/**
910
* Default bhndb(4) implementation of BHNDB_GET_HOSTB_CORE().
911
*
912
* This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged
913
* bhnd(4) devices.
914
*/
915
static int
916
bhndb_get_hostb_core(device_t dev, device_t child, struct bhnd_core_info *core)
917
{
918
struct bhndb_softc *sc = device_get_softc(dev);
919
920
*core = sc->bridge_core;
921
return (0);
922
}
923
924
/**
925
* Default bhndb(4) implementation of BHND_BUS_GET_SERVICE_REGISTRY().
926
*/
927
static struct bhnd_service_registry *
928
bhndb_get_service_registry(device_t dev, device_t child)
929
{
930
struct bhndb_softc *sc = device_get_softc(dev);
931
932
return (&sc->services);
933
}
934
935
/**
936
* Default bhndb(4) implementation of BUS_ALLOC_RESOURCE().
937
*/
938
static struct resource *
939
bhndb_alloc_resource(device_t dev, device_t child, int type,
940
int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
941
{
942
struct bhndb_softc *sc;
943
struct resource_list_entry *rle;
944
struct resource *rv;
945
struct rman *rm;
946
int error;
947
bool passthrough, isdefault;
948
949
sc = device_get_softc(dev);
950
passthrough = (device_get_parent(child) != dev);
951
isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
952
rle = NULL;
953
954
/* Fetch the resource manager */
955
rm = bhndb_get_rman(sc, child, type);
956
if (rm == NULL) {
957
/* Delegate to our parent device's bus; the requested
958
* resource type isn't handled locally. */
959
return (BUS_ALLOC_RESOURCE(device_get_parent(sc->parent_dev),
960
child, type, rid, start, end, count, flags));
961
}
962
963
/* Populate defaults */
964
if (!passthrough && isdefault) {
965
/* Fetch the resource list entry. */
966
rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
967
type, *rid);
968
if (rle == NULL) {
969
device_printf(dev,
970
"default resource %#x type %d for child %s "
971
"not found\n", *rid, type,
972
device_get_nameunit(child));
973
974
return (NULL);
975
}
976
977
if (rle->res != NULL) {
978
device_printf(dev,
979
"resource entry %#x type %d for child %s is busy\n",
980
*rid, type, device_get_nameunit(child));
981
982
return (NULL);
983
}
984
985
start = rle->start;
986
end = rle->end;
987
count = ulmax(count, rle->count);
988
}
989
990
/* Validate resource addresses */
991
if (start > end || count > ((end - start) + 1))
992
return (NULL);
993
994
/* Make our reservation */
995
rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
996
child);
997
if (rv == NULL)
998
return (NULL);
999
1000
rman_set_rid(rv, *rid);
1001
rman_set_type(rv, type);
1002
1003
/* Activate */
1004
if (flags & RF_ACTIVE) {
1005
error = bus_activate_resource(child, type, *rid, rv);
1006
if (error) {
1007
device_printf(dev,
1008
"failed to activate entry %#x type %d for "
1009
"child %s: %d\n",
1010
*rid, type, device_get_nameunit(child), error);
1011
1012
rman_release_resource(rv);
1013
1014
return (NULL);
1015
}
1016
}
1017
1018
/* Update child's resource list entry */
1019
if (rle != NULL) {
1020
rle->res = rv;
1021
rle->start = rman_get_start(rv);
1022
rle->end = rman_get_end(rv);
1023
rle->count = rman_get_size(rv);
1024
}
1025
1026
return (rv);
1027
}
1028
1029
/**
1030
* Default bhndb(4) implementation of BUS_RELEASE_RESOURCE().
1031
*/
1032
static int
1033
bhndb_release_resource(device_t dev, device_t child, struct resource *r)
1034
{
1035
struct bhndb_softc *sc;
1036
struct resource_list_entry *rle = NULL;
1037
bool passthrough;
1038
int error;
1039
1040
sc = device_get_softc(dev);
1041
passthrough = (device_get_parent(child) != dev);
1042
1043
/* Delegate to our parent device's bus if the requested resource type
1044
* isn't handled locally. */
1045
if (bhndb_get_rman(sc, child, rman_get_type(r)) == NULL) {
1046
return (BUS_RELEASE_RESOURCE(device_get_parent(sc->parent_dev),
1047
child, r));
1048
}
1049
1050
/* Deactivate resources */
1051
if (rman_get_flags(r) & RF_ACTIVE) {
1052
error = BUS_DEACTIVATE_RESOURCE(dev, child, r);
1053
if (error)
1054
return (error);
1055
}
1056
1057
/* Check for resource list entry */
1058
if (!passthrough)
1059
rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
1060
rman_get_type(r), rman_get_rid(r));
1061
1062
if ((error = rman_release_resource(r)))
1063
return (error);
1064
1065
/* Clean resource list entry */
1066
if (rle != NULL)
1067
rle->res = NULL;
1068
1069
return (0);
1070
}
1071
1072
/**
1073
* Default bhndb(4) implementation of BUS_ADJUST_RESOURCE().
1074
*/
1075
static int
1076
bhndb_adjust_resource(device_t dev, device_t child,
1077
struct resource *r, rman_res_t start, rman_res_t end)
1078
{
1079
struct bhndb_softc *sc;
1080
struct rman *rm;
1081
rman_res_t mstart, mend;
1082
int error;
1083
1084
sc = device_get_softc(dev);
1085
error = 0;
1086
1087
/* Delegate to our parent device's bus if the requested resource type
1088
* isn't handled locally. */
1089
rm = bhndb_get_rman(sc, child, rman_get_type(r));
1090
if (rm == NULL) {
1091
return (BUS_ADJUST_RESOURCE(device_get_parent(sc->parent_dev),
1092
child, r, start, end));
1093
}
1094
1095
/* Verify basic constraints */
1096
if (end <= start)
1097
return (EINVAL);
1098
1099
if (!rman_is_region_manager(r, rm))
1100
return (ENXIO);
1101
1102
BHNDB_LOCK(sc);
1103
1104
/* If not active, allow any range permitted by the resource manager */
1105
if (!(rman_get_flags(r) & RF_ACTIVE))
1106
goto done;
1107
1108
/* Otherwise, the range is limited by the bridged resource mapping */
1109
error = bhndb_find_resource_limits(sc->bus_res, r, &mstart,
1110
&mend);
1111
if (error)
1112
goto done;
1113
1114
if (start < mstart || end > mend) {
1115
error = EINVAL;
1116
goto done;
1117
}
1118
1119
/* Fall through */
1120
done:
1121
if (!error)
1122
error = rman_adjust_resource(r, start, end);
1123
1124
BHNDB_UNLOCK(sc);
1125
return (error);
1126
}
1127
1128
/**
1129
* Initialize child resource @p r with a virtual address, tag, and handle
1130
* copied from @p parent, adjusted to contain only the range defined by
1131
* @p offsize and @p size.
1132
*
1133
* @param r The register to be initialized.
1134
* @param parent The parent bus resource that fully contains the subregion.
1135
* @param offset The subregion offset within @p parent.
1136
* @param size The subregion size.
1137
* @p r.
1138
*/
1139
static int
1140
bhndb_init_child_resource(struct resource *r,
1141
struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
1142
{
1143
bus_space_handle_t bh, child_bh;
1144
bus_space_tag_t bt;
1145
uintptr_t vaddr;
1146
int error;
1147
1148
/* Fetch the parent resource's real bus values */
1149
vaddr = (uintptr_t) rman_get_virtual(parent);
1150
bt = rman_get_bustag(parent);
1151
bh = rman_get_bushandle(parent);
1152
1153
/* Configure child resource with window-adjusted real bus values */
1154
vaddr += offset;
1155
error = bus_space_subregion(bt, bh, offset, size, &child_bh);
1156
if (error)
1157
return (error);
1158
1159
rman_set_virtual(r, (void *) vaddr);
1160
rman_set_bustag(r, bt);
1161
rman_set_bushandle(r, child_bh);
1162
1163
return (0);
1164
}
1165
1166
/**
1167
* Attempt activation of a fixed register window mapping for @p child.
1168
*
1169
* @param sc BHNDB device state.
1170
* @param region The static region definition capable of mapping @p r.
1171
* @param child A child requesting resource activation.
1172
* @param type Resource type.
1173
* @param rid Resource identifier.
1174
* @param r Resource to be activated.
1175
*
1176
* @retval 0 if @p r was activated successfully
1177
* @retval ENOENT if no fixed register window was found.
1178
* @retval non-zero if @p r could not be activated.
1179
*/
1180
static int
1181
bhndb_activate_static_region(struct bhndb_softc *sc,
1182
struct bhndb_region *region, device_t child, struct resource *r)
1183
{
1184
struct resource *bridge_res;
1185
const struct bhndb_regwin *win;
1186
bhnd_size_t parent_offset;
1187
rman_res_t r_start, r_size;
1188
int error;
1189
1190
win = region->static_regwin;
1191
1192
KASSERT(win != NULL && BHNDB_REGWIN_T_IS_STATIC(win->win_type),
1193
("can't activate non-static region"));
1194
1195
r_start = rman_get_start(r);
1196
r_size = rman_get_size(r);
1197
1198
/* Find the corresponding bridge resource */
1199
bridge_res = bhndb_host_resource_for_regwin(sc->bus_res->res, win);
1200
if (bridge_res == NULL)
1201
return (ENXIO);
1202
1203
/* Calculate subregion offset within the parent resource */
1204
parent_offset = r_start - region->addr;
1205
parent_offset += win->win_offset;
1206
1207
/* Configure resource with its real bus values. */
1208
error = bhndb_init_child_resource(r, bridge_res, parent_offset, r_size);
1209
if (error)
1210
return (error);
1211
1212
/* Mark active */
1213
if ((error = rman_activate_resource(r)))
1214
return (error);
1215
1216
return (0);
1217
}
1218
1219
/**
1220
* Attempt to allocate/retain a dynamic register window for @p r, returning
1221
* the retained window.
1222
*
1223
* @param sc The bhndb driver state.
1224
* @param r The resource for which a window will be retained.
1225
*/
1226
static struct bhndb_dw_alloc *
1227
bhndb_retain_dynamic_window(struct bhndb_softc *sc, struct resource *r)
1228
{
1229
struct bhndb_dw_alloc *dwa;
1230
rman_res_t r_start, r_size;
1231
int error;
1232
1233
BHNDB_LOCK_ASSERT(sc, MA_OWNED);
1234
1235
r_start = rman_get_start(r);
1236
r_size = rman_get_size(r);
1237
1238
/* Look for an existing dynamic window we can reference */
1239
dwa = bhndb_dw_find_mapping(sc->bus_res, r_start, r_size);
1240
if (dwa != NULL) {
1241
if (bhndb_dw_retain(sc->bus_res, dwa, r) == 0)
1242
return (dwa);
1243
1244
return (NULL);
1245
}
1246
1247
/* Otherwise, try to reserve a free window */
1248
dwa = bhndb_dw_next_free(sc->bus_res);
1249
if (dwa == NULL) {
1250
/* No free windows */
1251
return (NULL);
1252
}
1253
1254
/* Window must be large enough to map the entire resource */
1255
if (dwa->win->win_size < rman_get_size(r))
1256
return (NULL);
1257
1258
/* Set the window target */
1259
error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, rman_get_start(r),
1260
rman_get_size(r));
1261
if (error) {
1262
device_printf(sc->dev, "dynamic window initialization "
1263
"for 0x%llx-0x%llx failed: %d\n",
1264
(unsigned long long) r_start,
1265
(unsigned long long) r_start + r_size - 1,
1266
error);
1267
return (NULL);
1268
}
1269
1270
/* Add our reservation */
1271
if (bhndb_dw_retain(sc->bus_res, dwa, r))
1272
return (NULL);
1273
1274
return (dwa);
1275
}
1276
1277
/**
1278
* Activate a resource using any viable static or dynamic register window.
1279
*
1280
* @param sc The bhndb driver state.
1281
* @param child The child holding ownership of @p r.
1282
* @param r The resource to be activated
1283
* @param[out] indirect On error and if not NULL, will be set to 'true' if
1284
* the caller should instead use an indirect resource mapping.
1285
*
1286
* @retval 0 success
1287
* @retval non-zero activation failed.
1288
*/
1289
static int
1290
bhndb_try_activate_resource(struct bhndb_softc *sc, device_t child,
1291
struct resource *r, bool *indirect)
1292
{
1293
struct bhndb_region *region;
1294
struct bhndb_dw_alloc *dwa;
1295
bhndb_priority_t dw_priority;
1296
rman_res_t r_start, r_size;
1297
rman_res_t parent_offset;
1298
int error, type;
1299
1300
BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED);
1301
1302
if (indirect != NULL)
1303
*indirect = false;
1304
1305
type = rman_get_type(r);
1306
switch (type) {
1307
case SYS_RES_IRQ:
1308
/* IRQ resources are always directly mapped */
1309
return (rman_activate_resource(r));
1310
1311
case SYS_RES_MEMORY:
1312
/* Handled below */
1313
break;
1314
1315
default:
1316
device_printf(sc->dev, "unsupported resource type %d\n", type);
1317
return (ENXIO);
1318
}
1319
1320
/* Only MMIO resources can be mapped via register windows */
1321
KASSERT(type == SYS_RES_MEMORY, ("invalid type: %d", type));
1322
1323
r_start = rman_get_start(r);
1324
r_size = rman_get_size(r);
1325
1326
/* Activate native addrspace resources using the host address space */
1327
if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_NATIVE) {
1328
struct resource *parent;
1329
1330
/* Find the bridge resource referenced by the child */
1331
parent = bhndb_host_resource_for_range(sc->bus_res->res,
1332
type, r_start, r_size);
1333
if (parent == NULL) {
1334
device_printf(sc->dev, "host resource not found "
1335
"for 0x%llx-0x%llx\n",
1336
(unsigned long long) r_start,
1337
(unsigned long long) r_start + r_size - 1);
1338
return (ENOENT);
1339
}
1340
1341
/* Initialize child resource with the real bus values */
1342
error = bhndb_init_child_resource(r, parent,
1343
r_start - rman_get_start(parent), r_size);
1344
if (error)
1345
return (error);
1346
1347
/* Try to activate child resource */
1348
return (rman_activate_resource(r));
1349
}
1350
1351
/* Default to low priority */
1352
dw_priority = BHNDB_PRIORITY_LOW;
1353
1354
/* Look for a bus region matching the resource's address range */
1355
region = bhndb_find_resource_region(sc->bus_res, r_start, r_size);
1356
if (region != NULL)
1357
dw_priority = region->priority;
1358
1359
/* Prefer static mappings over consuming a dynamic windows. */
1360
if (region && region->static_regwin) {
1361
error = bhndb_activate_static_region(sc, region, child, r);
1362
if (error)
1363
device_printf(sc->dev, "static window allocation "
1364
"for 0x%llx-0x%llx failed\n",
1365
(unsigned long long) r_start,
1366
(unsigned long long) r_start + r_size - 1);
1367
return (error);
1368
}
1369
1370
/* A dynamic window will be required; is this resource high enough
1371
* priority to be reserved a dynamic window? */
1372
if (dw_priority < sc->bus_res->min_prio) {
1373
if (indirect)
1374
*indirect = true;
1375
1376
return (ENOMEM);
1377
}
1378
1379
/* Find and retain a usable window */
1380
BHNDB_LOCK(sc); {
1381
dwa = bhndb_retain_dynamic_window(sc, r);
1382
} BHNDB_UNLOCK(sc);
1383
1384
if (dwa == NULL) {
1385
if (indirect)
1386
*indirect = true;
1387
return (ENOMEM);
1388
}
1389
1390
/* Configure resource with its real bus values. */
1391
parent_offset = dwa->win->win_offset;
1392
parent_offset += r_start - dwa->target;
1393
1394
error = bhndb_init_child_resource(r, dwa->parent_res, parent_offset,
1395
dwa->win->win_size);
1396
if (error)
1397
goto failed;
1398
1399
/* Mark active */
1400
if ((error = rman_activate_resource(r)))
1401
goto failed;
1402
1403
return (0);
1404
1405
failed:
1406
/* Release our region allocation. */
1407
BHNDB_LOCK(sc);
1408
bhndb_dw_release(sc->bus_res, dwa, r);
1409
BHNDB_UNLOCK(sc);
1410
1411
return (error);
1412
}
1413
1414
/**
1415
* Default bhndb(4) implementation of BUS_ACTIVATE_RESOURCE().
1416
*/
1417
static int
1418
bhndb_activate_resource(device_t dev, device_t child, struct resource *r)
1419
{
1420
struct bhndb_softc *sc = device_get_softc(dev);
1421
1422
/* Delegate directly to our parent device's bus if the requested
1423
* resource type isn't handled locally. */
1424
if (bhndb_get_rman(sc, child, rman_get_type(r)) == NULL) {
1425
return (BUS_ACTIVATE_RESOURCE(device_get_parent(sc->parent_dev),
1426
child, r));
1427
}
1428
1429
return (bhndb_try_activate_resource(sc, child, r, NULL));
1430
}
1431
1432
/**
1433
* Default bhndb(4) implementation of BUS_DEACTIVATE_RESOURCE().
1434
*/
1435
static int
1436
bhndb_deactivate_resource(device_t dev, device_t child, struct resource *r)
1437
{
1438
struct bhndb_dw_alloc *dwa;
1439
struct bhndb_softc *sc;
1440
struct rman *rm;
1441
int error, type;
1442
1443
sc = device_get_softc(dev);
1444
type = rman_get_type(r);
1445
1446
/* Delegate directly to our parent device's bus if the requested
1447
* resource type isn't handled locally. */
1448
rm = bhndb_get_rman(sc, child, type);
1449
if (rm == NULL) {
1450
return (BUS_DEACTIVATE_RESOURCE(
1451
device_get_parent(sc->parent_dev), child, r));
1452
}
1453
1454
/* Mark inactive */
1455
if ((error = rman_deactivate_resource(r)))
1456
return (error);
1457
1458
switch (type) {
1459
case SYS_RES_IRQ:
1460
/* No bridge-level state to be freed */
1461
return (0);
1462
1463
case SYS_RES_MEMORY:
1464
/* Free any dynamic window allocation. */
1465
if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) {
1466
BHNDB_LOCK(sc);
1467
dwa = bhndb_dw_find_resource(sc->bus_res, r);
1468
if (dwa != NULL)
1469
bhndb_dw_release(sc->bus_res, dwa, r);
1470
BHNDB_UNLOCK(sc);
1471
}
1472
1473
return (0);
1474
1475
default:
1476
device_printf(dev, "unsupported resource type %d\n", type);
1477
return (ENXIO);
1478
}
1479
}
1480
1481
/**
1482
* Default bhndb(4) implementation of BUS_GET_RESOURCE_LIST().
1483
*/
1484
static struct resource_list *
1485
bhndb_get_resource_list(device_t dev, device_t child)
1486
{
1487
struct bhndb_devinfo *dinfo = device_get_ivars(child);
1488
return (&dinfo->resources);
1489
}
1490
1491
/**
1492
* Default bhndb(4) implementation of BHND_BUS_ACTIVATE_RESOURCE().
1493
*
1494
* For BHNDB_ADDRSPACE_NATIVE children, all resources are activated as direct
1495
* resources via BUS_ACTIVATE_RESOURCE().
1496
*
1497
* For BHNDB_ADDRSPACE_BRIDGED children, the resource priority is determined,
1498
* and if possible, the resource is activated as a direct resource. For example,
1499
* depending on resource priority and bridge resource availability, this
1500
* function will attempt to activate SYS_RES_MEMORY resources using either a
1501
* static register window, a dynamic register window, or it will configure @p r
1502
* as an indirect resource -- in that order.
1503
*/
1504
static int
1505
bhndb_activate_bhnd_resource(device_t dev, device_t child,
1506
int type, int rid, struct bhnd_resource *r)
1507
{
1508
struct bhndb_softc *sc;
1509
struct bhndb_region *region;
1510
bhndb_priority_t r_prio;
1511
rman_res_t r_start, r_size;
1512
int error;
1513
bool indirect;
1514
1515
KASSERT(!r->direct,
1516
("direct flag set on inactive resource"));
1517
1518
KASSERT(!(rman_get_flags(r->res) & RF_ACTIVE),
1519
("RF_ACTIVE set on inactive resource"));
1520
1521
sc = device_get_softc(dev);
1522
1523
/* Delegate directly to BUS_ACTIVATE_RESOURCE() if the requested
1524
* resource type isn't handled locally. */
1525
if (bhndb_get_rman(sc, child, type) == NULL) {
1526
error = BUS_ACTIVATE_RESOURCE(dev, child, r->res);
1527
if (error == 0)
1528
r->direct = true;
1529
return (error);
1530
}
1531
1532
r_start = rman_get_start(r->res);
1533
r_size = rman_get_size(r->res);
1534
1535
/* Determine the resource priority of bridged resources, and skip direct
1536
* allocation if the priority is too low. */
1537
if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) {
1538
switch (type) {
1539
case SYS_RES_IRQ:
1540
/* IRQ resources are always direct */
1541
break;
1542
1543
case SYS_RES_MEMORY:
1544
region = bhndb_find_resource_region(sc->bus_res,
1545
r_start, r_size);
1546
if (region != NULL)
1547
r_prio = region->priority;
1548
else
1549
r_prio = BHNDB_PRIORITY_NONE;
1550
1551
/* If less than the minimum dynamic window priority,
1552
* this resource should always be indirect. */
1553
if (r_prio < sc->bus_res->min_prio)
1554
return (0);
1555
1556
break;
1557
1558
default:
1559
device_printf(dev, "unsupported resource type %d\n",
1560
type);
1561
return (ENXIO);
1562
}
1563
}
1564
1565
/* Attempt direct activation */
1566
error = bhndb_try_activate_resource(sc, child, r->res, &indirect);
1567
if (!error) {
1568
r->direct = true;
1569
} else if (indirect) {
1570
/* The request was valid, but no viable register window is
1571
* available; indirection must be employed. */
1572
error = 0;
1573
r->direct = false;
1574
}
1575
1576
if (BHNDB_DEBUG(PRIO) &&
1577
bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED)
1578
{
1579
device_printf(child, "activated 0x%llx-0x%llx as %s "
1580
"resource\n",
1581
(unsigned long long) r_start,
1582
(unsigned long long) r_start + r_size - 1,
1583
r->direct ? "direct" : "indirect");
1584
}
1585
1586
return (error);
1587
}
1588
1589
/**
1590
* Default bhndb(4) implementation of BHND_BUS_DEACTIVATE_RESOURCE().
1591
*/
1592
static int
1593
bhndb_deactivate_bhnd_resource(device_t dev, device_t child,
1594
int type, int rid, struct bhnd_resource *r)
1595
{
1596
int error;
1597
1598
/* Indirect resources don't require activation */
1599
if (!r->direct)
1600
return (0);
1601
1602
KASSERT(rman_get_flags(r->res) & RF_ACTIVE,
1603
("RF_ACTIVE not set on direct resource"));
1604
1605
/* Perform deactivation */
1606
error = BUS_DEACTIVATE_RESOURCE(dev, child, r->res);
1607
if (!error)
1608
r->direct = false;
1609
1610
return (error);
1611
}
1612
1613
/**
1614
* Find the best available bridge resource allocation record capable of handling
1615
* bus I/O requests of @p size at @p addr.
1616
*
1617
* In order of preference, this function will either:
1618
*
1619
* - Configure and return a free allocation record
1620
* - Return an existing allocation record mapping the requested space, or
1621
* - Steal, configure, and return an in-use allocation record.
1622
*
1623
* Will panic if a usable record cannot be found.
1624
*
1625
* @param sc Bridge driver state.
1626
* @param addr The I/O target address.
1627
* @param size The size of the I/O operation to be performed at @p addr.
1628
* @param[out] borrowed Set to true if the allocation record was borrowed to
1629
* fulfill this request; the borrowed record maps the target address range,
1630
* and must not be modified.
1631
* @param[out] stolen Set to true if the allocation record was stolen to fulfill
1632
* this request. If a stolen allocation record is returned,
1633
* bhndb_io_resource_restore() must be called upon completion of the bus I/O
1634
* request.
1635
* @param[out] restore If the allocation record was stolen, this will be set
1636
* to the target that must be restored.
1637
*/
1638
static struct bhndb_dw_alloc *
1639
bhndb_io_resource_get_window(struct bhndb_softc *sc, bus_addr_t addr,
1640
bus_size_t size, bool *borrowed, bool *stolen, bus_addr_t *restore)
1641
{
1642
struct bhndb_resources *br;
1643
struct bhndb_dw_alloc *dwa;
1644
struct bhndb_region *region;
1645
1646
BHNDB_LOCK_ASSERT(sc, MA_OWNED);
1647
1648
br = sc->bus_res;
1649
*borrowed = false;
1650
*stolen = false;
1651
1652
/* Try to fetch a free window */
1653
if ((dwa = bhndb_dw_next_free(br)) != NULL)
1654
return (dwa);
1655
1656
/* Search for an existing dynamic mapping of this address range.
1657
* Static regions are not searched, as a statically mapped
1658
* region would never be allocated as an indirect resource. */
1659
for (size_t i = 0; i < br->dwa_count; i++) {
1660
const struct bhndb_regwin *win;
1661
1662
dwa = &br->dw_alloc[i];
1663
win = dwa->win;
1664
1665
KASSERT(win->win_type == BHNDB_REGWIN_T_DYN,
1666
("invalid register window type"));
1667
1668
/* Verify the range */
1669
if (addr < dwa->target)
1670
continue;
1671
1672
if (addr + size > dwa->target + win->win_size)
1673
continue;
1674
1675
/* Found */
1676
*borrowed = true;
1677
return (dwa);
1678
}
1679
1680
/* Try to steal a window; this should only be required on very early
1681
* PCI_V0 (BCM4318, etc) Wi-Fi chipsets */
1682
region = bhndb_find_resource_region(br, addr, size);
1683
if (region == NULL)
1684
return (NULL);
1685
1686
if ((region->alloc_flags & BHNDB_ALLOC_FULFILL_ON_OVERCOMMIT) == 0)
1687
return (NULL);
1688
1689
/* Steal a window. This acquires our backing spinlock, disabling
1690
* interrupts; the spinlock will be released by
1691
* bhndb_dw_return_stolen() */
1692
if ((dwa = bhndb_dw_steal(br, restore)) != NULL) {
1693
*stolen = true;
1694
return (dwa);
1695
}
1696
1697
panic("register windows exhausted attempting to map 0x%llx-0x%llx\n",
1698
(unsigned long long) addr, (unsigned long long) addr+size-1);
1699
}
1700
1701
/**
1702
* Return a borrowed reference to a bridge resource allocation record capable
1703
* of handling bus I/O requests of @p size at @p addr.
1704
*
1705
* This will either return a reference to an existing allocation record mapping
1706
* the requested space, or will configure and return a free allocation record.
1707
*
1708
* Will panic if a usable record cannot be found.
1709
*
1710
* @param sc Bridge driver state.
1711
* @param addr The I/O target address.
1712
* @param size The size of the I/O operation to be performed at @p addr.
1713
* @param[out] offset The offset within the returned resource at which
1714
* to perform the I/O request.
1715
* @param[out] stolen Set to true if the allocation record was stolen to fulfill
1716
* this request. If a stolen allocation record is returned,
1717
* bhndb_io_resource_restore() must be called upon completion of the bus I/O
1718
* request.
1719
* @param[out] restore If the allocation record was stolen, this will be set
1720
* to the target that must be restored.
1721
*/
1722
static inline struct bhndb_dw_alloc *
1723
bhndb_io_resource(struct bhndb_softc *sc, bus_addr_t addr, bus_size_t size,
1724
bus_size_t *offset, bool *stolen, bus_addr_t *restore)
1725
{
1726
struct bhndb_dw_alloc *dwa;
1727
bool borrowed;
1728
int error;
1729
1730
BHNDB_LOCK_ASSERT(sc, MA_OWNED);
1731
1732
dwa = bhndb_io_resource_get_window(sc, addr, size, &borrowed, stolen,
1733
restore);
1734
1735
/* Adjust the window if the I/O request won't fit in the current
1736
* target range. */
1737
if (addr < dwa->target ||
1738
addr > dwa->target + dwa->win->win_size ||
1739
(dwa->target + dwa->win->win_size) - addr < size)
1740
{
1741
/* Cannot modify target of borrowed windows */
1742
if (borrowed) {
1743
panic("borrowed register window does not map expected "
1744
"range 0x%llx-0x%llx\n",
1745
(unsigned long long) addr,
1746
(unsigned long long) addr+size-1);
1747
}
1748
1749
error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, addr,
1750
size);
1751
if (error) {
1752
panic("failed to set register window target mapping "
1753
"0x%llx-0x%llx\n",
1754
(unsigned long long) addr,
1755
(unsigned long long) addr+size-1);
1756
}
1757
}
1758
1759
/* Calculate the offset and return */
1760
*offset = (addr - dwa->target) + dwa->win->win_offset;
1761
return (dwa);
1762
}
1763
1764
/*
1765
* BHND_BUS_(READ|WRITE_* implementations
1766
*/
1767
1768
/* bhndb_bus_(read|write) common implementation */
1769
#define BHNDB_IO_COMMON_SETUP(_io_size) \
1770
struct bhndb_softc *sc; \
1771
struct bhndb_dw_alloc *dwa; \
1772
struct resource *io_res; \
1773
bus_size_t io_offset; \
1774
bus_addr_t restore; \
1775
bool stolen; \
1776
\
1777
sc = device_get_softc(dev); \
1778
\
1779
BHNDB_LOCK(sc); \
1780
dwa = bhndb_io_resource(sc, rman_get_start(r->res) + \
1781
offset, _io_size, &io_offset, &stolen, &restore); \
1782
io_res = dwa->parent_res; \
1783
\
1784
KASSERT(!r->direct, \
1785
("bhnd_bus slow path used for direct resource")); \
1786
\
1787
KASSERT(rman_get_flags(io_res) & RF_ACTIVE, \
1788
("i/o resource is not active"));
1789
1790
#define BHNDB_IO_COMMON_TEARDOWN() \
1791
if (stolen) { \
1792
bhndb_dw_return_stolen(sc->dev, sc->bus_res, \
1793
dwa, restore); \
1794
} \
1795
BHNDB_UNLOCK(sc);
1796
1797
/* Defines a bhndb_bus_read_* method implementation */
1798
#define BHNDB_IO_READ(_type, _name) \
1799
static _type \
1800
bhndb_bus_read_ ## _name (device_t dev, device_t child, \
1801
struct bhnd_resource *r, bus_size_t offset) \
1802
{ \
1803
_type v; \
1804
BHNDB_IO_COMMON_SETUP(sizeof(_type)); \
1805
v = bus_read_ ## _name (io_res, io_offset); \
1806
BHNDB_IO_COMMON_TEARDOWN(); \
1807
\
1808
return (v); \
1809
}
1810
1811
/* Defines a bhndb_bus_write_* method implementation */
1812
#define BHNDB_IO_WRITE(_type, _name) \
1813
static void \
1814
bhndb_bus_write_ ## _name (device_t dev, device_t child, \
1815
struct bhnd_resource *r, bus_size_t offset, _type value) \
1816
{ \
1817
BHNDB_IO_COMMON_SETUP(sizeof(_type)); \
1818
bus_write_ ## _name (io_res, io_offset, value); \
1819
BHNDB_IO_COMMON_TEARDOWN(); \
1820
}
1821
1822
/* Defines a bhndb_bus_(read|write|set)_(multi|region)_* method */
1823
#define BHNDB_IO_MISC(_type, _ptr, _op, _size) \
1824
static void \
1825
bhndb_bus_ ## _op ## _ ## _size (device_t dev, \
1826
device_t child, struct bhnd_resource *r, bus_size_t offset, \
1827
_type _ptr datap, bus_size_t count) \
1828
{ \
1829
BHNDB_IO_COMMON_SETUP(sizeof(_type) * count); \
1830
bus_ ## _op ## _ ## _size (io_res, io_offset, \
1831
datap, count); \
1832
BHNDB_IO_COMMON_TEARDOWN(); \
1833
}
1834
1835
/* Defines a complete set of read/write methods */
1836
#define BHNDB_IO_METHODS(_type, _size) \
1837
BHNDB_IO_READ(_type, _size) \
1838
BHNDB_IO_WRITE(_type, _size) \
1839
\
1840
BHNDB_IO_READ(_type, stream_ ## _size) \
1841
BHNDB_IO_WRITE(_type, stream_ ## _size) \
1842
\
1843
BHNDB_IO_MISC(_type, *, read_multi, _size) \
1844
BHNDB_IO_MISC(_type, *, write_multi, _size) \
1845
\
1846
BHNDB_IO_MISC(_type, *, read_multi_stream, _size) \
1847
BHNDB_IO_MISC(_type, *, write_multi_stream, _size) \
1848
\
1849
BHNDB_IO_MISC(_type, , set_multi, _size) \
1850
BHNDB_IO_MISC(_type, , set_region, _size) \
1851
BHNDB_IO_MISC(_type, *, read_region, _size) \
1852
BHNDB_IO_MISC(_type, *, write_region, _size) \
1853
\
1854
BHNDB_IO_MISC(_type, *, read_region_stream, _size) \
1855
BHNDB_IO_MISC(_type, *, write_region_stream, _size)
1856
1857
BHNDB_IO_METHODS(uint8_t, 1);
1858
BHNDB_IO_METHODS(uint16_t, 2);
1859
BHNDB_IO_METHODS(uint32_t, 4);
1860
1861
/**
1862
* Default bhndb(4) implementation of BHND_BUS_BARRIER().
1863
*/
1864
static void
1865
bhndb_bus_barrier(device_t dev, device_t child, struct bhnd_resource *r,
1866
bus_size_t offset, bus_size_t length, int flags)
1867
{
1868
BHNDB_IO_COMMON_SETUP(length);
1869
1870
bus_barrier(io_res, io_offset + offset, length, flags);
1871
1872
BHNDB_IO_COMMON_TEARDOWN();
1873
}
1874
1875
/**
1876
* Default bhndb(4) implementation of BHND_MAP_INTR().
1877
*/
1878
static int
1879
bhndb_bhnd_map_intr(device_t dev, device_t child, u_int intr, rman_res_t *irq)
1880
{
1881
u_int ivec;
1882
int error;
1883
1884
/* Is the intr valid? */
1885
if (intr >= bhnd_get_intr_count(child))
1886
return (EINVAL);
1887
1888
/* Fetch the interrupt vector */
1889
if ((error = bhnd_get_intr_ivec(child, intr, &ivec)))
1890
return (error);
1891
1892
/* Map directly to the actual backplane interrupt vector */
1893
*irq = ivec;
1894
1895
return (0);
1896
}
1897
1898
/**
1899
* Default bhndb(4) implementation of BHND_UNMAP_INTR().
1900
*/
1901
static void
1902
bhndb_bhnd_unmap_intr(device_t dev, device_t child, rman_res_t irq)
1903
{
1904
/* No state to clean up */
1905
}
1906
1907
/**
1908
* Default bhndb(4) implementation of BUS_SETUP_INTR().
1909
*/
1910
static int
1911
bhndb_setup_intr(device_t dev, device_t child, struct resource *r,
1912
int flags, driver_filter_t filter, driver_intr_t handler, void *arg,
1913
void **cookiep)
1914
{
1915
struct bhndb_softc *sc;
1916
struct bhndb_intr_isrc *isrc;
1917
struct bhndb_intr_handler *ih;
1918
int error;
1919
1920
sc = device_get_softc(dev);
1921
1922
/* Fetch the isrc */
1923
if ((error = BHNDB_MAP_INTR_ISRC(dev, r, &isrc))) {
1924
device_printf(dev, "failed to fetch isrc: %d\n", error);
1925
return (error);
1926
}
1927
1928
/* Allocate new ihandler entry */
1929
ih = bhndb_alloc_intr_handler(child, r, isrc);
1930
if (ih == NULL)
1931
return (ENOMEM);
1932
1933
/* Perform actual interrupt setup via the host isrc */
1934
error = bus_setup_intr(isrc->is_owner, isrc->is_res, flags, filter,
1935
handler, arg, &ih->ih_cookiep);
1936
if (error) {
1937
bhndb_free_intr_handler(ih);
1938
return (error);
1939
}
1940
1941
/* Add to our interrupt handler list */
1942
BHNDB_LOCK(sc);
1943
bhndb_register_intr_handler(sc->bus_res, ih);
1944
BHNDB_UNLOCK(sc);
1945
1946
/* Provide the interrupt handler entry as our cookiep value */
1947
*cookiep = ih;
1948
return (0);
1949
}
1950
1951
/**
1952
* Default bhndb(4) implementation of BUS_TEARDOWN_INTR().
1953
*/
1954
static int
1955
bhndb_teardown_intr(device_t dev, device_t child, struct resource *r,
1956
void *cookiep)
1957
{
1958
struct bhndb_softc *sc;
1959
struct bhndb_intr_handler *ih;
1960
struct bhndb_intr_isrc *isrc;
1961
int error;
1962
1963
sc = device_get_softc(dev);
1964
1965
/* Locate and claim ownership of the interrupt handler entry */
1966
BHNDB_LOCK(sc);
1967
1968
ih = bhndb_find_intr_handler(sc->bus_res, cookiep);
1969
if (ih == NULL) {
1970
panic("%s requested teardown of invalid cookiep %p",
1971
device_get_nameunit(child), cookiep);
1972
}
1973
1974
bhndb_deregister_intr_handler(sc->bus_res, ih);
1975
1976
BHNDB_UNLOCK(sc);
1977
1978
/* Perform actual interrupt teardown via the host isrc */
1979
isrc = ih->ih_isrc;
1980
error = bus_teardown_intr(isrc->is_owner, isrc->is_res, ih->ih_cookiep);
1981
if (error) {
1982
/* If teardown fails, we need to reinsert the handler entry
1983
* to allow later teardown */
1984
BHNDB_LOCK(sc);
1985
bhndb_register_intr_handler(sc->bus_res, ih);
1986
BHNDB_UNLOCK(sc);
1987
1988
return (error);
1989
}
1990
1991
/* Free the entry */
1992
bhndb_free_intr_handler(ih);
1993
return (0);
1994
}
1995
1996
/**
1997
* Default bhndb(4) implementation of BUS_BIND_INTR().
1998
*/
1999
static int
2000
bhndb_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
2001
{
2002
struct bhndb_softc *sc;
2003
struct bhndb_intr_handler *ih;
2004
struct bhndb_intr_isrc *isrc;
2005
2006
sc = device_get_softc(dev);
2007
isrc = NULL;
2008
2009
/* Fetch the isrc corresponding to the child IRQ resource */
2010
BHNDB_LOCK(sc);
2011
STAILQ_FOREACH(ih, &sc->bus_res->bus_intrs, ih_link) {
2012
if (ih->ih_res == irq) {
2013
isrc = ih->ih_isrc;
2014
break;
2015
}
2016
}
2017
BHNDB_UNLOCK(sc);
2018
2019
if (isrc == NULL) {
2020
panic("%s requested bind of invalid irq %#jx-%#jx",
2021
device_get_nameunit(child), rman_get_start(irq),
2022
rman_get_end(irq));
2023
}
2024
2025
/* Perform actual bind via the host isrc */
2026
return (bus_bind_intr(isrc->is_owner, isrc->is_res, cpu));
2027
}
2028
2029
/**
2030
* Default bhndb(4) implementation of BUS_DESCRIBE_INTR().
2031
*/
2032
static int
2033
bhndb_describe_intr(device_t dev, device_t child, struct resource *irq,
2034
void *cookie, const char *descr)
2035
{
2036
struct bhndb_softc *sc;
2037
struct bhndb_intr_handler *ih;
2038
struct bhndb_intr_isrc *isrc;
2039
2040
sc = device_get_softc(dev);
2041
2042
/* Locate the interrupt handler entry; the caller owns the handler
2043
* reference, and thus our entry is guaranteed to remain valid after
2044
* we drop out lock below. */
2045
BHNDB_LOCK(sc);
2046
2047
ih = bhndb_find_intr_handler(sc->bus_res, cookie);
2048
if (ih == NULL) {
2049
panic("%s requested invalid cookiep %p",
2050
device_get_nameunit(child), cookie);
2051
}
2052
2053
isrc = ih->ih_isrc;
2054
2055
BHNDB_UNLOCK(sc);
2056
2057
/* Perform the actual request via the host isrc */
2058
return (BUS_DESCRIBE_INTR(device_get_parent(isrc->is_owner),
2059
isrc->is_owner, isrc->is_res, ih->ih_cookiep, descr));
2060
}
2061
2062
/**
2063
* Default bhndb(4) implementation of BUS_CONFIG_INTR().
2064
*/
2065
static int
2066
bhndb_config_intr(device_t dev, int irq, enum intr_trigger trig,
2067
enum intr_polarity pol)
2068
{
2069
/* Unsupported */
2070
return (ENXIO);
2071
}
2072
2073
/**
2074
* Default bhndb(4) implementation of BUS_REMAP_INTR().
2075
*/
2076
static int
2077
bhndb_remap_intr(device_t dev, device_t child, u_int irq)
2078
{
2079
/* Unsupported */
2080
return (ENXIO);
2081
}
2082
2083
/**
2084
* Default bhndb(4) implementation of BHND_BUS_GET_DMA_TRANSLATION().
2085
*/
2086
static inline int
2087
bhndb_get_dma_translation(device_t dev, device_t child, u_int width,
2088
uint32_t flags, bus_dma_tag_t *dmat,
2089
struct bhnd_dma_translation *translation)
2090
{
2091
struct bhndb_softc *sc;
2092
const struct bhndb_hwcfg *hwcfg;
2093
const struct bhnd_dma_translation *match;
2094
bus_dma_tag_t match_dmat;
2095
bhnd_addr_t addr_mask, match_addr_mask;
2096
2097
sc = device_get_softc(dev);
2098
hwcfg = sc->bus_res->cfg;
2099
2100
/* Is DMA supported? */
2101
if (sc->bus_res->res->dma_tags == NULL)
2102
return (ENODEV);
2103
2104
/* Is the requested width supported? */
2105
if (width > BHND_DMA_ADDR_32BIT) {
2106
/* Backplane must support 64-bit addressing */
2107
if (!(sc->chipid.chip_caps & BHND_CAP_BP64))
2108
width = BHND_DMA_ADDR_32BIT;
2109
}
2110
2111
/* Find the best matching descriptor for the requested width */
2112
addr_mask = BHND_DMA_ADDR_BITMASK(width);
2113
2114
match = NULL;
2115
match_addr_mask = 0x0;
2116
match_dmat = NULL;
2117
2118
for (size_t i = 0; i < sc->bus_res->res->num_dma_tags; i++) {
2119
const struct bhnd_dma_translation *dwin;
2120
bhnd_addr_t masked;
2121
2122
dwin = &hwcfg->dma_translations[i];
2123
2124
/* The base address must be device addressable */
2125
if ((dwin->base_addr & addr_mask) != dwin->base_addr)
2126
continue;
2127
2128
/* The flags must match */
2129
if ((dwin->flags & flags) != flags)
2130
continue;
2131
2132
/* The window must cover at least part of our addressable
2133
* range */
2134
masked = (dwin->addr_mask | dwin->addrext_mask) & addr_mask;
2135
if (masked == 0)
2136
continue;
2137
2138
/* Is this a better match? */
2139
if (match == NULL || masked > match_addr_mask) {
2140
match = dwin;
2141
match_addr_mask = masked;
2142
match_dmat = sc->bus_res->res->dma_tags[i];
2143
}
2144
}
2145
2146
if (match == NULL || match_addr_mask == 0)
2147
return (ENOENT);
2148
2149
if (dmat != NULL)
2150
*dmat = match_dmat;
2151
2152
if (translation != NULL)
2153
*translation = *match;
2154
2155
return (0);
2156
}
2157
2158
/**
2159
* Default bhndb(4) implementation of BUS_GET_DMA_TAG().
2160
*/
2161
static bus_dma_tag_t
2162
bhndb_get_dma_tag(device_t dev, device_t child)
2163
{
2164
struct bhndb_softc *sc = device_get_softc(dev);
2165
2166
/*
2167
* A bridge may have multiple DMA translation descriptors, each with
2168
* their own incompatible restrictions; drivers should in general call
2169
* BHND_BUS_GET_DMA_TRANSLATION() to fetch both the best available DMA
2170
* translation, and its corresponding DMA tag.
2171
*
2172
* Child drivers that do not use BHND_BUS_GET_DMA_TRANSLATION() are
2173
* responsible for creating their own restricted DMA tag; since we
2174
* cannot do this for them in BUS_GET_DMA_TAG(), we simply return the
2175
* bridge parent's DMA tag directly;
2176
*/
2177
return (bus_get_dma_tag(sc->parent_dev));
2178
}
2179
2180
static device_method_t bhndb_methods[] = {
2181
/* Device interface */ \
2182
DEVMETHOD(device_probe, bhndb_generic_probe),
2183
DEVMETHOD(device_detach, bhndb_generic_detach),
2184
DEVMETHOD(device_shutdown, bus_generic_shutdown),
2185
DEVMETHOD(device_suspend, bhndb_generic_suspend),
2186
DEVMETHOD(device_resume, bhndb_generic_resume),
2187
2188
/* Bus interface */
2189
DEVMETHOD(bus_probe_nomatch, bhndb_probe_nomatch),
2190
DEVMETHOD(bus_print_child, bhndb_print_child),
2191
DEVMETHOD(bus_child_location, bhndb_child_location),
2192
DEVMETHOD(bus_add_child, bhndb_add_child),
2193
DEVMETHOD(bus_child_deleted, bhndb_child_deleted),
2194
2195
DEVMETHOD(bus_alloc_resource, bhndb_alloc_resource),
2196
DEVMETHOD(bus_release_resource, bhndb_release_resource),
2197
DEVMETHOD(bus_activate_resource, bhndb_activate_resource),
2198
DEVMETHOD(bus_deactivate_resource, bhndb_deactivate_resource),
2199
2200
DEVMETHOD(bus_setup_intr, bhndb_setup_intr),
2201
DEVMETHOD(bus_teardown_intr, bhndb_teardown_intr),
2202
DEVMETHOD(bus_config_intr, bhndb_config_intr),
2203
DEVMETHOD(bus_bind_intr, bhndb_bind_intr),
2204
DEVMETHOD(bus_describe_intr, bhndb_describe_intr),
2205
DEVMETHOD(bus_remap_intr, bhndb_remap_intr),
2206
2207
DEVMETHOD(bus_get_dma_tag, bhndb_get_dma_tag),
2208
2209
DEVMETHOD(bus_adjust_resource, bhndb_adjust_resource),
2210
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
2211
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
2212
DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
2213
DEVMETHOD(bus_get_resource_list, bhndb_get_resource_list),
2214
2215
DEVMETHOD(bus_read_ivar, bhndb_read_ivar),
2216
DEVMETHOD(bus_write_ivar, bhndb_write_ivar),
2217
2218
/* BHNDB interface */
2219
DEVMETHOD(bhndb_get_chipid, bhndb_get_chipid),
2220
DEVMETHOD(bhndb_is_core_disabled, bhndb_is_core_disabled),
2221
DEVMETHOD(bhndb_get_hostb_core, bhndb_get_hostb_core),
2222
DEVMETHOD(bhndb_suspend_resource, bhndb_suspend_resource),
2223
DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource),
2224
2225
/* BHND interface */
2226
DEVMETHOD(bhnd_bus_get_chipid, bhndb_get_chipid),
2227
DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource),
2228
DEVMETHOD(bhnd_bus_deactivate_resource, bhndb_deactivate_bhnd_resource),
2229
DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var),
2230
DEVMETHOD(bhnd_bus_map_intr, bhndb_bhnd_map_intr),
2231
DEVMETHOD(bhnd_bus_unmap_intr, bhndb_bhnd_unmap_intr),
2232
DEVMETHOD(bhnd_bus_get_dma_translation, bhndb_get_dma_translation),
2233
2234
DEVMETHOD(bhnd_bus_get_service_registry,bhndb_get_service_registry),
2235
DEVMETHOD(bhnd_bus_register_provider, bhnd_bus_generic_sr_register_provider),
2236
DEVMETHOD(bhnd_bus_deregister_provider, bhnd_bus_generic_sr_deregister_provider),
2237
DEVMETHOD(bhnd_bus_retain_provider, bhnd_bus_generic_sr_retain_provider),
2238
DEVMETHOD(bhnd_bus_release_provider, bhnd_bus_generic_sr_release_provider),
2239
2240
DEVMETHOD(bhnd_bus_read_1, bhndb_bus_read_1),
2241
DEVMETHOD(bhnd_bus_read_2, bhndb_bus_read_2),
2242
DEVMETHOD(bhnd_bus_read_4, bhndb_bus_read_4),
2243
DEVMETHOD(bhnd_bus_write_1, bhndb_bus_write_1),
2244
DEVMETHOD(bhnd_bus_write_2, bhndb_bus_write_2),
2245
DEVMETHOD(bhnd_bus_write_4, bhndb_bus_write_4),
2246
2247
DEVMETHOD(bhnd_bus_read_stream_1, bhndb_bus_read_stream_1),
2248
DEVMETHOD(bhnd_bus_read_stream_2, bhndb_bus_read_stream_2),
2249
DEVMETHOD(bhnd_bus_read_stream_4, bhndb_bus_read_stream_4),
2250
DEVMETHOD(bhnd_bus_write_stream_1, bhndb_bus_write_stream_1),
2251
DEVMETHOD(bhnd_bus_write_stream_2, bhndb_bus_write_stream_2),
2252
DEVMETHOD(bhnd_bus_write_stream_4, bhndb_bus_write_stream_4),
2253
2254
DEVMETHOD(bhnd_bus_read_multi_1, bhndb_bus_read_multi_1),
2255
DEVMETHOD(bhnd_bus_read_multi_2, bhndb_bus_read_multi_2),
2256
DEVMETHOD(bhnd_bus_read_multi_4, bhndb_bus_read_multi_4),
2257
DEVMETHOD(bhnd_bus_write_multi_1, bhndb_bus_write_multi_1),
2258
DEVMETHOD(bhnd_bus_write_multi_2, bhndb_bus_write_multi_2),
2259
DEVMETHOD(bhnd_bus_write_multi_4, bhndb_bus_write_multi_4),
2260
2261
DEVMETHOD(bhnd_bus_read_multi_stream_1, bhndb_bus_read_multi_stream_1),
2262
DEVMETHOD(bhnd_bus_read_multi_stream_2, bhndb_bus_read_multi_stream_2),
2263
DEVMETHOD(bhnd_bus_read_multi_stream_4, bhndb_bus_read_multi_stream_4),
2264
DEVMETHOD(bhnd_bus_write_multi_stream_1,bhndb_bus_write_multi_stream_1),
2265
DEVMETHOD(bhnd_bus_write_multi_stream_2,bhndb_bus_write_multi_stream_2),
2266
DEVMETHOD(bhnd_bus_write_multi_stream_4,bhndb_bus_write_multi_stream_4),
2267
2268
DEVMETHOD(bhnd_bus_set_multi_1, bhndb_bus_set_multi_1),
2269
DEVMETHOD(bhnd_bus_set_multi_2, bhndb_bus_set_multi_2),
2270
DEVMETHOD(bhnd_bus_set_multi_4, bhndb_bus_set_multi_4),
2271
DEVMETHOD(bhnd_bus_set_region_1, bhndb_bus_set_region_1),
2272
DEVMETHOD(bhnd_bus_set_region_2, bhndb_bus_set_region_2),
2273
DEVMETHOD(bhnd_bus_set_region_4, bhndb_bus_set_region_4),
2274
2275
DEVMETHOD(bhnd_bus_read_region_1, bhndb_bus_read_region_1),
2276
DEVMETHOD(bhnd_bus_read_region_2, bhndb_bus_read_region_2),
2277
DEVMETHOD(bhnd_bus_read_region_4, bhndb_bus_read_region_4),
2278
DEVMETHOD(bhnd_bus_write_region_1, bhndb_bus_write_region_1),
2279
DEVMETHOD(bhnd_bus_write_region_2, bhndb_bus_write_region_2),
2280
DEVMETHOD(bhnd_bus_write_region_4, bhndb_bus_write_region_4),
2281
2282
DEVMETHOD(bhnd_bus_read_region_stream_1,bhndb_bus_read_region_stream_1),
2283
DEVMETHOD(bhnd_bus_read_region_stream_2,bhndb_bus_read_region_stream_2),
2284
DEVMETHOD(bhnd_bus_read_region_stream_4,bhndb_bus_read_region_stream_4),
2285
DEVMETHOD(bhnd_bus_write_region_stream_1,bhndb_bus_write_region_stream_1),
2286
DEVMETHOD(bhnd_bus_write_region_stream_2,bhndb_bus_write_region_stream_2),
2287
DEVMETHOD(bhnd_bus_write_region_stream_4,bhndb_bus_write_region_stream_4),
2288
2289
DEVMETHOD(bhnd_bus_barrier, bhndb_bus_barrier),
2290
2291
DEVMETHOD_END
2292
};
2293
2294
DEFINE_CLASS_0(bhndb, bhndb_driver, bhndb_methods, sizeof(struct bhndb_softc));
2295
2296
MODULE_VERSION(bhndb, 1);
2297
MODULE_DEPEND(bhndb, bhnd, 1, 1, 1);
2298
2299