Import 2.3.18pre1
[davej-history.git] / kernel / resource.c
blob26ee5e29d692c7635a42f0b8cd20ec9d6c24458a
1 /*
2 * linux/kernel/resource.c
4 * Copyright (C) 1999 Linus Torvalds
5 * Copyright (C) 1999 Martin Mares <mj@ucw.cz>
7 * Arbitrary resource management.
8 */
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/ioport.h>
13 #include <linux/init.h>
14 #include <linux/malloc.h>
15 #include <linux/spinlock.h>
17 struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF, IORESOURCE_IO };
18 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF, IORESOURCE_MEM };
20 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
23 * This generates reports for /proc/ioports and /proc/memory
25 static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
27 if (offset < 0)
28 offset = 0;
30 while (entry) {
31 const char *name = entry->name;
32 unsigned long from, to;
34 if ((int) (end-buf) < 80)
35 return buf;
37 from = entry->start;
38 to = entry->end;
39 if (!name)
40 name = "<BAD>";
42 buf += sprintf(buf, fmt + offset, from, to, name);
43 if (entry->child)
44 buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
45 entry = entry->sibling;
48 return buf;
51 int get_resource_list(struct resource *root, char *buf, int size)
53 char *fmt;
54 int retval;
56 fmt = " %08lx-%08lx : %s\n";
57 if (root == &ioport_resource)
58 fmt = " %04lx-%04lx : %s\n";
59 read_lock(&resource_lock);
60 retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
61 read_unlock(&resource_lock);
62 return retval;
65 /* Return the conflict entry if you can't request it */
66 static struct resource * __request_resource(struct resource *root, struct resource *new)
68 unsigned long start = new->start;
69 unsigned long end = new->end;
70 struct resource *tmp, **p;
72 if (end < start)
73 return root;
74 if (start < root->start)
75 return root;
76 if (end > root->end)
77 return root;
78 p = &root->child;
79 for (;;) {
80 tmp = *p;
81 if (!tmp || tmp->start > end) {
82 new->sibling = tmp;
83 *p = new;
84 new->parent = root;
85 return NULL;
87 p = &tmp->sibling;
88 if (tmp->end < start)
89 continue;
90 return tmp;
94 int request_resource(struct resource *root, struct resource *new)
96 struct resource *conflict;
98 write_lock(&resource_lock);
99 conflict = __request_resource(root, new);
100 write_unlock(&resource_lock);
101 return conflict ? -EBUSY : 0;
104 int release_resource(struct resource *old)
106 struct resource *tmp, **p;
108 p = &old->parent->child;
109 for (;;) {
110 tmp = *p;
111 if (!tmp)
112 break;
113 if (tmp == old) {
114 *p = tmp->sibling;
115 old->parent = NULL;
116 return 0;
118 p = &tmp->sibling;
120 return -EINVAL;
124 * Find empty slot in the resource tree given range and alignment.
126 static int find_resource(struct resource *root, struct resource *new,
127 unsigned long size,
128 unsigned long min, unsigned long max,
129 unsigned long align)
131 struct resource *this = root->child;
132 unsigned long start, end;
134 start = root->start;
135 for(;;) {
136 if (this)
137 end = this->start;
138 else
139 end = root->end;
140 if (start < min)
141 start = min;
142 if (end > max)
143 end = max;
144 start = (start + align - 1) & ~(align - 1);
145 if (start < end && end - start + 1 >= size) {
146 new->start = start;
147 new->end = start + size - 1;
148 return 0;
150 if (!this)
151 break;
152 start = this->end + 1;
153 this = this->sibling;
155 return -EBUSY;
159 * Allocate empty slot in the resource tree given range and alignment.
161 int allocate_resource(struct resource *root, struct resource *new,
162 unsigned long size,
163 unsigned long min, unsigned long max,
164 unsigned long align)
166 int err;
168 write_lock(&resource_lock);
169 err = find_resource(root, new, size, min, max, align);
170 if (err >= 0 && __request_resource(root, new))
171 err = -EBUSY;
172 write_unlock(&resource_lock);
173 return err;
177 * This is compatibility stuff for IO resources.
179 * Note how this, unlike the above, knows about
180 * the IO flag meanings (busy etc).
182 * Request-region creates a new busy region.
184 * Check-region returns non-zero if the area is already busy
186 * Release-region releases a matching busy region.
188 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
190 struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
192 if (res) {
193 memset(res, 0, sizeof(*res));
194 res->name = name;
195 res->start = start;
196 res->end = start + n - 1;
197 res->flags = IORESOURCE_BUSY;
199 write_lock(&resource_lock);
201 for (;;) {
202 struct resource *conflict;
204 conflict = __request_resource(parent, res);
205 if (!conflict)
206 break;
207 if (conflict != parent) {
208 parent = conflict;
209 if (!(conflict->flags & IORESOURCE_BUSY))
210 continue;
213 /* Uhhuh, that didn't work out.. */
214 kfree(res);
215 res = NULL;
216 break;
218 write_unlock(&resource_lock);
220 return res;
223 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
225 struct resource * res;
227 res = __request_region(parent, start, n, "check-region");
228 if (!res)
229 return -EBUSY;
231 release_resource(res);
232 kfree(res);
233 return 0;
236 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
238 struct resource **p;
239 unsigned long end;
241 p = &parent->child;
242 end = start + n - 1;
244 for (;;) {
245 struct resource *res = *p;
247 if (!res)
248 break;
249 if (res->start <= start && res->end >= end) {
250 if (!(res->flags & IORESOURCE_BUSY)) {
251 p = &res->child;
252 continue;
254 if (res->start != start || res->end != end)
255 break;
256 *p = res->sibling;
257 kfree(res);
258 return;
260 p = &res->sibling;
262 printk("Trying to free nonexistent resource <%04lx-%04lx>\n", start, end);
266 * Called from init/main.c to reserve IO ports.
268 #define MAXRESERVE 4
269 static int __init reserve_setup(char *str)
271 int opt = 2, io_start, io_num;
272 static int reserved = 0;
273 static struct resource reserve[MAXRESERVE];
275 while (opt==2) {
276 int x = reserved;
278 if (get_option (&str, &io_start) != 2) break;
279 if (get_option (&str, &io_num) == 0) break;
280 if (x < MAXRESERVE) {
281 struct resource *res = reserve + x;
282 res->name = "reserved";
283 res->start = io_start;
284 res->end = io_start + io_num - 1;
285 res->child = NULL;
286 if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
287 reserved = x+1;
290 return 1;
293 __setup("reserve=", reserve_setup);