aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c5
-rw-r--r--arch/powerpc/kernel/prom.c89
-rw-r--r--arch/powerpc/kernel/prom_init.c55
-rw-r--r--arch/powerpc/kernel/setup_64.c3
-rw-r--r--arch/powerpc/mm/lmb.c43
-rw-r--r--arch/powerpc/platforms/iseries/setup.c22
-rw-r--r--include/asm-powerpc/kexec.h13
7 files changed, 100 insertions, 130 deletions
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index ee166c586642..1ccb188ba40d 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -339,3 +339,8 @@ void __init kexec_setup(void)
339{ 339{
340 export_htab_values(); 340 export_htab_values();
341} 341}
342
343int overlaps_crashkernel(unsigned long start, unsigned long size)
344{
345 return (start + size) > crashk_res.start && start <= crashk_res.end;
346}
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 4ca608c9cd72..a04f726d3bab 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -50,6 +50,7 @@
50#include <asm/machdep.h> 50#include <asm/machdep.h>
51#include <asm/pSeries_reconfig.h> 51#include <asm/pSeries_reconfig.h>
52#include <asm/pci-bridge.h> 52#include <asm/pci-bridge.h>
53#include <asm/kexec.h>
53 54
54#ifdef DEBUG 55#ifdef DEBUG
55#define DBG(fmt...) printk(KERN_ERR fmt) 56#define DBG(fmt...) printk(KERN_ERR fmt)
@@ -836,6 +837,42 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
836 return mem; 837 return mem;
837} 838}
838 839
840static int __init early_parse_mem(char *p)
841{
842 if (!p)
843 return 1;
844
845 memory_limit = PAGE_ALIGN(memparse(p, &p));
846 DBG("memory limit = 0x%lx\n", memory_limit);
847
848 return 0;
849}
850early_param("mem", early_parse_mem);
851
852/*
853 * The device tree may be allocated below our memory limit, or inside the
854 * crash kernel region for kdump. If so, move it out now.
855 */
856static void move_device_tree(void)
857{
858 unsigned long start, size;
859 void *p;
860
861 DBG("-> move_device_tree\n");
862
863 start = __pa(initial_boot_params);
864 size = initial_boot_params->totalsize;
865
866 if ((memory_limit && (start + size) > memory_limit) ||
867 overlaps_crashkernel(start, size)) {
868 p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size));
869 memcpy(p, initial_boot_params, size);
870 initial_boot_params = (struct boot_param_header *)p;
871 DBG("Moved device tree to 0x%p\n", p);
872 }
873
874 DBG("<- move_device_tree\n");
875}
839 876
840/** 877/**
841 * unflattens the device-tree passed by the firmware, creating the 878 * unflattens the device-tree passed by the firmware, creating the
@@ -1070,6 +1107,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
1070 iommu_force_on = 1; 1107 iommu_force_on = 1;
1071#endif 1108#endif
1072 1109
1110 /* mem=x on the command line is the preferred mechanism */
1073 lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); 1111 lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
1074 if (lprop) 1112 if (lprop)
1075 memory_limit = *lprop; 1113 memory_limit = *lprop;
@@ -1123,17 +1161,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
1123 1161
1124 DBG("Command line is: %s\n", cmd_line); 1162 DBG("Command line is: %s\n", cmd_line);
1125 1163
1126 if (strstr(cmd_line, "mem=")) {
1127 char *p, *q;
1128
1129 for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
1130 q = p + 4;
1131 if (p > cmd_line && p[-1] != ' ')
1132 continue;
1133 memory_limit = memparse(q, &q);
1134 }
1135 }
1136
1137 /* break now */ 1164 /* break now */
1138 return 1; 1165 return 1;
1139} 1166}
@@ -1297,11 +1324,6 @@ void __init early_init_devtree(void *params)
1297 strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); 1324 strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
1298 parse_early_param(); 1325 parse_early_param();
1299 1326
1300 lmb_enforce_memory_limit(memory_limit);
1301 lmb_analyze();
1302
1303 DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
1304
1305 /* Reserve LMB regions used by kernel, initrd, dt, etc... */ 1327 /* Reserve LMB regions used by kernel, initrd, dt, etc... */
1306 lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); 1328 lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
1307#ifdef CONFIG_CRASH_DUMP 1329#ifdef CONFIG_CRASH_DUMP
@@ -1309,6 +1331,15 @@ void __init early_init_devtree(void *params)
1309#endif 1331#endif
1310 early_reserve_mem(); 1332 early_reserve_mem();
1311 1333
1334 lmb_enforce_memory_limit(memory_limit);
1335 lmb_analyze();
1336
1337 DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
1338
1339 /* We may need to relocate the flat tree, do it now.
1340 * FIXME .. and the initrd too? */
1341 move_device_tree();
1342
1312 DBG("Scanning CPUs ...\n"); 1343 DBG("Scanning CPUs ...\n");
1313 1344
1314 /* Retreive CPU related informations from the flat tree 1345 /* Retreive CPU related informations from the flat tree
@@ -2058,29 +2089,3 @@ int prom_update_property(struct device_node *np,
2058 return 0; 2089 return 0;
2059} 2090}
2060 2091
2061#ifdef CONFIG_KEXEC
2062/* We may have allocated the flat device tree inside the crash kernel region
2063 * in prom_init. If so we need to move it out into regular memory. */
2064void kdump_move_device_tree(void)
2065{
2066 unsigned long start, end;
2067 struct boot_param_header *new;
2068
2069 start = __pa((unsigned long)initial_boot_params);
2070 end = start + initial_boot_params->totalsize;
2071
2072 if (end < crashk_res.start || start > crashk_res.end)
2073 return;
2074
2075 new = (struct boot_param_header*)
2076 __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE));
2077
2078 memcpy(new, initial_boot_params, initial_boot_params->totalsize);
2079
2080 initial_boot_params = new;
2081
2082 DBG("Flat device tree blob moved to %p\n", initial_boot_params);
2083
2084 /* XXX should we unreserve the old DT? */
2085}
2086#endif /* CONFIG_KEXEC */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 078fb5533541..a52377c68fc6 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -194,8 +194,6 @@ static int __initdata of_platform;
194 194
195static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; 195static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
196 196
197static unsigned long __initdata prom_memory_limit;
198
199static unsigned long __initdata alloc_top; 197static unsigned long __initdata alloc_top;
200static unsigned long __initdata alloc_top_high; 198static unsigned long __initdata alloc_top_high;
201static unsigned long __initdata alloc_bottom; 199static unsigned long __initdata alloc_bottom;
@@ -594,16 +592,6 @@ static void __init early_cmdline_parse(void)
594 } 592 }
595#endif 593#endif
596 594
597 opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
598 if (opt) {
599 opt += 4;
600 RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
601#ifdef CONFIG_PPC64
602 /* Align to 16 MB == size of ppc64 large page */
603 RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
604#endif
605 }
606
607#ifdef CONFIG_KEXEC 595#ifdef CONFIG_KEXEC
608 /* 596 /*
609 * crashkernel=size@addr specifies the location to reserve for 597 * crashkernel=size@addr specifies the location to reserve for
@@ -1115,29 +1103,6 @@ static void __init prom_init_mem(void)
1115 } 1103 }
1116 1104
1117 /* 1105 /*
1118 * If prom_memory_limit is set we reduce the upper limits *except* for
1119 * alloc_top_high. This must be the real top of RAM so we can put
1120 * TCE's up there.
1121 */
1122
1123 RELOC(alloc_top_high) = RELOC(ram_top);
1124
1125 if (RELOC(prom_memory_limit)) {
1126 if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
1127 prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
1128 RELOC(prom_memory_limit));
1129 RELOC(prom_memory_limit) = 0;
1130 } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
1131 prom_printf("Ignoring mem=%x >= ram_top.\n",
1132 RELOC(prom_memory_limit));
1133 RELOC(prom_memory_limit) = 0;
1134 } else {
1135 RELOC(ram_top) = RELOC(prom_memory_limit);
1136 RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
1137 }
1138 }
1139
1140 /*
1141 * Setup our top alloc point, that is top of RMO or top of 1106 * Setup our top alloc point, that is top of RMO or top of
1142 * segment 0 when running non-LPAR. 1107 * segment 0 when running non-LPAR.
1143 * Some RS64 machines have buggy firmware where claims up at 1108 * Some RS64 machines have buggy firmware where claims up at
@@ -1149,9 +1114,9 @@ static void __init prom_init_mem(void)
1149 RELOC(rmo_top) = RELOC(ram_top); 1114 RELOC(rmo_top) = RELOC(ram_top);
1150 RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top)); 1115 RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
1151 RELOC(alloc_top) = RELOC(rmo_top); 1116 RELOC(alloc_top) = RELOC(rmo_top);
1117 RELOC(alloc_top_high) = RELOC(ram_top);
1152 1118
1153 prom_printf("memory layout at init:\n"); 1119 prom_printf("memory layout at init:\n");
1154 prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
1155 prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); 1120 prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
1156 prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); 1121 prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
1157 prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); 1122 prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
@@ -1348,16 +1313,10 @@ static void __init prom_initialize_tce_table(void)
1348 1313
1349 reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); 1314 reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
1350 1315
1351 if (RELOC(prom_memory_limit)) { 1316 /* These are only really needed if there is a memory limit in
1352 /* 1317 * effect, but we don't know so export them always. */
1353 * We align the start to a 16MB boundary so we can map 1318 RELOC(prom_tce_alloc_start) = local_alloc_bottom;
1354 * the TCE area using large pages if possible. 1319 RELOC(prom_tce_alloc_end) = local_alloc_top;
1355 * The end should be the top of RAM so no need to align it.
1356 */
1357 RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom,
1358 0x1000000);
1359 RELOC(prom_tce_alloc_end) = local_alloc_top;
1360 }
1361 1320
1362 /* Flag the first invalid entry */ 1321 /* Flag the first invalid entry */
1363 prom_debug("ending prom_initialize_tce_table\n"); 1322 prom_debug("ending prom_initialize_tce_table\n");
@@ -2265,10 +2224,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2265 /* 2224 /*
2266 * Fill in some infos for use by the kernel later on 2225 * Fill in some infos for use by the kernel later on
2267 */ 2226 */
2268 if (RELOC(prom_memory_limit))
2269 prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
2270 &RELOC(prom_memory_limit),
2271 sizeof(prom_memory_limit));
2272#ifdef CONFIG_PPC64 2227#ifdef CONFIG_PPC64
2273 if (RELOC(ppc64_iommu_off)) 2228 if (RELOC(ppc64_iommu_off))
2274 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", 2229 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 6224624c3d38..59773d9044ba 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -347,9 +347,6 @@ void __init setup_system(void)
347{ 347{
348 DBG(" -> setup_system()\n"); 348 DBG(" -> setup_system()\n");
349 349
350#ifdef CONFIG_KEXEC
351 kdump_move_device_tree();
352#endif
353 /* 350 /*
354 * Unflatten the device-tree passed by prom_init or kexec 351 * Unflatten the device-tree passed by prom_init or kexec
355 */ 352 */
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c
index 417d58518558..8b6f522655a6 100644
--- a/arch/powerpc/mm/lmb.c
+++ b/arch/powerpc/mm/lmb.c
@@ -89,20 +89,25 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn,
89 return lmb_addrs_adjacent(base1, size1, base2, size2); 89 return lmb_addrs_adjacent(base1, size1, base2, size2);
90} 90}
91 91
92/* Assumption: base addr of region 1 < base addr of region 2 */ 92static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
93static void __init lmb_coalesce_regions(struct lmb_region *rgn,
94 unsigned long r1, unsigned long r2)
95{ 93{
96 unsigned long i; 94 unsigned long i;
97 95
98 rgn->region[r1].size += rgn->region[r2].size; 96 for (i = r; i < rgn->cnt - 1; i++) {
99 for (i=r2; i < rgn->cnt-1; i++) { 97 rgn->region[i].base = rgn->region[i + 1].base;
100 rgn->region[i].base = rgn->region[i+1].base; 98 rgn->region[i].size = rgn->region[i + 1].size;
101 rgn->region[i].size = rgn->region[i+1].size;
102 } 99 }
103 rgn->cnt--; 100 rgn->cnt--;
104} 101}
105 102
103/* Assumption: base addr of region 1 < base addr of region 2 */
104static void __init lmb_coalesce_regions(struct lmb_region *rgn,
105 unsigned long r1, unsigned long r2)
106{
107 rgn->region[r1].size += rgn->region[r2].size;
108 lmb_remove_region(rgn, r2);
109}
110
106/* This routine called with relocation disabled. */ 111/* This routine called with relocation disabled. */
107void __init lmb_init(void) 112void __init lmb_init(void)
108{ 113{
@@ -294,17 +299,16 @@ unsigned long __init lmb_end_of_DRAM(void)
294 return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); 299 return (lmb.memory.region[idx].base + lmb.memory.region[idx].size);
295} 300}
296 301
297/* 302/* You must call lmb_analyze() after this. */
298 * Truncate the lmb list to memory_limit if it's set
299 * You must call lmb_analyze() after this.
300 */
301void __init lmb_enforce_memory_limit(unsigned long memory_limit) 303void __init lmb_enforce_memory_limit(unsigned long memory_limit)
302{ 304{
303 unsigned long i, limit; 305 unsigned long i, limit;
306 struct lmb_property *p;
304 307
305 if (! memory_limit) 308 if (! memory_limit)
306 return; 309 return;
307 310
311 /* Truncate the lmb regions to satisfy the memory limit. */
308 limit = memory_limit; 312 limit = memory_limit;
309 for (i = 0; i < lmb.memory.cnt; i++) { 313 for (i = 0; i < lmb.memory.cnt; i++) {
310 if (limit > lmb.memory.region[i].size) { 314 if (limit > lmb.memory.region[i].size) {
@@ -316,4 +320,21 @@ void __init lmb_enforce_memory_limit(unsigned long memory_limit)
316 lmb.memory.cnt = i + 1; 320 lmb.memory.cnt = i + 1;
317 break; 321 break;
318 } 322 }
323
324 lmb.rmo_size = lmb.memory.region[0].size;
325
326 /* And truncate any reserves above the limit also. */
327 for (i = 0; i < lmb.reserved.cnt; i++) {
328 p = &lmb.reserved.region[i];
329
330 if (p->base > memory_limit)
331 p->size = 0;
332 else if ((p->base + p->size) > memory_limit)
333 p->size = memory_limit - p->base;
334
335 if (p->size == 0) {
336 lmb_remove_region(&lmb.reserved, i);
337 i--;
338 }
339 }
319} 340}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 074d1d949708..fd6d0ebe8ddd 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -90,8 +90,6 @@ extern unsigned long embedded_sysmap_end;
90extern unsigned long iSeries_recal_tb; 90extern unsigned long iSeries_recal_tb;
91extern unsigned long iSeries_recal_titan; 91extern unsigned long iSeries_recal_titan;
92 92
93static unsigned long cmd_mem_limit;
94
95struct MemoryBlock { 93struct MemoryBlock {
96 unsigned long absStart; 94 unsigned long absStart;
97 unsigned long absEnd; 95 unsigned long absEnd;
@@ -1026,8 +1024,6 @@ void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
1026 /* /chosen */ 1024 /* /chosen */
1027 dt_start_node(dt, "chosen"); 1025 dt_start_node(dt, "chosen");
1028 dt_prop_str(dt, "bootargs", cmd_line); 1026 dt_prop_str(dt, "bootargs", cmd_line);
1029 if (cmd_mem_limit)
1030 dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit);
1031 dt_end_node(dt); 1027 dt_end_node(dt);
1032 1028
1033 dt_cpus(dt); 1029 dt_cpus(dt);
@@ -1053,29 +1049,11 @@ void * __init iSeries_early_setup(void)
1053 1049
1054 iSeries_get_cmdline(); 1050 iSeries_get_cmdline();
1055 1051
1056 /* Save unparsed command line copy for /proc/cmdline */
1057 strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
1058
1059 /* Parse early parameters, in particular mem=x */
1060 parse_early_param();
1061
1062 build_flat_dt(&iseries_dt, phys_mem_size); 1052 build_flat_dt(&iseries_dt, phys_mem_size);
1063 1053
1064 return (void *) __pa(&iseries_dt); 1054 return (void *) __pa(&iseries_dt);
1065} 1055}
1066 1056
1067/*
1068 * On iSeries we just parse the mem=X option from the command line.
1069 * On pSeries it's a bit more complicated, see prom_init_mem()
1070 */
1071static int __init early_parsemem(char *p)
1072{
1073 if (p)
1074 cmd_mem_limit = ALIGN(memparse(p, &p), PAGE_SIZE);
1075 return 0;
1076}
1077early_param("mem", early_parsemem);
1078
1079static void hvputc(char c) 1057static void hvputc(char c)
1080{ 1058{
1081 if (c == '\n') 1059 if (c == '\n')
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 6a2af2f6853b..0a1afced173f 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -31,9 +31,10 @@
31#define KEXEC_ARCH KEXEC_ARCH_PPC 31#define KEXEC_ARCH KEXEC_ARCH_PPC
32#endif 32#endif
33 33
34#ifndef __ASSEMBLY__
35
34#ifdef CONFIG_KEXEC 36#ifdef CONFIG_KEXEC
35 37
36#ifndef __ASSEMBLY__
37#ifdef __powerpc64__ 38#ifdef __powerpc64__
38/* 39/*
39 * This function is responsible for capturing register states if coming 40 * This function is responsible for capturing register states if coming
@@ -123,8 +124,16 @@ extern int default_machine_kexec_prepare(struct kimage *image);
123extern void default_machine_crash_shutdown(struct pt_regs *regs); 124extern void default_machine_crash_shutdown(struct pt_regs *regs);
124 125
125extern void machine_kexec_simple(struct kimage *image); 126extern void machine_kexec_simple(struct kimage *image);
127extern int overlaps_crashkernel(unsigned long start, unsigned long size);
128
129#else /* !CONFIG_KEXEC */
130
131static inline int overlaps_crashkernel(unsigned long start, unsigned long size)
132{
133 return 0;
134}
126 135
127#endif /* ! __ASSEMBLY__ */
128#endif /* CONFIG_KEXEC */ 136#endif /* CONFIG_KEXEC */
137#endif /* ! __ASSEMBLY__ */
129#endif /* __KERNEL__ */ 138#endif /* __KERNEL__ */
130#endif /* _ASM_POWERPC_KEXEC_H */ 139#endif /* _ASM_POWERPC_KEXEC_H */