File: /usr/src/linux/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 *, 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     	static int reserved = 0;
301     	static struct resource reserve[MAXRESERVE];
302     
303     	for (;;) {
304     		int io_start, io_num;
305     		int x = reserved;
306     
307     		if (get_option (&str, &io_start) != 2)
308     			break;
309     		if (get_option (&str, &io_num)   == 0)
310     			break;
311     		if (x < MAXRESERVE) {
312     			struct resource *res = reserve + x;
313     			res->name = "reserved";
314     			res->start = io_start;
315     			res->end = io_start + io_num - 1;
316     			res->flags = IORESOURCE_BUSY;
317     			res->child = NULL;
318     			if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
319     				reserved = x+1;
320     		}
321     	}
322     	return 1;
323     }
324     
325     __setup("reserve=", reserve_setup);
326