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