diff options
author | bob picco <bpicco@meloft.net> | 2014-09-16 09:29:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-16 21:23:11 -0400 |
commit | 7c21d533ab2ffa1e681bdaf4a53ce3046f6e0e17 (patch) | |
tree | 53c5e1f017233064af515d6dc7a656df95e19636 /arch/sparc/mm | |
parent | 3dee9df54836d5f844f3d58281d3f3e6331b467f (diff) |
sparc64: mem boot option correction
The "mem" boot option can result in many unexpected consequences. This patch
attempts to prevent boot hangs which have been experienced on T4-4 and T5-8.
Basically the boot loader allocates vmlinuz and initrd higher in available
OBP physical memory. For example, on a 2Tb T5-8 it isn't possible to boot
with mem=20G.
The patch utilizes memblock to avoid reserved regions and trim memory which
is only free. Other improvements are possible for a multi-node machine.
This is a snippet of the boot log with mem=20G on T5-8 with the patch applied:
MEMBLOCK configuration: <- before memory reduction
memory size = 0x1ffad6ce000 reserved size = 0xa1adf44
memory.cnt = 0xb
memory[0x0] [0x00000030400000-0x00003fdde47fff], 0x3fada48000 bytes
memory[0x1] [0x00003fdde4e000-0x00003fdde4ffff], 0x2000 bytes
memory[0x2] [0x00080000000000-0x00083fffffffff], 0x4000000000 bytes
memory[0x3] [0x00100000000000-0x00103fffffffff], 0x4000000000 bytes
memory[0x4] [0x00180000000000-0x00183fffffffff], 0x4000000000 bytes
memory[0x5] [0x00200000000000-0x00203fffffffff], 0x4000000000 bytes
memory[0x6] [0x00280000000000-0x00283fffffffff], 0x4000000000 bytes
memory[0x7] [0x00300000000000-0x00303fffffffff], 0x4000000000 bytes
memory[0x8] [0x00380000000000-0x00383fffc71fff], 0x3fffc72000 bytes
memory[0x9] [0x00383fffc92000-0x00383fffca1fff], 0x10000 bytes
memory[0xa] [0x00383fffcb4000-0x00383fffcb5fff], 0x2000 bytes
reserved.cnt = 0x2
reserved[0x0] [0x00380000000000-0x0038000117e7f8], 0x117e7f9 bytes
reserved[0x1] [0x00380004000000-0x0038000d02f74a], 0x902f74b bytes
...
MEMBLOCK configuration: <- after reduction of memory
memory size = 0x50a1adf44 reserved size = 0xa1adf44
memory.cnt = 0x4
memory[0x0] [0x00380000000000-0x0038000117e7f8], 0x117e7f9 bytes
memory[0x1] [0x00380004000000-0x0038050d01d74a], 0x50901d74b bytes
memory[0x2] [0x00383fffc92000-0x00383fffca1fff], 0x10000 bytes
memory[0x3] [0x00383fffcb4000-0x00383fffcb5fff], 0x2000 bytes
reserved.cnt = 0x2
reserved[0x0] [0x00380000000000-0x0038000117e7f8], 0x117e7f9 bytes
reserved[0x1] [0x00380004000000-0x0038000d02f74a], 0x902f74b bytes
...
Early memory node ranges
node 7: [mem 0x380000000000-0x38000117dfff]
node 7: [mem 0x380004000000-0x380f0d01bfff]
node 7: [mem 0x383fffc92000-0x383fffca1fff]
node 7: [mem 0x383fffcb4000-0x383fffcb5fff]
Could not find start_pfn for node 0
Could not find start_pfn for node 1
Could not find start_pfn for node 2
Could not find start_pfn for node 3
Could not find start_pfn for node 4
Could not find start_pfn for node 5
Could not find start_pfn for node 6
.
The patch was tested on T4-1, T5-8 and Jalap?no.
Cc: sparclinux@vger.kernel.org
Signed-off-by: Bob Picco <bob.picco@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r-- | arch/sparc/mm/init_64.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 3b045058d726..c8bccafea4f3 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -1861,6 +1861,52 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD]; | |||
1861 | static void sun4u_pgprot_init(void); | 1861 | static void sun4u_pgprot_init(void); |
1862 | static void sun4v_pgprot_init(void); | 1862 | static void sun4v_pgprot_init(void); |
1863 | 1863 | ||
1864 | static phys_addr_t __init available_memory(void) | ||
1865 | { | ||
1866 | phys_addr_t available = 0ULL; | ||
1867 | phys_addr_t pa_start, pa_end; | ||
1868 | u64 i; | ||
1869 | |||
1870 | for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL) | ||
1871 | available = available + (pa_end - pa_start); | ||
1872 | |||
1873 | return available; | ||
1874 | } | ||
1875 | |||
1876 | /* We need to exclude reserved regions. This exclusion will include | ||
1877 | * vmlinux and initrd. To be more precise the initrd size could be used to | ||
1878 | * compute a new lower limit because it is freed later during initialization. | ||
1879 | */ | ||
1880 | static void __init reduce_memory(phys_addr_t limit_ram) | ||
1881 | { | ||
1882 | phys_addr_t avail_ram = available_memory(); | ||
1883 | phys_addr_t pa_start, pa_end; | ||
1884 | u64 i; | ||
1885 | |||
1886 | if (limit_ram >= avail_ram) | ||
1887 | return; | ||
1888 | |||
1889 | for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL) { | ||
1890 | phys_addr_t region_size = pa_end - pa_start; | ||
1891 | phys_addr_t clip_start = pa_start; | ||
1892 | |||
1893 | avail_ram = avail_ram - region_size; | ||
1894 | /* Are we consuming too much? */ | ||
1895 | if (avail_ram < limit_ram) { | ||
1896 | phys_addr_t give_back = limit_ram - avail_ram; | ||
1897 | |||
1898 | region_size = region_size - give_back; | ||
1899 | clip_start = clip_start + give_back; | ||
1900 | } | ||
1901 | |||
1902 | memblock_remove(clip_start, region_size); | ||
1903 | |||
1904 | if (avail_ram <= limit_ram) | ||
1905 | break; | ||
1906 | i = 0UL; | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1864 | void __init paging_init(void) | 1910 | void __init paging_init(void) |
1865 | { | 1911 | { |
1866 | unsigned long end_pfn, shift, phys_base; | 1912 | unsigned long end_pfn, shift, phys_base; |
@@ -1940,7 +1986,8 @@ void __init paging_init(void) | |||
1940 | 1986 | ||
1941 | find_ramdisk(phys_base); | 1987 | find_ramdisk(phys_base); |
1942 | 1988 | ||
1943 | memblock_enforce_memory_limit(cmdline_memory_size); | 1989 | if (cmdline_memory_size) |
1990 | reduce_memory(cmdline_memory_size); | ||
1944 | 1991 | ||
1945 | memblock_allow_resize(); | 1992 | memblock_allow_resize(); |
1946 | memblock_dump_all(); | 1993 | memblock_dump_all(); |