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
This commit is contained in:
John Baldwin 2023-11-24 09:28:00 -08:00
parent 73902ed85a
commit 751615c538
3 changed files with 198 additions and 0 deletions

View file

@ -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?

View file

@ -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().
*

View file

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