|
@@ -408,6 +408,7 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
|
|
|
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);
|
|
@@ -443,8 +444,11 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -492,10 +496,39 @@ find_block:
|
|
|
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;
|
|
@@ -515,16 +548,23 @@ find_block:
|
|
|
* 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;
|
|
|
}
|
|
|
|
|
@@ -544,16 +584,7 @@ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -653,22 +684,7 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
/**
|