Linux 3.2.80
[pandora-kernel.git] / kernel / resource.c
index c8dc249..240e26e 100644 (file)
@@ -7,7 +7,7 @@
  * Arbitrary resource management.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
@@ -757,6 +757,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;
@@ -766,21 +767,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,
@@ -860,9 +886,10 @@ struct resource * __request_region(struct resource *parent,
                if (!conflict)
                        break;
                if (conflict != parent) {
-                       parent = conflict;
-                       if (!(conflict->flags & IORESOURCE_BUSY))
+                       if (!(conflict->flags & IORESOURCE_BUSY)) {
+                               parent = conflict;
                                continue;
+                       }
                }
                if (conflict->flags & flags & IORESOURCE_MUXED) {
                        add_wait_queue(&muxed_resource_wait, &wait);