subr_rman.c revision 160958
1279377Simp/*-
2279377Simp * Copyright 1998 Massachusetts Institute of Technology
3279377Simp *
4279377Simp * Permission to use, copy, modify, and distribute this software and
5279377Simp * its documentation for any purpose and without fee is hereby
6279377Simp * granted, provided that both the above copyright notice and this
7279377Simp * permission notice appear in all copies, that both the above
8279377Simp * copyright notice and this permission notice appear in all
9279377Simp * supporting documentation, and that the name of M.I.T. not be used
10279377Simp * in advertising or publicity pertaining to distribution of the
11279377Simp * software without specific, written prior permission.  M.I.T. makes
12279377Simp * no representations about the suitability of this software for any
13279377Simp * purpose.  It is provided "as is" without express or implied
14279377Simp * warranty.
15279377Simp *
16279377Simp * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17279377Simp * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18279377Simp * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19279377Simp * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20279377Simp * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21279377Simp * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22279377Simp * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23279377Simp * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24279377Simp * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25279377Simp * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26279377Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27279377Simp * SUCH DAMAGE.
28279377Simp */
29279377Simp
30279377Simp/*
31279377Simp * The kernel resource manager.  This code is responsible for keeping track
32279377Simp * of hardware resources which are apportioned out to various drivers.
33279377Simp * It does not actually assign those resources, and it is not expected
34279377Simp * that end-device drivers will call into this code directly.  Rather,
35279377Simp * the code which implements the buses that those devices are attached to,
36279377Simp * and the code which manages CPU resources, will call this code, and the
37279377Simp * end-device drivers will make upcalls to that code to actually perform
38279377Simp * the allocation.
39279377Simp *
40279377Simp * There are two sorts of resources managed by this code.  The first is
41279377Simp * the more familiar array (RMAN_ARRAY) type; resources in this class
42279377Simp * consist of a sequence of individually-allocatable objects which have
43279377Simp * been numbered in some well-defined order.  Most of the resources
44279377Simp * are of this type, as it is the most familiar.  The second type is
45279377Simp * called a gauge (RMAN_GAUGE), and models fungible resources (i.e.,
46279377Simp * resources in which each instance is indistinguishable from every
47279377Simp * other instance).  The principal anticipated application of gauges
48279377Simp * is in the context of power consumption, where a bus may have a specific
49279377Simp * power budget which all attached devices share.  RMAN_GAUGE is not
50279377Simp * implemented yet.
51279377Simp *
52279377Simp * For array resources, we make one simplifying assumption: two clients
53279377Simp * sharing the same resource must use the same range of indices.  That
54279377Simp * is to say, sharing of overlapping-but-not-identical regions is not
55279377Simp * permitted.
56279377Simp */
57279377Simp
58279377Simp#include <sys/cdefs.h>
59279377Simp__FBSDID("$FreeBSD: head/sys/kern/subr_rman.c 160958 2006-08-03 21:19:13Z jb $");
60279377Simp
61279377Simp#include <sys/param.h>
62279377Simp#include <sys/systm.h>
63279377Simp#include <sys/kernel.h>
64279377Simp#include <sys/lock.h>
65279377Simp#include <sys/malloc.h>
66279377Simp#include <sys/mutex.h>
67279377Simp#include <sys/bus.h>		/* XXX debugging */
68279377Simp#include <machine/bus.h>
69279377Simp#include <sys/rman.h>
70279377Simp#include <sys/sysctl.h>
71279377Simp
72279377Simp/*
73279377Simp * We use a linked list rather than a bitmap because we need to be able to
74279377Simp * represent potentially huge objects (like all of a processor's physical
75279377Simp * address space).  That is also why the indices are defined to have type
76279377Simp * `unsigned long' -- that being the largest integral type in ISO C (1990).
77279377Simp * The 1999 version of C allows `long long'; we may need to switch to that
78279377Simp * at some point in the future, particularly if we want to support 36-bit
79279377Simp * addresses on IA32 hardware.
80279377Simp */
81279377Simpstruct resource_i {
82279377Simp	struct resource		r_r;
83279377Simp	TAILQ_ENTRY(resource_i)	r_link;
84279377Simp	LIST_ENTRY(resource_i)	r_sharelink;
85279377Simp	LIST_HEAD(, resource_i)	*r_sharehead;
86279377Simp	u_long	r_start;	/* index of the first entry in this resource */
87279377Simp	u_long	r_end;		/* index of the last entry (inclusive) */
88279377Simp	u_int	r_flags;
89279377Simp	void	*r_virtual;	/* virtual address of this resource */
90279377Simp	struct	device *r_dev;	/* device which has allocated this resource */
91279377Simp	struct	rman *r_rm;	/* resource manager from whence this came */
92279377Simp	int	r_rid;		/* optional rid for this resource. */
93279377Simp};
94279377Simp
95279377Simpint     rman_debug = 0;
96279377SimpTUNABLE_INT("debug.rman_debug", &rman_debug);
97279377SimpSYSCTL_INT(_debug, OID_AUTO, rman_debug, CTLFLAG_RW,
98279377Simp    &rman_debug, 0, "rman debug");
99279377Simp
100279377Simp#define DPRINTF(params) if (rman_debug) printf params
101279377Simp
102279377Simpstatic MALLOC_DEFINE(M_RMAN, "rman", "Resource manager");
103279377Simp
104279377Simpstruct	rman_head rman_head;
105279377Simpstatic	struct mtx rman_mtx; /* mutex to protect rman_head */
106279377Simpstatic	int int_rman_activate_resource(struct rman *rm, struct resource_i *r,
107279377Simp				       struct resource_i **whohas);
108279377Simpstatic	int int_rman_deactivate_resource(struct resource_i *r);
109279377Simpstatic	int int_rman_release_resource(struct rman *rm, struct resource_i *r);
110279377Simp
111279377Simpstatic __inline struct resource_i *
112279377Simpint_alloc_resource(int malloc_flag)
113279377Simp{
114279377Simp	struct resource_i *r;
115279377Simp
116279377Simp	r = malloc(sizeof *r, M_RMAN, malloc_flag | M_ZERO);
117279377Simp	if (r != NULL) {
118279377Simp		r->r_r.__r_i = r;
119279377Simp	}
120279377Simp	return (r);
121279377Simp}
122279377Simp
123279377Simpint
124279377Simprman_init(struct rman *rm)
125279377Simp{
126279377Simp	static int once = 0;
127279377Simp
128279377Simp	if (once == 0) {
129279377Simp		once = 1;
130279377Simp		TAILQ_INIT(&rman_head);
131279377Simp		mtx_init(&rman_mtx, "rman head", NULL, MTX_DEF);
132279377Simp	}
133279377Simp
134279377Simp	if (rm->rm_type == RMAN_UNINIT)
135279377Simp		panic("rman_init");
136279377Simp	if (rm->rm_type == RMAN_GAUGE)
137279377Simp		panic("implement RMAN_GAUGE");
138279377Simp
139279377Simp	TAILQ_INIT(&rm->rm_list);
140279377Simp	rm->rm_mtx = malloc(sizeof *rm->rm_mtx, M_RMAN, M_NOWAIT | M_ZERO);
141279377Simp	if (rm->rm_mtx == NULL)
142279377Simp		return ENOMEM;
143279377Simp	mtx_init(rm->rm_mtx, "rman", NULL, MTX_DEF);
144279377Simp
145279377Simp	mtx_lock(&rman_mtx);
146279377Simp	TAILQ_INSERT_TAIL(&rman_head, rm, rm_link);
147279377Simp	mtx_unlock(&rman_mtx);
148279377Simp	return 0;
149279377Simp}
150279377Simp
151279377Simp/*
152279377Simp * NB: this interface is not robust against programming errors which
153279377Simp * add multiple copies of the same region.
154279377Simp */
155279377Simpint
156279377Simprman_manage_region(struct rman *rm, u_long start, u_long end)
157279377Simp{
158279377Simp	struct resource_i *r, *s;
159279377Simp
160279377Simp	DPRINTF(("rman_manage_region: <%s> request: start %#lx, end %#lx\n",
161279377Simp	    rm->rm_descr, start, end));
162279377Simp	r = int_alloc_resource(M_NOWAIT);
163279377Simp	if (r == NULL)
164279377Simp		return ENOMEM;
165279377Simp	r->r_start = start;
166279377Simp	r->r_end = end;
167279377Simp	r->r_rm = rm;
168279377Simp
169279377Simp	mtx_lock(rm->rm_mtx);
170279377Simp	for (s = TAILQ_FIRST(&rm->rm_list);
171279377Simp	     s && s->r_end < r->r_start;
172279377Simp	     s = TAILQ_NEXT(s, r_link))
173279377Simp		;
174279377Simp
175279377Simp	if (s == NULL) {
176279377Simp		TAILQ_INSERT_TAIL(&rm->rm_list, r, r_link);
177279377Simp	} else {
178279377Simp		TAILQ_INSERT_BEFORE(s, r, r_link);
179279377Simp	}
180279377Simp
181279377Simp	mtx_unlock(rm->rm_mtx);
182279377Simp	return 0;
183279377Simp}
184279377Simp
185279377Simpint
186279377Simprman_init_from_resource(struct rman *rm, struct resource *r)
187279377Simp{
188279377Simp	int rv;
189279377Simp
190279377Simp	if ((rv = rman_init(rm)) != 0)
191279377Simp		return (rv);
192279377Simp	return (rman_manage_region(rm, r->__r_i->r_start, r->__r_i->r_end));
193279377Simp}
194279377Simp
195279377Simpint
196279377Simprman_fini(struct rman *rm)
197279377Simp{
198279377Simp	struct resource_i *r;
199279377Simp
200279377Simp	mtx_lock(rm->rm_mtx);
201279377Simp	TAILQ_FOREACH(r, &rm->rm_list, r_link) {
202279377Simp		if (r->r_flags & RF_ALLOCATED) {
203279377Simp			mtx_unlock(rm->rm_mtx);
204279377Simp			return EBUSY;
205279377Simp		}
206279377Simp	}
207279377Simp
208279377Simp	/*
209279377Simp	 * There really should only be one of these if we are in this
210279377Simp	 * state and the code is working properly, but it can't hurt.
211279377Simp	 */
212279377Simp	while (!TAILQ_EMPTY(&rm->rm_list)) {
213279377Simp		r = TAILQ_FIRST(&rm->rm_list);
214279377Simp		TAILQ_REMOVE(&rm->rm_list, r, r_link);
215279377Simp		free(r, M_RMAN);
216279377Simp	}
217279377Simp	mtx_unlock(rm->rm_mtx);
218279377Simp	mtx_lock(&rman_mtx);
219279377Simp	TAILQ_REMOVE(&rman_head, rm, rm_link);
220279377Simp	mtx_unlock(&rman_mtx);
221279377Simp	mtx_destroy(rm->rm_mtx);
222279377Simp	free(rm->rm_mtx, M_RMAN);
223279377Simp
224279377Simp	return 0;
225279377Simp}
226279377Simp
227279377Simpstruct resource *
228279377Simprman_reserve_resource_bound(struct rman *rm, u_long start, u_long end,
229279377Simp		      u_long count, u_long bound,  u_int flags,
230279377Simp		      struct device *dev)
231279377Simp{
232279377Simp	u_int	want_activate;
233279377Simp	struct	resource_i *r, *s, *rv;
234279377Simp	u_long	rstart, rend, amask, bmask;
235279377Simp
236279377Simp	rv = NULL;
237279377Simp
238279377Simp	DPRINTF(("rman_reserve_resource_bound: <%s> request: [%#lx, %#lx], "
239279377Simp	       "length %#lx, flags %u, device %s\n", rm->rm_descr, start, end,
240279377Simp	       count, flags,
241279377Simp	       dev == NULL ? "<null>" : device_get_nameunit(dev)));
242279377Simp	want_activate = (flags & RF_ACTIVE);
243279377Simp	flags &= ~RF_ACTIVE;
244279377Simp
245279377Simp	mtx_lock(rm->rm_mtx);
246279377Simp
247279377Simp	for (r = TAILQ_FIRST(&rm->rm_list);
248279377Simp	     r && r->r_end < start;
249279377Simp	     r = TAILQ_NEXT(r, r_link))
250279377Simp		;
251279377Simp
252279377Simp	if (r == NULL) {
253279377Simp		DPRINTF(("could not find a region\n"));
254279377Simp		goto out;
255279377Simp	}
256279377Simp
257279377Simp	amask = (1ul << RF_ALIGNMENT(flags)) - 1;
258279377Simp	/* If bound is 0, bmask will also be 0 */
259279377Simp	bmask = ~(bound - 1);
260279377Simp	/*
261279377Simp	 * First try to find an acceptable totally-unshared region.
262279377Simp	 */
263279377Simp	for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
264279377Simp		DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end));
265279377Simp		if (s->r_start + count - 1 > end) {
266279377Simp			DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n",
267279377Simp			    s->r_start, end));
268279377Simp			break;
269279377Simp		}
270279377Simp		if (s->r_flags & RF_ALLOCATED) {
271279377Simp			DPRINTF(("region is allocated\n"));
272279377Simp			continue;
273279377Simp		}
274279377Simp		rstart = ulmax(s->r_start, start);
275279377Simp		/*
276279377Simp		 * Try to find a region by adjusting to boundary and alignment
277279377Simp		 * until both conditions are satisfied. This is not an optimal
278279377Simp		 * algorithm, but in most cases it isn't really bad, either.
279279377Simp		 */
280279377Simp		do {
281279377Simp			rstart = (rstart + amask) & ~amask;
282279377Simp			if (((rstart ^ (rstart + count - 1)) & bmask) != 0)
283279377Simp				rstart += bound - (rstart & ~bmask);
284279377Simp		} while ((rstart & amask) != 0 && rstart < end &&
285279377Simp		    rstart < s->r_end);
286279377Simp		rend = ulmin(s->r_end, ulmax(rstart + count - 1, end));
287279377Simp		if (rstart > rend) {
288279377Simp			DPRINTF(("adjusted start exceeds end\n"));
289279377Simp			continue;
290279377Simp		}
291279377Simp		DPRINTF(("truncated region: [%#lx, %#lx]; size %#lx (requested %#lx)\n",
292279377Simp		       rstart, rend, (rend - rstart + 1), count));
293279377Simp
294279377Simp		if ((rend - rstart + 1) >= count) {
295279377Simp			DPRINTF(("candidate region: [%#lx, %#lx], size %#lx\n",
296279377Simp			       rstart, rend, (rend - rstart + 1)));
297279377Simp			if ((s->r_end - s->r_start + 1) == count) {
298279377Simp				DPRINTF(("candidate region is entire chunk\n"));
299279377Simp				rv = s;
300279377Simp				rv->r_flags |= RF_ALLOCATED | flags;
301279377Simp				rv->r_dev = dev;
302279377Simp				goto out;
303279377Simp			}
304279377Simp
305279377Simp			/*
306279377Simp			 * If s->r_start < rstart and
307279377Simp			 *    s->r_end > rstart + count - 1, then
308279377Simp			 * we need to split the region into three pieces
309279377Simp			 * (the middle one will get returned to the user).
310279377Simp			 * Otherwise, we are allocating at either the
311279377Simp			 * beginning or the end of s, so we only need to
312279377Simp			 * split it in two.  The first case requires
313279377Simp			 * two new allocations; the second requires but one.
314279377Simp			 */
315279377Simp			rv = int_alloc_resource(M_NOWAIT);
316279377Simp			if (rv == NULL)
317279377Simp				goto out;
318279377Simp			rv->r_start = rstart;
319279377Simp			rv->r_end = rstart + count - 1;
320279377Simp			rv->r_flags = flags | RF_ALLOCATED;
321279377Simp			rv->r_dev = dev;
322279377Simp			rv->r_rm = rm;
323279377Simp
324279377Simp			if (s->r_start < rv->r_start && s->r_end > rv->r_end) {
325279377Simp				DPRINTF(("splitting region in three parts: "
326279377Simp				       "[%#lx, %#lx]; [%#lx, %#lx]; [%#lx, %#lx]\n",
327279377Simp				       s->r_start, rv->r_start - 1,
328279377Simp				       rv->r_start, rv->r_end,
329279377Simp				       rv->r_end + 1, s->r_end));
330279377Simp				/*
331279377Simp				 * We are allocating in the middle.
332279377Simp				 */
333279377Simp				r = int_alloc_resource(M_NOWAIT);
334279377Simp				if (r == NULL) {
335279377Simp					free(rv, M_RMAN);
336279377Simp					rv = NULL;
337279377Simp					goto out;
338279377Simp				}
339279377Simp				r->r_start = rv->r_end + 1;
340279377Simp				r->r_end = s->r_end;
341279377Simp				r->r_flags = s->r_flags;
342279377Simp				r->r_rm = rm;
343279377Simp				s->r_end = rv->r_start - 1;
344279377Simp				TAILQ_INSERT_AFTER(&rm->rm_list, s, rv,
345279377Simp						     r_link);
346279377Simp				TAILQ_INSERT_AFTER(&rm->rm_list, rv, r,
347279377Simp						     r_link);
348279377Simp			} else if (s->r_start == rv->r_start) {
349279377Simp				DPRINTF(("allocating from the beginning\n"));
350279377Simp				/*
351279377Simp				 * We are allocating at the beginning.
352279377Simp				 */
353279377Simp				s->r_start = rv->r_end + 1;
354279377Simp				TAILQ_INSERT_BEFORE(s, rv, r_link);
355279377Simp			} else {
356279377Simp				DPRINTF(("allocating at the end\n"));
357279377Simp				/*
358279377Simp				 * We are allocating at the end.
359279377Simp				 */
360279377Simp				s->r_end = rv->r_start - 1;
361279377Simp				TAILQ_INSERT_AFTER(&rm->rm_list, s, rv,
362279377Simp						     r_link);
363279377Simp			}
364279377Simp			goto out;
365279377Simp		}
366279377Simp	}
367279377Simp
368279377Simp	/*
369279377Simp	 * Now find an acceptable shared region, if the client's requirements
370279377Simp	 * allow sharing.  By our implementation restriction, a candidate
371279377Simp	 * region must match exactly by both size and sharing type in order
372279377Simp	 * to be considered compatible with the client's request.  (The
373279377Simp	 * former restriction could probably be lifted without too much
374279377Simp	 * additional work, but this does not seem warranted.)
375279377Simp	 */
376279377Simp	DPRINTF(("no unshared regions found\n"));
377279377Simp	if ((flags & (RF_SHAREABLE | RF_TIMESHARE)) == 0)
378279377Simp		goto out;
379279377Simp
380279377Simp	for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
381279377Simp		if (s->r_start > end)
382279377Simp			break;
383279377Simp		if ((s->r_flags & flags) != flags)
384279377Simp			continue;
385279377Simp		rstart = ulmax(s->r_start, start);
386279377Simp		rend = ulmin(s->r_end, ulmax(start + count - 1, end));
387279377Simp		if (s->r_start >= start && s->r_end <= end
388279377Simp		    && (s->r_end - s->r_start + 1) == count &&
389279377Simp		    (s->r_start & amask) == 0 &&
390279377Simp		    ((s->r_start ^ s->r_end) & bmask) == 0) {
391279377Simp			rv = int_alloc_resource(M_NOWAIT);
392279377Simp			if (rv == NULL)
393279377Simp				goto out;
394279377Simp			rv->r_start = s->r_start;
395279377Simp			rv->r_end = s->r_end;
396279377Simp			rv->r_flags = s->r_flags &
397279377Simp				(RF_ALLOCATED | RF_SHAREABLE | RF_TIMESHARE);
398279377Simp			rv->r_dev = dev;
399279377Simp			rv->r_rm = rm;
400279377Simp			if (s->r_sharehead == NULL) {
401279377Simp				s->r_sharehead = malloc(sizeof *s->r_sharehead,
402279377Simp						M_RMAN, M_NOWAIT | M_ZERO);
403279377Simp				if (s->r_sharehead == NULL) {
404279377Simp					free(rv, M_RMAN);
405279377Simp					rv = NULL;
406279377Simp					goto out;
407279377Simp				}
408279377Simp				LIST_INIT(s->r_sharehead);
409279377Simp				LIST_INSERT_HEAD(s->r_sharehead, s,
410279377Simp						 r_sharelink);
411279377Simp				s->r_flags |= RF_FIRSTSHARE;
412279377Simp			}
413279377Simp			rv->r_sharehead = s->r_sharehead;
414279377Simp			LIST_INSERT_HEAD(s->r_sharehead, rv, r_sharelink);
415279377Simp			goto out;
416279377Simp		}
417279377Simp	}
418279377Simp
419279377Simp	/*
420279377Simp	 * We couldn't find anything.
421279377Simp	 */
422279377Simpout:
423279377Simp	/*
424279377Simp	 * If the user specified RF_ACTIVE in the initial flags,
425279377Simp	 * which is reflected in `want_activate', we attempt to atomically
426279377Simp	 * activate the resource.  If this fails, we release the resource
427279377Simp	 * and indicate overall failure.  (This behavior probably doesn't
428279377Simp	 * make sense for RF_TIMESHARE-type resources.)
429279377Simp	 */
430279377Simp	if (rv && want_activate) {
431279377Simp		struct resource_i *whohas;
432279377Simp		if (int_rman_activate_resource(rm, rv, &whohas)) {
433279377Simp			int_rman_release_resource(rm, rv);
434279377Simp			rv = NULL;
435279377Simp		}
436279377Simp	}
437279377Simp
438279377Simp	mtx_unlock(rm->rm_mtx);
439279377Simp	return (rv == NULL ? NULL : &rv->r_r);
440279377Simp}
441279377Simp
442279377Simpstruct resource *
443279377Simprman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count,
444279377Simp		      u_int flags, struct device *dev)
445279377Simp{
446279377Simp
447279377Simp	return (rman_reserve_resource_bound(rm, start, end, count, 0, flags,
448279377Simp	    dev));
449279377Simp}
450279377Simp
451279377Simpstatic int
452279377Simpint_rman_activate_resource(struct rman *rm, struct resource_i *r,
453279377Simp			   struct resource_i **whohas)
454279377Simp{
455279377Simp	struct resource_i *s;
456279377Simp	int ok;
457279377Simp
458279377Simp	/*
459279377Simp	 * If we are not timesharing, then there is nothing much to do.
460279377Simp	 * If we already have the resource, then there is nothing at all to do.
461279377Simp	 * If we are not on a sharing list with anybody else, then there is
462279377Simp	 * little to do.
463279377Simp	 */
464279377Simp	if ((r->r_flags & RF_TIMESHARE) == 0
465279377Simp	    || (r->r_flags & RF_ACTIVE) != 0
466279377Simp	    || r->r_sharehead == NULL) {
467279377Simp		r->r_flags |= RF_ACTIVE;
468279377Simp		return 0;
469279377Simp	}
470279377Simp
471279377Simp	ok = 1;
472279377Simp	for (s = LIST_FIRST(r->r_sharehead); s && ok;
473279377Simp	     s = LIST_NEXT(s, r_sharelink)) {
474279377Simp		if ((s->r_flags & RF_ACTIVE) != 0) {
475279377Simp			ok = 0;
476279377Simp			*whohas = s;
477279377Simp		}
478279377Simp	}
479279377Simp	if (ok) {
480279377Simp		r->r_flags |= RF_ACTIVE;
481279377Simp		return 0;
482279377Simp	}
483279377Simp	return EBUSY;
484279377Simp}
485279377Simp
486279377Simpint
487279377Simprman_activate_resource(struct resource *re)
488279377Simp{
489279377Simp	int rv;
490279377Simp	struct resource_i *r, *whohas;
491279377Simp	struct rman *rm;
492279377Simp
493279377Simp	r = re->__r_i;
494279377Simp	rm = r->r_rm;
495279377Simp	mtx_lock(rm->rm_mtx);
496279377Simp	rv = int_rman_activate_resource(rm, r, &whohas);
497279377Simp	mtx_unlock(rm->rm_mtx);
498279377Simp	return rv;
499279377Simp}
500279377Simp
501279377Simpint
502279377Simprman_await_resource(struct resource *re, int pri, int timo)
503279377Simp{
504279377Simp	int	rv;
505279377Simp	struct	resource_i *r, *whohas;
506279377Simp	struct	rman *rm;
507279377Simp
508279377Simp	r = re->__r_i;
509279377Simp	rm = r->r_rm;
510279377Simp	mtx_lock(rm->rm_mtx);
511279377Simp	for (;;) {
512279377Simp		rv = int_rman_activate_resource(rm, r, &whohas);
513279377Simp		if (rv != EBUSY)
514279377Simp			return (rv);	/* returns with mutex held */
515279377Simp
516279377Simp		if (r->r_sharehead == NULL)
517279377Simp			panic("rman_await_resource");
518279377Simp		whohas->r_flags |= RF_WANTED;
519279377Simp		rv = msleep(r->r_sharehead, rm->rm_mtx, pri, "rmwait", timo);
520279377Simp		if (rv) {
521279377Simp			mtx_unlock(rm->rm_mtx);
522279377Simp			return (rv);
523279377Simp		}
524279377Simp	}
525279377Simp}
526279377Simp
527279377Simpstatic int
528279377Simpint_rman_deactivate_resource(struct resource_i *r)
529279377Simp{
530279377Simp
531279377Simp	r->r_flags &= ~RF_ACTIVE;
532279377Simp	if (r->r_flags & RF_WANTED) {
533279377Simp		r->r_flags &= ~RF_WANTED;
534279377Simp		wakeup(r->r_sharehead);
535279377Simp	}
536279377Simp	return 0;
537279377Simp}
538279377Simp
539279377Simpint
540279377Simprman_deactivate_resource(struct resource *r)
541279377Simp{
542279377Simp	struct	rman *rm;
543279377Simp
544279377Simp	rm = r->__r_i->r_rm;
545279377Simp	mtx_lock(rm->rm_mtx);
546279377Simp	int_rman_deactivate_resource(r->__r_i);
547279377Simp	mtx_unlock(rm->rm_mtx);
548279377Simp	return 0;
549279377Simp}
550279377Simp
551279377Simpstatic int
552279377Simpint_rman_release_resource(struct rman *rm, struct resource_i *r)
553279377Simp{
554279377Simp	struct	resource_i *s, *t;
555279377Simp
556279377Simp	if (r->r_flags & RF_ACTIVE)
557279377Simp		int_rman_deactivate_resource(r);
558279377Simp
559279377Simp	/*
560279377Simp	 * Check for a sharing list first.  If there is one, then we don't
561279377Simp	 * have to think as hard.
562279377Simp	 */
563279377Simp	if (r->r_sharehead) {
564279377Simp		/*
565279377Simp		 * If a sharing list exists, then we know there are at
566279377Simp		 * least two sharers.
567279377Simp		 *
568279377Simp		 * If we are in the main circleq, appoint someone else.
569279377Simp		 */
570279377Simp		LIST_REMOVE(r, r_sharelink);
571279377Simp		s = LIST_FIRST(r->r_sharehead);
572279377Simp		if (r->r_flags & RF_FIRSTSHARE) {
573279377Simp			s->r_flags |= RF_FIRSTSHARE;
574279377Simp			TAILQ_INSERT_BEFORE(r, s, r_link);
575279377Simp			TAILQ_REMOVE(&rm->rm_list, r, r_link);
576279377Simp		}
577279377Simp
578279377Simp		/*
579279377Simp		 * Make sure that the sharing list goes away completely
580279377Simp		 * if the resource is no longer being shared at all.
581279377Simp		 */
582279377Simp		if (LIST_NEXT(s, r_sharelink) == NULL) {
583279377Simp			free(s->r_sharehead, M_RMAN);
584279377Simp			s->r_sharehead = NULL;
585279377Simp			s->r_flags &= ~RF_FIRSTSHARE;
586279377Simp		}
587279377Simp		goto out;
588279377Simp	}
589279377Simp
590279377Simp	/*
591279377Simp	 * Look at the adjacent resources in the list and see if our
592279377Simp	 * segment can be merged with any of them.  If either of the
593279377Simp	 * resources is allocated or is not exactly adjacent then they
594279377Simp	 * cannot be merged with our segment.
595279377Simp	 */
596279377Simp	s = TAILQ_PREV(r, resource_head, r_link);
597279377Simp	if (s != NULL && ((s->r_flags & RF_ALLOCATED) != 0 ||
598279377Simp	    s->r_end + 1 != r->r_start))
599279377Simp		s = NULL;
600279377Simp	t = TAILQ_NEXT(r, r_link);
601279377Simp	if (t != NULL && ((t->r_flags & RF_ALLOCATED) != 0 ||
602279377Simp	    r->r_end + 1 != t->r_start))
603279377Simp		t = NULL;
604279377Simp
605279377Simp	if (s != NULL && t != NULL) {
606279377Simp		/*
607279377Simp		 * Merge all three segments.
608279377Simp		 */
609279377Simp		s->r_end = t->r_end;
610279377Simp		TAILQ_REMOVE(&rm->rm_list, r, r_link);
611279377Simp		TAILQ_REMOVE(&rm->rm_list, t, r_link);
612279377Simp		free(t, M_RMAN);
613279377Simp	} else if (s != NULL) {
614279377Simp		/*
615279377Simp		 * Merge previous segment with ours.
616279377Simp		 */
617279377Simp		s->r_end = r->r_end;
618279377Simp		TAILQ_REMOVE(&rm->rm_list, r, r_link);
619279377Simp	} else if (t != NULL) {
620279377Simp		/*
621279377Simp		 * Merge next segment with ours.
622279377Simp		 */
623279377Simp		t->r_start = r->r_start;
624279377Simp		TAILQ_REMOVE(&rm->rm_list, r, r_link);
625279377Simp	} else {
626279377Simp		/*
627279377Simp		 * At this point, we know there is nothing we
628279377Simp		 * can potentially merge with, because on each
629279377Simp		 * side, there is either nothing there or what is
630279377Simp		 * there is still allocated.  In that case, we don't
631279377Simp		 * want to remove r from the list; we simply want to
632279377Simp		 * change it to an unallocated region and return
633279377Simp		 * without freeing anything.
634279377Simp		 */
635279377Simp		r->r_flags &= ~RF_ALLOCATED;
636279377Simp		return 0;
637279377Simp	}
638279377Simp
639279377Simpout:
640279377Simp	free(r, M_RMAN);
641279377Simp	return 0;
642279377Simp}
643279377Simp
644279377Simpint
645279377Simprman_release_resource(struct resource *re)
646279377Simp{
647279377Simp	int	rv;
648279377Simp	struct	resource_i *r;
649279377Simp	struct	rman *rm;
650
651	r = re->__r_i;
652	rm = r->r_rm;
653	mtx_lock(rm->rm_mtx);
654	rv = int_rman_release_resource(rm, r);
655	mtx_unlock(rm->rm_mtx);
656	return (rv);
657}
658
659uint32_t
660rman_make_alignment_flags(uint32_t size)
661{
662	int	i;
663
664	/*
665	 * Find the hightest bit set, and add one if more than one bit
666	 * set.  We're effectively computing the ceil(log2(size)) here.
667	 */
668	for (i = 31; i > 0; i--)
669		if ((1 << i) & size)
670			break;
671	if (~(1 << i) & size)
672		i++;
673
674	return(RF_ALIGNMENT_LOG2(i));
675}
676
677u_long
678rman_get_start(struct resource *r)
679{
680	return (r->__r_i->r_start);
681}
682
683u_long
684rman_get_end(struct resource *r)
685{
686	return (r->__r_i->r_end);
687}
688
689u_long
690rman_get_size(struct resource *r)
691{
692	return (r->__r_i->r_end - r->__r_i->r_start + 1);
693}
694
695u_int
696rman_get_flags(struct resource *r)
697{
698	return (r->__r_i->r_flags);
699}
700
701void
702rman_set_virtual(struct resource *r, void *v)
703{
704	r->__r_i->r_virtual = v;
705}
706
707void *
708rman_get_virtual(struct resource *r)
709{
710	return (r->__r_i->r_virtual);
711}
712
713void
714rman_set_bustag(struct resource *r, bus_space_tag_t t)
715{
716	r->r_bustag = t;
717}
718
719bus_space_tag_t
720rman_get_bustag(struct resource *r)
721{
722	return (r->r_bustag);
723}
724
725void
726rman_set_bushandle(struct resource *r, bus_space_handle_t h)
727{
728	r->r_bushandle = h;
729}
730
731bus_space_handle_t
732rman_get_bushandle(struct resource *r)
733{
734	return (r->r_bushandle);
735}
736
737void
738rman_set_rid(struct resource *r, int rid)
739{
740	r->__r_i->r_rid = rid;
741}
742
743void
744rman_set_start(struct resource *r, u_long start)
745{
746	r->__r_i->r_start = start;
747}
748
749void
750rman_set_end(struct resource *r, u_long end)
751{
752	r->__r_i->r_end = end;
753}
754
755int
756rman_get_rid(struct resource *r)
757{
758	return (r->__r_i->r_rid);
759}
760
761struct device *
762rman_get_device(struct resource *r)
763{
764	return (r->__r_i->r_dev);
765}
766
767void
768rman_set_device(struct resource *r, struct device *dev)
769{
770	r->__r_i->r_dev = dev;
771}
772
773int
774rman_is_region_manager(struct resource *r, struct rman *rm)
775{
776
777	return (r->__r_i->r_rm == rm);
778}
779
780/*
781 * Sysctl interface for scanning the resource lists.
782 *
783 * We take two input parameters; the index into the list of resource
784 * managers, and the resource offset into the list.
785 */
786static int
787sysctl_rman(SYSCTL_HANDLER_ARGS)
788{
789	int			*name = (int *)arg1;
790	u_int			namelen = arg2;
791	int			rman_idx, res_idx;
792	struct rman		*rm;
793	struct resource_i	*res;
794	struct u_rman		urm;
795	struct u_resource	ures;
796	int			error;
797
798	if (namelen != 3)
799		return (EINVAL);
800
801	if (bus_data_generation_check(name[0]))
802		return (EINVAL);
803	rman_idx = name[1];
804	res_idx = name[2];
805
806	/*
807	 * Find the indexed resource manager
808	 */
809	mtx_lock(&rman_mtx);
810	TAILQ_FOREACH(rm, &rman_head, rm_link) {
811		if (rman_idx-- == 0)
812			break;
813	}
814	mtx_unlock(&rman_mtx);
815	if (rm == NULL)
816		return (ENOENT);
817
818	/*
819	 * If the resource index is -1, we want details on the
820	 * resource manager.
821	 */
822	if (res_idx == -1) {
823		bzero(&urm, sizeof(urm));
824		urm.rm_handle = (uintptr_t)rm;
825		strlcpy(urm.rm_descr, rm->rm_descr, RM_TEXTLEN);
826		urm.rm_start = rm->rm_start;
827		urm.rm_size = rm->rm_end - rm->rm_start + 1;
828		urm.rm_type = rm->rm_type;
829
830		error = SYSCTL_OUT(req, &urm, sizeof(urm));
831		return (error);
832	}
833
834	/*
835	 * Find the indexed resource and return it.
836	 */
837	mtx_lock(rm->rm_mtx);
838	TAILQ_FOREACH(res, &rm->rm_list, r_link) {
839		if (res_idx-- == 0) {
840			bzero(&ures, sizeof(ures));
841			ures.r_handle = (uintptr_t)res;
842			ures.r_parent = (uintptr_t)res->r_rm;
843			ures.r_device = (uintptr_t)res->r_dev;
844			if (res->r_dev != NULL) {
845				if (device_get_name(res->r_dev) != NULL) {
846					snprintf(ures.r_devname, RM_TEXTLEN,
847					    "%s%d",
848					    device_get_name(res->r_dev),
849					    device_get_unit(res->r_dev));
850				} else {
851					strlcpy(ures.r_devname, "nomatch",
852					    RM_TEXTLEN);
853				}
854			} else {
855				ures.r_devname[0] = '\0';
856			}
857			ures.r_start = res->r_start;
858			ures.r_size = res->r_end - res->r_start + 1;
859			ures.r_flags = res->r_flags;
860
861			mtx_unlock(rm->rm_mtx);
862			error = SYSCTL_OUT(req, &ures, sizeof(ures));
863			return (error);
864		}
865	}
866	mtx_unlock(rm->rm_mtx);
867	return (ENOENT);
868}
869
870SYSCTL_NODE(_hw_bus, OID_AUTO, rman, CTLFLAG_RD, sysctl_rman,
871    "kernel resource manager");
872