aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Krill <ben@codiert.org>2009-07-27 18:02:39 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-08-19 20:29:25 -0400
commitcf68787b68a2011664f1670a827c8f202ddb7c3d (patch)
treef9ce6c87b0421920281fee78f7e4ab994e5b8b33
parenta888ad451a96881a7e40f40f717d05f1f3b26ad4 (diff)
powerpc/prom_init: Evaluate mem kernel parameter for early allocation
Evaluate mem kernel parameter for early memory allocations. If mem is set no allocation in the region above the given boundary is allowed. The current code doesn't take care about this and allocate memory above the given mem boundary. Signed-off-by: Benjamin Krill <ben@codiert.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/kernel/prom_init.c103
1 files changed, 101 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index d942404779c1..864334b337a3 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -190,6 +190,8 @@ static int __initdata of_platform;
190 190
191static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; 191static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
192 192
193static unsigned long __initdata prom_memory_limit;
194
193static unsigned long __initdata alloc_top; 195static unsigned long __initdata alloc_top;
194static unsigned long __initdata alloc_top_high; 196static unsigned long __initdata alloc_top_high;
195static unsigned long __initdata alloc_bottom; 197static unsigned long __initdata alloc_bottom;
@@ -484,6 +486,67 @@ static int __init prom_setprop(phandle node, const char *nodename,
484 return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd); 486 return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
485} 487}
486 488
489/* We can't use the standard versions because of RELOC headaches. */
490#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
491 || ('a' <= (c) && (c) <= 'f') \
492 || ('A' <= (c) && (c) <= 'F'))
493
494#define isdigit(c) ('0' <= (c) && (c) <= '9')
495#define islower(c) ('a' <= (c) && (c) <= 'z')
496#define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c))
497
498unsigned long prom_strtoul(const char *cp, const char **endp)
499{
500 unsigned long result = 0, base = 10, value;
501
502 if (*cp == '0') {
503 base = 8;
504 cp++;
505 if (toupper(*cp) == 'X') {
506 cp++;
507 base = 16;
508 }
509 }
510
511 while (isxdigit(*cp) &&
512 (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
513 result = result * base + value;
514 cp++;
515 }
516
517 if (endp)
518 *endp = cp;
519
520 return result;
521}
522
523unsigned long prom_memparse(const char *ptr, const char **retptr)
524{
525 unsigned long ret = prom_strtoul(ptr, retptr);
526 int shift = 0;
527
528 /*
529 * We can't use a switch here because GCC *may* generate a
530 * jump table which won't work, because we're not running at
531 * the address we're linked at.
532 */
533 if ('G' == **retptr || 'g' == **retptr)
534 shift = 30;
535
536 if ('M' == **retptr || 'm' == **retptr)
537 shift = 20;
538
539 if ('K' == **retptr || 'k' == **retptr)
540 shift = 10;
541
542 if (shift) {
543 ret <<= shift;
544 (*retptr)++;
545 }
546
547 return ret;
548}
549
487/* 550/*
488 * Early parsing of the command line passed to the kernel, used for 551 * Early parsing of the command line passed to the kernel, used for
489 * "mem=x" and the options that affect the iommu 552 * "mem=x" and the options that affect the iommu
@@ -491,9 +554,8 @@ static int __init prom_setprop(phandle node, const char *nodename,
491static void __init early_cmdline_parse(void) 554static void __init early_cmdline_parse(void)
492{ 555{
493 struct prom_t *_prom = &RELOC(prom); 556 struct prom_t *_prom = &RELOC(prom);
494#ifdef CONFIG_PPC64
495 const char *opt; 557 const char *opt;
496#endif 558
497 char *p; 559 char *p;
498 int l = 0; 560 int l = 0;
499 561
@@ -521,6 +583,15 @@ static void __init early_cmdline_parse(void)
521 RELOC(prom_iommu_force_on) = 1; 583 RELOC(prom_iommu_force_on) = 1;
522 } 584 }
523#endif 585#endif
586 opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
587 if (opt) {
588 opt += 4;
589 RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
590#ifdef CONFIG_PPC64
591 /* Align to 16 MB == size of ppc64 large page */
592 RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
593#endif
594 }
524} 595}
525 596
526#ifdef CONFIG_PPC_PSERIES 597#ifdef CONFIG_PPC_PSERIES
@@ -1027,6 +1098,29 @@ static void __init prom_init_mem(void)
1027 } 1098 }
1028 1099
1029 /* 1100 /*
1101 * If prom_memory_limit is set we reduce the upper limits *except* for
1102 * alloc_top_high. This must be the real top of RAM so we can put
1103 * TCE's up there.
1104 */
1105
1106 RELOC(alloc_top_high) = RELOC(ram_top);
1107
1108 if (RELOC(prom_memory_limit)) {
1109 if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
1110 prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
1111 RELOC(prom_memory_limit));
1112 RELOC(prom_memory_limit) = 0;
1113 } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
1114 prom_printf("Ignoring mem=%x >= ram_top.\n",
1115 RELOC(prom_memory_limit));
1116 RELOC(prom_memory_limit) = 0;
1117 } else {
1118 RELOC(ram_top) = RELOC(prom_memory_limit);
1119 RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
1120 }
1121 }
1122
1123 /*
1030 * Setup our top alloc point, that is top of RMO or top of 1124 * Setup our top alloc point, that is top of RMO or top of
1031 * segment 0 when running non-LPAR. 1125 * segment 0 when running non-LPAR.
1032 * Some RS64 machines have buggy firmware where claims up at 1126 * Some RS64 machines have buggy firmware where claims up at
@@ -1041,6 +1135,7 @@ static void __init prom_init_mem(void)
1041 RELOC(alloc_top_high) = RELOC(ram_top); 1135 RELOC(alloc_top_high) = RELOC(ram_top);
1042 1136
1043 prom_printf("memory layout at init:\n"); 1137 prom_printf("memory layout at init:\n");
1138 prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
1044 prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); 1139 prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
1045 prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); 1140 prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
1046 prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); 1141 prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
@@ -2395,6 +2490,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2395 /* 2490 /*
2396 * Fill in some infos for use by the kernel later on 2491 * Fill in some infos for use by the kernel later on
2397 */ 2492 */
2493 if (RELOC(prom_memory_limit))
2494 prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
2495 &RELOC(prom_memory_limit),
2496 sizeof(prom_memory_limit));
2398#ifdef CONFIG_PPC64 2497#ifdef CONFIG_PPC64
2399 if (RELOC(prom_iommu_off)) 2498 if (RELOC(prom_iommu_off))
2400 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", 2499 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",