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);