unsigned long size, unsigned long align,
                                unsigned long goal, unsigned long limit)
 {
+       unsigned long fallback = 0;
        unsigned long min, max, start, sidx, midx, step;
 
        BUG_ON(!size);
        midx = max - PFN_DOWN(bdata->node_boot_start);
 
        if (bdata->hint_idx > sidx) {
-               /* Make sure we retry on failure */
-               goal = 1;
+               /*
+                * Handle the valid case of sidx being zero and still
+                * catch the fallback below.
+                */
+               fallback = sidx + 1;
                sidx = ALIGN(bdata->hint_idx, step);
        }
 
                return region;
        }
 
+       if (fallback) {
+               sidx = ALIGN(fallback - 1, step);
+               fallback = 0;
+               goto find_block;
+       }
+
+       return NULL;
+}
+
+static void * __init ___alloc_bootmem_nopanic(unsigned long size,
+                                       unsigned long align,
+                                       unsigned long goal,
+                                       unsigned long limit)
+{
+       bootmem_data_t *bdata;
+
+restart:
+       list_for_each_entry(bdata, &bdata_list, list) {
+               void *region;
+
+               if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
+                       continue;
+               if (limit && bdata->node_boot_start >= limit)
+                       break;
+
+               region = alloc_bootmem_core(bdata, size, align, goal, limit);
+               if (region)
+                       return region;
+       }
+
        if (goal) {
                goal = 0;
-               sidx = 0;
-               goto find_block;
+               goto restart;
        }
 
        return NULL;
  * Returns NULL on failure.
  */
 void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
-                                     unsigned long goal)
+                                       unsigned long goal)
 {
-       bootmem_data_t *bdata;
-       void *ptr;
+       return ___alloc_bootmem_nopanic(size, align, goal, 0);
+}
 
-       list_for_each_entry(bdata, &bdata_list, list) {
-               ptr = alloc_bootmem_core(bdata, size, align, goal, 0);
-               if (ptr)
-                       return ptr;
-       }
+static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
+                                       unsigned long goal, unsigned long limit)
+{
+       void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
+
+       if (mem)
+               return mem;
+       /*
+        * Whoops, we cannot satisfy the allocation request.
+        */
+       printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+       panic("Out of memory");
        return NULL;
 }
 
 void * __init __alloc_bootmem(unsigned long size, unsigned long align,
                              unsigned long goal)
 {
-       void *mem = __alloc_bootmem_nopanic(size,align,goal);
-
-       if (mem)
-               return mem;
-       /*
-        * Whoops, we cannot satisfy the allocation request.
-        */
-       printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
-       panic("Out of memory");
-       return NULL;
+       return ___alloc_bootmem(size, align, goal, 0);
 }
 
 /**
 void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
                                  unsigned long goal)
 {
-       bootmem_data_t *bdata;
-       void *ptr;
-
-       list_for_each_entry(bdata, &bdata_list, list) {
-               ptr = alloc_bootmem_core(bdata, size, align, goal,
-                                       ARCH_LOW_ADDRESS_LIMIT);
-               if (ptr)
-                       return ptr;
-       }
-
-       /*
-        * Whoops, we cannot satisfy the allocation request.
-        */
-       printk(KERN_ALERT "low bootmem alloc of %lu bytes failed!\n", size);
-       panic("Out of low memory");
-       return NULL;
+       return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
 }
 
 /**