60 #include <sys/cdefs.h>
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/limits.h>
68 #include <sys/malloc.h>
69 #include <sys/mutex.h>
71 #include <machine/bus.h>
73 #include <sys/sysctl.h>
104 SYSCTL_INT(_debug, OID_AUTO, rman_debug, CTLFLAG_RW,
105 &rman_debug, 0, "rman debug");
107 #define DPRINTF(params) if (rman_debug) printf params
120 r =
malloc(
sizeof *r, M_RMAN, malloc_flag | M_ZERO);
138 if (rm->rm_start == 0 && rm->rm_end == 0)
140 if (rm->rm_type == RMAN_UNINIT)
142 if (rm->rm_type == RMAN_GAUGE)
143 panic(
"implement RMAN_GAUGE");
145 TAILQ_INIT(&rm->rm_list);
146 rm->rm_mtx =
malloc(
sizeof *rm->rm_mtx, M_RMAN, M_NOWAIT | M_ZERO);
147 if (rm->rm_mtx == NULL)
149 mtx_init(rm->rm_mtx,
"rman", NULL, MTX_DEF);
152 TAILQ_INSERT_TAIL(&
rman_head, rm, rm_link);
162 DPRINTF((
"rman_manage_region: <%s> request: start %#lx, end %#lx\n",
163 rm->rm_descr, start, end));
164 if (start < rm->rm_start || end > rm->rm_end)
173 mtx_lock(rm->rm_mtx);
176 TAILQ_FOREACH(s, &rm->rm_list, r_link) {
177 if (s->r_end == ULONG_MAX)
179 if (s->r_end + 1 >= r->r_start)
185 TAILQ_INSERT_TAIL(&rm->rm_list, r, r_link);
188 if (r->r_start <= s->r_end && r->r_end >= s->r_start)
192 t = TAILQ_NEXT(s, r_link);
193 if (t && r->r_start <= t->r_end && r->r_end >= t->r_start)
200 if (t && (r->r_end + 1 != t->r_start || t->r_flags != 0))
204 if (s->r_end + 1 == r->r_start && s->r_flags == 0) {
208 TAILQ_REMOVE(&rm->rm_list, t, r_link);
215 }
else if (t != NULL) {
217 t->r_start = r->r_start;
219 }
else if (s->r_end < r->r_start) {
220 TAILQ_INSERT_AFTER(&rm->rm_list, s, r, r_link);
222 TAILQ_INSERT_BEFORE(s, r, r_link);
226 mtx_unlock(rm->rm_mtx);
245 mtx_lock(rm->rm_mtx);
246 TAILQ_FOREACH(r, &rm->rm_list, r_link) {
247 if (r->r_flags & RF_ALLOCATED) {
248 mtx_unlock(rm->rm_mtx);
257 while (!TAILQ_EMPTY(&rm->rm_list)) {
258 r = TAILQ_FIRST(&rm->rm_list);
259 TAILQ_REMOVE(&rm->rm_list, r, r_link);
262 mtx_unlock(rm->rm_mtx);
267 free(rm->rm_mtx, M_RMAN);
277 mtx_lock(rm->rm_mtx);
278 TAILQ_FOREACH(r, &rm->rm_list, r_link) {
279 if (!(r->r_flags & RF_ALLOCATED)) {
282 mtx_unlock(rm->rm_mtx);
286 mtx_unlock(rm->rm_mtx);
295 mtx_lock(rm->rm_mtx);
296 TAILQ_FOREACH_REVERSE(r, &rm->rm_list, resource_head, r_link) {
297 if (!(r->r_flags & RF_ALLOCATED)) {
300 mtx_unlock(rm->rm_mtx);
304 mtx_unlock(rm->rm_mtx);
317 if (r->r_flags & RF_SHAREABLE)
325 if (end < r->r_start || r->r_end < start)
333 mtx_lock(rm->rm_mtx);
335 TAILQ_FOREACH(s, &rm->rm_list, r_link) {
340 panic(
"resource not in list");
342 s = TAILQ_PREV(r, resource_head, r_link);
343 t = TAILQ_NEXT(r, r_link);
344 KASSERT(s == NULL || s->r_end + 1 == r->r_start,
345 (
"prev resource mismatch"));
346 KASSERT(t == NULL || r->r_end + 1 == t->r_start,
347 (
"next resource mismatch"));
353 if (start < r->r_start && (s == NULL || (s->r_flags & RF_ALLOCATED) ||
354 s->r_start > start)) {
355 mtx_unlock(rm->rm_mtx);
358 if (end > r->r_end && (t == NULL || (t->r_flags & RF_ALLOCATED) ||
360 mtx_unlock(rm->rm_mtx);
370 if (start < r->r_start ||
371 (start > r->r_start && s != NULL && !(s->r_flags & RF_ALLOCATED))) {
372 KASSERT(s->r_flags == 0, (
"prev is busy"));
374 if (s->r_start == start) {
375 TAILQ_REMOVE(&rm->rm_list, s, r_link);
378 s->r_end = start - 1;
380 if (end > r->r_end ||
381 (end < r->r_end && t != NULL && !(t->r_flags & RF_ALLOCATED))) {
382 KASSERT(t->r_flags == 0, (
"next is busy"));
384 if (t->r_end == end) {
385 TAILQ_REMOVE(&rm->rm_list, t, r_link);
388 t->r_start = end + 1;
390 mtx_unlock(rm->rm_mtx);
397 if (start > r->r_start) {
399 new->r_start = r->r_start;
400 new->r_end = start - 1;
402 mtx_lock(rm->rm_mtx);
404 s = TAILQ_PREV(r, resource_head, r_link);
405 if (s != NULL && !(s->r_flags & RF_ALLOCATED)) {
406 s->r_end = start - 1;
409 TAILQ_INSERT_BEFORE(r,
new, r_link);
410 mtx_unlock(rm->rm_mtx);
412 if (end < r->r_end) {
414 new->r_start = end + 1;
415 new->r_end = r->r_end;
417 mtx_lock(rm->rm_mtx);
419 t = TAILQ_NEXT(r, r_link);
420 if (t != NULL && !(t->r_flags & RF_ALLOCATED)) {
421 t->r_start = end + 1;
424 TAILQ_INSERT_AFTER(&rm->rm_list, r,
new, r_link);
425 mtx_unlock(rm->rm_mtx);
430 #define SHARE_TYPE(f) (f & (RF_SHAREABLE | RF_PREFETCHABLE))
434 u_long
count, u_long bound, u_int flags,
439 u_long rstart, rend, amask, bmask;
443 DPRINTF((
"rman_reserve_resource_bound: <%s> request: [%#lx, %#lx], "
444 "length %#lx, flags %u, device %s\n", rm->rm_descr, start, end,
447 KASSERT((flags & RF_FIRSTSHARE) == 0,
448 (
"invalid flags %#x", flags));
449 new_rflags = (flags & ~RF_FIRSTSHARE) | RF_ALLOCATED;
451 mtx_lock(rm->rm_mtx);
453 for (r = TAILQ_FIRST(&rm->rm_list);
454 r && r->r_end < start + count - 1;
455 r = TAILQ_NEXT(r, r_link))
459 DPRINTF((
"could not find a region\n"));
463 amask = (1ul << RF_ALIGNMENT(flags)) - 1;
464 KASSERT(start <= ULONG_MAX - amask,
465 (
"start (%#lx) + amask (%#lx) would wrap around", start, amask));
468 bmask = ~(bound - 1);
472 for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
473 DPRINTF((
"considering [%#lx, %#lx]\n", s->r_start, s->r_end));
478 if (s->r_start > end - (count - 1)) {
479 DPRINTF((
"s->r_start (%#lx) + count - 1> end (%#lx)\n",
483 if (s->r_start > ULONG_MAX - amask) {
484 DPRINTF((
"s->r_start (%#lx) + amask (%#lx) too large\n",
488 if (s->r_flags & RF_ALLOCATED) {
489 DPRINTF((
"region is allocated\n"));
492 rstart = ulmax(s->r_start, start);
499 rstart = (rstart + amask) & ~amask;
500 if (((rstart ^ (rstart + count - 1)) & bmask) != 0)
501 rstart += bound - (rstart & ~bmask);
502 }
while ((rstart & amask) != 0 && rstart < end &&
504 rend = ulmin(s->r_end, ulmax(rstart + count - 1, end));
506 DPRINTF((
"adjusted start exceeds end\n"));
509 DPRINTF((
"truncated region: [%#lx, %#lx]; size %#lx (requested %#lx)\n",
510 rstart, rend, (rend - rstart + 1), count));
512 if ((rend - rstart + 1) >= count) {
513 DPRINTF((
"candidate region: [%#lx, %#lx], size %#lx\n",
514 rstart, rend, (rend - rstart + 1)));
515 if ((s->r_end - s->r_start + 1) == count) {
516 DPRINTF((
"candidate region is entire chunk\n"));
518 rv->r_flags = new_rflags;
536 rv->r_start = rstart;
537 rv->r_end = rstart + count - 1;
538 rv->r_flags = new_rflags;
542 if (s->r_start < rv->r_start && s->r_end > rv->r_end) {
543 DPRINTF((
"splitting region in three parts: "
544 "[%#lx, %#lx]; [%#lx, %#lx]; [%#lx, %#lx]\n",
545 s->r_start, rv->r_start - 1,
546 rv->r_start, rv->r_end,
547 rv->r_end + 1, s->r_end));
557 r->r_start = rv->r_end + 1;
559 r->r_flags = s->r_flags;
561 s->r_end = rv->r_start - 1;
562 TAILQ_INSERT_AFTER(&rm->rm_list, s, rv,
564 TAILQ_INSERT_AFTER(&rm->rm_list, rv, r,
566 }
else if (s->r_start == rv->r_start) {
567 DPRINTF((
"allocating from the beginning\n"));
571 s->r_start = rv->r_end + 1;
572 TAILQ_INSERT_BEFORE(s, rv, r_link);
574 DPRINTF((
"allocating at the end\n"));
578 s->r_end = rv->r_start - 1;
579 TAILQ_INSERT_AFTER(&rm->rm_list, s, rv,
594 DPRINTF((
"no unshared regions found\n"));
595 if ((flags & RF_SHAREABLE) == 0)
598 for (s = r; s && s->r_end <= end; s = TAILQ_NEXT(s, r_link)) {
600 s->r_start >= start &&
601 (s->r_end - s->r_start + 1) == count &&
602 (s->r_start & amask) == 0 &&
603 ((s->r_start ^ s->r_end) & bmask) == 0) {
607 rv->r_start = s->r_start;
608 rv->r_end = s->r_end;
609 rv->r_flags = new_rflags;
612 if (s->r_sharehead == NULL) {
613 s->r_sharehead =
malloc(
sizeof *s->r_sharehead,
614 M_RMAN, M_NOWAIT | M_ZERO);
615 if (s->r_sharehead == NULL) {
620 LIST_INIT(s->r_sharehead);
621 LIST_INSERT_HEAD(s->r_sharehead, s,
623 s->r_flags |= RF_FIRSTSHARE;
625 rv->r_sharehead = s->r_sharehead;
626 LIST_INSERT_HEAD(s->r_sharehead, rv, r_sharelink);
635 mtx_unlock(rm->rm_mtx);
636 return (rv == NULL ? NULL : &rv->
r_r);
641 u_int flags,
struct device *dev)
656 mtx_lock(rm->rm_mtx);
657 r->r_flags |= RF_ACTIVE;
658 mtx_unlock(rm->rm_mtx);
668 mtx_lock(rm->rm_mtx);
669 r->__r_i->r_flags &= ~RF_ACTIVE;
670 mtx_unlock(rm->rm_mtx);
679 if (r->r_flags & RF_ACTIVE)
680 r->r_flags &= ~RF_ACTIVE;
686 if (r->r_sharehead) {
693 LIST_REMOVE(r, r_sharelink);
694 s = LIST_FIRST(r->r_sharehead);
695 if (r->r_flags & RF_FIRSTSHARE) {
696 s->r_flags |= RF_FIRSTSHARE;
697 TAILQ_INSERT_BEFORE(r, s, r_link);
698 TAILQ_REMOVE(&rm->rm_list, r, r_link);
705 if (LIST_NEXT(s, r_sharelink) == NULL) {
706 free(s->r_sharehead, M_RMAN);
707 s->r_sharehead = NULL;
708 s->r_flags &= ~RF_FIRSTSHARE;
719 s = TAILQ_PREV(r, resource_head, r_link);
720 if (s != NULL && ((s->r_flags & RF_ALLOCATED) != 0 ||
721 s->r_end + 1 != r->r_start))
723 t = TAILQ_NEXT(r, r_link);
724 if (t != NULL && ((t->r_flags & RF_ALLOCATED) != 0 ||
725 r->r_end + 1 != t->r_start))
728 if (s != NULL && t != NULL) {
733 TAILQ_REMOVE(&rm->rm_list, r, r_link);
734 TAILQ_REMOVE(&rm->rm_list, t, r_link);
736 }
else if (s != NULL) {
741 TAILQ_REMOVE(&rm->rm_list, r, r_link);
742 }
else if (t != NULL) {
746 t->r_start = r->r_start;
747 TAILQ_REMOVE(&rm->rm_list, r, r_link);
758 r->r_flags &= ~RF_ALLOCATED;
777 mtx_lock(rm->rm_mtx);
779 mtx_unlock(rm->rm_mtx);
792 for (i = 31; i > 0; i--)
795 if (~(1 << i) & size)
798 return(RF_ALIGNMENT_LOG2(i));
805 r->__r_i->r_start =
start;
812 return (r->__r_i->r_start);
819 r->__r_i->r_end = end;
826 return (r->__r_i->r_end);
833 return (r->__r_i->r_end - r->__r_i->r_start + 1);
840 return (r->__r_i->r_flags);
847 r->__r_i->r_virtual = v;
854 return (r->__r_i->r_virtual);
868 return (r->r_bustag);
882 return (r->r_bushandle);
889 r->__r_i->r_rid = rid;
896 return (r->__r_i->r_rid);
903 r->__r_i->r_dev = dev;
910 return (r->__r_i->r_dev);
917 return (r->__r_i->r_rm == rm);
929 int *
name = (
int *)arg1;
930 u_int namelen = arg2;
931 int rman_idx, res_idx;
936 struct u_resource ures;
964 bzero(&urm,
sizeof(urm));
965 urm.rm_handle = (uintptr_t)rm;
966 if (rm->rm_descr != NULL)
967 strlcpy(urm.rm_descr, rm->rm_descr, RM_TEXTLEN);
968 urm.rm_start = rm->rm_start;
969 urm.rm_size = rm->rm_end - rm->rm_start + 1;
970 urm.rm_type = rm->rm_type;
972 error = SYSCTL_OUT(req, &urm,
sizeof(urm));
979 mtx_lock(rm->rm_mtx);
980 TAILQ_FOREACH(res, &rm->rm_list, r_link) {
981 if (res->r_sharehead != NULL) {
982 LIST_FOREACH(sres, res->r_sharehead, r_sharelink)
983 if (res_idx-- == 0) {
988 else if (res_idx-- == 0)
991 mtx_unlock(rm->rm_mtx);
995 bzero(&ures,
sizeof(ures));
996 ures.r_handle = (uintptr_t)res;
997 ures.r_parent = (uintptr_t)res->r_rm;
998 ures.r_device = (uintptr_t)res->r_dev;
999 if (res->r_dev != NULL) {
1001 snprintf(ures.r_devname, RM_TEXTLEN,
1006 strlcpy(ures.r_devname,
"nomatch",
1010 ures.r_devname[0] =
'\0';
1012 ures.r_start = res->r_start;
1013 ures.r_size = res->r_end - res->r_start + 1;
1014 ures.r_flags = res->r_flags;
1016 mtx_unlock(rm->rm_mtx);
1017 error = SYSCTL_OUT(req, &ures,
sizeof(ures));
1022 "kernel resource manager");
1026 dump_rman_header(
struct rman *rm)
1031 db_printf(
"rman %p: %s (0x%lx-0x%lx full range)\n",
1032 rm, rm->rm_descr, rm->rm_start, rm->rm_end);
1036 dump_rman(
struct rman *rm)
1039 const char *devname;
1043 TAILQ_FOREACH(r, &rm->rm_list, r_link) {
1044 if (r->r_dev != NULL) {
1046 if (devname == NULL)
1047 devname =
"nomatch";
1050 db_printf(
" 0x%lx-0x%lx (RID=%d) ",
1051 r->r_start, r->r_end, r->r_rid);
1052 if (devname != NULL)
1053 db_printf(
"(%s)\n", devname);
1055 db_printf(
"----\n");
1061 DB_SHOW_COMMAND(rman, db_show_rman)
1065 dump_rman_header((
struct rman *)addr);
1066 dump_rman((
struct rman *)addr);
1070 DB_SHOW_COMMAND(rmans, db_show_rmans)
1074 TAILQ_FOREACH(rm, &
rman_head, rm_link) {
1075 dump_rman_header(rm);
1079 DB_SHOW_ALL_COMMAND(rman, db_show_all_rman)
1083 TAILQ_FOREACH(rm, &
rman_head, rm_link) {
1084 dump_rman_header(rm);
1088 DB_SHOW_ALIAS(allrman, db_show_all_rman);
int rman_adjust_resource(struct resource *rr, u_long start, u_long end)
u_int rman_get_flags(struct resource *r)
TUNABLE_INT("debug.rman_debug",&rman_debug)
int rman_init(struct rman *rm)
struct resource * 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)
int snprintf(char *str, size_t size, const char *format,...)
int rman_get_rid(struct resource *r)
void rman_set_device(struct resource *r, struct device *dev)
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
bus_space_handle_t rman_get_bushandle(struct resource *r)
void * rman_get_virtual(struct resource *r)
int rman_activate_resource(struct resource *re)
void panic(const char *fmt,...)
uint32_t rman_make_alignment_flags(uint32_t size)
int device_get_unit(device_t dev)
Return the device's unit number.
bus_space_tag_t rman_get_bustag(struct resource *r)
void rman_set_end(struct resource *r, u_long end)
static __inline struct resource_i * int_alloc_resource(int malloc_flag)
int rman_first_free_region(struct rman *rm, u_long *start, u_long *end)
u_long rman_get_start(struct resource *r)
struct rman_head rman_head
Implementation of device.
struct resource * rman_reserve_resource(struct rman *rm, u_long start, u_long end, u_long count, u_int flags, struct device *dev)
void rman_set_start(struct resource *r, u_long start)
static int int_rman_release_resource(struct rman *rm, struct resource_i *r)
void rman_set_virtual(struct resource *r, void *v)
SYSCTL_INT(_debug, OID_AUTO, rman_debug, CTLFLAG_RW,&rman_debug, 0,"rman debug")
int bus_data_generation_check(int generation)
struct device * rman_get_device(struct resource *r)
u_long rman_get_size(struct resource *r)
void rman_set_bustag(struct resource *r, bus_space_tag_t t)
int rman_init_from_resource(struct rman *rm, struct resource *r)
void rman_set_rid(struct resource *r, int rid)
int rman_deactivate_resource(struct resource *r)
static MALLOC_DEFINE(M_RMAN,"rman","Resource manager")
void free(void *addr, struct malloc_type *mtp)
int rman_is_region_manager(struct resource *r, struct rman *rm)
void rman_set_bushandle(struct resource *r, bus_space_handle_t h)
int rman_manage_region(struct rman *rm, u_long start, u_long end)
int rman_fini(struct rman *rm)
void mtx_init(struct mtx *m, const char *name, const char *type, int opts)
static struct mtx rman_mtx
static SYSCTL_NODE(_hw_bus, OID_AUTO, rman, CTLFLAG_RD, sysctl_rman,"kernel resource manager")
u_long rman_get_end(struct resource *r)
int rman_release_resource(struct resource *re)
int rman_last_free_region(struct rman *rm, u_long *start, u_long *end)
const char * device_get_nameunit(device_t dev)
Return a string containing the device's devclass name followed by an ascii representation of the devi...
const char * device_get_name(device_t dev)
Return the name of the device's devclass or NULL if there is none.
static int sysctl_rman(SYSCTL_HANDLER_ARGS)
void mtx_destroy(struct mtx *m)