git: 751615c53844 - main - newbus: Add a set of bus resource helpers for nexus-like devices
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 24 Nov 2023 17:28:54 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=751615c538446ea0384f8faa9cb2508670c3799a
commit 751615c538446ea0384f8faa9cb2508670c3799a
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2023-11-24 17:28:00 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2023-11-24 17:28:00 +0000
newbus: Add a set of bus resource helpers for nexus-like devices
These routines can be used to implement
bus_alloc/adjust/activate/deactive/release_resource on bus drivers
which suballocate resources from rman(9) resource managers.
These methods require a new bus_get_rman method in the bus driver to
return the suitable rman for a given resource type. The
activate/deactivate helpers also require the bus to implement the
bus_map/ummap_resource methods.
Reviewed by: imp
Differential Revision: https://reviews.freebsd.org/D42739
---
sys/kern/bus_if.m | 24 ++++++++
sys/kern/subr_bus.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++
sys/sys/bus.h | 17 ++++++
3 files changed, 198 insertions(+)
diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m
index 7bd08fb713f8..7078683911b8 100644
--- a/sys/kern/bus_if.m
+++ b/sys/kern/bus_if.m
@@ -77,6 +77,12 @@ CODE {
{
return (0);
}
+
+ static struct rman *
+ null_get_rman(device_t bus, int type, u_int flags)
+ {
+ return (NULL);
+ }
};
/**
@@ -622,6 +628,24 @@ METHOD struct resource_list * get_resource_list {
device_t _child;
} DEFAULT bus_generic_get_resource_list;
+/**
+ * @brief Return a struct rman.
+ *
+ * Used by drivers which use bus_generic_rman_alloc_resource() etc. to
+ * implement their resource handling. It should return the resource
+ * manager used for the given resource type.
+ *
+ * @param _dev the bus device
+ * @param _type the resource type
+ * @param _flags resource flags (@c RF_XXX flags in
+ * <sys/rman.h>)
+ */
+METHOD struct rman * get_rman {
+ device_t _dev;
+ int _type;
+ u_int _flags;
+} DEFAULT null_get_rman;
+
/**
* @brief Is the hardware described by @p _child still attached to the
* system?
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 80fe182eab56..9e191f4c3a4f 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -4189,6 +4189,163 @@ bus_generic_rl_alloc_resource(device_t dev, device_t child, int type,
start, end, count, flags));
}
+/**
+ * @brief Helper function for implementing BUS_ALLOC_RESOURCE().
+ *
+ * This implementation of BUS_ALLOC_RESOURCE() allocates a
+ * resource from a resource manager. It uses BUS_GET_RMAN()
+ * to obtain the resource manager.
+ */
+struct resource *
+bus_generic_rman_alloc_resource(device_t dev, device_t child, int type,
+ int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct resource *r;
+ struct rman *rm;
+
+ rm = BUS_GET_RMAN(dev, type, flags);
+ if (rm == NULL)
+ return (NULL);
+
+ r = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+ child);
+ if (r == NULL)
+ return (NULL);
+ rman_set_rid(r, *rid);
+
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, r) != 0) {
+ rman_release_resource(r);
+ return (NULL);
+ }
+ }
+
+ return (r);
+}
+
+/**
+ * @brief Helper function for implementing BUS_ADJUST_RESOURCE().
+ *
+ * This implementation of BUS_ADJUST_RESOURCE() adjusts resources only
+ * if they were allocated from the resource manager returned by
+ * BUS_GET_RMAN().
+ */
+int
+bus_generic_rman_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, rman_res_t start, rman_res_t end)
+{
+ struct rman *rm;
+
+ rm = BUS_GET_RMAN(dev, type, rman_get_flags(r));
+ if (rm == NULL)
+ return (ENXIO);
+ if (!rman_is_region_manager(r, rm))
+ return (EINVAL);
+ return (rman_adjust_resource(r, start, end));
+}
+
+/**
+ * @brief Helper function for implementing BUS_RELEASE_RESOURCE().
+ *
+ * This implementation of BUS_RELEASE_RESOURCE() releases resources
+ * allocated by bus_generic_rman_alloc_resource.
+ */
+int
+bus_generic_rman_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+#ifdef INVARIANTS
+ struct rman *rm;
+#endif
+ int error;
+
+#ifdef INVARIANTS
+ rm = BUS_GET_RMAN(dev, type, rman_get_flags(r));
+ KASSERT(rman_is_region_manager(r, rm),
+ ("%s: rman %p doesn't match for resource %p", __func__, rm, r));
+#endif
+
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type, rid, r);
+ if (error != 0)
+ return (error);
+ }
+ return (rman_release_resource(r));
+}
+
+/**
+ * @brief Helper function for implementing BUS_ACTIVATE_RESOURCE().
+ *
+ * This implementation of BUS_ACTIVATE_RESOURCE() activates resources
+ * allocated by bus_generic_rman_alloc_resource.
+ */
+int
+bus_generic_rman_activate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_map map;
+#ifdef INVARIANTS
+ struct rman *rm;
+#endif
+ int error;
+
+#ifdef INVARIANTS
+ rm = BUS_GET_RMAN(dev, type, rman_get_flags(r));
+ KASSERT(rman_is_region_manager(r, rm),
+ ("%s: rman %p doesn't match for resource %p", __func__, rm, r));
+#endif
+
+ error = rman_activate_resource(r);
+ if (error != 0)
+ return (error);
+
+ if ((rman_get_flags(r) & RF_UNMAPPED) == 0 &&
+ (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT)) {
+ error = BUS_MAP_RESOURCE(dev, child, type, r, NULL, &map);
+ if (error != 0) {
+ rman_deactivate_resource(r);
+ return (error);
+ }
+
+ rman_set_mapping(r, &map);
+ }
+ return (0);
+}
+
+/**
+ * @brief Helper function for implementing BUS_DEACTIVATE_RESOURCE().
+ *
+ * This implementation of BUS_DEACTIVATE_RESOURCE() deactivates
+ * resources allocated by bus_generic_rman_alloc_resource.
+ */
+int
+bus_generic_rman_deactivate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_map map;
+#ifdef INVARIANTS
+ struct rman *rm;
+#endif
+ int error;
+
+#ifdef INVARIANTS
+ rm = BUS_GET_RMAN(dev, type, rman_get_flags(r));
+ KASSERT(rman_is_region_manager(r, rm),
+ ("%s: rman %p doesn't match for resource %p", __func__, rm, r));
+#endif
+
+ error = rman_deactivate_resource(r);
+ if (error != 0)
+ return (error);
+
+ if ((rman_get_flags(r) & RF_UNMAPPED) == 0 &&
+ (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT)) {
+ rman_get_mapping(r, &map);
+ BUS_UNMAP_RESOURCE(dev, child, type, r, &map);
+ }
+ return (0);
+}
+
/**
* @brief Helper function for implementing BUS_CHILD_PRESENT().
*
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index 88ae4000004b..2ec735659452 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -499,6 +499,23 @@ int bus_generic_rl_set_resource (device_t, device_t, int, int, rman_res_t,
rman_res_t);
int bus_generic_rl_release_resource (device_t, device_t, int, int,
struct resource *);
+struct resource *
+ bus_generic_rman_alloc_resource(device_t dev, device_t child, int type,
+ int *rid, rman_res_t start,
+ rman_res_t end, rman_res_t count,
+ u_int flags);
+int bus_generic_rman_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, rman_res_t start,
+ rman_res_t end);
+int bus_generic_rman_release_resource(device_t dev, device_t child,
+ int type, int rid,
+ struct resource *r);
+int bus_generic_rman_activate_resource(device_t dev, device_t child,
+ int type, int rid,
+ struct resource *r);
+int bus_generic_rman_deactivate_resource(device_t dev, device_t child,
+ int type, int rid,
+ struct resource *r);
int bus_generic_shutdown(device_t dev);
int bus_generic_suspend(device_t dev);