diff options
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 103 |
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 | ||
191 | static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; | 191 | static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; |
192 | 192 | ||
193 | static unsigned long __initdata prom_memory_limit; | ||
194 | |||
193 | static unsigned long __initdata alloc_top; | 195 | static unsigned long __initdata alloc_top; |
194 | static unsigned long __initdata alloc_top_high; | 196 | static unsigned long __initdata alloc_top_high; |
195 | static unsigned long __initdata alloc_bottom; | 197 | static 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 | |||
498 | unsigned 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 | |||
523 | unsigned 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, | |||
491 | static void __init early_cmdline_parse(void) | 554 | static 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", |