Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Handle initmem in systems with kernel not in add_memory_region() mem

This patch addresses a couple of related problems:

1) The kernel may reside in physical memory outside of the ranges set
by plat_mem_setup(). If this is the case, init mem cannot be
reused as it resides outside of the range of pages that the kernel
memory allocators control.

2) initrd images might be loaded in physical memory outside of the
ranges set by plat_mem_setup(). The memory likewise cannot be
reused. The patch doesn't handle this specific case, but the
infrastructure is useful for future patches that do.

The crux of the problem is that there are memory regions that need be
memory_present(), but that cannot be free_bootmem() at the time of
arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM)
for use with add_memory_region(). Then arch_mem_init() adds the init
mem with this type if the init mem is not already covered by existing
ranges.

When memory is being freed into the bootmem allocator, we skip the
BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal
them as memory_present(). This way when they are later freed, the
necessary memory manager structures have initialized and the Sparse
allocater is prevented from crashing.

The Octeon specific code that handled this case is removed, because
the new general purpose code handles the case.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/1988/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

David Daney and committed by
Ralf Baechle
43064c0c b1c10bea

+49 -16
-8
arch/mips/cavium-octeon/setup.c
··· 642 642 643 643 total = 0; 644 644 645 - /* First add the init memory we will be returning. */ 646 - memory = __pa_symbol(&__init_begin) & PAGE_MASK; 647 - mem_alloc_size = (__pa_symbol(&__init_end) & PAGE_MASK) - memory; 648 - if (mem_alloc_size > 0) { 649 - add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM); 650 - total += mem_alloc_size; 651 - } 652 - 653 645 /* 654 646 * The Mips memory init uses the first memory location for 655 647 * some memory vectors. When SPARSEMEM is in use, it doesn't
+1
arch/mips/include/asm/bootinfo.h
··· 86 86 #define BOOT_MEM_RAM 1 87 87 #define BOOT_MEM_ROM_DATA 2 88 88 #define BOOT_MEM_RESERVED 3 89 + #define BOOT_MEM_INIT_RAM 4 89 90 90 91 /* 91 92 * A memory map that's built upon what was determined
+41 -6
arch/mips/kernel/setup.c
··· 121 121 case BOOT_MEM_RAM: 122 122 printk(KERN_CONT "(usable)\n"); 123 123 break; 124 + case BOOT_MEM_INIT_RAM: 125 + printk(KERN_CONT "(usable after init)\n"); 126 + break; 124 127 case BOOT_MEM_ROM_DATA: 125 128 printk(KERN_CONT "(ROM data)\n"); 126 129 break; ··· 364 361 for (i = 0; i < boot_mem_map.nr_map; i++) { 365 362 unsigned long start, end, size; 366 363 367 - /* 368 - * Reserve usable memory. 369 - */ 370 - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) 371 - continue; 372 - 373 364 start = PFN_UP(boot_mem_map.map[i].addr); 374 365 end = PFN_DOWN(boot_mem_map.map[i].addr 375 366 + boot_mem_map.map[i].size); 367 + 368 + /* 369 + * Reserve usable memory. 370 + */ 371 + switch (boot_mem_map.map[i].type) { 372 + case BOOT_MEM_RAM: 373 + break; 374 + case BOOT_MEM_INIT_RAM: 375 + memory_present(0, start, end); 376 + continue; 377 + default: 378 + /* Not usable memory */ 379 + continue; 380 + } 381 + 376 382 /* 377 383 * We are rounding up the start address of usable memory 378 384 * and at the end of the usable range downwards. ··· 467 455 468 456 static void __init arch_mem_init(char **cmdline_p) 469 457 { 458 + phys_t init_mem, init_end, init_size; 459 + 470 460 extern void plat_mem_setup(void); 471 461 472 462 /* call board setup routine */ 473 463 plat_mem_setup(); 464 + 465 + init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT; 466 + init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT; 467 + init_size = init_end - init_mem; 468 + if (init_size) { 469 + /* Make sure it is in the boot_mem_map */ 470 + int i, found; 471 + found = 0; 472 + for (i = 0; i < boot_mem_map.nr_map; i++) { 473 + if (init_mem >= boot_mem_map.map[i].addr && 474 + init_mem < (boot_mem_map.map[i].addr + 475 + boot_mem_map.map[i].size)) { 476 + found = 1; 477 + break; 478 + } 479 + } 480 + if (!found) 481 + add_memory_region(init_mem, init_size, 482 + BOOT_MEM_INIT_RAM); 483 + } 474 484 475 485 pr_info("Determined physical RAM map:\n"); 476 486 print_memory_map(); ··· 557 523 res = alloc_bootmem(sizeof(struct resource)); 558 524 switch (boot_mem_map.map[i].type) { 559 525 case BOOT_MEM_RAM: 526 + case BOOT_MEM_INIT_RAM: 560 527 case BOOT_MEM_ROM_DATA: 561 528 res->name = "System RAM"; 562 529 break;
+7 -2
arch/mips/mm/init.c
··· 304 304 for (i = 0; i < boot_mem_map.nr_map; i++) { 305 305 unsigned long addr, end; 306 306 307 - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) 307 + switch (boot_mem_map.map[i].type) { 308 + case BOOT_MEM_RAM: 309 + case BOOT_MEM_INIT_RAM: 310 + break; 311 + default: 308 312 /* not usable memory */ 309 313 continue; 314 + } 310 315 311 316 addr = PFN_UP(boot_mem_map.map[i].addr); 312 317 end = PFN_DOWN(boot_mem_map.map[i].addr + ··· 384 379 385 380 reservedpages = ram = 0; 386 381 for (tmp = 0; tmp < max_low_pfn; tmp++) 387 - if (page_is_ram(tmp)) { 382 + if (page_is_ram(tmp) && pfn_valid(tmp)) { 388 383 ram++; 389 384 if (PageReserved(pfn_to_page(tmp))) 390 385 reservedpages++;