2 * linux/kernel/resource.c
4 * Copyright (C) 1999 Linus Torvalds
5 * Copyright (C) 1999 Martin Mares <mj@ucw.cz>
7 * Arbitrary resource management.
10 #include <lwk/errno.h>
11 #include <lwk/resource.h>
13 #include <lwk/spinlock.h>
16 struct resource ioport_resource = {
19 .end = IO_SPACE_LIMIT,
20 .flags = IORESOURCE_IO,
23 struct resource iomem_resource = {
27 .flags = IORESOURCE_MEM,
30 static DEFINE_RWLOCK(resource_lock);
32 /* Return the conflict entry if you can't request it */
33 static struct resource * __request_resource(struct resource *root, struct resource *new)
35 unsigned long start = new->start;
36 unsigned long end = new->end;
37 struct resource *tmp, **p;
41 if (start < root->start)
48 if (!tmp || tmp->start > end) {
61 static int __release_resource(struct resource *old)
63 struct resource *tmp, **p;
67 p = &old->parent->child;
82 int request_resource(struct resource *root, struct resource *new)
84 struct resource *conflict;
86 write_lock(&resource_lock);
87 conflict = __request_resource(root, new);
88 write_unlock(&resource_lock);
89 return conflict ? -EBUSY : 0;
92 struct resource *____request_resource(struct resource *root, struct resource *new)
94 struct resource *conflict;
96 write_lock(&resource_lock);
97 conflict = __request_resource(root, new);
98 write_unlock(&resource_lock);
102 int release_resource(struct resource *old)
106 write_lock(&resource_lock);
107 retval = __release_resource(old);
108 write_unlock(&resource_lock);
113 * Find empty slot in the resource tree given range and alignment.
115 static int find_resource(struct resource *root, struct resource *new,
117 unsigned long min, unsigned long max,
119 void (*alignf)(void *, struct resource *,
120 unsigned long, unsigned long),
123 struct resource *this = root->child;
125 new->start = root->start;
127 * Skip past an allocated resource that starts at 0, since the assignment
128 * of this->start - 1 to new->end below would cause an underflow.
130 if (this && this->start == 0) {
131 new->start = this->end + 1;
132 this = this->sibling;
136 new->end = this->start - 1;
138 new->end = root->end;
139 if (new->start < min)
143 new->start = ALIGN(new->start, align);
145 alignf(alignf_data, new, size, align);
146 if (new->start < new->end && new->end - new->start >= size - 1) {
147 new->end = new->start + size - 1;
152 new->start = this->end + 1;
153 this = this->sibling;
159 * Allocate empty slot in the resource tree given range and alignment.
161 int allocate_resource(struct resource *root, struct resource *new,
163 unsigned long min, unsigned long max,
165 void (*alignf)(void *, struct resource *,
166 unsigned long, unsigned long),
171 write_lock(&resource_lock);
172 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
173 if (err >= 0 && __request_resource(root, new))
175 write_unlock(&resource_lock);
180 * insert_resource - Inserts a resource in the resource tree
181 * @parent: parent of the new resource
182 * @new: new resource to insert
184 * Returns 0 on success, -EBUSY if the resource can't be inserted.
186 * This function is equivalent to request_resource when no conflict
187 * happens. If a conflict happens, and the conflicting resources
188 * entirely fit within the range of the new resource, then the new
189 * resource is inserted and the conflicting resources become children of
192 int insert_resource(struct resource *parent, struct resource *new)
195 struct resource *first, *next;
197 write_lock(&resource_lock);
199 for (;; parent = first) {
201 first = __request_resource(parent, new);
209 if ((first->start > new->start) || (first->end < new->end))
211 if ((first->start == new->start) && (first->end == new->end))
215 for (next = first; ; next = next->sibling) {
216 /* Partial overlap? Bad, and unfixable */
217 if (next->start < new->start || next->end > new->end)
221 if (next->sibling->start > new->end)
227 new->parent = parent;
228 new->sibling = next->sibling;
231 next->sibling = NULL;
232 for (next = first; next; next = next->sibling)
235 if (parent->child == first) {
238 next = parent->child;
239 while (next->sibling != first)
240 next = next->sibling;
245 write_unlock(&resource_lock);
250 * Given an existing resource, change its start and size to match the
251 * arguments. Returns -EBUSY if it can't fit. Existing children of
252 * the resource are assumed to be immutable.
254 int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
256 struct resource *tmp, *parent = res->parent;
257 unsigned long end = start + size - 1;
260 write_lock(&resource_lock);
262 if ((start < parent->start) || (end > parent->end))
265 for (tmp = res->child; tmp; tmp = tmp->sibling) {
266 if ((tmp->start < start) || (tmp->end > end))
270 if (res->sibling && (res->sibling->start <= end))
275 while (tmp->sibling != res)
277 if (start <= tmp->end)
286 write_unlock(&resource_lock);