summaryrefslogtreecommitdiffstats
path: root/sys/sparc64/ebus
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2011-10-02 23:22:38 +0000
committermarius <marius@FreeBSD.org>2011-10-02 23:22:38 +0000
commitb730263346b617e3949a799cd7cbbaec0a0faaba (patch)
tree8a3ccb0c4cbe92ab406722848f03d20132c1e280 /sys/sparc64/ebus
parent2dc050638298978fc3e396cc2d0206c599dc8c46 (diff)
downloadFreeBSD-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.c102
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
OpenPOWER on IntegriCloud