aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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",