ANDROID: memblock: track memblock changed at early param
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. Bug: 340432773 Signed-off-by: Jaewon Kim <jaewon31.kim@samsung.com> Link: https://lore.kernel.org/linux-mm/20240521023957.2587005-6-jaewon31.kim@samsung.com/ Change-Id: Ib01e88b303be4ab958db46f1e369d15042a5d9fd
This commit is contained in:
committed by
Suren Baghdasaryan
parent
f3f83a6edf
commit
7227090784
@@ -597,10 +597,14 @@ static inline void memtest_report_meminfo(struct seq_file *m) { }
|
||||
extern void __init_memblock memblock_memsize_record(const char *name,
|
||||
phys_addr_t base, phys_addr_t size, bool nomap, bool reusable);
|
||||
extern void __init memblock_memsize_detect_hole(void);
|
||||
extern void __init memblock_memsize_set_name(const char *name);
|
||||
extern void __init memblock_memsize_unset_name(void);
|
||||
#else
|
||||
static inline void __init_memblock memblock_memsize_record(const char *name,
|
||||
phys_addr_t base, phys_addr_t size, bool nomap, bool reusable) { }
|
||||
static inline void __init memblock_memsize_detect_hole(void) { }
|
||||
static inline void __init memblock_memsize_set_name(const char *name) { }
|
||||
static inline void __init memblock_memsize_unset_name(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_MEMBLOCK_H */
|
||||
|
||||
+11
-2
@@ -212,8 +212,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);
|
||||
@@ -758,8 +765,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. */
|
||||
|
||||
+92
-2
@@ -175,6 +175,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
|
||||
|
||||
/*
|
||||
* Address comparison utilities
|
||||
*/
|
||||
@@ -591,6 +603,7 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
|
||||
phys_addr_t end = base + memblock_cap_size(base, &size);
|
||||
int idx, nr_new, start_rgn = -1, end_rgn;
|
||||
struct memblock_region *rgn;
|
||||
phys_addr_t new_size = 0;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
@@ -604,7 +617,8 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
|
||||
memblock_set_region_node(&type->regions[0], nid);
|
||||
type->total_size = size;
|
||||
type->cnt = 1;
|
||||
return 0;
|
||||
new_size = size;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -651,6 +665,7 @@ repeat:
|
||||
memblock_insert_region(type, idx++, base,
|
||||
rbase - base, nid,
|
||||
flags);
|
||||
new_size += rbase - base;
|
||||
}
|
||||
}
|
||||
/* area below @rend is dealt with, forget about it */
|
||||
@@ -666,6 +681,7 @@ repeat:
|
||||
end_rgn = idx + 1;
|
||||
memblock_insert_region(type, idx, base, end - base,
|
||||
nid, flags);
|
||||
new_size += end - base;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,8 +700,11 @@ repeat:
|
||||
goto repeat;
|
||||
} else {
|
||||
memblock_merge_regions(type, start_rgn, end_rgn);
|
||||
return 0;
|
||||
}
|
||||
done:
|
||||
if (new_size == size)
|
||||
memblock_memsize_record_add(type, obase, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -856,6 +875,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;
|
||||
}
|
||||
|
||||
@@ -2049,6 +2069,7 @@ struct memsize_rgn_struct {
|
||||
|
||||
static struct memsize_rgn_struct memsize_rgn[CONFIG_MAX_MEMBLOCK_MEMSIZE] __initdata_memblock;
|
||||
static int memsize_rgn_count __initdata_memblock;
|
||||
static const char *memblock_memsize_name __initdata_memblock;
|
||||
|
||||
static void __init_memblock memsize_get_valid_name(char *valid_name, const char *name)
|
||||
{
|
||||
@@ -2245,6 +2266,75 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user