Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 Feb 2023 20:52:23 GMT
From:      Mitchell Horne <mhorne@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: f9bdaab95ec4 - main - ofwbus: remove handling of resources from ofwbus
Message-ID:  <202302082052.318KqNUL052449@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by mhorne:

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

commit f9bdaab95ec469738fbfc1f0edd3e8c744b7f71f
Author:     Elliott Mitchell <ehem+freebsd@m5p.com>
AuthorDate: 2023-02-08 20:17:03 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-02-08 20:50:46 +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
---
 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 81500f9b8e35..a2e043ff7c31 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 defd6755c48e..50604fd22e98 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 a64f03b8099a..5ea0ba313353 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);
 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));
 }
diff --git a/sys/powerpc/powerpc/nexus.c b/sys/powerpc/powerpc/nexus.c
index ccac47cee0ec..2e756782d47d 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,
@@ -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,
diff --git a/sys/riscv/riscv/nexus.c b/sys/riscv/riscv/nexus.c
index 3818f9e91996..ae0bfe388484 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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202302082052.318KqNUL052449>