1
2
3
4
5
6
7
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
18struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
19struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
20
21static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
22
23
24
25
26static 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
52int 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
67static 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
95static 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
114int 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
124int 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
134int 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
150
151static 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
188
189int 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
209
210
211
212
213
214
215
216
217
218
219struct 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
245 kfree(res);
246 res = NULL;
247 break;
248 }
249 write_unlock(&resource_lock);
250 }
251 return res;
252}
253
254int __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
267void __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(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
294}
295
296
297
298
299#define MAXRESERVE 4
300static 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);
328