diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r-- | arch/powerpc/kernel/prom.c | 94 |
1 files changed, 86 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index aac889074292..877fad9b3745 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -84,6 +84,33 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); +/** + * move_device_tree - move tree to an unused area, if needed. + * + * The device tree may be allocated beyond our memory limit, or inside the + * crash kernel region for kdump. If so, move it out of the way. + */ +static void __init move_device_tree(void) +{ + unsigned long start, size; + void *p; + + DBG("-> move_device_tree\n"); + + start = __pa(initial_boot_params); + size = initial_boot_params->totalsize; + + if ((memory_limit && (start + size) > memory_limit) || + overlaps_crashkernel(start, size)) { + p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size)); + memcpy(p, initial_boot_params, size); + initial_boot_params = (struct boot_param_header *)p; + DBG("Moved device tree to 0x%p\n", p); + } + + DBG("<- move_device_tree\n"); +} + /* * ibm,pa-features is a per-cpu property that contains a string of * attribute descriptors, each of which has a 2 byte header plus up @@ -240,8 +267,9 @@ static void __init check_cpu_feature_properties(unsigned long node) } } -int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, - int depth, void *data) +static int __init early_init_dt_scan_cpus(unsigned long node, + const char *uname, int depth, + void *data) { static int logical_cpuid = 0; char *type = of_get_flat_dt_prop(node, "device_type", NULL); @@ -455,8 +483,8 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node) #define early_init_dt_scan_drconf_memory(node) 0 #endif /* CONFIG_PPC_PSERIES */ -int __init early_init_dt_scan_memory(unsigned long node, const char *uname, - int depth, void *data) +static int __init early_init_dt_scan_memory(unsigned long node, + const char *uname, int depth, void *data) { char *type = of_get_flat_dt_prop(node, "device_type", NULL); __be32 *reg, *endp; @@ -515,7 +543,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, return 0; } -void __init early_reserve_mem(void) +static void __init early_reserve_mem(void) { u64 base, size; u64 *reserve_map; @@ -607,7 +635,7 @@ static inline unsigned long phyp_dump_calculate_reserve_size(void) * without reserving anything. The memory in case of dump being * active is freed when the dump is collected (by userland tools). */ -void __init phyp_dump_reserve_mem(void) +static void __init phyp_dump_reserve_mem(void) { unsigned long base, size; unsigned long variable_reserve_size; @@ -646,13 +674,44 @@ void __init phyp_dump_reserve_mem(void) } } #else -inline void __init phyp_dump_reserve_mem(void) {} +static inline void __init phyp_dump_reserve_mem(void) {} #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ -void __init early_init_devtree_arch(void) + +void __init early_init_devtree(void *params) { phys_addr_t limit; + DBG(" -> early_init_devtree(%p)\n", params); + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + +#ifdef CONFIG_PPC_RTAS + /* Some machines might need RTAS info for debugging, grab it now. */ + of_scan_flat_dt(early_init_dt_scan_rtas, NULL); +#endif + +#ifdef CONFIG_PHYP_DUMP + /* scan tree to see if dump occured during last boot */ + of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); +#endif + + /* Retrieve various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size, TCE reserve, and more ... + */ + of_scan_flat_dt(early_init_dt_scan_chosen, NULL); + + /* Scan memory nodes and rebuild LMBs */ + lmb_init(); + of_scan_flat_dt(early_init_dt_scan_root, NULL); + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + + /* Save command line for /proc/cmdline and then parse parameters */ + strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); + parse_early_param(); + /* Reserve LMB regions used by kernel, initrd, dt, etc... */ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); /* If relocatable, reserve first 32k for interrupt vectors etc. */ @@ -675,8 +734,27 @@ void __init early_init_devtree_arch(void) limit = memsize & PAGE_MASK; } lmb_enforce_memory_limit(limit); + + lmb_analyze(); + lmb_dump_all(); + + DBG("Phys. mem: %llx\n", lmb_phys_mem_size()); + + /* We may need to relocate the flat tree, do it now. + * FIXME .. and the initrd too? */ + move_device_tree(); + + DBG("Scanning CPUs ...\n"); + + /* Retreive CPU related informations from the flat tree + * (altivec support, boot CPU ID, ...) + */ + of_scan_flat_dt(early_init_dt_scan_cpus, NULL); + + DBG(" <- early_init_devtree()\n"); } + /** * Indicates whether the root node has a given value in its * compatible property. |