debuggers.hg

view xen/common/resource.c @ 3650:beb0887c54bc

bitkeeper revision 1.1159.238.1 (4200c8d8KsGlaM3w6o3y4GHhK1jKjg)

A typesafe allocator submitted by Rusty Russel with trivial renames by me.
Signed-off-by: Rusty Russel <rusty@rustcorp.com.au> (authored)
Signed-off-by: ian.pratt@cl.cam.ac.uk
author iap10@labyrinth.cl.cam.ac.uk
date Wed Feb 02 12:34:32 2005 +0000 (2005-02-02)
parents dae98734f12e
children 0ef6e8e6e85d
line source
1 /*
2 * linux/kernel/resource.c
3 *
4 * Copyright (C) 1999 Linus Torvalds
5 * Copyright (C) 1999 Martin Mares <mj@ucw.cz>
6 *
7 * Arbitrary resource management.
8 */
10 #include <xen/config.h>
11 #include <xen/lib.h>
12 #include <xen/sched.h>
13 #include <xen/errno.h>
14 #include <xen/ioport.h>
15 #include <xen/init.h>
16 #include <xen/slab.h>
17 #include <xen/spinlock.h>
18 #include <asm/io.h>
20 struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
21 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
23 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
25 /*
26 * This generates reports for /proc/ioports and /proc/iomem
27 */
28 static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
29 {
30 if (offset < 0)
31 offset = 0;
33 while (entry) {
34 const char *name = entry->name;
35 unsigned long from, to;
37 if ((int) (end-buf) < 80)
38 return buf;
40 from = entry->start;
41 to = entry->end;
42 if (!name)
43 name = "<BAD>";
45 buf += sprintf(buf, fmt + offset, from, to, name);
46 if (entry->child)
47 buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
48 entry = entry->sibling;
49 }
51 return buf;
52 }
54 int get_resource_list(struct resource *root, char *buf, int size)
55 {
56 char *fmt;
57 int retval;
59 fmt = " %08lx-%08lx : %s\n";
60 if (root->end < 0x10000)
61 fmt = " %04lx-%04lx : %s\n";
62 read_lock(&resource_lock);
63 retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
64 read_unlock(&resource_lock);
65 return retval;
66 }
68 /* Return the conflict entry if you can't request it */
69 static struct resource * __request_resource(struct resource *root, struct resource *new)
70 {
71 unsigned long start = new->start;
72 unsigned long end = new->end;
73 struct resource *tmp, **p;
75 if (end < start)
76 return root;
77 if (start < root->start)
78 return root;
79 if (end > root->end)
80 return root;
81 p = &root->child;
82 for (;;) {
83 tmp = *p;
84 if (!tmp || tmp->start > end) {
85 new->sibling = tmp;
86 *p = new;
87 new->parent = root;
88 return NULL;
89 }
90 p = &tmp->sibling;
91 if (tmp->end < start)
92 continue;
93 return tmp;
94 }
95 }
97 static int __release_resource(struct resource *old)
98 {
99 struct resource *tmp, **p;
101 p = &old->parent->child;
102 for (;;) {
103 tmp = *p;
104 if (!tmp)
105 break;
106 if (tmp == old) {
107 *p = tmp->sibling;
108 old->parent = NULL;
109 return 0;
110 }
111 p = &tmp->sibling;
112 }
113 return -EINVAL;
114 }
116 int request_resource(struct resource *root, struct resource *new)
117 {
118 struct resource *conflict;
120 write_lock(&resource_lock);
121 conflict = __request_resource(root, new);
122 write_unlock(&resource_lock);
123 return conflict ? -EBUSY : 0;
124 }
126 int release_resource(struct resource *old)
127 {
128 int retval;
130 write_lock(&resource_lock);
131 retval = __release_resource(old);
132 write_unlock(&resource_lock);
133 return retval;
134 }
136 int check_resource(struct resource *root, unsigned long start, unsigned long len)
137 {
138 struct resource *conflict, tmp;
140 tmp.start = start;
141 tmp.end = start + len - 1;
142 write_lock(&resource_lock);
143 conflict = __request_resource(root, &tmp);
144 if (!conflict)
145 __release_resource(&tmp);
146 write_unlock(&resource_lock);
147 return conflict ? -EBUSY : 0;
148 }
150 /*
151 * Find empty slot in the resource tree given range and alignment.
152 */
153 static int find_resource(struct resource *root, struct resource *new,
154 unsigned long size,
155 unsigned long min, unsigned long max,
156 unsigned long align,
157 void (*alignf)(void *, struct resource *,
158 unsigned long, unsigned long),
159 void *alignf_data)
160 {
161 struct resource *this = root->child;
163 new->start = root->start;
164 for(;;) {
165 if (this)
166 new->end = this->start;
167 else
168 new->end = root->end;
169 if (new->start < min)
170 new->start = min;
171 if (new->end > max)
172 new->end = max;
173 new->start = (new->start + align - 1) & ~(align - 1);
174 if (alignf)
175 alignf(alignf_data, new, size, align);
176 if (new->start < new->end && new->end - new->start + 1 >= size) {
177 new->end = new->start + size - 1;
178 return 0;
179 }
180 if (!this)
181 break;
182 new->start = this->end + 1;
183 this = this->sibling;
184 }
185 return -EBUSY;
186 }
188 /*
189 * Allocate empty slot in the resource tree given range and alignment.
190 */
191 int allocate_resource(struct resource *root, struct resource *new,
192 unsigned long size,
193 unsigned long min, unsigned long max,
194 unsigned long align,
195 void (*alignf)(void *, struct resource *,
196 unsigned long, unsigned long),
197 void *alignf_data)
198 {
199 int err;
201 write_lock(&resource_lock);
202 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
203 if (err >= 0 && __request_resource(root, new))
204 err = -EBUSY;
205 write_unlock(&resource_lock);
206 return err;
207 }
209 /*
210 * This is compatibility stuff for IO resources.
211 *
212 * Note how this, unlike the above, knows about
213 * the IO flag meanings (busy etc).
214 *
215 * Request-region creates a new busy region.
216 *
217 * Check-region returns non-zero if the area is already busy
218 *
219 * Release-region releases a matching busy region.
220 */
221 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
222 {
223 struct resource *res = xmalloc(struct resource);
225 if (res) {
226 memset(res, 0, sizeof(*res));
227 res->name = name;
228 res->start = start;
229 res->end = start + n - 1;
230 res->flags = IORESOURCE_BUSY;
232 write_lock(&resource_lock);
234 for (;;) {
235 struct resource *conflict;
237 conflict = __request_resource(parent, res);
238 if (!conflict)
239 break;
240 if (conflict != parent) {
241 parent = conflict;
242 if (!(conflict->flags & IORESOURCE_BUSY))
243 continue;
244 }
246 /* Uhhuh, that didn't work out.. */
247 xfree(res);
248 res = NULL;
249 break;
250 }
251 write_unlock(&resource_lock);
252 }
253 return res;
254 }
256 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
257 {
258 struct resource * res;
260 res = __request_region(parent, start, n, "check-region");
261 if (!res)
262 return -EBUSY;
264 release_resource(res);
265 xfree(res);
266 return 0;
267 }
269 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
270 {
271 struct resource **p;
272 unsigned long end;
274 p = &parent->child;
275 end = start + n - 1;
277 for (;;) {
278 struct resource *res = *p;
280 if (!res)
281 break;
282 if (res->start <= start && res->end >= end) {
283 if (!(res->flags & IORESOURCE_BUSY)) {
284 p = &res->child;
285 continue;
286 }
287 if (res->start != start || res->end != end)
288 break;
289 *p = res->sibling;
290 xfree(res);
291 return;
292 }
293 p = &res->sibling;
294 }
295 printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
296 }
299 #if 0
300 /*
301 * Called from init/main.c to reserve IO ports.
302 */
303 #define MAXRESERVE 4
304 static int __init reserve_setup(char *str)
305 {
306 static int reserved = 0;
307 static struct resource reserve[MAXRESERVE];
309 for (;;) {
310 int io_start, io_num;
311 int x = reserved;
313 if (get_option (&str, &io_start) != 2)
314 break;
315 if (get_option (&str, &io_num) == 0)
316 break;
317 if (x < MAXRESERVE) {
318 struct resource *res = reserve + x;
319 res->name = "reserved";
320 res->start = io_start;
321 res->end = io_start + io_num - 1;
322 res->flags = IORESOURCE_BUSY;
323 res->child = NULL;
324 if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
325 reserved = x+1;
326 }
327 }
328 return 1;
329 }
331 __setup("reserve=", reserve_setup);
332 #endif