Subject: [PATCH] x86, memblock: Add memblock_x86_find_in_range_low() Generic version is going from high to low, and it seems it can not find right area compact enough. the x86 version will go from goal to limit and just like the way We used for early_res to make crashkernel happy with 32bit kdump Signed-off-by: Yinghai Lu --- arch/x86/include/asm/memblock.h | 2 + arch/x86/kernel/setup.c | 2 - arch/x86/mm/memblock.c | 52 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) Index: linux-2.6/arch/x86/mm/memblock.c =================================================================== --- linux-2.6.orig/arch/x86/mm/memblock.c +++ linux-2.6/arch/x86/mm/memblock.c @@ -346,3 +346,55 @@ u64 __init memblock_x86_hole_size(u64 st return end - start - ((u64)ram << PAGE_SHIFT); } + +/* Check for already reserved areas */ +static inline bool __init check_with_memblock_reserved(u64 *addrp, u64 size, u64 align) +{ + u64 addr = *addrp; + bool changed = false; + struct memblock_region *r; +again: + for_each_memblock(reserved, r) { + if ((addr + size) > r->base && addr < (r->base + r->size)) { + addr = round_up(r->base + r->size, align); + changed = true; + goto again; + } + } + + if (changed) + *addrp = addr; + + return changed; +} + +/* + * Find a free area with specified alignment in a specific range from bottom up + */ +u64 __init memblock_x86_find_in_range_low(u64 start, u64 end, u64 size, u64 align) +{ + struct memblock_region *r; + + for_each_memblock(memory, r) { + u64 ei_start = r->base; + u64 ei_last = ei_start + r->size; + u64 addr, last; + + addr = round_up(ei_start, align); + if (addr < start) + addr = round_up(start, align); + if (addr >= ei_last) + continue; + while (check_with_memblock_reserved(&addr, size, align) && addr+size <= ei_last) + ; + last = addr + size; + if (last > ei_last) + continue; + if (last > end) + continue; + + return addr; + } + + return MEMBLOCK_ERROR; +} Index: linux-2.6/arch/x86/include/asm/memblock.h =================================================================== --- linux-2.6.orig/arch/x86/include/asm/memblock.h +++ linux-2.6/arch/x86/include/asm/memblock.h @@ -20,4 +20,6 @@ u64 memblock_x86_find_in_range_node(int u64 memblock_x86_free_memory_in_range(u64 addr, u64 limit); u64 memblock_x86_memory_in_range(u64 addr, u64 limit); +u64 memblock_x86_find_in_range_low(u64 start, u64 end, u64 size, u64 align); + #endif Index: linux-2.6/arch/x86/kernel/setup.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/setup.c +++ linux-2.6/arch/x86/kernel/setup.c @@ -522,7 +522,7 @@ static void __init reserve_crashkernel(v /* * kexec want bzImage is below DEFAULT_BZIMAGE_ADDR_MAX */ - crash_base = memblock_find_in_range(alignment, + crash_base = memblock_x86_find_in_range_low(alignment, DEFAULT_BZIMAGE_ADDR_MAX, crash_size, alignment); if (crash_base == MEMBLOCK_ERROR) {