aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/bus_if.m24
-rw-r--r--sys/kern/subr_bus.c157
-rw-r--r--sys/sys/bus.h17
3 files changed, 198 insertions, 0 deletions
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);
+ }
};
/**
@@ -623,6 +629,24 @@ METHOD struct resource_list * get_resource_list {
} 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
@@ -4190,6 +4190,163 @@ bus_generic_rl_alloc_resource(device_t dev, device_t child, int type,
}
/**
+ * @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().
*
* This simple implementation of BUS_CHILD_PRESENT() simply calls the
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);