Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ofw/ofwbus.c
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* The ofwbus (which is a pseudo-bus actually) iterates over the nodes that | * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that | ||||
* hang from the Open Firmware root node and adds them as devices to this bus | * hang from the Open Firmware root node and adds them as devices to this bus | ||||
* (except some special nodes which are excluded) so that drivers can be | * (except some special nodes which are excluded) so that drivers can be | ||||
* attached to them. | * attached to them. | ||||
* | * | ||||
*/ | */ | ||||
struct ofwbus_softc { | |||||
struct simplebus_softc simplebus_sc; | |||||
struct rman sc_intr_rman; | |||||
struct rman sc_mem_rman; | |||||
}; | |||||
#ifndef __aarch64__ | #ifndef __aarch64__ | ||||
static device_identify_t ofwbus_identify; | static device_identify_t ofwbus_identify; | ||||
#endif | #endif | ||||
static device_probe_t ofwbus_probe; | static device_probe_t ofwbus_probe; | ||||
static device_attach_t ofwbus_attach; | static device_attach_t ofwbus_attach; | ||||
static bus_alloc_resource_t ofwbus_alloc_resource; | |||||
static bus_adjust_resource_t ofwbus_adjust_resource; | |||||
static bus_release_resource_t ofwbus_release_resource; | |||||
static device_method_t ofwbus_methods[] = { | static device_method_t ofwbus_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
#ifndef __aarch64__ | #ifndef __aarch64__ | ||||
DEVMETHOD(device_identify, ofwbus_identify), | DEVMETHOD(device_identify, ofwbus_identify), | ||||
#endif | #endif | ||||
DEVMETHOD(device_probe, ofwbus_probe), | DEVMETHOD(device_probe, ofwbus_probe), | ||||
DEVMETHOD(device_attach, ofwbus_attach), | DEVMETHOD(device_attach, ofwbus_attach), | ||||
/* Bus interface */ | |||||
DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), | |||||
DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), | |||||
DEVMETHOD(bus_release_resource, ofwbus_release_resource), | |||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, | DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, | ||||
sizeof(struct ofwbus_softc), simplebus_driver); | sizeof(struct simplebus_softc), simplebus_driver); | ||||
static devclass_t ofwbus_devclass; | static devclass_t ofwbus_devclass; | ||||
EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, | EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, | ||||
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); | BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); | ||||
MODULE_VERSION(ofwbus, 1); | MODULE_VERSION(ofwbus, 1); | ||||
#ifndef __aarch64__ | #ifndef __aarch64__ | ||||
static void | static void | ||||
ofwbus_identify(driver_t *driver, device_t parent) | ofwbus_identify(driver_t *driver, device_t parent) | ||||
Show All 19 Lines | #endif | ||||
device_set_desc(dev, "Open Firmware Device Tree"); | device_set_desc(dev, "Open Firmware Device Tree"); | ||||
return (BUS_PROBE_NOWILDCARD); | return (BUS_PROBE_NOWILDCARD); | ||||
} | } | ||||
static int | static int | ||||
ofwbus_attach(device_t dev) | ofwbus_attach(device_t dev) | ||||
{ | { | ||||
struct ofwbus_softc *sc; | |||||
phandle_t node; | phandle_t node; | ||||
struct ofw_bus_devinfo obd; | struct ofw_bus_devinfo obd; | ||||
sc = device_get_softc(dev); | |||||
node = OF_peer(0); | node = OF_peer(0); | ||||
/* | /* | ||||
* If no Open Firmware, bail early | * If no Open Firmware, bail early | ||||
*/ | */ | ||||
if (node == -1) | if (node == -1) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* | /* | ||||
* ofwbus bus starts on unamed node in FDT, so we cannot make | * ofwbus bus starts on unamed node in FDT, so we cannot make | ||||
* ofw_bus_devinfo from it. Pass node to simplebus_init directly. | * ofw_bus_devinfo from it. Pass node to simplebus_init directly. | ||||
*/ | */ | ||||
simplebus_init(dev, node); | simplebus_init(dev, node); | ||||
sc->sc_intr_rman.rm_type = RMAN_ARRAY; | |||||
sc->sc_intr_rman.rm_descr = "Interrupts"; | |||||
sc->sc_mem_rman.rm_type = RMAN_ARRAY; | |||||
sc->sc_mem_rman.rm_descr = "Device Memory"; | |||||
if (rman_init(&sc->sc_intr_rman) != 0 || | |||||
rman_init(&sc->sc_mem_rman) != 0 || | |||||
rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || | |||||
rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) | |||||
panic("%s: failed to set up rmans.", __func__); | |||||
/* | /* | ||||
* Allow devices to identify. | * Allow devices to identify. | ||||
*/ | */ | ||||
bus_generic_probe(dev); | bus_generic_probe(dev); | ||||
/* | /* | ||||
* Now walk the OFW tree and attach top-level devices. | * Now walk the OFW tree and attach top-level devices. | ||||
*/ | */ | ||||
for (node = OF_child(node); node > 0; node = OF_peer(node)) { | for (node = OF_child(node); node > 0; node = OF_peer(node)) { | ||||
if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) | if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) | ||||
continue; | continue; | ||||
simplebus_add_device(dev, node, 0, NULL, -1, NULL); | simplebus_add_device(dev, node, 0, NULL, -1, NULL); | ||||
} | } | ||||
return (bus_generic_attach(dev)); | return (bus_generic_attach(dev)); | ||||
} | |||||
static struct resource * | |||||
ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, | |||||
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) | |||||
{ | |||||
struct ofwbus_softc *sc; | |||||
struct rman *rm; | |||||
struct resource *rv; | |||||
struct resource_list_entry *rle; | |||||
int isdefault, passthrough; | |||||
isdefault = RMAN_IS_DEFAULT_RANGE(start, end); | |||||
passthrough = (device_get_parent(child) != bus); | |||||
sc = device_get_softc(bus); | |||||
rle = NULL; | |||||
if (!passthrough && isdefault) { | |||||
rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), | |||||
type, *rid); | |||||
if (rle == NULL) { | |||||
if (bootverbose) | |||||
device_printf(bus, "no default resources for " | |||||
"rid = %d, type = %d\n", *rid, type); | |||||
return (NULL); | |||||
} | |||||
start = rle->start; | |||||
count = ummax(count, rle->count); | |||||
end = ummax(rle->end, start + count - 1); | |||||
} | |||||
switch (type) { | |||||
case SYS_RES_IRQ: | |||||
rm = &sc->sc_intr_rman; | |||||
break; | |||||
case SYS_RES_MEMORY: | |||||
rm = &sc->sc_mem_rman; | |||||
break; | |||||
default: | |||||
return (NULL); | |||||
} | |||||
rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, | |||||
child); | |||||
if (rv == NULL) | |||||
return (NULL); | |||||
rman_set_rid(rv, *rid); | |||||
if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, | |||||
*rid, rv) != 0) { | |||||
rman_release_resource(rv); | |||||
return (NULL); | |||||
} | |||||
if (!passthrough && rle != NULL) { | |||||
rle->res = rv; | |||||
rle->start = rman_get_start(rv); | |||||
rle->end = rman_get_end(rv); | |||||
rle->count = rle->end - rle->start + 1; | |||||
} | |||||
return (rv); | |||||
} | |||||
static int | |||||
ofwbus_adjust_resource(device_t bus, device_t child __unused, int type, | |||||
struct resource *r, rman_res_t start, rman_res_t end) | |||||
{ | |||||
struct ofwbus_softc *sc; | |||||
struct rman *rm; | |||||
device_t ofwbus; | |||||
ofwbus = bus; | |||||
while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) | |||||
ofwbus = device_get_parent(ofwbus); | |||||
sc = device_get_softc(ofwbus); | |||||
switch (type) { | |||||
case SYS_RES_IRQ: | |||||
rm = &sc->sc_intr_rman; | |||||
break; | |||||
case SYS_RES_MEMORY: | |||||
rm = &sc->sc_mem_rman; | |||||
break; | |||||
default: | |||||
return (EINVAL); | |||||
} | |||||
if (rm == NULL) | |||||
return (ENXIO); | |||||
if (rman_is_region_manager(r, rm) == 0) | |||||
return (EINVAL); | |||||
return (rman_adjust_resource(r, start, end)); | |||||
} | |||||
static int | |||||
ofwbus_release_resource(device_t bus, device_t child, int type, | |||||
int rid, struct resource *r) | |||||
{ | |||||
struct resource_list_entry *rle; | |||||
int passthrough; | |||||
int error; | |||||
passthrough = (device_get_parent(child) != bus); | |||||
if (!passthrough) { | |||||
/* Clean resource list entry */ | |||||
rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), | |||||
type, rid); | |||||
if (rle != NULL) | |||||
rle->res = NULL; | |||||
} | |||||
if ((rman_get_flags(r) & RF_ACTIVE) != 0) { | |||||
error = bus_deactivate_resource(child, type, rid, r); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
return (rman_release_resource(r)); | |||||
} | } |