X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fkernel%2Fprom_init.c;h=2e9c95386efa29ae05985c5c8a7ba30a796d3dd2;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=59465e56811af49f308febc34dd3377dc00c69f6;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 59465e568..2e9c95386 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -16,6 +16,7 @@ #undef DEBUG_PROM #include +#include #include #include #include @@ -193,12 +194,19 @@ static int __initdata of_platform; 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_high; static unsigned long __initdata alloc_bottom; static unsigned long __initdata rmo_top; static unsigned long __initdata ram_top; +#ifdef CONFIG_KEXEC +static unsigned long __initdata prom_crashk_base; +static unsigned long __initdata prom_crashk_size; +#endif + static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; static int __initdata mem_reserve_cnt; @@ -557,9 +565,7 @@ unsigned long prom_memparse(const char *ptr, const char **retptr) static void __init early_cmdline_parse(void) { struct prom_t *_prom = &RELOC(prom); -#ifdef CONFIG_PPC64 const char *opt; -#endif char *p; int l = 0; @@ -568,7 +574,7 @@ static void __init early_cmdline_parse(void) if ((long)_prom->chosen > 0) l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); #ifdef CONFIG_CMDLINE - if (l <= 0 || p[0] == '\0') /* dbl check */ + if (l == 0) /* dbl check */ strlcpy(RELOC(prom_cmd_line), RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); #endif /* CONFIG_CMDLINE */ @@ -587,6 +593,45 @@ static void __init early_cmdline_parse(void) RELOC(iommu_force_on) = 1; } #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_KEXEC + /* + * crashkernel=size@addr specifies the location to reserve for + * crash kernel. + */ + opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel=")); + if (opt) { + opt += 12; + RELOC(prom_crashk_size) = + prom_memparse(opt, (const char **)&opt); + + if (ALIGN(RELOC(prom_crashk_size), 0x1000000) != + RELOC(prom_crashk_size)) { + prom_printf("Warning: crashkernel size is not " + "aligned to 16MB\n"); + } + + /* + * At present, the crash kernel always run at 32MB. + * Just ignore whatever user passed. + */ + RELOC(prom_crashk_base) = 0x2000000; + if (*opt == '@') { + prom_printf("Warning: PPC64 kdump kernel always runs " + "at 32 MB\n"); + } + } +#endif } #ifdef CONFIG_PPC_PSERIES @@ -646,13 +691,13 @@ static unsigned char ibm_architecture_vec[] = { 5 - 1, /* 5 option vectors */ /* option vector 1: processor architectures supported */ - 3 - 2, /* length */ + 3 - 1, /* length */ 0, /* don't ignore, don't halt */ OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | OV1_PPC_2_04 | OV1_PPC_2_05, /* option vector 2: Open Firmware options supported */ - 34 - 2, /* length */ + 34 - 1, /* length */ OV2_REAL_MODE, 0, 0, W(0xffffffff), /* real_base */ @@ -666,16 +711,16 @@ static unsigned char ibm_architecture_vec[] = { 48, /* max log_2(hash table size) */ /* option vector 3: processor options supported */ - 3 - 2, /* length */ + 3 - 1, /* length */ 0, /* don't ignore, don't halt */ OV3_FP | OV3_VMX, /* option vector 4: IBM PAPR implementation */ - 2 - 2, /* length */ + 2 - 1, /* length */ 0, /* don't halt */ /* option vector 5: PAPR/OF options */ - 3 - 2, /* length */ + 3 - 1, /* length */ 0, /* don't ignore, don't halt */ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES, }; @@ -989,7 +1034,7 @@ static void reserve_mem(u64 base, u64 size) } /* - * Initialize memory allocation mechanism, parse "memory" nodes and + * Initialize memory allocation mecanism, parse "memory" nodes and * obtain that way the top of memory and RMO to setup out local allocator */ static void __init prom_init_mem(void) @@ -1070,6 +1115,29 @@ static void __init prom_init_mem(void) 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 * segment 0 when running non-LPAR. @@ -1082,14 +1150,20 @@ static void __init prom_init_mem(void) RELOC(rmo_top) = RELOC(ram_top); RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top)); RELOC(alloc_top) = RELOC(rmo_top); - RELOC(alloc_top_high) = RELOC(ram_top); 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_top : %x\n", RELOC(alloc_top)); prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); prom_printf(" ram_top : %x\n", RELOC(ram_top)); +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) { + prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base)); + prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size)); + } +#endif } @@ -1275,10 +1349,16 @@ static void __init prom_initialize_tce_table(void) reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); - /* These are only really needed if there is a memory limit in - * effect, but we don't know so export them always. */ - RELOC(prom_tce_alloc_start) = local_alloc_bottom; - RELOC(prom_tce_alloc_end) = local_alloc_top; + if (RELOC(prom_memory_limit)) { + /* + * We align the start to a 16MB boundary so we can map + * the TCE area using large pages if possible. + * The end should be the top of RAM so no need to align it. + */ + RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, + 0x1000000); + RELOC(prom_tce_alloc_end) = local_alloc_top; + } /* Flag the first invalid entry */ prom_debug("ending prom_initialize_tce_table\n"); @@ -1961,7 +2041,11 @@ static void __init flatten_device_tree(void) /* Version 16 is not backward compatible */ hdr->last_comp_version = 0x10; - /* Copy the reserve map in */ + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + reserve_mem(RELOC(dt_header_start), hdr->totalsize); memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); #ifdef DEBUG_PROM @@ -1974,9 +2058,6 @@ static void __init flatten_device_tree(void) RELOC(mem_reserve_map)[i].size); } #endif - /* Bump mem_reserve_cnt to cause further reservations to fail - * since it's too late. - */ RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; prom_printf("Device tree strings 0x%x -> 0x%x\n", @@ -1992,22 +2073,12 @@ static void __init flatten_device_tree(void) static void __init fixup_device_tree_maple(void) { phandle isa; - u32 rloc = 0x01002000; /* IO space; PCI device = 4 */ u32 isa_ranges[6]; - char *name; - - name = "/ht@0/isa@4"; - isa = call_prom("finddevice", 1, 1, ADDR(name)); - if (!PHANDLE_VALID(isa)) { - name = "/ht@0/isa@6"; - isa = call_prom("finddevice", 1, 1, ADDR(name)); - rloc = 0x01003000; /* IO space; PCI device = 6 */ - } + + isa = call_prom("finddevice", 1, 1, ADDR("/ht@0/isa@4")); if (!PHANDLE_VALID(isa)) return; - if (prom_getproplen(isa, "ranges") != 12) - return; if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges)) == PROM_ERROR) return; @@ -2017,54 +2088,21 @@ static void __init fixup_device_tree_maple(void) isa_ranges[2] != 0x00010000) return; - prom_printf("Fixing up bogus ISA range on Maple/Apache...\n"); + prom_printf("fixing up bogus ISA range on Maple...\n"); isa_ranges[0] = 0x1; isa_ranges[1] = 0x0; - isa_ranges[2] = rloc; + isa_ranges[2] = 0x01002000; /* IO space; PCI device = 4 */ isa_ranges[3] = 0x0; isa_ranges[4] = 0x0; isa_ranges[5] = 0x00010000; - prom_setprop(isa, name, "ranges", + prom_setprop(isa, "/ht@0/isa@4", "ranges", isa_ranges, sizeof(isa_ranges)); } #else #define fixup_device_tree_maple() #endif -#ifdef CONFIG_PPC_CHRP -/* Pegasos lacks the "ranges" property in the isa node */ -static void __init fixup_device_tree_chrp(void) -{ - phandle isa; - u32 isa_ranges[6]; - char *name; - int rc; - - name = "/pci@80000000/isa@c"; - isa = call_prom("finddevice", 1, 1, ADDR(name)); - if (!PHANDLE_VALID(isa)) - return; - - rc = prom_getproplen(isa, "ranges"); - if (rc != 0 && rc != PROM_ERROR) - return; - - prom_printf("Fixing up missing ISA range on Pegasos...\n"); - - isa_ranges[0] = 0x1; - isa_ranges[1] = 0x0; - isa_ranges[2] = 0x01006000; - isa_ranges[3] = 0x0; - isa_ranges[4] = 0x0; - isa_ranges[5] = 0x00010000; - prom_setprop(isa, name, "ranges", - isa_ranges, sizeof(isa_ranges)); -} -#else -#define fixup_device_tree_chrp() -#endif - #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC) static void __init fixup_device_tree_pmac(void) { @@ -2112,7 +2150,6 @@ static void __init fixup_device_tree_pmac(void) static void __init fixup_device_tree(void) { fixup_device_tree_maple(); - fixup_device_tree_chrp(); fixup_device_tree_pmac(); } @@ -2243,6 +2280,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_init_mem(); +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) + reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size)); +#endif /* * Determine which cpu is actually running right _now_ */ @@ -2276,6 +2317,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* * 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 if (RELOC(ppc64_iommu_off)) prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", @@ -2295,6 +2340,16 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, } #endif +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) { + prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base", + PTRRELOC(&prom_crashk_base), + sizeof(RELOC(prom_crashk_base))); + prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size", + PTRRELOC(&prom_crashk_size), + sizeof(RELOC(prom_crashk_size))); + } +#endif /* * Fixup any known bugs in the device-tree */