diff options
author | marius <marius@FreeBSD.org> | 2011-10-02 23:22:38 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2011-10-02 23:22:38 +0000 |
commit | b730263346b617e3949a799cd7cbbaec0a0faaba (patch) | |
tree | 8a3ccb0c4cbe92ab406722848f03d20132c1e280 /sys/sparc64/ebus | |
parent | 2dc050638298978fc3e396cc2d0206c599dc8c46 (diff) | |
download | FreeBSD-src-b730263346b617e3949a799cd7cbbaec0a0faaba.zip FreeBSD-src-b730263346b617e3949a799cd7cbbaec0a0faaba.tar.gz |
Make sparc64 compatible with NEW_PCIB and enable it:
- Implement bus_adjust_resource() methods as far as necessary and in non-PCI
bridge drivers as far as feasible without rototilling them.
- As NEW_PCIB does a layering violation by activating resources at layers
above pci(4) without previously bubbling up their allocation there, move
the assignment of bus tags and handles from the bus_alloc_resource() to
the bus_activate_resource() methods like at least the other NEW_PCIB
enabled architectures do. This is somewhat unfortunate as previously
sparc64 (ab)used resource activation to indicate whether SYS_RES_MEMORY
resources should be mapped into KVA, which is only necessary if their
going to be accessed via the pointer returned from rman_get_virtual() but
not for bus_space(9) as the later always uses physical access on sparc64.
Besides wasting KVA if we always map in SYS_RES_MEMORY resources, a driver
also may deliberately not map them in if the firmware already has done so,
possibly in a special way. So in order to still allow a driver to decide
whether a SYS_RES_MEMORY resource should be mapped into KVA we let it
indicate that by calling bus_space_map(9) with BUS_SPACE_MAP_LINEAR as
actually documented in the bus_space(9) page. This is implemented by
allocating a separate bus tag per SYS_RES_MEMORY resource and passing the
resource via the previously unused bus tag cookie so we later on can call
rman_set_virtual() in sparc64_bus_mem_map(). As a side effect this now
also allows to actually indicate that a SYS_RES_MEMORY resource should be
mapped in as cacheable and/or read-only via BUS_SPACE_MAP_CACHEABLE and
BUS_SPACE_MAP_READONLY respectively.
- Do some minor cleanup like taking advantage of rman_init_from_resource(),
factor out the common part of bus tag allocation into a newly added
sparc64_alloc_bus_tag(), hook up some missing newbus methods and replace
some homegrown versions with the generic counterparts etc.
- While at it, let apb_attach() (which can't use the generic NEW_PCIB code
as APB bridges just don't have the base and limit registers implemented)
regarding the config space registers cached in pcib_softc and the SYSCTL
reporting nodes set up.
Diffstat (limited to 'sys/sparc64/ebus')
-rw-r--r-- | sys/sparc64/ebus/ebus.c | 102 |
1 files changed, 65 insertions, 37 deletions
diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c index 317cdfa..42bac06 100644 --- a/sys/sparc64/ebus/ebus.c +++ b/sys/sparc64/ebus/ebus.c @@ -136,6 +136,8 @@ static device_attach_t ebus_pci_attach; static bus_print_child_t ebus_print_child; static bus_probe_nomatch_t ebus_probe_nomatch; static bus_alloc_resource_t ebus_alloc_resource; +static bus_activate_resource_t ebus_activate_resource; +static bus_adjust_resource_t ebus_adjust_resource; static bus_release_resource_t ebus_release_resource; static bus_setup_intr_t ebus_setup_intr; static bus_get_resource_list_t ebus_get_resource_list; @@ -161,8 +163,9 @@ static device_method_t ebus_nexus_methods[] = { DEVMETHOD(bus_print_child, ebus_print_child), DEVMETHOD(bus_probe_nomatch, ebus_probe_nomatch), DEVMETHOD(bus_alloc_resource, ebus_alloc_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_activate_resource, ebus_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_adjust_resource, ebus_adjust_resource), DEVMETHOD(bus_release_resource, ebus_release_resource), DEVMETHOD(bus_setup_intr, ebus_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), @@ -342,16 +345,10 @@ ebus_pci_attach(device_t dev) eri->eri_res = res; eri->eri_rman.rm_type = RMAN_ARRAY; eri->eri_rman.rm_descr = "EBus range"; - if (rman_init(&eri->eri_rman) != 0) { + if (rman_init_from_resource(&eri->eri_rman, res) != 0) { printf("%s: failed to initialize rman!", __func__); goto fail; } - if (rman_manage_region(&eri->eri_rman, rman_get_start(res), - rman_get_end(res)) != 0) { - printf("%s: failed to register region!", __func__); - rman_fini(&eri->eri_rman); - goto fail; - } } return (ebus_attach(dev, sc, node)); @@ -423,12 +420,10 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid, struct resource_list *rl; struct resource_list_entry *rle = NULL; struct resource *res; - struct ebus_rinfo *ri; + struct ebus_rinfo *eri; struct ebus_nexus_ranges *enr; - bus_space_tag_t bt; - bus_space_handle_t bh; uint64_t cend, cstart, offset; - int i, isdefault, passthrough, ridx, rv; + int i, isdefault, passthrough, ridx; isdefault = (start == 0UL && end == ~0UL); passthrough = (device_get_parent(child) != bus); @@ -459,23 +454,17 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid, */ (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange, &start, &end, &ridx); - ri = &sc->sc_rinfo[ridx]; - res = rman_reserve_resource(&ri->eri_rman, start, end, - count, flags, child); + eri = &sc->sc_rinfo[ridx]; + res = rman_reserve_resource(&eri->eri_rman, start, + end, count, flags & ~RF_ACTIVE, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); - bt = rman_get_bustag(ri->eri_res); - rman_set_bustag(res, bt); - rv = bus_space_subregion(bt, - rman_get_bushandle(ri->eri_res), - rman_get_start(res) - rman_get_start(ri->eri_res), - count, &bh); - if (rv != 0) { + if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( + child, type, *rid, res) != 0) { rman_release_resource(res); return (NULL); } - rman_set_bushandle(res, bh); } else { /* Map EBus ranges to nexus ranges. */ for (i = 0; i < sc->sc_nrange; i++) { @@ -496,7 +485,6 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid, break; } } - } if (!passthrough) rle->res = res; @@ -509,6 +497,48 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid, } static int +ebus_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *res) +{ + struct ebus_softc *sc; + struct ebus_rinfo *eri; + bus_space_tag_t bt; + bus_space_handle_t bh; + int i, rv; + + sc = device_get_softc(bus); + if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { + for (i = 0; i < sc->sc_nrange; i++) { + eri = &sc->sc_rinfo[i]; + if (rman_is_region_manager(res, &eri->eri_rman) != 0) { + bt = rman_get_bustag(eri->eri_res); + rv = bus_space_subregion(bt, + rman_get_bushandle(eri->eri_res), + rman_get_start(res) - + rman_get_start(eri->eri_res), + rman_get_size(res), &bh); + if (rv != 0) + return (rv); + rman_set_bustag(res, bt); + rman_set_bushandle(res, bh); + return (rman_activate_resource(res)); + } + } + return (EINVAL); + } + return (bus_generic_activate_resource(bus, child, type, rid, res)); +} + +static int +ebus_adjust_resource(device_t bus __unused, device_t child __unused, + int type __unused, struct resource *res __unused, u_long start __unused, + u_long end __unused) +{ + + return (ENXIO); +} + +static int ebus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { @@ -519,13 +549,15 @@ ebus_release_resource(device_t bus, device_t child, int type, int rid, passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); - switch (type) { - case SYS_RES_MEMORY: - sc = device_get_softc(bus); - if ((sc->sc_flags & EBUS_PCI) == 0) - return (resource_list_release(rl, bus, child, type, - rid, res)); - if ((rv = rman_release_resource(res)) != 0) + sc = device_get_softc(bus); + if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { + if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ + rv = bus_deactivate_resource(child, type, rid, res); + if (rv != 0) + return (rv); + } + rv = rman_release_resource(res); + if (rv != 0) return (rv); if (!passthrough) { rle = resource_list_find(rl, type, rid); @@ -535,13 +567,9 @@ ebus_release_resource(device_t bus, device_t child, int type, int rid, ("%s: resource entry is not busy", __func__)); rle->res = NULL; } - break; - case SYS_RES_IRQ: - return (resource_list_release(rl, bus, child, type, rid, res)); - default: - panic("%s: unsupported resource type %d", __func__, type); + return (0); } - return (0); + return (resource_list_release(rl, bus, child, type, rid, res)); } static int |