diff options
author | tmm <tmm@FreeBSD.org> | 2001-12-21 21:40:55 +0000 |
---|---|---|
committer | tmm <tmm@FreeBSD.org> | 2001-12-21 21:40:55 +0000 |
commit | dadac692002f0972c05f77679ecf7a78e8446731 (patch) | |
tree | fd3fd84eab4e6d6f24fe8e79f8ec19e5b3c7509a /sys/kern/subr_rman.c | |
parent | 16ac60366771ec42dee26cdd84ddd63cc06ef0aa (diff) | |
download | FreeBSD-src-dadac692002f0972c05f77679ecf7a78e8446731.zip FreeBSD-src-dadac692002f0972c05f77679ecf7a78e8446731.tar.gz |
Add a rman_reserve_resource_bound() function that takes an additional
argument specifying the boundary for the resource allocation.
Use ulmin()/ulmax() instead of min()/max() in some places to correctly
deal with the u_long resource range specifications.
Diffstat (limited to 'sys/kern/subr_rman.c')
-rw-r--r-- | sys/kern/subr_rman.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c index 0210dae..119a967 100644 --- a/sys/kern/subr_rman.c +++ b/sys/kern/subr_rman.c @@ -175,12 +175,13 @@ rman_fini(struct rman *rm) } struct resource * -rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, - u_int flags, struct device *dev) +rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end, + u_long count, u_long bound, u_int flags, + struct device *dev) { u_int want_activate; struct resource *r, *s, *rv; - u_long rstart, rend; + u_long rstart, rend, amask, bmask; rv = 0; @@ -202,6 +203,9 @@ rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, goto out; } + amask = (1ul << RF_ALIGNMENT(flags)) - 1; + /* If bound is 0, bmask will also be 0 */ + bmask = ~(bound - 1); /* * First try to find an acceptable totally-unshared region. */ @@ -215,10 +219,19 @@ rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, DPRINTF(("region is allocated\n")); continue; } - rstart = max(s->r_start, start); - rstart = (rstart + ((1ul << RF_ALIGNMENT(flags))) - 1) & - ~((1ul << RF_ALIGNMENT(flags)) - 1); - rend = min(s->r_end, max(rstart + count, end)); + rstart = ulmax(s->r_start, start); + /* + * Try to find a region by adjusting to boundary and alignment + * until both conditions are satisfied. This is not an optimal + * algorithm, but in most cases it isn't really bad, either. + */ + do { + rstart = (rstart + amask) & ~amask; + if (((rstart ^ (rstart + count)) & bmask) != 0) + rstart += bound - (rstart & ~bmask); + } while ((rstart & amask) != 0 && rstart < end && + rstart < s->r_end); + rend = ulmin(s->r_end, ulmax(rstart + count, end)); DPRINTF(("truncated region: [%#lx, %#lx]; size %#lx (requested %#lx)\n", rstart, rend, (rend - rstart + 1), count)); @@ -313,10 +326,12 @@ rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, break; if ((s->r_flags & flags) != flags) continue; - rstart = max(s->r_start, start); - rend = min(s->r_end, max(start + count, end)); + rstart = ulmax(s->r_start, start); + rend = ulmin(s->r_end, ulmax(start + count, end)); if (s->r_start >= start && s->r_end <= end - && (s->r_end - s->r_start + 1) == count) { + && (s->r_end - s->r_start + 1) == count && + (s->r_start & amask) == 0 && + ((s->r_start ^ s->r_end) & bmask) == 0) { rv = malloc(sizeof *rv, M_RMAN, M_NOWAIT | M_ZERO); if (rv == 0) goto out; @@ -368,6 +383,15 @@ out: return (rv); } +struct resource * +rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, + u_int flags, struct device *dev) +{ + + return (rman_reserve_resource_bound(rm, start, end, count, 0, flags, + dev)); +} + static int int_rman_activate_resource(struct rman *rm, struct resource *r, struct resource **whohas) @@ -575,7 +599,7 @@ rman_make_alignment_flags(uint32_t size) * Find the hightest bit set, and add one if more than one bit * set. We're effectively computing the ceil(log2(size)) here. */ - for (i = 32; i > 0; i--) + for (i = 31; i > 0; i--) if ((1 << i) & size) break; if (~(1 << i) & size) |