It will try find area according with size/align in specified range (start, end). Need use it find correct buffer for new lmb.reserved.region. also make it more easy for x86 to use lmb. x86 early_res is using find/reserve pattern instead of alloc. find_lmb_area() will hohor goal When we need temperary buff for range array etc for range work, if We are using lmb_alloc(), We will need to add some post fix code for buffer that is used by range array, because it is in the lmb.reserved already. Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- include/linux/lmb.h | 4 ++ mm/lmb.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 0 deletions(-) diff --git a/include/linux/lmb.h b/include/linux/lmb.h index e14ea8d..05234bd 100644 --- a/include/linux/lmb.h +++ b/include/linux/lmb.h @@ -83,6 +83,10 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) lmb_size_pages(type, region_nr); } +u64 __find_lmb_area(u64 ei_start, u64 ei_last, u64 start, u64 end, + u64 size, u64 align); +u64 find_lmb_area(u64 start, u64 end, u64 size, u64 align); + #include <asm/lmb.h> #endif /* __KERNEL__ */ diff --git a/mm/lmb.c b/mm/lmb.c index 65b62dc..d5d5dc4 100644 --- a/mm/lmb.c +++ b/mm/lmb.c @@ -11,9 +11,13 @@ */ #include <linux/kernel.h> +#include <linux/types.h> #include <linux/init.h> #include <linux/bitops.h> #include <linux/lmb.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/range.h> #define LMB_ALLOC_ANYWHERE 0 @@ -546,3 +550,80 @@ int lmb_find(struct lmb_property *res) } return -1; } + +static int __init find_overlapped_early(u64 start, u64 end) +{ + int i; + struct lmb_property *r; + + for (i = 0; i < lmb.reserved.cnt && lmb.reserved.region[i].size; i++) { + r = &lmb.reserved.region[i]; + if (end > r->base && start < (r->base + r->size)) + break; + } + + return i; +} + +/* Check for already reserved areas */ +static inline bool __init bad_addr(u64 *addrp, u64 size, u64 align) +{ + int i; + u64 addr = *addrp; + bool changed = false; + struct lmb_property *r; +again: + i = find_overlapped_early(addr, addr + size); + r = &lmb.reserved.region[i]; + if (i < lmb.reserved.cnt && r->size) { + *addrp = addr = round_up(r->base + r->size, align); + changed = true; + goto again; + } + return changed; +} + +u64 __init __find_lmb_area(u64 ei_start, u64 ei_last, u64 start, u64 end, + u64 size, u64 align) +{ + u64 addr, last; + + addr = round_up(ei_start, align); + if (addr < start) + addr = round_up(start, align); + if (addr >= ei_last) + goto out; + while (bad_addr(&addr, size, align) && addr+size <= ei_last) + ; + last = addr + size; + if (last > ei_last) + goto out; + if (last > end) + goto out; + + return addr; + +out: + return -1ULL; +} + +/* + * Find a free area with specified alignment in a specific range. + */ +u64 __init find_lmb_area(u64 start, u64 end, u64 size, u64 align) +{ + int i; + + for (i = 0; i < lmb.memory.cnt; i++) { + u64 ei_start = lmb.memory.region[i].base; + u64 ei_last = ei_start + lmb.memory.region[i].size; + u64 addr; + + addr = __find_lmb_area(ei_start, ei_last, start, end, + size, align); + + if (addr != -1ULL) + return addr; + } + return -1ULL; +} -- 1.6.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html