diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-09-04 21:04:04 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-04 21:04:04 +0200 |
commit | 8040d77688014987ca5738bf1731db72ab273441 (patch) | |
tree | 99caf0f4ca88eeeb6e2b812a4002c5c0387f3ef9 /kernel | |
parent | fb481dd56adf3c5b0993b8f052cc9ba966e3959d (diff) | |
parent | 268364a0f48aee2f851f9d1ef8a6cda0f3039ef1 (diff) | |
download | blackbird-op-linux-8040d77688014987ca5738bf1731db72ab273441.tar.gz blackbird-op-linux-8040d77688014987ca5738bf1731db72ab273441.zip |
Merge branch 'core/resources' into x86/core
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/resource.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index 03d796c1b2e9..414d6fc9131e 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -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); /** |