git: 9cb88cc937ec - stable/13 - ofwbus: remove handling of resources from ofwbus

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Mon, 17 Apr 2023 17:04:00 UTC
The branch stable/13 has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=9cb88cc937eca838065538652929ffb9d77624da

commit 9cb88cc937eca838065538652929ffb9d77624da
Author:     Elliott Mitchell <ehem+freebsd@m5p.com>
AuthorDate: 2023-02-08 20:17:03 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-04-17 16:04:23 +0000

    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
    
    (cherry picked from commit f9bdaab95ec469738fbfc1f0edd3e8c744b7f71f)
---
 sys/arm/arm/nexus.c         | 24 ++++++++++++
 sys/arm64/arm64/nexus.c     | 24 ++++++++++++
 sys/dev/ofw/ofwbus.c        | 92 +++++----------------------------------------
 sys/powerpc/powerpc/nexus.c | 92 +++++++++++++++++++++++++++++++++++++++++++++
 sys/riscv/riscv/nexus.c     | 24 ++++++++++++
 5 files changed, 173 insertions(+), 83 deletions(-)

diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c
index f2506dfb3cb5..3991ec91ed0d 100644
--- a/sys/arm/arm/nexus.c
+++ b/sys/arm/arm/nexus.c
@@ -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)
diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c
index 0775cc820a8c..350ad9d1be76 100644
--- a/sys/arm64/arm64/nexus.c
+++ b/sys/arm64/arm64/nexus.c
@@ -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)
diff --git a/sys/dev/ofw/ofwbus.c b/sys/dev/ofw/ofwbus.c
index 6ea5be694af6..4432f1704392 100644
--- a/sys/dev/ofw/ofwbus.c
+++ b/sys/dev/ofw/ofwbus.c
@@ -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);
 static devclass_t ofwbus_devclass;
 EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0,
     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
@@ -134,12 +126,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);
 
 	/*
@@ -153,15 +142,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.
@@ -184,15 +164,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),
@@ -208,28 +185,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;
@@ -241,42 +201,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) {
@@ -287,10 +217,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));
 }
diff --git a/sys/powerpc/powerpc/nexus.c b/sys/powerpc/powerpc/nexus.c
index 1c6bc275ebdd..6edc7f258d39 100644
--- a/sys/powerpc/powerpc/nexus.c
+++ b/sys/powerpc/powerpc/nexus.c
@@ -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,
@@ -90,8 +96,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);
 
@@ -215,6 +233,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)
@@ -257,6 +313,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,
diff --git a/sys/riscv/riscv/nexus.c b/sys/riscv/riscv/nexus.c
index 16fe971b6521..9cafb90fd34a 100644
--- a/sys/riscv/riscv/nexus.c
+++ b/sys/riscv/riscv/nexus.c
@@ -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)