1
0
Fork 0

MIPS: init: Drop boot_mem_map

boot_mem_map was introduced very early and cannot handle memory maps
with nid. Nowadays, memblock can exactly replace boot_mem_map.

Detect pfn info and setup resources with memblock maps.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
[paul.burton@mips.com: Fix size calculation in check_kernel_sections_mem]
Signed-off-by: Paul Burton <paul.burton@mips.com>
Cc: linux-mips@vger.kernel.org
Cc: yasha.che3@gmail.com
Cc: aurelien@aurel32.net
Cc: sfr@canb.auug.org.au
Cc: fancer.lancer@gmail.com
Cc: matt.redfearn@mips.com
Cc: chenhc@lemote.com
alistair/sunxi64-5.4-dsi
Jiaxun Yang 2019-08-19 22:23:13 +08:00 committed by Paul Burton
parent a5718fe8f7
commit a94e4f24ec
No known key found for this signature in database
GPG Key ID: 3EA79FACB57500DD
2 changed files with 98 additions and 299 deletions

View File

@ -88,28 +88,12 @@ const char *get_system_type(void);
extern unsigned long mips_machtype; extern unsigned long mips_machtype;
#define BOOT_MEM_MAP_MAX 32
#define BOOT_MEM_RAM 1 #define BOOT_MEM_RAM 1
#define BOOT_MEM_ROM_DATA 2 #define BOOT_MEM_ROM_DATA 2
#define BOOT_MEM_RESERVED 3 #define BOOT_MEM_RESERVED 3
#define BOOT_MEM_INIT_RAM 4 #define BOOT_MEM_INIT_RAM 4
#define BOOT_MEM_NOMAP 5 #define BOOT_MEM_NOMAP 5
/*
* A memory map that's built upon what was determined
* or specified on the command line.
*/
struct boot_mem_map {
int nr_map;
struct boot_mem_map_entry {
phys_addr_t addr; /* start of memory segment */
phys_addr_t size; /* size of memory segment */
long type; /* type of memory segment */
} map[BOOT_MEM_MAP_MAX];
};
extern struct boot_mem_map boot_mem_map;
extern void add_memory_region(phys_addr_t start, phys_addr_t size, long type); extern void add_memory_region(phys_addr_t start, phys_addr_t size, long type);
extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max); extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max);

View File

@ -63,8 +63,6 @@ unsigned long mips_machtype __read_mostly = MACH_UNKNOWN;
EXPORT_SYMBOL(mips_machtype); EXPORT_SYMBOL(mips_machtype);
struct boot_mem_map boot_mem_map;
static char __initdata command_line[COMMAND_LINE_SIZE]; static char __initdata command_line[COMMAND_LINE_SIZE];
char __initdata arcs_cmdline[COMMAND_LINE_SIZE]; char __initdata arcs_cmdline[COMMAND_LINE_SIZE];
@ -92,8 +90,10 @@ EXPORT_SYMBOL(ARCH_PFN_OFFSET);
void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type) void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
{ {
int x = boot_mem_map.nr_map; /*
int i; * Note: This function only exists for historical reason,
* new code should use memblock_add or memblock_add_node instead.
*/
/* /*
* If the region reaches the top of the physical address space, adjust * If the region reaches the top of the physical address space, adjust
@ -108,38 +108,20 @@ void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
return; return;
} }
/* memblock_add(start, size);
* Try to merge with existing entry, if any. /* Reserve any memory except the ordinary RAM ranges. */
*/ switch (type) {
for (i = 0; i < boot_mem_map.nr_map; i++) { case BOOT_MEM_RAM:
struct boot_mem_map_entry *entry = boot_mem_map.map + i; break;
unsigned long top;
if (entry->type != type) case BOOT_MEM_NOMAP: /* Discard the range from the system. */
continue; memblock_remove(start, size);
break;
if (start + size < entry->addr) default: /* Reserve the rest of the memory types at boot time */
continue; /* no overlap */ memblock_reserve(start, size);
break;
if (entry->addr + entry->size < start)
continue; /* no overlap */
top = max(entry->addr + entry->size, start + size);
entry->addr = min(entry->addr, start);
entry->size = top - entry->addr;
return;
} }
if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) {
pr_err("Ooops! Too many entries in the memory map!\n");
return;
}
boot_mem_map.map[x].addr = start;
boot_mem_map.map[x].size = size;
boot_mem_map.map[x].type = type;
boot_mem_map.nr_map++;
} }
void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
@ -161,70 +143,6 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
add_memory_region(start, size, BOOT_MEM_RAM); add_memory_region(start, size, BOOT_MEM_RAM);
} }
static bool __init __maybe_unused memory_region_available(phys_addr_t start,
phys_addr_t size)
{
int i;
bool in_ram = false, free = true;
for (i = 0; i < boot_mem_map.nr_map; i++) {
phys_addr_t start_, end_;
start_ = boot_mem_map.map[i].addr;
end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
if (start >= start_ && start + size <= end_)
in_ram = true;
break;
case BOOT_MEM_RESERVED:
case BOOT_MEM_NOMAP:
if ((start >= start_ && start < end_) ||
(start < start_ && start + size >= start_))
free = false;
break;
default:
continue;
}
}
return in_ram && free;
}
static void __init print_memory_map(void)
{
int i;
const int field = 2 * sizeof(unsigned long);
for (i = 0; i < boot_mem_map.nr_map; i++) {
printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
field, (unsigned long long) boot_mem_map.map[i].size,
field, (unsigned long long) boot_mem_map.map[i].addr);
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
printk(KERN_CONT "(usable)\n");
break;
case BOOT_MEM_INIT_RAM:
printk(KERN_CONT "(usable after init)\n");
break;
case BOOT_MEM_ROM_DATA:
printk(KERN_CONT "(ROM data)\n");
break;
case BOOT_MEM_RESERVED:
printk(KERN_CONT "(reserved)\n");
break;
case BOOT_MEM_NOMAP:
printk(KERN_CONT "(nomap)\n");
break;
default:
printk(KERN_CONT "type %lu\n", boot_mem_map.map[i].type);
break;
}
}
}
/* /*
* Manage initrd * Manage initrd
*/ */
@ -376,8 +294,11 @@ static void __init bootmem_init(void)
static void __init bootmem_init(void) static void __init bootmem_init(void)
{ {
phys_addr_t ramstart = PHYS_ADDR_MAX; struct memblock_region *mem;
int i; phys_addr_t ramstart, ramend;
ramstart = memblock_start_of_DRAM();
ramend = memblock_end_of_DRAM();
/* /*
* Sanity check any INITRD first. We don't take it into account * Sanity check any INITRD first. We don't take it into account
@ -391,47 +312,7 @@ static void __init bootmem_init(void)
memblock_reserve(__pa_symbol(&_text), memblock_reserve(__pa_symbol(&_text),
__pa_symbol(&_end) - __pa_symbol(&_text)); __pa_symbol(&_end) - __pa_symbol(&_text));
/* /* max_low_pfn is not a number of pages but the end pfn of low mem */
* max_low_pfn is not a number of pages. The number of pages
* of the system is given by 'max_low_pfn - min_low_pfn'.
*/
min_low_pfn = ~0UL;
max_low_pfn = 0;
/* Find the highest and lowest page frame numbers we have available. */
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
continue;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
ramstart = min(ramstart, boot_mem_map.map[i].addr);
#ifndef CONFIG_HIGHMEM
/*
* Skip highmem here so we get an accurate max_low_pfn if low
* memory stops short of high memory.
* If the region overlaps HIGHMEM_START, end is clipped so
* max_pfn excludes the highmem portion.
*/
if (start >= PFN_DOWN(HIGHMEM_START))
continue;
if (end > PFN_DOWN(HIGHMEM_START))
end = PFN_DOWN(HIGHMEM_START);
#endif
if (end > max_low_pfn)
max_low_pfn = end;
if (start < min_low_pfn)
min_low_pfn = start;
}
if (min_low_pfn >= max_low_pfn)
panic("Incorrect memory mapping !!!");
#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
ARCH_PFN_OFFSET = PFN_UP(ramstart); ARCH_PFN_OFFSET = PFN_UP(ramstart);
@ -439,75 +320,59 @@ static void __init bootmem_init(void)
/* /*
* Reserve any memory between the start of RAM and PHYS_OFFSET * Reserve any memory between the start of RAM and PHYS_OFFSET
*/ */
if (ramstart > PHYS_OFFSET) { if (ramstart > PHYS_OFFSET)
add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, memblock_reserve(PHYS_OFFSET, PFN_UP(ramstart) - PHYS_OFFSET);
BOOT_MEM_RESERVED);
memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
}
if (min_low_pfn > ARCH_PFN_OFFSET) { if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
pr_info("Wasting %lu bytes for tracking %lu unused pages\n", pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
(min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page), (unsigned long)((PFN_UP(ramstart) - ARCH_PFN_OFFSET) * sizeof(struct page)),
min_low_pfn - ARCH_PFN_OFFSET); (unsigned long)(PFN_UP(ramstart) - ARCH_PFN_OFFSET));
} else if (ARCH_PFN_OFFSET - min_low_pfn > 0UL) {
pr_info("%lu free pages won't be used\n",
ARCH_PFN_OFFSET - min_low_pfn);
} }
#endif
min_low_pfn = ARCH_PFN_OFFSET; min_low_pfn = ARCH_PFN_OFFSET;
#endif max_pfn = PFN_DOWN(ramend);
for_each_memblock(memory, mem) {
/* unsigned long start = memblock_region_memory_base_pfn(mem);
* Determine low and high memory ranges unsigned long end = memblock_region_memory_end_pfn(mem);
*/
max_pfn = max_low_pfn;
if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
#ifdef CONFIG_HIGHMEM
highstart_pfn = PFN_DOWN(HIGHMEM_START);
highend_pfn = max_low_pfn;
#endif
max_low_pfn = PFN_DOWN(HIGHMEM_START);
}
/* Install all valid RAM ranges to the memblock memory region */
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
if (start < min_low_pfn)
start = min_low_pfn;
#ifndef CONFIG_HIGHMEM
/* Ignore highmem regions if highmem is unsupported */
if (end > max_low_pfn)
end = max_low_pfn;
#endif
if (end <= start)
continue;
memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
/* Reserve any memory except the ordinary RAM ranges. */
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
break;
case BOOT_MEM_NOMAP: /* Discard the range from the system. */
memblock_remove(PFN_PHYS(start), PFN_PHYS(end - start));
continue;
default: /* Reserve the rest of the memory types at boot time */
memblock_reserve(PFN_PHYS(start), PFN_PHYS(end - start));
break;
}
/* /*
* In any case the added to the memblock memory regions * Skip highmem here so we get an accurate max_low_pfn if low
* (highmem/lowmem, available/reserved, etc) are considered * memory stops short of high memory.
* as present, so inform sparsemem about them. * If the region overlaps HIGHMEM_START, end is clipped so
* max_pfn excludes the highmem portion.
*/ */
memory_present(0, start, end); if (memblock_is_nomap(mem))
continue;
if (start >= PFN_DOWN(HIGHMEM_START))
continue;
if (end > PFN_DOWN(HIGHMEM_START))
end = PFN_DOWN(HIGHMEM_START);
if (end > max_low_pfn)
max_low_pfn = end;
} }
if (min_low_pfn >= max_low_pfn)
panic("Incorrect memory mapping !!!");
if (max_pfn > PFN_DOWN(HIGHMEM_START)) {
#ifdef CONFIG_HIGHMEM
highstart_pfn = PFN_DOWN(HIGHMEM_START);
highend_pfn = max_pfn;
#else
max_low_pfn = PFN_DOWN(HIGHMEM_START);
max_pfn = max_low_pfn;
#endif
}
/*
* In any case the added to the memblock memory regions
* (highmem/lowmem, available/reserved, etc) are considered
* as present, so inform sparsemem about them.
*/
memblocks_present();
/* /*
* Reserve initrd memory if needed. * Reserve initrd memory if needed.
*/ */
@ -528,8 +393,9 @@ static int __init early_parse_mem(char *p)
* size. * size.
*/ */
if (usermem == 0) { if (usermem == 0) {
boot_mem_map.nr_map = 0;
usermem = 1; usermem = 1;
memblock_remove(memblock_start_of_DRAM(),
memblock_end_of_DRAM() - memblock_start_of_DRAM());
} }
start = 0; start = 0;
size = memparse(p, &p); size = memparse(p, &p);
@ -586,14 +452,13 @@ early_param("memmap", early_parse_memmap);
unsigned long setup_elfcorehdr, setup_elfcorehdr_size; unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
static int __init early_parse_elfcorehdr(char *p) static int __init early_parse_elfcorehdr(char *p)
{ {
int i; struct memblock_region *mem;
setup_elfcorehdr = memparse(p, &p); setup_elfcorehdr = memparse(p, &p);
for (i = 0; i < boot_mem_map.nr_map; i++) { for_each_memblock(memory, mem) {
unsigned long start = boot_mem_map.map[i].addr; unsigned long start = mem->base;
unsigned long end = (boot_mem_map.map[i].addr + unsigned long end = mem->end;
boot_mem_map.map[i].size);
if (setup_elfcorehdr >= start && setup_elfcorehdr < end) { if (setup_elfcorehdr >= start && setup_elfcorehdr < end) {
/* /*
* Reserve from the elf core header to the end of * Reserve from the elf core header to the end of
@ -613,47 +478,20 @@ static int __init early_parse_elfcorehdr(char *p)
early_param("elfcorehdr", early_parse_elfcorehdr); early_param("elfcorehdr", early_parse_elfcorehdr);
#endif #endif
static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
{
phys_addr_t size;
int i;
size = end - mem;
if (!size)
return;
/* Make sure it is in the boot_mem_map */
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (mem >= boot_mem_map.map[i].addr &&
mem < (boot_mem_map.map[i].addr +
boot_mem_map.map[i].size))
return;
}
add_memory_region(mem, size, type);
}
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
static inline unsigned long long get_total_mem(void)
{
unsigned long long total;
total = max_pfn - min_low_pfn;
return total << PAGE_SHIFT;
}
static void __init mips_parse_crashkernel(void) static void __init mips_parse_crashkernel(void)
{ {
unsigned long long total_mem; unsigned long long total_mem;
unsigned long long crash_size, crash_base; unsigned long long crash_size, crash_base;
int ret; int ret;
total_mem = get_total_mem(); total_mem = memblock_phys_mem_size();
ret = parse_crashkernel(boot_command_line, total_mem, ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base); &crash_size, &crash_base);
if (ret != 0 || crash_size <= 0) if (ret != 0 || crash_size <= 0)
return; return;
if (!memory_region_available(crash_base, crash_size)) { if (!memblock_find_in_range(crash_base, crash_base + crash_size, crash_size, 0)) {
pr_warn("Invalid memory region reserved for crash kernel\n"); pr_warn("Invalid memory region reserved for crash kernel\n");
return; return;
} }
@ -686,6 +524,17 @@ static void __init request_crashkernel(struct resource *res)
} }
#endif /* !defined(CONFIG_KEXEC) */ #endif /* !defined(CONFIG_KEXEC) */
static void __init check_kernel_sections_mem(void)
{
phys_addr_t start = PFN_PHYS(PFN_DOWN(__pa_symbol(&_text)));
phys_addr_t size = PFN_PHYS(PFN_UP(__pa_symbol(&_end))) - start;
if (!memblock_is_region_memory(start, size)) {
pr_info("Kernel sections are not in the memory maps\n");
memblock_add(start, size);
}
}
#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER) #define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) #define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) #define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
@ -731,25 +580,6 @@ static void __init arch_mem_init(char **cmdline_p)
plat_mem_setup(); plat_mem_setup();
memblock_set_bottom_up(true); memblock_set_bottom_up(true);
/*
* Make sure all kernel memory is in the maps. The "UP" and
* "DOWN" are opposite for initdata since if it crosses over
* into another memory section you don't want that to be
* freed when the initdata is freed.
*/
arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
BOOT_MEM_RAM);
arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
BOOT_MEM_INIT_RAM);
arch_mem_addpart(PFN_DOWN(__pa_symbol(&__bss_start)) << PAGE_SHIFT,
PFN_UP(__pa_symbol(&__bss_stop)) << PAGE_SHIFT,
BOOT_MEM_RAM);
pr_info("Determined physical RAM map:\n");
print_memory_map();
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE) #if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else #else
@ -783,14 +613,17 @@ static void __init arch_mem_init(char **cmdline_p)
parse_early_param(); parse_early_param();
if (usermem) { if (usermem)
pr_info("User-defined physical RAM map:\n"); pr_info("User-defined physical RAM map overwrite\n");
print_memory_map();
} check_kernel_sections_mem();
early_init_fdt_reserve_self(); early_init_fdt_reserve_self();
early_init_fdt_scan_reserved_mem(); early_init_fdt_scan_reserved_mem();
#ifndef CONFIG_NUMA
memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
#endif
bootmem_init(); bootmem_init();
/* /*
@ -830,12 +663,12 @@ static void __init arch_mem_init(char **cmdline_p)
memblock_dump_all(); memblock_dump_all();
early_memtest(PFN_PHYS(min_low_pfn), PFN_PHYS(max_low_pfn)); early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
} }
static void __init resource_init(void) static void __init resource_init(void)
{ {
int i; struct memblock_region *region;
if (UNCAC_BASE != IO_BASE) if (UNCAC_BASE != IO_BASE)
return; return;
@ -847,16 +680,10 @@ static void __init resource_init(void)
bss_resource.start = __pa_symbol(&__bss_start); bss_resource.start = __pa_symbol(&__bss_start);
bss_resource.end = __pa_symbol(&__bss_stop) - 1; bss_resource.end = __pa_symbol(&__bss_stop) - 1;
for (i = 0; i < boot_mem_map.nr_map; i++) { for_each_memblock(memory, region) {
phys_addr_t start = PFN_PHYS(memblock_region_memory_base_pfn(region));
phys_addr_t end = PFN_PHYS(memblock_region_memory_end_pfn(region)) - 1;
struct resource *res; struct resource *res;
unsigned long start, end;
start = boot_mem_map.map[i].addr;
end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
if (start >= HIGHMEM_START)
continue;
if (end >= HIGHMEM_START)
end = HIGHMEM_START - 1;
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES); res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
if (!res) if (!res)
@ -865,20 +692,8 @@ static void __init resource_init(void)
res->start = start; res->start = start;
res->end = end; res->end = end;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
res->name = "System RAM";
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
case BOOT_MEM_INIT_RAM:
case BOOT_MEM_ROM_DATA:
res->name = "System RAM";
res->flags |= IORESOURCE_SYSRAM;
break;
case BOOT_MEM_RESERVED:
case BOOT_MEM_NOMAP:
default:
res->name = "reserved";
}
request_resource(&iomem_resource, res); request_resource(&iomem_resource, res);