aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/resource.c')
-rw-r--r--kernel/resource.c61
1 files changed, 49 insertions, 12 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index 7b36976e5dea..798e2fae2a06 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -357,6 +357,32 @@ int __weak page_is_ram(unsigned long pfn)
357 return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; 357 return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
358} 358}
359 359
360void __weak arch_remove_reservations(struct resource *avail)
361{
362}
363
364static resource_size_t simple_align_resource(void *data,
365 const struct resource *avail,
366 resource_size_t size,
367 resource_size_t align)
368{
369 return avail->start;
370}
371
372static void resource_clip(struct resource *res, resource_size_t min,
373 resource_size_t max)
374{
375 if (res->start < min)
376 res->start = min;
377 if (res->end > max)
378 res->end = max;
379}
380
381static bool resource_contains(struct resource *res1, struct resource *res2)
382{
383 return res1->start <= res2->start && res1->end >= res2->end;
384}
385
360/* 386/*
361 * Find empty slot in the resource tree given range and alignment. 387 * Find empty slot in the resource tree given range and alignment.
362 */ 388 */
@@ -370,8 +396,9 @@ static int find_resource(struct resource *root, struct resource *new,
370 void *alignf_data) 396 void *alignf_data)
371{ 397{
372 struct resource *this = root->child; 398 struct resource *this = root->child;
373 struct resource tmp = *new; 399 struct resource tmp = *new, avail, alloc;
374 400
401 tmp.flags = new->flags;
375 tmp.start = root->start; 402 tmp.start = root->start;
376 /* 403 /*
377 * Skip past an allocated resource that starts at 0, since the assignment 404 * Skip past an allocated resource that starts at 0, since the assignment
@@ -386,17 +413,22 @@ static int find_resource(struct resource *root, struct resource *new,
386 tmp.end = this->start - 1; 413 tmp.end = this->start - 1;
387 else 414 else
388 tmp.end = root->end; 415 tmp.end = root->end;
389 if (tmp.start < min) 416
390 tmp.start = min; 417 resource_clip(&tmp, min, max);
391 if (tmp.end > max) 418 arch_remove_reservations(&tmp);
392 tmp.end = max; 419
393 tmp.start = ALIGN(tmp.start, align); 420 /* Check for overflow after ALIGN() */
394 if (alignf) 421 avail = *new;
395 tmp.start = alignf(alignf_data, &tmp, size, align); 422 avail.start = ALIGN(tmp.start, align);
396 if (tmp.start < tmp.end && tmp.end - tmp.start >= size - 1) { 423 avail.end = tmp.end;
397 new->start = tmp.start; 424 if (avail.start >= tmp.start) {
398 new->end = tmp.start + size - 1; 425 alloc.start = alignf(alignf_data, &avail, size, align);
399 return 0; 426 alloc.end = alloc.start + size - 1;
427 if (resource_contains(&avail, &alloc)) {
428 new->start = alloc.start;
429 new->end = alloc.end;
430 return 0;
431 }
400 } 432 }
401 if (!this) 433 if (!this)
402 break; 434 break;
@@ -428,6 +460,9 @@ int allocate_resource(struct resource *root, struct resource *new,
428{ 460{
429 int err; 461 int err;
430 462
463 if (!alignf)
464 alignf = simple_align_resource;
465
431 write_lock(&resource_lock); 466 write_lock(&resource_lock);
432 err = find_resource(root, new, size, min, max, align, alignf, alignf_data); 467 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
433 if (err >= 0 && __request_resource(root, new)) 468 if (err >= 0 && __request_resource(root, new))
@@ -453,6 +488,8 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
453 488
454 if (first == parent) 489 if (first == parent)
455 return first; 490 return first;
491 if (WARN_ON(first == new)) /* duplicated insertion */
492 return first;
456 493
457 if ((first->start > new->start) || (first->end < new->end)) 494 if ((first->start > new->start) || (first->end < new->end))
458 break; 495 break;