|
@@ -763,6 +763,7 @@ static void __init __reserve_region_with_split(struct resource *root,
|
|
|
struct resource *parent = root;
|
|
|
struct resource *conflict;
|
|
|
struct resource *res = kzalloc(sizeof(*res), GFP_ATOMIC);
|
|
|
+ struct resource *next_res = NULL;
|
|
|
|
|
|
if (!res)
|
|
|
return;
|
|
@@ -772,21 +773,46 @@ static void __init __reserve_region_with_split(struct resource *root,
|
|
|
res->end = end;
|
|
|
res->flags = IORESOURCE_BUSY;
|
|
|
|
|
|
- conflict = __request_resource(parent, res);
|
|
|
- if (!conflict)
|
|
|
- return;
|
|
|
+ while (1) {
|
|
|
|
|
|
- /* failed, split and try again */
|
|
|
- kfree(res);
|
|
|
+ conflict = __request_resource(parent, res);
|
|
|
+ if (!conflict) {
|
|
|
+ if (!next_res)
|
|
|
+ break;
|
|
|
+ res = next_res;
|
|
|
+ next_res = NULL;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- /* conflict covered whole area */
|
|
|
- if (conflict->start <= start && conflict->end >= end)
|
|
|
- return;
|
|
|
+ /* conflict covered whole area */
|
|
|
+ if (conflict->start <= res->start &&
|
|
|
+ conflict->end >= res->end) {
|
|
|
+ kfree(res);
|
|
|
+ WARN_ON(next_res);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* failed, split and try again */
|
|
|
+ if (conflict->start > res->start) {
|
|
|
+ end = res->end;
|
|
|
+ res->end = conflict->start - 1;
|
|
|
+ if (conflict->end < end) {
|
|
|
+ next_res = kzalloc(sizeof(*next_res),
|
|
|
+ GFP_ATOMIC);
|
|
|
+ if (!next_res) {
|
|
|
+ kfree(res);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ next_res->name = name;
|
|
|
+ next_res->start = conflict->end + 1;
|
|
|
+ next_res->end = end;
|
|
|
+ next_res->flags = IORESOURCE_BUSY;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ res->start = conflict->end + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (conflict->start > start)
|
|
|
- __reserve_region_with_split(root, start, conflict->start-1, name);
|
|
|
- if (conflict->end < end)
|
|
|
- __reserve_region_with_split(root, conflict->end+1, end, name);
|
|
|
}
|
|
|
|
|
|
void __init reserve_region_with_split(struct resource *root,
|