subr_rman.c revision 53225
140711Swollman/* 240711Swollman * Copyright 1998 Massachusetts Institute of Technology 340711Swollman * 440711Swollman * Permission to use, copy, modify, and distribute this software and 540711Swollman * its documentation for any purpose and without fee is hereby 640711Swollman * granted, provided that both the above copyright notice and this 740711Swollman * permission notice appear in all copies, that both the above 840711Swollman * copyright notice and this permission notice appear in all 940711Swollman * supporting documentation, and that the name of M.I.T. not be used 1040711Swollman * in advertising or publicity pertaining to distribution of the 1140711Swollman * software without specific, written prior permission. M.I.T. makes 1240711Swollman * no representations about the suitability of this software for any 1340711Swollman * purpose. It is provided "as is" without express or implied 1440711Swollman * warranty. 1540711Swollman * 1640711Swollman * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1740711Swollman * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1840711Swollman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1940711Swollman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2040711Swollman * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2140711Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2240711Swollman * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2340711Swollman * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2440711Swollman * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2540711Swollman * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2640711Swollman * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2740711Swollman * SUCH DAMAGE. 2840711Swollman * 2950477Speter * $FreeBSD: head/sys/kern/subr_rman.c 53225 1999-11-16 16:28:58Z phk $ 3040711Swollman */ 3140711Swollman 3240711Swollman/* 3340711Swollman * The kernel resource manager. This code is responsible for keeping track 3440711Swollman * of hardware resources which are apportioned out to various drivers. 3540711Swollman * It does not actually assign those resources, and it is not expected 3640711Swollman * that end-device drivers will call into this code directly. Rather, 3740711Swollman * the code which implements the buses that those devices are attached to, 3840711Swollman * and the code which manages CPU resources, will call this code, and the 3940711Swollman * end-device drivers will make upcalls to that code to actually perform 4040711Swollman * the allocation. 4140711Swollman * 4240711Swollman * There are two sorts of resources managed by this code. The first is 4340711Swollman * the more familiar array (RMAN_ARRAY) type; resources in this class 4440711Swollman * consist of a sequence of individually-allocatable objects which have 4540711Swollman * been numbered in some well-defined order. Most of the resources 4640711Swollman * are of this type, as it is the most familiar. The second type is 4740711Swollman * called a gauge (RMAN_GAUGE), and models fungible resources (i.e., 4840711Swollman * resources in which each instance is indistinguishable from every 4940711Swollman * other instance). The principal anticipated application of gauges 5040711Swollman * is in the context of power consumption, where a bus may have a specific 5140711Swollman * power budget which all attached devices share. RMAN_GAUGE is not 5240711Swollman * implemented yet. 5340711Swollman * 5440711Swollman * For array resources, we make one simplifying assumption: two clients 5540711Swollman * sharing the same resource must use the same range of indices. That 5640711Swollman * is to say, sharing of overlapping-but-not-identical regions is not 5740711Swollman * permitted. 5840711Swollman */ 5940711Swollman 6040711Swollman#include <sys/param.h> 6140711Swollman#include <sys/systm.h> 6241304Sbde#include <sys/kernel.h> 6340711Swollman#include <sys/lock.h> 6440711Swollman#include <sys/malloc.h> 6545720Speter#include <sys/bus.h> /* XXX debugging */ 6645720Speter#include <machine/bus.h> 6740711Swollman#include <sys/rman.h> 6840711Swollman 6945569Seivindstatic MALLOC_DEFINE(M_RMAN, "rman", "Resource manager"); 7040711Swollman 7140711Swollmanstruct rman_head rman_head; 7242248Sbde#ifndef NULL_SIMPLELOCKS 7340711Swollmanstatic struct simplelock rman_lock; /* mutex to protect rman_head */ 7442248Sbde#endif 7540711Swollmanstatic int int_rman_activate_resource(struct rman *rm, struct resource *r, 7640711Swollman struct resource **whohas); 7745720Speterstatic int int_rman_deactivate_resource(struct resource *r); 7840711Swollmanstatic int int_rman_release_resource(struct rman *rm, struct resource *r); 7940711Swollman 8040711Swollman#define CIRCLEQ_TERMCOND(var, head) (var == (void *)&(head)) 8140711Swollman 8240711Swollmanint 8340711Swollmanrman_init(struct rman *rm) 8440711Swollman{ 8540711Swollman static int once; 8640711Swollman 8740711Swollman if (once == 0) { 8840711Swollman once = 1; 8940711Swollman TAILQ_INIT(&rman_head); 9040711Swollman simple_lock_init(&rman_lock); 9140711Swollman } 9240711Swollman 9340711Swollman if (rm->rm_type == RMAN_UNINIT) 9440711Swollman panic("rman_init"); 9540711Swollman if (rm->rm_type == RMAN_GAUGE) 9640711Swollman panic("implement RMAN_GAUGE"); 9740711Swollman 9840711Swollman CIRCLEQ_INIT(&rm->rm_list); 9940711Swollman rm->rm_slock = malloc(sizeof *rm->rm_slock, M_RMAN, M_NOWAIT); 10040711Swollman if (rm->rm_slock == 0) 10140711Swollman return ENOMEM; 10240711Swollman simple_lock_init(rm->rm_slock); 10340711Swollman 10440711Swollman simple_lock(&rman_lock); 10540711Swollman TAILQ_INSERT_TAIL(&rman_head, rm, rm_link); 10640711Swollman simple_unlock(&rman_lock); 10740711Swollman return 0; 10840711Swollman} 10940711Swollman 11040711Swollman/* 11140711Swollman * NB: this interface is not robust against programming errors which 11240711Swollman * add multiple copies of the same region. 11340711Swollman */ 11440711Swollmanint 11540711Swollmanrman_manage_region(struct rman *rm, u_long start, u_long end) 11640711Swollman{ 11740711Swollman struct resource *r, *s; 11840711Swollman 11940711Swollman r = malloc(sizeof *r, M_RMAN, M_NOWAIT); 12040711Swollman if (r == 0) 12140711Swollman return ENOMEM; 12245720Speter bzero(r, sizeof *r); 12340711Swollman r->r_sharehead = 0; 12440711Swollman r->r_start = start; 12540711Swollman r->r_end = end; 12640711Swollman r->r_flags = 0; 12740711Swollman r->r_dev = 0; 12840711Swollman r->r_rm = rm; 12940711Swollman 13040711Swollman simple_lock(rm->rm_slock); 13153225Sphk for (s = CIRCLEQ_FIRST(&rm->rm_list); 13240711Swollman !CIRCLEQ_TERMCOND(s, rm->rm_list) && s->r_end < r->r_start; 13353225Sphk s = CIRCLEQ_NEXT(s, r_link)) 13440711Swollman ; 13540711Swollman 13640711Swollman if (CIRCLEQ_TERMCOND(s, rm->rm_list)) { 13740711Swollman CIRCLEQ_INSERT_TAIL(&rm->rm_list, r, r_link); 13840711Swollman } else { 13940711Swollman CIRCLEQ_INSERT_BEFORE(&rm->rm_list, s, r, r_link); 14040711Swollman } 14140711Swollman 14240711Swollman simple_unlock(rm->rm_slock); 14340711Swollman return 0; 14440711Swollman} 14540711Swollman 14640711Swollmanint 14740711Swollmanrman_fini(struct rman *rm) 14840711Swollman{ 14940711Swollman struct resource *r; 15040711Swollman 15140711Swollman simple_lock(rm->rm_slock); 15253225Sphk CIRCLEQ_FOREACH(r, &rm->rm_list, r_link) { 15345720Speter if (r->r_flags & RF_ALLOCATED) { 15445720Speter simple_unlock(rm->rm_slock); 15540711Swollman return EBUSY; 15645720Speter } 15740711Swollman } 15840711Swollman 15940711Swollman /* 16040711Swollman * There really should only be one of these if we are in this 16140711Swollman * state and the code is working properly, but it can't hurt. 16240711Swollman */ 16353225Sphk while (!CIRCLEQ_EMPTY(&rm->rm_list)) { 16453225Sphk r = CIRCLEQ_FIRST(&rm->rm_list); 16540711Swollman CIRCLEQ_REMOVE(&rm->rm_list, r, r_link); 16640711Swollman free(r, M_RMAN); 16740711Swollman } 16840711Swollman simple_unlock(rm->rm_slock); 16940711Swollman simple_lock(&rman_lock); 17040711Swollman TAILQ_REMOVE(&rman_head, rm, rm_link); 17140711Swollman simple_unlock(&rman_lock); 17240711Swollman free(rm->rm_slock, M_RMAN); 17340711Swollman 17440711Swollman return 0; 17540711Swollman} 17640711Swollman 17740711Swollmanstruct resource * 17840711Swollmanrman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, 17940711Swollman u_int flags, struct device *dev) 18040711Swollman{ 18140711Swollman u_int want_activate; 18240711Swollman struct resource *r, *s, *rv; 18340711Swollman u_long rstart, rend; 18440711Swollman 18540711Swollman rv = 0; 18640711Swollman 18740711Swollman#ifdef RMAN_DEBUG 18840711Swollman printf("rman_reserve_resource: <%s> request: [%#lx, %#lx], length " 18940711Swollman "%#lx, flags %u, device %s%d\n", rm->rm_descr, start, end, 19040711Swollman count, flags, device_get_name(dev), device_get_unit(dev)); 19140711Swollman#endif /* RMAN_DEBUG */ 19240711Swollman want_activate = (flags & RF_ACTIVE); 19340711Swollman flags &= ~RF_ACTIVE; 19440711Swollman 19540711Swollman simple_lock(rm->rm_slock); 19640711Swollman 19753225Sphk for (r = CIRCLEQ_FIRST(&rm->rm_list); 19840711Swollman !CIRCLEQ_TERMCOND(r, rm->rm_list) && r->r_end < start; 19953225Sphk r = CIRCLEQ_NEXT(r, r_link)) 20040711Swollman ; 20140711Swollman 20240711Swollman if (CIRCLEQ_TERMCOND(r, rm->rm_list)) { 20340711Swollman#ifdef RMAN_DEBUG 20440711Swollman printf("could not find a region\n"); 20540711Swollman#endif RMAN_DEBUG 20640711Swollman goto out; 20740711Swollman } 20840711Swollman 20940711Swollman /* 21040711Swollman * First try to find an acceptable totally-unshared region. 21140711Swollman */ 21240711Swollman for (s = r; !CIRCLEQ_TERMCOND(s, rm->rm_list); 21353225Sphk s = CIRCLEQ_NEXT(s, r_link)) { 21440711Swollman#ifdef RMAN_DEBUG 21540711Swollman printf("considering [%#lx, %#lx]\n", s->r_start, s->r_end); 21640711Swollman#endif /* RMAN_DEBUG */ 21740711Swollman if (s->r_start > end) { 21840711Swollman#ifdef RMAN_DEBUG 21940711Swollman printf("s->r_start (%#lx) > end (%#lx)\n", s->r_start, end); 22040711Swollman#endif /* RMAN_DEBUG */ 22140711Swollman break; 22240711Swollman } 22340711Swollman if (s->r_flags & RF_ALLOCATED) { 22440711Swollman#ifdef RMAN_DEBUG 22540711Swollman printf("region is allocated\n"); 22640711Swollman#endif /* RMAN_DEBUG */ 22740711Swollman continue; 22840711Swollman } 22940711Swollman rstart = max(s->r_start, start); 23040711Swollman rend = min(s->r_end, max(start + count, end)); 23140711Swollman#ifdef RMAN_DEBUG 23240711Swollman printf("truncated region: [%#lx, %#lx]; size %#lx (requested %#lx)\n", 23340711Swollman rstart, rend, (rend - rstart + 1), count); 23440711Swollman#endif /* RMAN_DEBUG */ 23540711Swollman 23640711Swollman if ((rend - rstart + 1) >= count) { 23740711Swollman#ifdef RMAN_DEBUG 23840711Swollman printf("candidate region: [%#lx, %#lx], size %#lx\n", 23940711Swollman rend, rstart, (rend - rstart + 1)); 24040711Swollman#endif /* RMAN_DEBUG */ 24140711Swollman if ((s->r_end - s->r_start + 1) == count) { 24240711Swollman#ifdef RMAN_DEBUG 24340711Swollman printf("candidate region is entire chunk\n"); 24440711Swollman#endif /* RMAN_DEBUG */ 24540711Swollman rv = s; 24648235Sdfr rv->r_flags |= RF_ALLOCATED | flags; 24740711Swollman rv->r_dev = dev; 24840711Swollman goto out; 24940711Swollman } 25040711Swollman 25140711Swollman /* 25240711Swollman * If s->r_start < rstart and 25340711Swollman * s->r_end > rstart + count - 1, then 25440711Swollman * we need to split the region into three pieces 25540711Swollman * (the middle one will get returned to the user). 25640711Swollman * Otherwise, we are allocating at either the 25740711Swollman * beginning or the end of s, so we only need to 25840711Swollman * split it in two. The first case requires 25940711Swollman * two new allocations; the second requires but one. 26040711Swollman */ 26145720Speter rv = malloc(sizeof *rv, M_RMAN, M_NOWAIT); 26240711Swollman if (rv == 0) 26340711Swollman goto out; 26445720Speter bzero(rv, sizeof *rv); 26540711Swollman rv->r_start = rstart; 26640711Swollman rv->r_end = rstart + count - 1; 26740711Swollman rv->r_flags = flags | RF_ALLOCATED; 26840711Swollman rv->r_dev = dev; 26940711Swollman rv->r_sharehead = 0; 27045720Speter rv->r_rm = rm; 27140711Swollman 27240711Swollman if (s->r_start < rv->r_start && s->r_end > rv->r_end) { 27340711Swollman#ifdef RMAN_DEBUG 27440711Swollman printf("splitting region in three parts: " 27540711Swollman "[%#lx, %#lx]; [%#lx, %#lx]; [%#lx, %#lx]\n", 27640711Swollman s->r_start, rv->r_start - 1, 27740711Swollman rv->r_start, rv->r_end, 27840711Swollman rv->r_end + 1, s->r_end); 27940711Swollman#endif /* RMAN_DEBUG */ 28040711Swollman /* 28140711Swollman * We are allocating in the middle. 28240711Swollman */ 28340711Swollman r = malloc(sizeof *r, M_RMAN, M_NOWAIT); 28440711Swollman if (r == 0) { 28540711Swollman free(rv, M_RMAN); 28640711Swollman rv = 0; 28740711Swollman goto out; 28840711Swollman } 28945720Speter bzero(r, sizeof *r); 29040711Swollman r->r_start = rv->r_end + 1; 29140711Swollman r->r_end = s->r_end; 29240711Swollman r->r_flags = s->r_flags; 29340711Swollman r->r_dev = 0; 29440711Swollman r->r_sharehead = 0; 29545720Speter r->r_rm = rm; 29640711Swollman s->r_end = rv->r_start - 1; 29740711Swollman CIRCLEQ_INSERT_AFTER(&rm->rm_list, s, rv, 29840711Swollman r_link); 29940711Swollman CIRCLEQ_INSERT_AFTER(&rm->rm_list, rv, r, 30040711Swollman r_link); 30140711Swollman } else if (s->r_start == rv->r_start) { 30240711Swollman#ifdef RMAN_DEBUG 30340711Swollman printf("allocating from the beginning\n"); 30440711Swollman#endif /* RMAN_DEBUG */ 30540711Swollman /* 30640711Swollman * We are allocating at the beginning. 30740711Swollman */ 30840711Swollman s->r_start = rv->r_end + 1; 30940711Swollman CIRCLEQ_INSERT_BEFORE(&rm->rm_list, s, rv, 31040711Swollman r_link); 31140711Swollman } else { 31240711Swollman#ifdef RMAN_DEBUG 31340711Swollman printf("allocating at the end\n"); 31440711Swollman#endif /* RMAN_DEBUG */ 31540711Swollman /* 31640711Swollman * We are allocating at the end. 31740711Swollman */ 31840711Swollman s->r_end = rv->r_start - 1; 31940711Swollman CIRCLEQ_INSERT_AFTER(&rm->rm_list, s, rv, 32040711Swollman r_link); 32140711Swollman } 32240711Swollman goto out; 32340711Swollman } 32440711Swollman } 32540711Swollman 32640711Swollman /* 32740711Swollman * Now find an acceptable shared region, if the client's requirements 32840711Swollman * allow sharing. By our implementation restriction, a candidate 32940711Swollman * region must match exactly by both size and sharing type in order 33040711Swollman * to be considered compatible with the client's request. (The 33140711Swollman * former restriction could probably be lifted without too much 33240711Swollman * additional work, but this does not seem warranted.) 33340711Swollman */ 33440711Swollman#ifdef RMAN_DEBUG 33540711Swollman printf("no unshared regions found\n"); 33640711Swollman#endif /* RMAN_DEBUG */ 33740711Swollman if ((flags & (RF_SHAREABLE | RF_TIMESHARE)) == 0) 33840711Swollman goto out; 33940711Swollman 34040711Swollman for (s = r; !CIRCLEQ_TERMCOND(s, rm->rm_list); 34153225Sphk s = CIRCLEQ_NEXT(s, r_link)) { 34240711Swollman if (s->r_start > end) 34340711Swollman break; 34440711Swollman if ((s->r_flags & flags) != flags) 34540711Swollman continue; 34640711Swollman rstart = max(s->r_start, start); 34740711Swollman rend = min(s->r_end, max(start + count, end)); 34840711Swollman if (s->r_start >= start && s->r_end <= end 34940711Swollman && (s->r_end - s->r_start + 1) == count) { 35040711Swollman rv = malloc(sizeof *rv, M_RMAN, M_NOWAIT); 35140711Swollman if (rv == 0) 35240711Swollman goto out; 35345720Speter bzero(rv, sizeof *rv); 35440711Swollman rv->r_start = s->r_start; 35540711Swollman rv->r_end = s->r_end; 35640711Swollman rv->r_flags = s->r_flags & 35740711Swollman (RF_ALLOCATED | RF_SHAREABLE | RF_TIMESHARE); 35840711Swollman rv->r_dev = dev; 35940711Swollman rv->r_rm = rm; 36040711Swollman if (s->r_sharehead == 0) { 36140711Swollman s->r_sharehead = malloc(sizeof *s->r_sharehead, 36240711Swollman M_RMAN, M_NOWAIT); 36340711Swollman if (s->r_sharehead == 0) { 36440711Swollman free(rv, M_RMAN); 36540711Swollman rv = 0; 36640711Swollman goto out; 36740711Swollman } 36845720Speter bzero(s->r_sharehead, sizeof *s->r_sharehead); 36940711Swollman LIST_INIT(s->r_sharehead); 37040711Swollman LIST_INSERT_HEAD(s->r_sharehead, s, 37140711Swollman r_sharelink); 37245106Sdfr s->r_flags |= RF_FIRSTSHARE; 37340711Swollman } 37440711Swollman rv->r_sharehead = s->r_sharehead; 37540711Swollman LIST_INSERT_HEAD(s->r_sharehead, rv, r_sharelink); 37640711Swollman goto out; 37740711Swollman } 37840711Swollman } 37940711Swollman 38040711Swollman /* 38140711Swollman * We couldn't find anything. 38240711Swollman */ 38340711Swollmanout: 38440711Swollman /* 38540711Swollman * If the user specified RF_ACTIVE in the initial flags, 38640711Swollman * which is reflected in `want_activate', we attempt to atomically 38740711Swollman * activate the resource. If this fails, we release the resource 38840711Swollman * and indicate overall failure. (This behavior probably doesn't 38940711Swollman * make sense for RF_TIMESHARE-type resources.) 39040711Swollman */ 39140711Swollman if (rv && want_activate) { 39240711Swollman struct resource *whohas; 39340711Swollman if (int_rman_activate_resource(rm, rv, &whohas)) { 39440711Swollman int_rman_release_resource(rm, rv); 39540711Swollman rv = 0; 39640711Swollman } 39740711Swollman } 39840711Swollman 39940711Swollman simple_unlock(rm->rm_slock); 40040711Swollman return (rv); 40140711Swollman} 40240711Swollman 40340711Swollmanstatic int 40440711Swollmanint_rman_activate_resource(struct rman *rm, struct resource *r, 40540711Swollman struct resource **whohas) 40640711Swollman{ 40740711Swollman struct resource *s; 40840711Swollman int ok; 40940711Swollman 41040711Swollman /* 41140711Swollman * If we are not timesharing, then there is nothing much to do. 41240711Swollman * If we already have the resource, then there is nothing at all to do. 41340711Swollman * If we are not on a sharing list with anybody else, then there is 41440711Swollman * little to do. 41540711Swollman */ 41640711Swollman if ((r->r_flags & RF_TIMESHARE) == 0 41740711Swollman || (r->r_flags & RF_ACTIVE) != 0 41840711Swollman || r->r_sharehead == 0) { 41940711Swollman r->r_flags |= RF_ACTIVE; 42040711Swollman return 0; 42140711Swollman } 42240711Swollman 42340711Swollman ok = 1; 42453225Sphk for (s = LIST_FIRST(r->r_sharehead); s && ok; 42553225Sphk s = LIST_NEXT(s, r_sharelink)) { 42640711Swollman if ((s->r_flags & RF_ACTIVE) != 0) { 42740711Swollman ok = 0; 42840711Swollman *whohas = s; 42940711Swollman } 43040711Swollman } 43140711Swollman if (ok) { 43240711Swollman r->r_flags |= RF_ACTIVE; 43340711Swollman return 0; 43440711Swollman } 43540711Swollman return EBUSY; 43640711Swollman} 43740711Swollman 43840711Swollmanint 43940711Swollmanrman_activate_resource(struct resource *r) 44040711Swollman{ 44140711Swollman int rv; 44240711Swollman struct resource *whohas; 44340711Swollman struct rman *rm; 44440711Swollman 44540711Swollman rm = r->r_rm; 44640711Swollman simple_lock(rm->rm_slock); 44740711Swollman rv = int_rman_activate_resource(rm, r, &whohas); 44840711Swollman simple_unlock(rm->rm_slock); 44940711Swollman return rv; 45040711Swollman} 45140711Swollman 45240711Swollmanint 45340711Swollmanrman_await_resource(struct resource *r, int pri, int timo) 45440711Swollman{ 45540711Swollman int rv, s; 45640711Swollman struct resource *whohas; 45740711Swollman struct rman *rm; 45840711Swollman 45940711Swollman rm = r->r_rm; 46040711Swollman for (;;) { 46140711Swollman simple_lock(rm->rm_slock); 46240711Swollman rv = int_rman_activate_resource(rm, r, &whohas); 46340711Swollman if (rv != EBUSY) 46445720Speter return (rv); /* returns with simplelock */ 46540711Swollman 46640711Swollman if (r->r_sharehead == 0) 46740711Swollman panic("rman_await_resource"); 46840711Swollman /* 46940711Swollman * splhigh hopefully will prevent a race between 47040711Swollman * simple_unlock and tsleep where a process 47140711Swollman * could conceivably get in and release the resource 47240711Swollman * before we have a chance to sleep on it. 47340711Swollman */ 47440711Swollman s = splhigh(); 47540711Swollman whohas->r_flags |= RF_WANTED; 47640711Swollman simple_unlock(rm->rm_slock); 47740711Swollman rv = tsleep(r->r_sharehead, pri, "rmwait", timo); 47840711Swollman if (rv) { 47940711Swollman splx(s); 48040711Swollman return rv; 48140711Swollman } 48240711Swollman simple_lock(rm->rm_slock); 48340711Swollman splx(s); 48440711Swollman } 48540711Swollman} 48640711Swollman 48745720Speterstatic int 48845720Speterint_rman_deactivate_resource(struct resource *r) 48940711Swollman{ 49040711Swollman struct rman *rm; 49140711Swollman 49240711Swollman rm = r->r_rm; 49340711Swollman r->r_flags &= ~RF_ACTIVE; 49440711Swollman if (r->r_flags & RF_WANTED) { 49540711Swollman r->r_flags &= ~RF_WANTED; 49640711Swollman wakeup(r->r_sharehead); 49740711Swollman } 49845720Speter return 0; 49945720Speter} 50045720Speter 50145720Speterint 50245720Speterrman_deactivate_resource(struct resource *r) 50345720Speter{ 50445720Speter struct rman *rm; 50545720Speter 50645720Speter rm = r->r_rm; 50745720Speter simple_lock(rm->rm_slock); 50845720Speter int_rman_deactivate_resource(r); 50940711Swollman simple_unlock(rm->rm_slock); 51040711Swollman return 0; 51140711Swollman} 51240711Swollman 51340711Swollmanstatic int 51440711Swollmanint_rman_release_resource(struct rman *rm, struct resource *r) 51540711Swollman{ 51640711Swollman struct resource *s, *t; 51740711Swollman 51840711Swollman if (r->r_flags & RF_ACTIVE) 51945720Speter int_rman_deactivate_resource(r); 52040711Swollman 52140711Swollman /* 52240711Swollman * Check for a sharing list first. If there is one, then we don't 52340711Swollman * have to think as hard. 52440711Swollman */ 52540711Swollman if (r->r_sharehead) { 52640711Swollman /* 52740711Swollman * If a sharing list exists, then we know there are at 52840711Swollman * least two sharers. 52940711Swollman * 53040711Swollman * If we are in the main circleq, appoint someone else. 53140711Swollman */ 53240711Swollman LIST_REMOVE(r, r_sharelink); 53353225Sphk s = LIST_FIRST(r->r_sharehead); 53440711Swollman if (r->r_flags & RF_FIRSTSHARE) { 53540711Swollman s->r_flags |= RF_FIRSTSHARE; 53640711Swollman CIRCLEQ_INSERT_BEFORE(&rm->rm_list, r, s, r_link); 53740711Swollman CIRCLEQ_REMOVE(&rm->rm_list, r, r_link); 53840711Swollman } 53940711Swollman 54040711Swollman /* 54140711Swollman * Make sure that the sharing list goes away completely 54240711Swollman * if the resource is no longer being shared at all. 54340711Swollman */ 54453225Sphk if (LIST_NEXT(s, r_sharelink) == 0) { 54540711Swollman free(s->r_sharehead, M_RMAN); 54640711Swollman s->r_sharehead = 0; 54740711Swollman s->r_flags &= ~RF_FIRSTSHARE; 54840711Swollman } 54940711Swollman goto out; 55040711Swollman } 55140711Swollman 55240711Swollman /* 55340711Swollman * Look at the adjacent resources in the list and see if our 55440711Swollman * segment can be merged with any of them. 55540711Swollman */ 55653225Sphk s = CIRCLEQ_PREV(r, r_link); 55753225Sphk t = CIRCLEQ_NEXT(r, r_link); 55840711Swollman 55940711Swollman if (s != (void *)&rm->rm_list && (s->r_flags & RF_ALLOCATED) == 0 56040711Swollman && t != (void *)&rm->rm_list && (t->r_flags & RF_ALLOCATED) == 0) { 56140711Swollman /* 56240711Swollman * Merge all three segments. 56340711Swollman */ 56440711Swollman s->r_end = t->r_end; 56540711Swollman CIRCLEQ_REMOVE(&rm->rm_list, r, r_link); 56640711Swollman CIRCLEQ_REMOVE(&rm->rm_list, t, r_link); 56740711Swollman free(t, M_RMAN); 56840711Swollman } else if (s != (void *)&rm->rm_list 56940711Swollman && (s->r_flags & RF_ALLOCATED) == 0) { 57040711Swollman /* 57140711Swollman * Merge previous segment with ours. 57240711Swollman */ 57340711Swollman s->r_end = r->r_end; 57440711Swollman CIRCLEQ_REMOVE(&rm->rm_list, r, r_link); 57540711Swollman } else if (t != (void *)&rm->rm_list 57640711Swollman && (t->r_flags & RF_ALLOCATED) == 0) { 57740711Swollman /* 57840711Swollman * Merge next segment with ours. 57940711Swollman */ 58040711Swollman t->r_start = r->r_start; 58140711Swollman CIRCLEQ_REMOVE(&rm->rm_list, r, r_link); 58240711Swollman } else { 58340711Swollman /* 58440711Swollman * At this point, we know there is nothing we 58540711Swollman * can potentially merge with, because on each 58640711Swollman * side, there is either nothing there or what is 58740711Swollman * there is still allocated. In that case, we don't 58840711Swollman * want to remove r from the list; we simply want to 58940711Swollman * change it to an unallocated region and return 59040711Swollman * without freeing anything. 59140711Swollman */ 59240711Swollman r->r_flags &= ~RF_ALLOCATED; 59340711Swollman return 0; 59440711Swollman } 59540711Swollman 59640711Swollmanout: 59740711Swollman free(r, M_RMAN); 59840711Swollman return 0; 59940711Swollman} 60040711Swollman 60140711Swollmanint 60240711Swollmanrman_release_resource(struct resource *r) 60340711Swollman{ 60440711Swollman int rv; 60540711Swollman struct rman *rm = r->r_rm; 60640711Swollman 60740711Swollman simple_lock(rm->rm_slock); 60840711Swollman rv = int_rman_release_resource(rm, r); 60940711Swollman simple_unlock(rm->rm_slock); 61040711Swollman return (rv); 61140711Swollman} 612