aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/resource.c')
-rw-r--r--kernel/resource.c110
1 files changed, 94 insertions, 16 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index af96c1e4b54b..9c358e263534 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -188,20 +188,65 @@ static int __release_resource(struct resource *old)
188 return -EINVAL; 188 return -EINVAL;
189} 189}
190 190
191static void __release_child_resources(struct resource *r)
192{
193 struct resource *tmp, *p;
194 resource_size_t size;
195
196 p = r->child;
197 r->child = NULL;
198 while (p) {
199 tmp = p;
200 p = p->sibling;
201
202 tmp->parent = NULL;
203 tmp->sibling = NULL;
204 __release_child_resources(tmp);
205
206 printk(KERN_DEBUG "release child resource %pR\n", tmp);
207 /* need to restore size, and keep flags */
208 size = resource_size(tmp);
209 tmp->start = 0;
210 tmp->end = size - 1;
211 }
212}
213
214void release_child_resources(struct resource *r)
215{
216 write_lock(&resource_lock);
217 __release_child_resources(r);
218 write_unlock(&resource_lock);
219}
220
191/** 221/**
192 * request_resource - request and reserve an I/O or memory resource 222 * request_resource_conflict - request and reserve an I/O or memory resource
193 * @root: root resource descriptor 223 * @root: root resource descriptor
194 * @new: resource descriptor desired by caller 224 * @new: resource descriptor desired by caller
195 * 225 *
196 * Returns 0 for success, negative error code on error. 226 * Returns 0 for success, conflict resource on error.
197 */ 227 */
198int request_resource(struct resource *root, struct resource *new) 228struct resource *request_resource_conflict(struct resource *root, struct resource *new)
199{ 229{
200 struct resource *conflict; 230 struct resource *conflict;
201 231
202 write_lock(&resource_lock); 232 write_lock(&resource_lock);
203 conflict = __request_resource(root, new); 233 conflict = __request_resource(root, new);
204 write_unlock(&resource_lock); 234 write_unlock(&resource_lock);
235 return conflict;
236}
237
238/**
239 * request_resource - request and reserve an I/O or memory resource
240 * @root: root resource descriptor
241 * @new: resource descriptor desired by caller
242 *
243 * Returns 0 for success, negative error code on error.
244 */
245int request_resource(struct resource *root, struct resource *new)
246{
247 struct resource *conflict;
248
249 conflict = request_resource_conflict(root, new);
205 return conflict ? -EBUSY : 0; 250 return conflict ? -EBUSY : 0;
206} 251}
207 252
@@ -274,7 +319,7 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
274 void *arg, int (*func)(unsigned long, unsigned long, void *)) 319 void *arg, int (*func)(unsigned long, unsigned long, void *))
275{ 320{
276 struct resource res; 321 struct resource res;
277 unsigned long pfn, len; 322 unsigned long pfn, end_pfn;
278 u64 orig_end; 323 u64 orig_end;
279 int ret = -1; 324 int ret = -1;
280 325
@@ -284,9 +329,10 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
284 orig_end = res.end; 329 orig_end = res.end;
285 while ((res.start < res.end) && 330 while ((res.start < res.end) &&
286 (find_next_system_ram(&res, "System RAM") >= 0)) { 331 (find_next_system_ram(&res, "System RAM") >= 0)) {
287 pfn = (unsigned long)(res.start >> PAGE_SHIFT); 332 pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT;
288 len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT); 333 end_pfn = (res.end + 1) >> PAGE_SHIFT;
289 ret = (*func)(pfn, len, arg); 334 if (end_pfn > pfn)
335 ret = (*func)(pfn, end_pfn - pfn, arg);
290 if (ret) 336 if (ret)
291 break; 337 break;
292 res.start = res.end + 1; 338 res.start = res.end + 1;
@@ -297,14 +343,29 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
297 343
298#endif 344#endif
299 345
346static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg)
347{
348 return 1;
349}
350/*
351 * This generic page_is_ram() returns true if specified address is
352 * registered as "System RAM" in iomem_resource list.
353 */
354int __weak page_is_ram(unsigned long pfn)
355{
356 return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
357}
358
300/* 359/*
301 * Find empty slot in the resource tree given range and alignment. 360 * Find empty slot in the resource tree given range and alignment.
302 */ 361 */
303static int find_resource(struct resource *root, struct resource *new, 362static int find_resource(struct resource *root, struct resource *new,
304 resource_size_t size, resource_size_t min, 363 resource_size_t size, resource_size_t min,
305 resource_size_t max, resource_size_t align, 364 resource_size_t max, resource_size_t align,
306 void (*alignf)(void *, struct resource *, 365 resource_size_t (*alignf)(void *,
307 resource_size_t, resource_size_t), 366 const struct resource *,
367 resource_size_t,
368 resource_size_t),
308 void *alignf_data) 369 void *alignf_data)
309{ 370{
310 struct resource *this = root->child; 371 struct resource *this = root->child;
@@ -330,7 +391,7 @@ static int find_resource(struct resource *root, struct resource *new,
330 tmp.end = max; 391 tmp.end = max;
331 tmp.start = ALIGN(tmp.start, align); 392 tmp.start = ALIGN(tmp.start, align);
332 if (alignf) 393 if (alignf)
333 alignf(alignf_data, &tmp, size, align); 394 tmp.start = alignf(alignf_data, &tmp, size, align);
334 if (tmp.start < tmp.end && tmp.end - tmp.start >= size - 1) { 395 if (tmp.start < tmp.end && tmp.end - tmp.start >= size - 1) {
335 new->start = tmp.start; 396 new->start = tmp.start;
336 new->end = tmp.start + size - 1; 397 new->end = tmp.start + size - 1;
@@ -358,8 +419,10 @@ static int find_resource(struct resource *root, struct resource *new,
358int allocate_resource(struct resource *root, struct resource *new, 419int allocate_resource(struct resource *root, struct resource *new,
359 resource_size_t size, resource_size_t min, 420 resource_size_t size, resource_size_t min,
360 resource_size_t max, resource_size_t align, 421 resource_size_t max, resource_size_t align,
361 void (*alignf)(void *, struct resource *, 422 resource_size_t (*alignf)(void *,
362 resource_size_t, resource_size_t), 423 const struct resource *,
424 resource_size_t,
425 resource_size_t),
363 void *alignf_data) 426 void *alignf_data)
364{ 427{
365 int err; 428 int err;
@@ -426,25 +489,40 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
426} 489}
427 490
428/** 491/**
429 * insert_resource - Inserts a resource in the resource tree 492 * insert_resource_conflict - Inserts resource in the resource tree
430 * @parent: parent of the new resource 493 * @parent: parent of the new resource
431 * @new: new resource to insert 494 * @new: new resource to insert
432 * 495 *
433 * Returns 0 on success, -EBUSY if the resource can't be inserted. 496 * Returns 0 on success, conflict resource if the resource can't be inserted.
434 * 497 *
435 * This function is equivalent to request_resource when no conflict 498 * This function is equivalent to request_resource_conflict when no conflict
436 * happens. If a conflict happens, and the conflicting resources 499 * happens. If a conflict happens, and the conflicting resources
437 * entirely fit within the range of the new resource, then the new 500 * entirely fit within the range of the new resource, then the new
438 * resource is inserted and the conflicting resources become children of 501 * resource is inserted and the conflicting resources become children of
439 * the new resource. 502 * the new resource.
440 */ 503 */
441int insert_resource(struct resource *parent, struct resource *new) 504struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
442{ 505{
443 struct resource *conflict; 506 struct resource *conflict;
444 507
445 write_lock(&resource_lock); 508 write_lock(&resource_lock);
446 conflict = __insert_resource(parent, new); 509 conflict = __insert_resource(parent, new);
447 write_unlock(&resource_lock); 510 write_unlock(&resource_lock);
511 return conflict;
512}
513
514/**
515 * insert_resource - Inserts a resource in the resource tree
516 * @parent: parent of the new resource
517 * @new: new resource to insert
518 *
519 * Returns 0 on success, -EBUSY if the resource can't be inserted.
520 */
521int insert_resource(struct resource *parent, struct resource *new)
522{
523 struct resource *conflict;
524
525 conflict = insert_resource_conflict(parent, new);
448 return conflict ? -EBUSY : 0; 526 return conflict ? -EBUSY : 0;
449} 527}
450 528