Index: head/sys/dev/bhnd/bhndb/bhndb.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb.c +++ head/sys/dev/bhnd/bhndb/bhndb.c @@ -1144,11 +1144,16 @@ { struct bhndb_softc *sc; struct rman *rm; + rman_res_t mstart, mend; int error; sc = device_get_softc(dev); error = 0; + /* Verify basic constraints */ + if (end <= start) + return (EINVAL); + /* Fetch resource manager */ rm = bhndb_get_rman(sc, child, type); if (rm == NULL) @@ -1157,16 +1162,29 @@ if (!rman_is_region_manager(r, rm)) return (ENXIO); - /* If active, adjustment is limited by the assigned window. */ BHNDB_LOCK(sc); - // TODO: Currently unsupported - error = ENODEV; + /* If not active, allow any range permitted by the resource manager */ + if (!(rman_get_flags(r) & RF_ACTIVE)) + goto done; - BHNDB_UNLOCK(sc); + /* Otherwise, the range is limited to the existing register window + * mapping */ + error = bhndb_find_resource_limits(sc->bus_res, r, &mstart, &mend); + if (error) + goto done; + + if (start < mstart || end > mend) { + error = EINVAL; + goto done; + } + + /* Fall through */ +done: if (!error) error = rman_adjust_resource(r, start, end); + BHNDB_UNLOCK(sc); return (error); } @@ -1536,7 +1554,8 @@ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { bhndb_priority_t r_prio; - region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); + region = bhndb_find_resource_region(sc->bus_res, r_start, + r_size); if (region != NULL) r_prio = region->priority; else Index: head/sys/dev/bhnd/bhndb/bhndb_private.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_private.h +++ head/sys/dev/bhnd/bhndb/bhndb_private.h @@ -71,6 +71,11 @@ bhndb_priority_t priority, const struct bhndb_regwin *static_regwin); +int bhndb_find_resource_limits( + struct bhndb_resources *br, + struct resource *r, rman_res_t *start, + rman_res_t *end); + struct bhndb_region *bhndb_find_resource_region( struct bhndb_resources *br, bhnd_addr_t addr, bhnd_size_t size); @@ -133,7 +138,7 @@ * Dynamic register window allocation reference. */ struct bhndb_dw_rentry { - struct resource *dw_res; /**< child resource */ + struct resource *dw_res; /**< child resource */ LIST_ENTRY(bhndb_dw_rentry) dw_link; }; Index: head/sys/dev/bhnd/bhndb/bhndb_subr.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_subr.c +++ head/sys/dev/bhnd/bhndb/bhndb_subr.c @@ -563,8 +563,52 @@ return (0); } + +/** + * Find the maximum start and end limits of the register window mapping + * resource @p r. + * + * If the memory range is not mapped by an existing dynamic or static register + * window, ENOENT will be returned. + * + * @param br The resource state to search. + * @param r The resource to search for in @p br. + * @param addr The requested starting address. + * @param size The requested size. + * + * @retval bhndb_region A region that fully contains the requested range. + * @retval NULL If no mapping region can be found. + */ +int +bhndb_find_resource_limits(struct bhndb_resources *br, struct resource *r, + rman_res_t *start, rman_res_t *end) +{ + struct bhndb_dw_alloc *dynamic; + struct bhndb_region *sregion; + + /* Check for an enclosing dynamic register window */ + if ((dynamic = bhndb_dw_find_resource(br, r))) { + *start = dynamic->target; + *end = dynamic->target + dynamic->win->win_size - 1; + return (0); + } + + /* Check for a static region */ + sregion = bhndb_find_resource_region(br, rman_get_start(r), + rman_get_size(r)); + if (sregion != NULL && sregion->static_regwin != NULL) { + *start = sregion->addr; + *end = sregion->addr + sregion->size - 1; + + return (0); + } + + /* Not found */ + return (ENOENT); +} + /** - * Find a bus region that maps @p size bytes at @p addr. + * Find the bus region that maps @p size bytes at @p addr. * * @param br The resource state to search. * @param addr The requested starting address.