Commit bef69ea0 authored by Linus Torvalds's avatar Linus Torvalds

Resource handling: add 'insert_resource_expand_to_fit()' function

Not used anywhere yet, but this complements the existing plain
'insert_resource()' functionality with a version that can expand the
resource we are adding in order to fix up any conflicts it has with
existing resources.
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 00aeb429
...@@ -109,6 +109,7 @@ extern struct resource iomem_resource; ...@@ -109,6 +109,7 @@ extern struct resource iomem_resource;
extern int request_resource(struct resource *root, struct resource *new); extern int request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new); extern int release_resource(struct resource *new);
extern int insert_resource(struct resource *parent, struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new);
extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
extern int allocate_resource(struct resource *root, struct resource *new, extern int allocate_resource(struct resource *root, struct resource *new,
resource_size_t size, resource_size_t min, resource_size_t size, resource_size_t min,
resource_size_t max, resource_size_t align, resource_size_t max, resource_size_t align,
......
...@@ -362,35 +362,21 @@ int allocate_resource(struct resource *root, struct resource *new, ...@@ -362,35 +362,21 @@ int allocate_resource(struct resource *root, struct resource *new,
EXPORT_SYMBOL(allocate_resource); EXPORT_SYMBOL(allocate_resource);
/** /*
* insert_resource - Inserts a resource in the resource tree * Insert a resource into the resource tree. If successful, return NULL,
* @parent: parent of the new resource * otherwise return the conflicting resource (compare to __request_resource())
* @new: new resource to insert
*
* Returns 0 on success, -EBUSY if the resource can't be inserted.
*
* This function is equivalent to request_resource when no conflict
* happens. If a conflict happens, and the conflicting resources
* entirely fit within the range of the new resource, then the new
* resource is inserted and the conflicting resources become children of
* the new resource.
*/ */
int insert_resource(struct resource *parent, struct resource *new) static struct resource * __insert_resource(struct resource *parent, struct resource *new)
{ {
int result;
struct resource *first, *next; struct resource *first, *next;
write_lock(&resource_lock);
for (;; parent = first) { for (;; parent = first) {
result = 0;
first = __request_resource(parent, new); first = __request_resource(parent, new);
if (!first) if (!first)
goto out; return first;
result = -EBUSY;
if (first == parent) if (first == parent)
goto out; return first;
if ((first->start > new->start) || (first->end < new->end)) if ((first->start > new->start) || (first->end < new->end))
break; break;
...@@ -401,15 +387,13 @@ int insert_resource(struct resource *parent, struct resource *new) ...@@ -401,15 +387,13 @@ int insert_resource(struct resource *parent, struct resource *new)
for (next = first; ; next = next->sibling) { for (next = first; ; next = next->sibling) {
/* Partial overlap? Bad, and unfixable */ /* Partial overlap? Bad, and unfixable */
if (next->start < new->start || next->end > new->end) if (next->start < new->start || next->end > new->end)
goto out; return next;
if (!next->sibling) if (!next->sibling)
break; break;
if (next->sibling->start > new->end) if (next->sibling->start > new->end)
break; break;
} }
result = 0;
new->parent = parent; new->parent = parent;
new->sibling = next->sibling; new->sibling = next->sibling;
new->child = first; new->child = first;
...@@ -426,10 +410,64 @@ int insert_resource(struct resource *parent, struct resource *new) ...@@ -426,10 +410,64 @@ int insert_resource(struct resource *parent, struct resource *new)
next = next->sibling; next = next->sibling;
next->sibling = new; next->sibling = new;
} }
return NULL;
}
out: /**
* insert_resource - Inserts a resource in the resource tree
* @parent: parent of the new resource
* @new: new resource to insert
*
* Returns 0 on success, -EBUSY if the resource can't be inserted.
*
* This function is equivalent to request_resource when no conflict
* happens. If a conflict happens, and the conflicting resources
* entirely fit within the range of the new resource, then the new
* resource is inserted and the conflicting resources become children of
* the new resource.
*/
int insert_resource(struct resource *parent, struct resource *new)
{
struct resource *conflict;
write_lock(&resource_lock);
conflict = __insert_resource(parent, new);
write_unlock(&resource_lock);
return conflict ? -EBUSY : 0;
}
/**
* insert_resource_expand_to_fit - Insert a resource into the resource tree
* @parent: parent of the new resource
* @new: new resource to insert
*
* Insert a resource into the resource tree, possibly expanding it in order
* to make it encompass any conflicting resources.
*/
void insert_resource_expand_to_fit(struct resource *root, struct resource *new)
{
if (new->parent)
return;
write_lock(&resource_lock);
for (;;) {
struct resource *conflict;
conflict = __insert_resource(root, new);
if (!conflict)
break;
if (conflict == root)
break;
/* Ok, expand resource to cover the conflict, then try again .. */
if (conflict->start < new->start)
new->start = conflict->start;
if (conflict->end > new->end)
new->end = conflict->end;
printk("Expanded resource %s due to conflict with %s\n", new->name, conflict->name);
}
write_unlock(&resource_lock); write_unlock(&resource_lock);
return result;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment