|
@@ -190,6 +190,8 @@ static int __initdata of_platform;
|
|
|
|
|
|
static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
|
|
static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
|
|
|
|
|
|
|
|
+static unsigned long __initdata prom_memory_limit;
|
|
|
|
+
|
|
static unsigned long __initdata alloc_top;
|
|
static unsigned long __initdata alloc_top;
|
|
static unsigned long __initdata alloc_top_high;
|
|
static unsigned long __initdata alloc_top_high;
|
|
static unsigned long __initdata alloc_bottom;
|
|
static unsigned long __initdata alloc_bottom;
|
|
@@ -484,6 +486,67 @@ static int __init prom_setprop(phandle node, const char *nodename,
|
|
return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
|
|
return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* We can't use the standard versions because of RELOC headaches. */
|
|
|
|
+#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|
|
|
|
+ || ('a' <= (c) && (c) <= 'f') \
|
|
|
|
+ || ('A' <= (c) && (c) <= 'F'))
|
|
|
|
+
|
|
|
|
+#define isdigit(c) ('0' <= (c) && (c) <= '9')
|
|
|
|
+#define islower(c) ('a' <= (c) && (c) <= 'z')
|
|
|
|
+#define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c))
|
|
|
|
+
|
|
|
|
+unsigned long prom_strtoul(const char *cp, const char **endp)
|
|
|
|
+{
|
|
|
|
+ unsigned long result = 0, base = 10, value;
|
|
|
|
+
|
|
|
|
+ if (*cp == '0') {
|
|
|
|
+ base = 8;
|
|
|
|
+ cp++;
|
|
|
|
+ if (toupper(*cp) == 'X') {
|
|
|
|
+ cp++;
|
|
|
|
+ base = 16;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (isxdigit(*cp) &&
|
|
|
|
+ (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
|
|
|
|
+ result = result * base + value;
|
|
|
|
+ cp++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (endp)
|
|
|
|
+ *endp = cp;
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+unsigned long prom_memparse(const char *ptr, const char **retptr)
|
|
|
|
+{
|
|
|
|
+ unsigned long ret = prom_strtoul(ptr, retptr);
|
|
|
|
+ int shift = 0;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We can't use a switch here because GCC *may* generate a
|
|
|
|
+ * jump table which won't work, because we're not running at
|
|
|
|
+ * the address we're linked at.
|
|
|
|
+ */
|
|
|
|
+ if ('G' == **retptr || 'g' == **retptr)
|
|
|
|
+ shift = 30;
|
|
|
|
+
|
|
|
|
+ if ('M' == **retptr || 'm' == **retptr)
|
|
|
|
+ shift = 20;
|
|
|
|
+
|
|
|
|
+ if ('K' == **retptr || 'k' == **retptr)
|
|
|
|
+ shift = 10;
|
|
|
|
+
|
|
|
|
+ if (shift) {
|
|
|
|
+ ret <<= shift;
|
|
|
|
+ (*retptr)++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Early parsing of the command line passed to the kernel, used for
|
|
* Early parsing of the command line passed to the kernel, used for
|
|
* "mem=x" and the options that affect the iommu
|
|
* "mem=x" and the options that affect the iommu
|
|
@@ -491,9 +554,8 @@ static int __init prom_setprop(phandle node, const char *nodename,
|
|
static void __init early_cmdline_parse(void)
|
|
static void __init early_cmdline_parse(void)
|
|
{
|
|
{
|
|
struct prom_t *_prom = &RELOC(prom);
|
|
struct prom_t *_prom = &RELOC(prom);
|
|
-#ifdef CONFIG_PPC64
|
|
|
|
const char *opt;
|
|
const char *opt;
|
|
-#endif
|
|
|
|
|
|
+
|
|
char *p;
|
|
char *p;
|
|
int l = 0;
|
|
int l = 0;
|
|
|
|
|
|
@@ -521,6 +583,15 @@ static void __init early_cmdline_parse(void)
|
|
RELOC(prom_iommu_force_on) = 1;
|
|
RELOC(prom_iommu_force_on) = 1;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
+ opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
|
|
|
|
+ if (opt) {
|
|
|
|
+ opt += 4;
|
|
|
|
+ RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
|
|
|
|
+#ifdef CONFIG_PPC64
|
|
|
|
+ /* Align to 16 MB == size of ppc64 large page */
|
|
|
|
+ RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PPC_PSERIES
|
|
#ifdef CONFIG_PPC_PSERIES
|
|
@@ -1026,6 +1097,29 @@ static void __init prom_init_mem(void)
|
|
RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
|
|
RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If prom_memory_limit is set we reduce the upper limits *except* for
|
|
|
|
+ * alloc_top_high. This must be the real top of RAM so we can put
|
|
|
|
+ * TCE's up there.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ RELOC(alloc_top_high) = RELOC(ram_top);
|
|
|
|
+
|
|
|
|
+ if (RELOC(prom_memory_limit)) {
|
|
|
|
+ if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
|
|
|
|
+ prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
|
|
|
|
+ RELOC(prom_memory_limit));
|
|
|
|
+ RELOC(prom_memory_limit) = 0;
|
|
|
|
+ } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
|
|
|
|
+ prom_printf("Ignoring mem=%x >= ram_top.\n",
|
|
|
|
+ RELOC(prom_memory_limit));
|
|
|
|
+ RELOC(prom_memory_limit) = 0;
|
|
|
|
+ } else {
|
|
|
|
+ RELOC(ram_top) = RELOC(prom_memory_limit);
|
|
|
|
+ RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Setup our top alloc point, that is top of RMO or top of
|
|
* Setup our top alloc point, that is top of RMO or top of
|
|
* segment 0 when running non-LPAR.
|
|
* segment 0 when running non-LPAR.
|
|
@@ -1041,6 +1135,7 @@ static void __init prom_init_mem(void)
|
|
RELOC(alloc_top_high) = RELOC(ram_top);
|
|
RELOC(alloc_top_high) = RELOC(ram_top);
|
|
|
|
|
|
prom_printf("memory layout at init:\n");
|
|
prom_printf("memory layout at init:\n");
|
|
|
|
+ prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
|
|
prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
|
|
prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
|
|
prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
|
|
prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
|
|
prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
|
|
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,
|
|
/*
|
|
/*
|
|
* Fill in some infos for use by the kernel later on
|
|
* Fill in some infos for use by the kernel later on
|
|
*/
|
|
*/
|
|
|
|
+ if (RELOC(prom_memory_limit))
|
|
|
|
+ prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
|
|
|
|
+ &RELOC(prom_memory_limit),
|
|
|
|
+ sizeof(prom_memory_limit));
|
|
#ifdef CONFIG_PPC64
|
|
#ifdef CONFIG_PPC64
|
|
if (RELOC(prom_iommu_off))
|
|
if (RELOC(prom_iommu_off))
|
|
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
|
|
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
|