diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 89 |
1 files changed, 47 insertions, 42 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4ca608c9cd72..a04f726d3bab 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <asm/machdep.h> | 50 | #include <asm/machdep.h> |
| 51 | #include <asm/pSeries_reconfig.h> | 51 | #include <asm/pSeries_reconfig.h> |
| 52 | #include <asm/pci-bridge.h> | 52 | #include <asm/pci-bridge.h> |
| 53 | #include <asm/kexec.h> | ||
| 53 | 54 | ||
| 54 | #ifdef DEBUG | 55 | #ifdef DEBUG |
| 55 | #define DBG(fmt...) printk(KERN_ERR fmt) | 56 | #define DBG(fmt...) printk(KERN_ERR fmt) |
| @@ -836,6 +837,42 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, | |||
| 836 | return mem; | 837 | return mem; |
| 837 | } | 838 | } |
| 838 | 839 | ||
| 840 | static int __init early_parse_mem(char *p) | ||
| 841 | { | ||
| 842 | if (!p) | ||
| 843 | return 1; | ||
| 844 | |||
| 845 | memory_limit = PAGE_ALIGN(memparse(p, &p)); | ||
| 846 | DBG("memory limit = 0x%lx\n", memory_limit); | ||
| 847 | |||
| 848 | return 0; | ||
| 849 | } | ||
| 850 | early_param("mem", early_parse_mem); | ||
| 851 | |||
| 852 | /* | ||
| 853 | * The device tree may be allocated below our memory limit, or inside the | ||
| 854 | * crash kernel region for kdump. If so, move it out now. | ||
| 855 | */ | ||
| 856 | static void move_device_tree(void) | ||
| 857 | { | ||
| 858 | unsigned long start, size; | ||
| 859 | void *p; | ||
| 860 | |||
| 861 | DBG("-> move_device_tree\n"); | ||
| 862 | |||
| 863 | start = __pa(initial_boot_params); | ||
| 864 | size = initial_boot_params->totalsize; | ||
| 865 | |||
| 866 | if ((memory_limit && (start + size) > memory_limit) || | ||
| 867 | overlaps_crashkernel(start, size)) { | ||
| 868 | p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size)); | ||
| 869 | memcpy(p, initial_boot_params, size); | ||
| 870 | initial_boot_params = (struct boot_param_header *)p; | ||
| 871 | DBG("Moved device tree to 0x%p\n", p); | ||
| 872 | } | ||
| 873 | |||
| 874 | DBG("<- move_device_tree\n"); | ||
| 875 | } | ||
| 839 | 876 | ||
| 840 | /** | 877 | /** |
| 841 | * unflattens the device-tree passed by the firmware, creating the | 878 | * unflattens the device-tree passed by the firmware, creating the |
| @@ -1070,6 +1107,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
| 1070 | iommu_force_on = 1; | 1107 | iommu_force_on = 1; |
| 1071 | #endif | 1108 | #endif |
| 1072 | 1109 | ||
| 1110 | /* mem=x on the command line is the preferred mechanism */ | ||
| 1073 | lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); | 1111 | lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); |
| 1074 | if (lprop) | 1112 | if (lprop) |
| 1075 | memory_limit = *lprop; | 1113 | memory_limit = *lprop; |
| @@ -1123,17 +1161,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
| 1123 | 1161 | ||
| 1124 | DBG("Command line is: %s\n", cmd_line); | 1162 | DBG("Command line is: %s\n", cmd_line); |
| 1125 | 1163 | ||
| 1126 | if (strstr(cmd_line, "mem=")) { | ||
| 1127 | char *p, *q; | ||
| 1128 | |||
| 1129 | for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { | ||
| 1130 | q = p + 4; | ||
| 1131 | if (p > cmd_line && p[-1] != ' ') | ||
| 1132 | continue; | ||
| 1133 | memory_limit = memparse(q, &q); | ||
| 1134 | } | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | /* break now */ | 1164 | /* break now */ |
| 1138 | return 1; | 1165 | return 1; |
| 1139 | } | 1166 | } |
| @@ -1297,11 +1324,6 @@ void __init early_init_devtree(void *params) | |||
| 1297 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 1324 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
| 1298 | parse_early_param(); | 1325 | parse_early_param(); |
| 1299 | 1326 | ||
| 1300 | lmb_enforce_memory_limit(memory_limit); | ||
| 1301 | lmb_analyze(); | ||
| 1302 | |||
| 1303 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | ||
| 1304 | |||
| 1305 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ | 1327 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ |
| 1306 | lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); | 1328 | lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); |
| 1307 | #ifdef CONFIG_CRASH_DUMP | 1329 | #ifdef CONFIG_CRASH_DUMP |
| @@ -1309,6 +1331,15 @@ void __init early_init_devtree(void *params) | |||
| 1309 | #endif | 1331 | #endif |
| 1310 | early_reserve_mem(); | 1332 | early_reserve_mem(); |
| 1311 | 1333 | ||
| 1334 | lmb_enforce_memory_limit(memory_limit); | ||
| 1335 | lmb_analyze(); | ||
| 1336 | |||
| 1337 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | ||
| 1338 | |||
| 1339 | /* We may need to relocate the flat tree, do it now. | ||
| 1340 | * FIXME .. and the initrd too? */ | ||
| 1341 | move_device_tree(); | ||
| 1342 | |||
| 1312 | DBG("Scanning CPUs ...\n"); | 1343 | DBG("Scanning CPUs ...\n"); |
| 1313 | 1344 | ||
| 1314 | /* Retreive CPU related informations from the flat tree | 1345 | /* Retreive CPU related informations from the flat tree |
| @@ -2058,29 +2089,3 @@ int prom_update_property(struct device_node *np, | |||
| 2058 | return 0; | 2089 | return 0; |
| 2059 | } | 2090 | } |
| 2060 | 2091 | ||
| 2061 | #ifdef CONFIG_KEXEC | ||
| 2062 | /* We may have allocated the flat device tree inside the crash kernel region | ||
| 2063 | * in prom_init. If so we need to move it out into regular memory. */ | ||
| 2064 | void kdump_move_device_tree(void) | ||
| 2065 | { | ||
| 2066 | unsigned long start, end; | ||
| 2067 | struct boot_param_header *new; | ||
| 2068 | |||
| 2069 | start = __pa((unsigned long)initial_boot_params); | ||
| 2070 | end = start + initial_boot_params->totalsize; | ||
| 2071 | |||
| 2072 | if (end < crashk_res.start || start > crashk_res.end) | ||
| 2073 | return; | ||
| 2074 | |||
| 2075 | new = (struct boot_param_header*) | ||
| 2076 | __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE)); | ||
| 2077 | |||
| 2078 | memcpy(new, initial_boot_params, initial_boot_params->totalsize); | ||
| 2079 | |||
| 2080 | initial_boot_params = new; | ||
| 2081 | |||
| 2082 | DBG("Flat device tree blob moved to %p\n", initial_boot_params); | ||
| 2083 | |||
| 2084 | /* XXX should we unreserve the old DT? */ | ||
| 2085 | } | ||
| 2086 | #endif /* CONFIG_KEXEC */ | ||
