In addition to reserved-memory in device tree, an option in cmdline may result in memblock allocation. This patch tries to distinguish memblock changes done at early param. A region in memsize will be created with name as the param string. And the region size will be updated during the param function. Signed-off-by: Jaewon Kim <jaewon31.kim@xxxxxxxxxxx> --- include/linux/memblock.h | 4 ++ init/main.c | 13 ++++- mm/memblock.c | 101 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 201f8723dfd8..4be4e0e6baf4 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -609,11 +609,15 @@ extern void memblock_memsize_record(const char *name, phys_addr_t base, phys_addr_t size, bool nomap, bool reusable); extern void memblock_memsize_detect_hole(void); +extern void memblock_memsize_set_name(const char *name); +extern void memblock_memsize_unset_name(void); #else static inline void memblock_memsize_record(const char *name, phys_addr_t base, phys_addr_t size, bool nomap, bool reusable) { } static inline void memblock_memsize_detect_hole(void) { } +static inline void memblock_memsize_set_name(const char *name) { } +static inline void memblock_memsize_unset_name(void) { } #endif #endif /* _LINUX_MEMBLOCK_H */ diff --git a/init/main.c b/init/main.c index 560f45c27ffe..ce59521b5ae5 100644 --- a/init/main.c +++ b/init/main.c @@ -214,8 +214,15 @@ static bool __init obsolete_checksetup(char *line) pr_warn("Parameter %s is obsolete, ignored\n", p->str); return true; - } else if (p->setup_func(line + n)) - return true; + } else { + int ret; + + memblock_memsize_set_name(p->str); + ret = p->setup_func(line + n); + memblock_memsize_unset_name(); + if (ret) + return true; + } } p++; } while (p < __setup_end); @@ -736,8 +743,10 @@ static int __init do_early_param(char *param, char *val, (strcmp(param, "console") == 0 && strcmp(p->str, "earlycon") == 0) ) { + memblock_memsize_set_name(p->str); if (p->setup_func(val) != 0) pr_warn("Malformed early option '%s'\n", param); + memblock_memsize_unset_name(); } } /* We accept everything at this stage. */ diff --git a/mm/memblock.c b/mm/memblock.c index 9195a51bfa5d..4f21b596687e 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -169,6 +169,18 @@ static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size) return *size = min(*size, PHYS_ADDR_MAX - base); } +#ifdef CONFIG_MEMBLOCK_MEMSIZE +static void memblock_memsize_record_add(struct memblock_type *type, + phys_addr_t base, phys_addr_t size); +static void memblock_memsize_record_remove(struct memblock_type *type, + phys_addr_t base, phys_addr_t size); +#else +static inline void memblock_memsize_record_add(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) { } +static inline void memblock_memsize_record_remove(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) { } +#endif /* CONFIG_MEMBLOCK_MEMSIZE */ + /* * Address comparison utilities */ @@ -578,6 +590,7 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, bool insert = false; phys_addr_t obase = base; phys_addr_t end = base + memblock_cap_size(base, &size); + phys_addr_t new_size = 0; int idx, nr_new; struct memblock_region *rgn; @@ -592,7 +605,8 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, type->regions[0].flags = flags; memblock_set_region_node(&type->regions[0], nid); type->total_size = size; - return 0; + new_size = size; + goto done; } repeat: /* @@ -621,10 +635,12 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, #endif WARN_ON(flags != rgn->flags); nr_new++; - if (insert) + if (insert) { memblock_insert_region(type, idx++, base, rbase - base, nid, flags); + new_size += rbase - base; + } } /* area below @rend is dealt with, forget about it */ base = min(rend, end); @@ -633,9 +649,11 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, /* insert the remaining portion */ if (base < end) { nr_new++; - if (insert) + if (insert) { memblock_insert_region(type, idx, base, end - base, nid, flags); + new_size += end - base; + } } if (!nr_new) @@ -653,8 +671,11 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, goto repeat; } else { memblock_merge_regions(type); - return 0; } +done: + if (new_size == size) + memblock_memsize_record_add(type, obase, size); + return 0; } /** @@ -790,6 +811,7 @@ static int __init_memblock memblock_remove_range(struct memblock_type *type, for (i = end_rgn - 1; i >= start_rgn; i--) memblock_remove_region(type, i); + memblock_memsize_record_remove(type, base, size); return 0; } @@ -2091,6 +2113,77 @@ void __init memblock_memsize_detect_hole(void) } } } + +/* assume that freeing region is NOT bigger than the previous region */ +static void __init_memblock memblock_memsize_free(phys_addr_t free_base, + phys_addr_t free_size) +{ + int i; + struct memsize_rgn_struct *rgn; + phys_addr_t free_end, end; + + free_end = free_base + free_size - 1; + memblock_dbg("%s %pa..%pa\n", + __func__, &free_base, &free_end); + + for (i = 0; i < memsize_rgn_count; i++) { + rgn = &memsize_rgn[i]; + + end = rgn->base + rgn->size; + if (free_base < rgn->base || + free_base >= end) + continue; + + free_end = free_base + free_size; + if (free_base == rgn->base) { + rgn->size -= free_size; + if (rgn->size != 0) + rgn->base += free_size; + } else if (free_end == end) { + rgn->size -= free_size; + } else { + memblock_memsize_record(rgn->name, free_end, + end - free_end, rgn->nomap, rgn->reusable); + rgn->size = free_base - rgn->base; + } + } +} + +static const char *memblock_memsize_name; + +void __init memblock_memsize_set_name(const char *name) +{ + memblock_memsize_name = name; +} + +void __init memblock_memsize_unset_name(void) +{ + memblock_memsize_name = NULL; +} + +static void __init_memblock memblock_memsize_record_add(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) +{ + if (memblock_memsize_name) { + if (type == &memblock.reserved) + memblock_memsize_record(memblock_memsize_name, + base, size, false, false); + else if (type == &memblock.memory) + memblock_memsize_free(base, size); + } +} + +static void __init_memblock memblock_memsize_record_remove(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) +{ + if (memblock_memsize_name) { + if (type == &memblock.reserved) + memblock_memsize_free(base, size); + else if (type == &memblock.memory) + memblock_memsize_record(memblock_memsize_name, + base, size, true, false); + } +} #endif /* MEMBLOCK_MEMSIZE */ static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn) -- 2.17.1