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 <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/ioport.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/spinlock.h>
16 #include <linux/seq_file.h>
19 struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
20 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
22 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
24 enum { MAX_IORES_LEVEL = 5 };
26 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
28 struct resource *p = v;
32 while (!p->sibling && p->parent)
37 static void *r_start(struct seq_file *m, loff_t *pos)
39 struct resource *p = m->private;
41 read_lock(&resource_lock);
42 for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
47 static void r_stop(struct seq_file *m, void *v)
49 read_unlock(&resource_lock);
52 static int r_show(struct seq_file *m, void *v)
54 struct resource *root = m->private;
55 struct resource *r = v, *p;
56 int width = root->end < 0x10000 ? 4 : 8;
59 for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
60 if (p->parent == root)
62 seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
66 r->name ? r->name : "<BAD>");
70 static struct seq_operations resource_op = {
77 static int ioports_open(struct inode *inode, struct file *file)
79 int res = seq_open(file, &resource_op);
81 struct seq_file *m = file->private_data;
82 m->private = &ioport_resource;
87 static int iomem_open(struct inode *inode, struct file *file)
89 int res = seq_open(file, &resource_op);
91 struct seq_file *m = file->private_data;
92 m->private = &iomem_resource;
97 struct file_operations proc_ioports_operations = {
101 .release = seq_release,
104 struct file_operations proc_iomem_operations = {
108 .release = seq_release,
111 /* Return the conflict entry if you can't request it */
112 static struct resource * __request_resource(struct resource *root, struct resource *new)
114 unsigned long start = new->start;
115 unsigned long end = new->end;
116 struct resource *tmp, **p;
120 if (start < root->start)
127 if (!tmp || tmp->start > end) {
134 if (tmp->end < start)
140 static int __release_resource(struct resource *old)
142 struct resource *tmp, **p;
144 p = &old->parent->child;
159 int request_resource(struct resource *root, struct resource *new)
161 struct resource *conflict;
163 write_lock(&resource_lock);
164 conflict = __request_resource(root, new);
165 write_unlock(&resource_lock);
166 return conflict ? -EBUSY : 0;
169 int release_resource(struct resource *old)
173 write_lock(&resource_lock);
174 retval = __release_resource(old);
175 write_unlock(&resource_lock);
179 int check_resource(struct resource *root, unsigned long start, unsigned long len)
181 struct resource *conflict, tmp;
184 tmp.end = start + len - 1;
185 write_lock(&resource_lock);
186 conflict = __request_resource(root, &tmp);
188 __release_resource(&tmp);
189 write_unlock(&resource_lock);
190 return conflict ? -EBUSY : 0;
194 * Find empty slot in the resource tree given range and alignment.
196 static int find_resource(struct resource *root, struct resource *new,
198 unsigned long min, unsigned long max,
200 void (*alignf)(void *, struct resource *,
201 unsigned long, unsigned long),
204 struct resource *this = root->child;
206 new->start = root->start;
209 new->end = this->start;
211 new->end = root->end;
212 if (new->start < min)
216 new->start = (new->start + align - 1) & ~(align - 1);
218 alignf(alignf_data, new, size, align);
219 if (new->start < new->end && new->end - new->start + 1 >= size) {
220 new->end = new->start + size - 1;
225 new->start = this->end + 1;
226 this = this->sibling;
232 * Allocate empty slot in the resource tree given range and alignment.
234 int allocate_resource(struct resource *root, struct resource *new,
236 unsigned long min, unsigned long max,
238 void (*alignf)(void *, struct resource *,
239 unsigned long, unsigned long),
244 write_lock(&resource_lock);
245 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
246 if (err >= 0 && __request_resource(root, new))
248 write_unlock(&resource_lock);
253 * This is compatibility stuff for IO resources.
255 * Note how this, unlike the above, knows about
256 * the IO flag meanings (busy etc).
258 * Request-region creates a new busy region.
260 * Check-region returns non-zero if the area is already busy
262 * Release-region releases a matching busy region.
264 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
266 struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
269 memset(res, 0, sizeof(*res));
272 res->end = start + n - 1;
273 res->flags = IORESOURCE_BUSY;
275 write_lock(&resource_lock);
278 struct resource *conflict;
280 conflict = __request_resource(parent, res);
283 if (conflict != parent) {
285 if (!(conflict->flags & IORESOURCE_BUSY))
289 /* Uhhuh, that didn't work out.. */
294 write_unlock(&resource_lock);
299 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
301 struct resource * res;
303 res = __request_region(parent, start, n, "check-region");
307 release_resource(res);
312 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
321 struct resource *res = *p;
325 if (res->start <= start && res->end >= end) {
326 if (!(res->flags & IORESOURCE_BUSY)) {
330 if (res->start != start || res->end != end)
338 printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
342 * Called from init/main.c to reserve IO ports.
345 static int __init reserve_setup(char *str)
347 static int reserved = 0;
348 static struct resource reserve[MAXRESERVE];
351 int io_start, io_num;
354 if (get_option (&str, &io_start) != 2)
356 if (get_option (&str, &io_num) == 0)
358 if (x < MAXRESERVE) {
359 struct resource *res = reserve + x;
360 res->name = "reserved";
361 res->start = io_start;
362 res->end = io_start + io_num - 1;
363 res->flags = IORESOURCE_BUSY;
365 if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
372 __setup("reserve=", reserve_setup);