Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / 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 <lwk/errno.h>
11 #include <lwk/resource.h>
12 #include <lwk/init.h>
13 #include <lwk/spinlock.h>
14 #include <arch/io.h>
15
16 struct resource ioport_resource = {
17         .name   = "PCI IO",
18         .start  = 0x0000,
19         .end    = IO_SPACE_LIMIT,
20         .flags  = IORESOURCE_IO,
21 };
22
23 struct resource iomem_resource = {
24         .name   = "PCI mem",
25         .start  = 0UL,
26         .end    = ~0UL,
27         .flags  = IORESOURCE_MEM,
28 };
29
30 static DEFINE_RWLOCK(resource_lock);
31
32 /* Return the conflict entry if you can't request it */
33 static struct resource * __request_resource(struct resource *root, struct resource *new)
34 {
35         unsigned long start = new->start;
36         unsigned long end = new->end;
37         struct resource *tmp, **p;
38
39         if (end < start)
40                 return root;
41         if (start < root->start)
42                 return root;
43         if (end > root->end)
44                 return root;
45         p = &root->child;
46         for (;;) {
47                 tmp = *p;
48                 if (!tmp || tmp->start > end) {
49                         new->sibling = tmp;
50                         *p = new;
51                         new->parent = root;
52                         return NULL;
53                 }
54                 p = &tmp->sibling;
55                 if (tmp->end < start)
56                         continue;
57                 return tmp;
58         }
59 }
60
61 static int __release_resource(struct resource *old)
62 {
63         struct resource *tmp, **p;
64
65         BUG_ON(old->child);
66
67         p = &old->parent->child;
68         for (;;) {
69                 tmp = *p;
70                 if (!tmp)
71                         break;
72                 if (tmp == old) {
73                         *p = tmp->sibling;
74                         old->parent = NULL;
75                         return 0;
76                 }
77                 p = &tmp->sibling;
78         }
79         return -EINVAL;
80 }
81
82 int request_resource(struct resource *root, struct resource *new)
83 {
84         struct resource *conflict;
85
86         write_lock(&resource_lock);
87         conflict = __request_resource(root, new);
88         write_unlock(&resource_lock);
89         return conflict ? -EBUSY : 0;
90 }
91
92 struct resource *____request_resource(struct resource *root, struct resource *new)
93 {
94         struct resource *conflict;
95
96         write_lock(&resource_lock);
97         conflict = __request_resource(root, new);
98         write_unlock(&resource_lock);
99         return conflict;
100 }
101
102 int release_resource(struct resource *old)
103 {
104         int retval;
105
106         write_lock(&resource_lock);
107         retval = __release_resource(old);
108         write_unlock(&resource_lock);
109         return retval;
110 }
111
112 /*
113  * Find empty slot in the resource tree given range and alignment.
114  */
115 static int find_resource(struct resource *root, struct resource *new,
116                          unsigned long size,
117                          unsigned long min, unsigned long max,
118                          unsigned long align,
119                          void (*alignf)(void *, struct resource *,
120                                         unsigned long, unsigned long),
121                          void *alignf_data)
122 {
123         struct resource *this = root->child;
124
125         new->start = root->start;
126         /*
127          * Skip past an allocated resource that starts at 0, since the assignment
128          * of this->start - 1 to new->end below would cause an underflow.
129          */
130         if (this && this->start == 0) {
131                 new->start = this->end + 1;
132                 this = this->sibling;
133         }
134         for(;;) {
135                 if (this)
136                         new->end = this->start - 1;
137                 else
138                         new->end = root->end;
139                 if (new->start < min)
140                         new->start = min;
141                 if (new->end > max)
142                         new->end = max;
143                 new->start = ALIGN(new->start, align);
144                 if (alignf)
145                         alignf(alignf_data, new, size, align);
146                 if (new->start < new->end && new->end - new->start >= size - 1) {
147                         new->end = new->start + size - 1;
148                         return 0;
149                 }
150                 if (!this)
151                         break;
152                 new->start = this->end + 1;
153                 this = this->sibling;
154         }
155         return -EBUSY;
156 }
157
158 /*
159  * Allocate empty slot in the resource tree given range and alignment.
160  */
161 int allocate_resource(struct resource *root, struct resource *new,
162                       unsigned long size,
163                       unsigned long min, unsigned long max,
164                       unsigned long align,
165                       void (*alignf)(void *, struct resource *,
166                                      unsigned long, unsigned long),
167                       void *alignf_data)
168 {
169         int err;
170
171         write_lock(&resource_lock);
172         err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
173         if (err >= 0 && __request_resource(root, new))
174                 err = -EBUSY;
175         write_unlock(&resource_lock);
176         return err;
177 }
178
179 /**
180  * insert_resource - Inserts a resource in the resource tree
181  * @parent: parent of the new resource
182  * @new: new resource to insert
183  *
184  * Returns 0 on success, -EBUSY if the resource can't be inserted.
185  *
186  * This function is equivalent to request_resource when no conflict
187  * happens. If a conflict happens, and the conflicting resources
188  * entirely fit within the range of the new resource, then the new
189  * resource is inserted and the conflicting resources become children of
190  * the new resource.
191  */
192 int insert_resource(struct resource *parent, struct resource *new)
193 {
194         int result;
195         struct resource *first, *next;
196
197         write_lock(&resource_lock);
198
199         for (;; parent = first) {
200                 result = 0;
201                 first = __request_resource(parent, new);
202                 if (!first)
203                         goto out;
204
205                 result = -EBUSY;
206                 if (first == parent)
207                         goto out;
208
209                 if ((first->start > new->start) || (first->end < new->end))
210                         break;
211                 if ((first->start == new->start) && (first->end == new->end))
212                         break;
213         }
214
215         for (next = first; ; next = next->sibling) {
216                 /* Partial overlap? Bad, and unfixable */
217                 if (next->start < new->start || next->end > new->end)
218                         goto out;
219                 if (!next->sibling)
220                         break;
221                 if (next->sibling->start > new->end)
222                         break;
223         }
224
225         result = 0;
226
227         new->parent = parent;
228         new->sibling = next->sibling;
229         new->child = first;
230
231         next->sibling = NULL;
232         for (next = first; next; next = next->sibling)
233                 next->parent = new;
234
235         if (parent->child == first) {
236                 parent->child = new;
237         } else {
238                 next = parent->child;
239                 while (next->sibling != first)
240                         next = next->sibling;
241                 next->sibling = new;
242         }
243
244  out:
245         write_unlock(&resource_lock);
246         return result;
247 }
248
249 /*
250  * Given an existing resource, change its start and size to match the
251  * arguments.  Returns -EBUSY if it can't fit.  Existing children of
252  * the resource are assumed to be immutable.
253  */
254 int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
255 {
256         struct resource *tmp, *parent = res->parent;
257         unsigned long end = start + size - 1;
258         int result = -EBUSY;
259
260         write_lock(&resource_lock);
261
262         if ((start < parent->start) || (end > parent->end))
263                 goto out;
264
265         for (tmp = res->child; tmp; tmp = tmp->sibling) {
266                 if ((tmp->start < start) || (tmp->end > end))
267                         goto out;
268         }
269
270         if (res->sibling && (res->sibling->start <= end))
271                 goto out;
272
273         tmp = parent->child;
274         if (tmp != res) {
275                 while (tmp->sibling != res)
276                         tmp = tmp->sibling;
277                 if (start <= tmp->end)
278                         goto out;
279         }
280
281         res->start = start;
282         res->end = end;
283         result = 0;
284
285  out:
286         write_unlock(&resource_lock);
287         return result;
288 }
289