|
@@ -516,6 +516,74 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+static void __init __reserve_region_with_split(struct resource *root,
|
|
|
+ resource_size_t start, resource_size_t end,
|
|
|
+ const char *name)
|
|
|
+{
|
|
|
+ struct resource *parent = root;
|
|
|
+ struct resource *conflict;
|
|
|
+ struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!res)
|
|
|
+ return;
|
|
|
+
|
|
|
+ res->name = name;
|
|
|
+ res->start = start;
|
|
|
+ res->end = end;
|
|
|
+ res->flags = IORESOURCE_BUSY;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ conflict = __request_resource(parent, res);
|
|
|
+ if (!conflict)
|
|
|
+ break;
|
|
|
+ if (conflict != parent) {
|
|
|
+ parent = conflict;
|
|
|
+ if (!(conflict->flags & IORESOURCE_BUSY))
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Uhhuh, that didn't work out.. */
|
|
|
+ kfree(res);
|
|
|
+ res = NULL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!res) {
|
|
|
+ printk(KERN_DEBUG " __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
|
|
|
+ conflict->name, conflict->start, conflict->end,
|
|
|
+ name, start, end);
|
|
|
+
|
|
|
+ /* failed, split and try again */
|
|
|
+
|
|
|
+ /* conflict coverred whole area */
|
|
|
+ if (conflict->start <= start && conflict->end >= end)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (conflict->start > start)
|
|
|
+ __reserve_region_with_split(root, start, conflict->start-1, name);
|
|
|
+ if (!(conflict->flags & IORESOURCE_BUSY)) {
|
|
|
+ resource_size_t common_start, common_end;
|
|
|
+
|
|
|
+ common_start = max(conflict->start, start);
|
|
|
+ common_end = min(conflict->end, end);
|
|
|
+ if (common_start < common_end)
|
|
|
+ __reserve_region_with_split(root, common_start, common_end, name);
|
|
|
+ }
|
|
|
+ if (conflict->end < end)
|
|
|
+ __reserve_region_with_split(root, conflict->end+1, end, name);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void reserve_region_with_split(struct resource *root,
|
|
|
+ resource_size_t start, resource_size_t end,
|
|
|
+ const char *name)
|
|
|
+{
|
|
|
+ write_lock(&resource_lock);
|
|
|
+ __reserve_region_with_split(root, start, end, name);
|
|
|
+ write_unlock(&resource_lock);
|
|
|
+}
|
|
|
+
|
|
|
EXPORT_SYMBOL(adjust_resource);
|
|
|
|
|
|
/**
|