1/* 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all --- 12 unchanged lines hidden (view full) --- 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * |
29 * $Id: subr_rman.c,v 1.6 1999/04/11 02:27:06 eivind Exp $ |
30 */ 31 32/* 33 * The kernel resource manager. This code is responsible for keeping track 34 * of hardware resources which are apportioned out to various drivers. 35 * It does not actually assign those resources, and it is not expected 36 * that end-device drivers will call into this code directly. Rather, 37 * the code which implements the buses that those devices are attached to, --- 19 unchanged lines hidden (view full) --- 57 * permitted. 58 */ 59 60#include <sys/param.h> 61#include <sys/systm.h> 62#include <sys/kernel.h> 63#include <sys/lock.h> 64#include <sys/malloc.h> |
65#include <sys/bus.h> /* XXX debugging */ |
66#include <machine/bus.h> 67#include <sys/rman.h> |
68 69static MALLOC_DEFINE(M_RMAN, "rman", "Resource manager"); 70 71struct rman_head rman_head; 72#ifndef NULL_SIMPLELOCKS 73static struct simplelock rman_lock; /* mutex to protect rman_head */ 74#endif 75static int int_rman_activate_resource(struct rman *rm, struct resource *r, 76 struct resource **whohas); |
77static int int_rman_deactivate_resource(struct resource *r); |
78static int int_rman_release_resource(struct rman *rm, struct resource *r); 79 80#define CIRCLEQ_TERMCOND(var, head) (var == (void *)&(head)) 81 82int 83rman_init(struct rman *rm) 84{ 85 static int once; --- 28 unchanged lines hidden (view full) --- 114int 115rman_manage_region(struct rman *rm, u_long start, u_long end) 116{ 117 struct resource *r, *s; 118 119 r = malloc(sizeof *r, M_RMAN, M_NOWAIT); 120 if (r == 0) 121 return ENOMEM; |
122 bzero(r, sizeof *r); |
123 r->r_sharehead = 0; 124 r->r_start = start; 125 r->r_end = end; 126 r->r_flags = 0; 127 r->r_dev = 0; 128 r->r_rm = rm; 129 130 simple_lock(rm->rm_slock); --- 15 unchanged lines hidden (view full) --- 146int 147rman_fini(struct rman *rm) 148{ 149 struct resource *r; 150 151 simple_lock(rm->rm_slock); 152 for (r = rm->rm_list.cqh_first; !CIRCLEQ_TERMCOND(r, rm->rm_list); 153 r = r->r_link.cqe_next) { |
154 if (r->r_flags & RF_ALLOCATED) { 155 simple_unlock(rm->rm_slock); |
156 return EBUSY; |
157 } |
158 } 159 160 /* 161 * There really should only be one of these if we are in this 162 * state and the code is working properly, but it can't hurt. 163 */ 164 for (r = rm->rm_list.cqh_first; !CIRCLEQ_TERMCOND(r, rm->rm_list); 165 r = rm->rm_list.cqh_first) { --- 88 unchanged lines hidden (view full) --- 254 * s->r_end > rstart + count - 1, then 255 * we need to split the region into three pieces 256 * (the middle one will get returned to the user). 257 * Otherwise, we are allocating at either the 258 * beginning or the end of s, so we only need to 259 * split it in two. The first case requires 260 * two new allocations; the second requires but one. 261 */ |
262 rv = malloc(sizeof *rv, M_RMAN, M_NOWAIT); |
263 if (rv == 0) 264 goto out; |
265 bzero(rv, sizeof *rv); |
266 rv->r_start = rstart; 267 rv->r_end = rstart + count - 1; 268 rv->r_flags = flags | RF_ALLOCATED; 269 rv->r_dev = dev; 270 rv->r_sharehead = 0; |
271 rv->r_rm = rm; |
272 273 if (s->r_start < rv->r_start && s->r_end > rv->r_end) { 274#ifdef RMAN_DEBUG 275 printf("splitting region in three parts: " 276 "[%#lx, %#lx]; [%#lx, %#lx]; [%#lx, %#lx]\n", 277 s->r_start, rv->r_start - 1, 278 rv->r_start, rv->r_end, 279 rv->r_end + 1, s->r_end); 280#endif /* RMAN_DEBUG */ 281 /* 282 * We are allocating in the middle. 283 */ 284 r = malloc(sizeof *r, M_RMAN, M_NOWAIT); 285 if (r == 0) { 286 free(rv, M_RMAN); 287 rv = 0; 288 goto out; 289 } |
290 bzero(r, sizeof *r); |
291 r->r_start = rv->r_end + 1; 292 r->r_end = s->r_end; 293 r->r_flags = s->r_flags; 294 r->r_dev = 0; 295 r->r_sharehead = 0; |
296 r->r_rm = rm; |
297 s->r_end = rv->r_start - 1; 298 CIRCLEQ_INSERT_AFTER(&rm->rm_list, s, rv, 299 r_link); 300 CIRCLEQ_INSERT_AFTER(&rm->rm_list, rv, r, 301 r_link); 302 } else if (s->r_start == rv->r_start) { 303#ifdef RMAN_DEBUG 304 printf("allocating from the beginning\n"); --- 41 unchanged lines hidden (view full) --- 346 continue; 347 rstart = max(s->r_start, start); 348 rend = min(s->r_end, max(start + count, end)); 349 if (s->r_start >= start && s->r_end <= end 350 && (s->r_end - s->r_start + 1) == count) { 351 rv = malloc(sizeof *rv, M_RMAN, M_NOWAIT); 352 if (rv == 0) 353 goto out; |
354 bzero(rv, sizeof *rv); |
355 rv->r_start = s->r_start; 356 rv->r_end = s->r_end; 357 rv->r_flags = s->r_flags & 358 (RF_ALLOCATED | RF_SHAREABLE | RF_TIMESHARE); 359 rv->r_dev = dev; 360 rv->r_rm = rm; 361 if (s->r_sharehead == 0) { 362 s->r_sharehead = malloc(sizeof *s->r_sharehead, 363 M_RMAN, M_NOWAIT); 364 if (s->r_sharehead == 0) { 365 free(rv, M_RMAN); 366 rv = 0; 367 goto out; 368 } |
369 bzero(s->r_sharehead, sizeof *s->r_sharehead); |
370 LIST_INIT(s->r_sharehead); 371 LIST_INSERT_HEAD(s->r_sharehead, s, 372 r_sharelink); 373 s->r_flags |= RF_FIRSTSHARE; 374 } 375 rv->r_sharehead = s->r_sharehead; 376 LIST_INSERT_HEAD(s->r_sharehead, rv, r_sharelink); 377 goto out; --- 79 unchanged lines hidden (view full) --- 457 struct resource *whohas; 458 struct rman *rm; 459 460 rm = r->r_rm; 461 for (;;) { 462 simple_lock(rm->rm_slock); 463 rv = int_rman_activate_resource(rm, r, &whohas); 464 if (rv != EBUSY) |
465 return (rv); /* returns with simplelock */ |
466 467 if (r->r_sharehead == 0) 468 panic("rman_await_resource"); 469 /* 470 * splhigh hopefully will prevent a race between 471 * simple_unlock and tsleep where a process 472 * could conceivably get in and release the resource 473 * before we have a chance to sleep on it. --- 6 unchanged lines hidden (view full) --- 480 splx(s); 481 return rv; 482 } 483 simple_lock(rm->rm_slock); 484 splx(s); 485 } 486} 487 |
488static int 489int_rman_deactivate_resource(struct resource *r) |
490{ 491 struct rman *rm; 492 493 rm = r->r_rm; |
494 r->r_flags &= ~RF_ACTIVE; 495 if (r->r_flags & RF_WANTED) { 496 r->r_flags &= ~RF_WANTED; 497 wakeup(r->r_sharehead); 498 } |
499 return 0; 500} 501 502int 503rman_deactivate_resource(struct resource *r) 504{ 505 struct rman *rm; 506 507 rm = r->r_rm; 508 simple_lock(rm->rm_slock); 509 int_rman_deactivate_resource(r); |
510 simple_unlock(rm->rm_slock); 511 return 0; 512} 513 514static int 515int_rman_release_resource(struct rman *rm, struct resource *r) 516{ 517 struct resource *s, *t; 518 519 if (r->r_flags & RF_ACTIVE) |
520 int_rman_deactivate_resource(r); |
521 522 /* 523 * Check for a sharing list first. If there is one, then we don't 524 * have to think as hard. 525 */ 526 if (r->r_sharehead) { 527 /* 528 * If a sharing list exists, then we know there are at --- 84 unchanged lines hidden --- |