ofwbus: remove handling of resources from ofwbus

The architecture nexus should handle allocation and release of memory and
interrupts. This is to ensure that system-wide resources such as these
are available to all devices, not just children of ofwbus0.

On powerpc this moves the ownership of these resources up one level,
from ofwbus0 to nexus0. Other architectures already have the required
logic in their nexus implementation, so this eliminates the duplication
of resources. An implementation of nexus_adjust_resource() is added for
arm, arm64, and riscv.

As noted by ian@ in the review, resource handling was the main bit of
logic distinguishing ofwbus from simplebus. With some attention to
detail, it should be possible to merge the two in the future.

Co-authored by:	mhorne
MFC after:	1 month
Differential Revision: https://reviews.freebsd.org/D30554
This commit is contained in:
Elliott Mitchell 2023-02-08 16:17:03 -04:00 committed by Mitchell Horne
parent 1d03c3578d
commit f9bdaab95e
5 changed files with 173 additions and 83 deletions

View File

@ -87,6 +87,8 @@ static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
rman_res_t, rman_res_t, rman_res_t, u_int);
static int nexus_activate_resource(device_t, device_t, int, int,
struct resource *);
static int nexus_adjust_resource(device_t, device_t, int, struct resource *,
rman_res_t, rman_res_t);
static bus_space_tag_t nexus_get_bus_tag(device_t, device_t);
static bus_dma_tag_t nexus_get_dma_tag(device_t dev, device_t child);
#ifdef SMP
@ -126,6 +128,7 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_add_child, nexus_add_child),
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
DEVMETHOD(bus_adjust_resource, nexus_adjust_resource),
DEVMETHOD(bus_config_intr, nexus_config_intr),
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_release_resource, nexus_release_resource),
@ -263,6 +266,27 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (rv);
}
static int
nexus_adjust_resource(device_t bus __unused, device_t child __unused, int type,
struct resource *r, rman_res_t start, rman_res_t end)
{
struct rman *rm;
switch (type) {
case SYS_RES_IRQ:
rm = &irq_rman;
break;
case SYS_RES_MEMORY:
rm = &mem_rman;
break;
default:
return (EINVAL);
}
if (rman_is_region_manager(r, rm) == 0)
return (EINVAL);
return (rman_adjust_resource(r, start, end));
}
static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)

View File

@ -104,6 +104,8 @@ static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
rman_res_t, rman_res_t, rman_res_t, u_int);
static int nexus_activate_resource(device_t, device_t, int, int,
struct resource *);
static int nexus_adjust_resource(device_t, device_t, int, struct resource *,
rman_res_t, rman_res_t);
static int nexus_map_resource(device_t, device_t, int, struct resource *,
struct resource_map_request *, struct resource_map *);
static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
@ -135,6 +137,7 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_add_child, nexus_add_child),
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
DEVMETHOD(bus_adjust_resource, nexus_adjust_resource),
DEVMETHOD(bus_map_resource, nexus_map_resource),
DEVMETHOD(bus_config_intr, nexus_config_intr),
DEVMETHOD(bus_get_resource_list, nexus_get_reslist),
@ -273,6 +276,27 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (rv);
}
static int
nexus_adjust_resource(device_t bus __unused, device_t child __unused, int type,
struct resource *r, rman_res_t start, rman_res_t end)
{
struct rman *rm;
switch (type) {
case SYS_RES_IRQ:
rm = &irq_rman;
break;
case SYS_RES_MEMORY:
rm = &mem_rman;
break;
default:
return (EINVAL);
}
if (rman_is_region_manager(r, rm) == 0)
return (EINVAL);
return (rman_adjust_resource(r, start, end));
}
static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)

View File

@ -63,22 +63,14 @@ __FBSDID("$FreeBSD$");
* 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
* attached to them.
*
*/
struct ofwbus_softc {
struct simplebus_softc simplebus_sc;
struct rman sc_intr_rman;
struct rman sc_mem_rman;
};
#ifndef __aarch64__
static device_identify_t ofwbus_identify;
#endif
static device_probe_t ofwbus_probe;
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[] = {
@ -91,14 +83,14 @@ static device_method_t ofwbus_methods[] = {
/* Bus interface */
DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource),
DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource),
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
DEVMETHOD(bus_release_resource, ofwbus_release_resource),
DEVMETHOD_END
};
DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods,
sizeof(struct ofwbus_softc), simplebus_driver);
sizeof(struct simplebus_softc), simplebus_driver);
EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, 0, 0,
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_VERSION(ofwbus, 1);
@ -133,12 +125,9 @@ ofwbus_probe(device_t dev)
static int
ofwbus_attach(device_t dev)
{
struct ofwbus_softc *sc;
phandle_t node;
struct ofw_bus_devinfo obd;
sc = device_get_softc(dev);
node = OF_peer(0);
/*
@ -152,15 +141,6 @@ ofwbus_attach(device_t dev)
* ofw_bus_devinfo from it. Pass node to simplebus_init directly.
*/
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.
@ -182,15 +162,12 @@ 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;
bool 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),
@ -206,28 +183,11 @@ ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
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);
/* Let nexus handle the allocation. */
rv = bus_generic_alloc_resource(bus, child, type, rid, start, end,
count, flags);
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;
@ -239,42 +199,12 @@ ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
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;
bool passthrough;
passthrough = (device_get_parent(child) != bus);
if (!passthrough) {
@ -285,10 +215,6 @@ ofwbus_release_resource(device_t bus, device_t child, int type,
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));
/* Let nexus handle the release. */
return (bus_generic_release_resource(bus, child, type, rid, r));
}

View File

@ -63,12 +63,18 @@ __FBSDID("$FreeBSD$");
* mapping. All direct subdevices of nexus are attached by DEVICE_IDENTIFY().
*/
static struct rman intr_rman;
static struct rman mem_rman;
static device_probe_t nexus_probe;
static device_attach_t nexus_attach;
static bus_setup_intr_t nexus_setup_intr;
static bus_teardown_intr_t nexus_teardown_intr;
static bus_alloc_resource_t nexus_alloc_resource;
static bus_activate_resource_t nexus_activate_resource;
static bus_deactivate_resource_t nexus_deactivate_resource;
static bus_adjust_resource_t nexus_adjust_resource;
static bus_release_resource_t nexus_release_resource;
static int nexus_map_resource(device_t bus, device_t child, int type,
struct resource *r,
struct resource_map_request *argsp,
@ -92,8 +98,11 @@ static device_method_t nexus_methods[] = {
/* Bus interface */
DEVMETHOD(bus_add_child, bus_generic_add_child),
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_adjust_resource, nexus_adjust_resource),
DEVMETHOD(bus_release_resource, nexus_release_resource),
DEVMETHOD(bus_map_resource, nexus_map_resource),
DEVMETHOD(bus_unmap_resource, nexus_unmap_resource),
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
@ -128,6 +137,15 @@ static int
nexus_attach(device_t dev)
{
intr_rman.rm_type = RMAN_ARRAY;
intr_rman.rm_descr = "Interrupts";
mem_rman.rm_type = RMAN_ARRAY;
mem_rman.rm_descr = "I/O memory addresses";
if (rman_init(&intr_rman) != 0 || rman_init(&mem_rman) != 0 ||
rman_manage_region(&intr_rman, 0, ~0) != 0 ||
rman_manage_region(&mem_rman, 0, BUS_SPACE_MAXADDR) != 0)
panic("%s: failed to set up rmans.", __func__);
bus_generic_probe(dev);
bus_generic_attach(dev);
@ -233,6 +251,44 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
return (intr);
}
/*
* Allocate a resource on behalf of child. NB: child is usually going to be a
* child of one of our descendants, not a direct child of nexus0.
*/
static struct resource *
nexus_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 rman *rm;
struct resource *rv;
switch (type) {
case SYS_RES_IRQ:
rm = &intr_rman;
break;
case SYS_RES_MEMORY:
rm = &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) {
if (bus_activate_resource(child, type, *rid, rv) != 0) {
rman_release_resource(rv);
return (NULL);
}
}
return (rv);
}
static int
nexus_activate_resource(device_t bus __unused, device_t child __unused,
int type, int rid __unused, struct resource *r)
@ -275,6 +331,42 @@ nexus_deactivate_resource(device_t bus __unused, device_t child __unused,
return (rman_deactivate_resource(r));
}
static int
nexus_adjust_resource(device_t bus, device_t child __unused, int type,
struct resource *r, rman_res_t start, rman_res_t end)
{
struct rman *rm;
switch (type) {
case SYS_RES_IRQ:
rm = &intr_rman;
break;
case SYS_RES_MEMORY:
rm = &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
nexus_release_resource(device_t bus, device_t child, int type,
int rid, struct resource *r)
{
int error;
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));
}
static int
nexus_map_resource(device_t bus, device_t child, int type, struct resource *r,

View File

@ -85,6 +85,8 @@ static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
rman_res_t, rman_res_t, rman_res_t, u_int);
static int nexus_activate_resource(device_t, device_t, int, int,
struct resource *);
static int nexus_adjust_resource(device_t, device_t, int, struct resource *,
rman_res_t, rman_res_t);
static int nexus_map_resource(device_t, device_t, int, struct resource *,
struct resource_map_request *, struct resource_map *);
static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
@ -118,6 +120,7 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_add_child, nexus_add_child),
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
DEVMETHOD(bus_adjust_resource, nexus_adjust_resource),
DEVMETHOD(bus_map_resource, nexus_map_resource),
DEVMETHOD(bus_config_intr, nexus_config_intr),
DEVMETHOD(bus_get_resource_list, nexus_get_reslist),
@ -265,6 +268,27 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (rv);
}
static int
nexus_adjust_resource(device_t bus __unused, device_t child __unused, int type,
struct resource *r, rman_res_t start, rman_res_t end)
{
struct rman *rm;
switch (type) {
case SYS_RES_IRQ:
rm = &irq_rman;
break;
case SYS_RES_MEMORY:
rm = &mem_rman;
break;
default:
return (EINVAL);
}
if (rman_is_region_manager(r, rm) == 0)
return (EINVAL);
return (rman_adjust_resource(r, start, end));
}
static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)