The branch main has been updated by jhb:

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

commit 751615c538446ea0384f8faa9cb2508670c3799a
Author:     John Baldwin <[email protected]>
AuthorDate: 2023-11-24 17:28:00 +0000
Commit:     John Baldwin <[email protected]>
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);

Reply via email to