~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/resource.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/malloc.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 *, unsigned long),
156                          void *alignf_data)
157 {
158         struct resource *this = root->child;
159 
160         new->start = root->start;
161         for(;;) {
162                 if (this)
163                         new->end = this->start;
164                 else
165                         new->end = root->end;
166                 if (new->start < min)
167                         new->start = min;
168                 if (new->end > max)
169                         new->end = max;
170                 new->start = (new->start + align - 1) & ~(align - 1);
171                 if (alignf)
172                         alignf(alignf_data, new, size);
173                 if (new->start < new->end && new->end - new->start + 1 >= size) {
174                         new->end = new->start + size - 1;
175                         return 0;
176                 }
177                 if (!this)
178                         break;
179                 new->start = this->end + 1;
180                 this = this->sibling;
181         }
182         return -EBUSY;
183 }
184 
185 /*
186  * Allocate empty slot in the resource tree given range and alignment.
187  */
188 int allocate_resource(struct resource *root, struct resource *new,
189                       unsigned long size,
190                       unsigned long min, unsigned long max,
191                       unsigned long align,
192                       void (*alignf)(void *, struct resource *, unsigned long),
193                       void *alignf_data)
194 {
195         int err;
196 
197         write_lock(&resource_lock);
198         err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
199         if (err >= 0 && __request_resource(root, new))
200                 err = -EBUSY;
201         write_unlock(&resource_lock);
202         return err;
203 }
204 
205 /*
206  * This is compatibility stuff for IO resources.
207  *
208  * Note how this, unlike the above, knows about
209  * the IO flag meanings (busy etc).
210  *
211  * Request-region creates a new busy region.
212  *
213  * Check-region returns non-zero if the area is already busy
214  *
215  * Release-region releases a matching busy region.
216  */
217 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
218 {
219         struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
220 
221         if (res) {
222                 memset(res, 0, sizeof(*res));
223                 res->name = name;
224                 res->start = start;
225                 res->end = start + n - 1;
226                 res->flags = IORESOURCE_BUSY;
227 
228                 write_lock(&resource_lock);
229 
230                 for (;;) {
231                         struct resource *conflict;
232 
233                         conflict = __request_resource(parent, res);
234                         if (!conflict)
235                                 break;
236                         if (conflict != parent) {
237                                 parent = conflict;
238                                 if (!(conflict->flags & IORESOURCE_BUSY))
239                                         continue;
240                         }
241 
242                         /* Uhhuh, that didn't work out.. */
243                         kfree(res);
244                         res = NULL;
245                         break;
246                 }
247                 write_unlock(&resource_lock);
248         }
249         return res;
250 }
251 
252 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
253 {
254         struct resource * res;
255 
256         res = __request_region(parent, start, n, "check-region");
257         if (!res)
258                 return -EBUSY;
259 
260         release_resource(res);
261         kfree(res);
262         return 0;
263 }
264 
265 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
266 {
267         struct resource **p;
268         unsigned long end;
269 
270         p = &parent->child;
271         end = start + n - 1;
272 
273         for (;;) {
274                 struct resource *res = *p;
275 
276                 if (!res)
277                         break;
278                 if (res->start <= start && res->end >= end) {
279                         if (!(res->flags & IORESOURCE_BUSY)) {
280                                 p = &res->child;
281                                 continue;
282                         }
283                         if (res->start != start || res->end != end)
284                                 break;
285                         *p = res->sibling;
286                         kfree(res);
287                         return;
288                 }
289                 p = &res->sibling;
290         }
291         printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
292 }
293 
294 /*
295  * Called from init/main.c to reserve IO ports.
296  */
297 #define MAXRESERVE 4
298 static int __init reserve_setup(char *str)
299 {
300         int opt = 2, io_start, io_num;
301         static int reserved = 0;
302         static struct resource reserve[MAXRESERVE];
303 
304     while (opt==2) {
305                 int x = reserved;
306 
307         if (get_option (&str, &io_start) != 2) break;
308         if (get_option (&str, &io_num)   == 0) break;
309                 if (x < MAXRESERVE) {
310                         struct resource *res = reserve + x;
311                         res->name = "reserved";
312                         res->start = io_start;
313                         res->end = io_start + io_num - 1;
314                         res->child = NULL;
315                         if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
316                                 reserved = x+1;
317                 }
318         }
319         return 1;
320 }
321 
322 __setup("reserve=", reserve_setup);
323 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.