cd14435488eda293b15428d9e2aaa210f6e638a5
[linux-2.4.git] / resource.c
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  */
9
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>
17 #include <asm/io.h>
18
19 struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
20 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
21
22 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
23
24 enum { MAX_IORES_LEVEL = 5 };
25
26 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
27 {
28         struct resource *p = v;
29         (*pos)++;
30         if (p->child)
31                 return p->child;
32         while (!p->sibling && p->parent)
33                 p = p->parent;
34         return p->sibling;
35 }
36
37 static void *r_start(struct seq_file *m, loff_t *pos)
38 {
39         struct resource *p = m->private;
40         loff_t l = 0;
41         read_lock(&resource_lock);
42         for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
43                 ;
44         return p;
45 }
46
47 static void r_stop(struct seq_file *m, void *v)
48 {
49         read_unlock(&resource_lock);
50 }
51
52 static int r_show(struct seq_file *m, void *v)
53 {
54         struct resource *root = m->private;
55         struct resource *r = v, *p;
56         int width = root->end < 0x10000 ? 4 : 8;
57         int depth;
58
59         for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
60                 if (p->parent == root)
61                         break;
62         seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
63                         depth * 2, "",
64                         width, r->start,
65                         width, r->end,
66                         r->name ? r->name : "<BAD>");
67         return 0;
68 }
69
70 static struct seq_operations resource_op = {
71         .start  = r_start,
72         .next   = r_next,
73         .stop   = r_stop,
74         .show   = r_show,
75 };
76
77 static int ioports_open(struct inode *inode, struct file *file)
78 {
79         int res = seq_open(file, &resource_op);
80         if (!res) {
81                 struct seq_file *m = file->private_data;
82                 m->private = &ioport_resource;
83         }
84         return res;
85 }
86
87 static int iomem_open(struct inode *inode, struct file *file)
88 {
89         int res = seq_open(file, &resource_op);
90         if (!res) {
91                 struct seq_file *m = file->private_data;
92                 m->private = &iomem_resource;
93         }
94         return res;
95 }
96
97 struct file_operations proc_ioports_operations = {
98         .open           = ioports_open,
99         .read           = seq_read,
100         .llseek         = seq_lseek,
101         .release        = seq_release,
102 };
103
104 struct file_operations proc_iomem_operations = {
105         .open           = iomem_open,
106         .read           = seq_read,
107         .llseek         = seq_lseek,
108         .release        = seq_release,
109 };
110
111 /* Return the conflict entry if you can't request it */
112 static struct resource * __request_resource(struct resource *root, struct resource *new)
113 {
114         unsigned long start = new->start;
115         unsigned long end = new->end;
116         struct resource *tmp, **p;
117
118         if (end < start)
119                 return root;
120         if (start < root->start)
121                 return root;
122         if (end > root->end)
123                 return root;
124         p = &root->child;
125         for (;;) {
126                 tmp = *p;
127                 if (!tmp || tmp->start > end) {
128                         new->sibling = tmp;
129                         *p = new;
130                         new->parent = root;
131                         return NULL;
132                 }
133                 p = &tmp->sibling;
134                 if (tmp->end < start)
135                         continue;
136                 return tmp;
137         }
138 }
139
140 static int __release_resource(struct resource *old)
141 {
142         struct resource *tmp, **p;
143
144         p = &old->parent->child;
145         for (;;) {
146                 tmp = *p;
147                 if (!tmp)
148                         break;
149                 if (tmp == old) {
150                         *p = tmp->sibling;
151                         old->parent = NULL;
152                         return 0;
153                 }
154                 p = &tmp->sibling;
155         }
156         return -EINVAL;
157 }
158
159 int request_resource(struct resource *root, struct resource *new)
160 {
161         struct resource *conflict;
162
163         write_lock(&resource_lock);
164         conflict = __request_resource(root, new);
165         write_unlock(&resource_lock);
166         return conflict ? -EBUSY : 0;
167 }
168
169 int release_resource(struct resource *old)
170 {
171         int retval;
172
173         write_lock(&resource_lock);
174         retval = __release_resource(old);
175         write_unlock(&resource_lock);
176         return retval;
177 }
178
179 int check_resource(struct resource *root, unsigned long start, unsigned long len)
180 {
181         struct resource *conflict, tmp;
182
183         tmp.start = start;
184         tmp.end = start + len - 1;
185         write_lock(&resource_lock);
186         conflict = __request_resource(root, &tmp);
187         if (!conflict)
188                 __release_resource(&tmp);
189         write_unlock(&resource_lock);
190         return conflict ? -EBUSY : 0;
191 }
192
193 /*
194  * Find empty slot in the resource tree given range and alignment.
195  */
196 static int find_resource(struct resource *root, struct resource *new,
197                          unsigned long size,
198                          unsigned long min, unsigned long max,
199                          unsigned long align,
200                          void (*alignf)(void *, struct resource *,
201                                         unsigned long, unsigned long),
202                          void *alignf_data)
203 {
204         struct resource *this = root->child;
205
206         new->start = root->start;
207         for(;;) {
208                 if (this)
209                         new->end = this->start;
210                 else
211                         new->end = root->end;
212                 if (new->start < min)
213                         new->start = min;
214                 if (new->end > max)
215                         new->end = max;
216                 new->start = (new->start + align - 1) & ~(align - 1);
217                 if (alignf)
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;
221                         return 0;
222                 }
223                 if (!this)
224                         break;
225                 new->start = this->end + 1;
226                 this = this->sibling;
227         }
228         return -EBUSY;
229 }
230
231 /*
232  * Allocate empty slot in the resource tree given range and alignment.
233  */
234 int allocate_resource(struct resource *root, struct resource *new,
235                       unsigned long size,
236                       unsigned long min, unsigned long max,
237                       unsigned long align,
238                       void (*alignf)(void *, struct resource *,
239                                      unsigned long, unsigned long),
240                       void *alignf_data)
241 {
242         int err;
243
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))
247                 err = -EBUSY;
248         write_unlock(&resource_lock);
249         return err;
250 }
251
252 /*
253  * This is compatibility stuff for IO resources.
254  *
255  * Note how this, unlike the above, knows about
256  * the IO flag meanings (busy etc).
257  *
258  * Request-region creates a new busy region.
259  *
260  * Check-region returns non-zero if the area is already busy
261  *
262  * Release-region releases a matching busy region.
263  */
264 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
265 {
266         struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
267
268         if (res) {
269                 memset(res, 0, sizeof(*res));
270                 res->name = name;
271                 res->start = start;
272                 res->end = start + n - 1;
273                 res->flags = IORESOURCE_BUSY;
274
275                 write_lock(&resource_lock);
276
277                 for (;;) {
278                         struct resource *conflict;
279
280                         conflict = __request_resource(parent, res);
281                         if (!conflict)
282                                 break;
283                         if (conflict != parent) {
284                                 parent = conflict;
285                                 if (!(conflict->flags & IORESOURCE_BUSY))
286                                         continue;
287                         }
288
289                         /* Uhhuh, that didn't work out.. */
290                         kfree(res);
291                         res = NULL;
292                         break;
293                 }
294                 write_unlock(&resource_lock);
295         }
296         return res;
297 }
298
299 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
300 {
301         struct resource * res;
302
303         res = __request_region(parent, start, n, "check-region");
304         if (!res)
305                 return -EBUSY;
306
307         release_resource(res);
308         kfree(res);
309         return 0;
310 }
311
312 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
313 {
314         struct resource **p;
315         unsigned long end;
316
317         p = &parent->child;
318         end = start + n - 1;
319
320         for (;;) {
321                 struct resource *res = *p;
322
323                 if (!res)
324                         break;
325                 if (res->start <= start && res->end >= end) {
326                         if (!(res->flags & IORESOURCE_BUSY)) {
327                                 p = &res->child;
328                                 continue;
329                         }
330                         if (res->start != start || res->end != end)
331                                 break;
332                         *p = res->sibling;
333                         kfree(res);
334                         return;
335                 }
336                 p = &res->sibling;
337         }
338         printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
339 }
340
341 /*
342  * Called from init/main.c to reserve IO ports.
343  */
344 #define MAXRESERVE 4
345 static int __init reserve_setup(char *str)
346 {
347         static int reserved = 0;
348         static struct resource reserve[MAXRESERVE];
349
350         for (;;) {
351                 int io_start, io_num;
352                 int x = reserved;
353
354                 if (get_option (&str, &io_start) != 2)
355                         break;
356                 if (get_option (&str, &io_num)   == 0)
357                         break;
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;
364                         res->child = NULL;
365                         if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
366                                 reserved = x+1;
367                 }
368         }
369         return 1;
370 }
371
372 __setup("reserve=", reserve_setup);