diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r-- | arch/powerpc/kernel/prom.c | 145 |
1 files changed, 107 insertions, 38 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 9a07f97f0712..483455c5bb02 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 |
@@ -911,7 +948,10 @@ static struct ibm_pa_feature { | |||
911 | {CPU_FTR_CTRL, 0, 0, 3, 0}, | 948 | {CPU_FTR_CTRL, 0, 0, 3, 0}, |
912 | {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, | 949 | {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, |
913 | {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, | 950 | {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, |
951 | #if 0 | ||
952 | /* put this back once we know how to test if firmware does 64k IO */ | ||
914 | {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, | 953 | {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, |
954 | #endif | ||
915 | }; | 955 | }; |
916 | 956 | ||
917 | static void __init check_cpu_pa_features(unsigned long node) | 957 | static void __init check_cpu_pa_features(unsigned long node) |
@@ -1070,6 +1110,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1070 | iommu_force_on = 1; | 1110 | iommu_force_on = 1; |
1071 | #endif | 1111 | #endif |
1072 | 1112 | ||
1113 | /* mem=x on the command line is the preferred mechanism */ | ||
1073 | lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); | 1114 | lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); |
1074 | if (lprop) | 1115 | if (lprop) |
1075 | memory_limit = *lprop; | 1116 | memory_limit = *lprop; |
@@ -1123,17 +1164,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1123 | 1164 | ||
1124 | DBG("Command line is: %s\n", cmd_line); | 1165 | DBG("Command line is: %s\n", cmd_line); |
1125 | 1166 | ||
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 */ | 1167 | /* break now */ |
1138 | return 1; | 1168 | return 1; |
1139 | } | 1169 | } |
@@ -1237,9 +1267,17 @@ static void __init early_reserve_mem(void) | |||
1237 | { | 1267 | { |
1238 | u64 base, size; | 1268 | u64 base, size; |
1239 | u64 *reserve_map; | 1269 | u64 *reserve_map; |
1270 | unsigned long self_base; | ||
1271 | unsigned long self_size; | ||
1240 | 1272 | ||
1241 | reserve_map = (u64 *)(((unsigned long)initial_boot_params) + | 1273 | reserve_map = (u64 *)(((unsigned long)initial_boot_params) + |
1242 | initial_boot_params->off_mem_rsvmap); | 1274 | initial_boot_params->off_mem_rsvmap); |
1275 | |||
1276 | /* before we do anything, lets reserve the dt blob */ | ||
1277 | self_base = __pa((unsigned long)initial_boot_params); | ||
1278 | self_size = initial_boot_params->totalsize; | ||
1279 | lmb_reserve(self_base, self_size); | ||
1280 | |||
1243 | #ifdef CONFIG_PPC32 | 1281 | #ifdef CONFIG_PPC32 |
1244 | /* | 1282 | /* |
1245 | * Handle the case where we might be booting from an old kexec | 1283 | * Handle the case where we might be booting from an old kexec |
@@ -1254,6 +1292,9 @@ static void __init early_reserve_mem(void) | |||
1254 | size_32 = *(reserve_map_32++); | 1292 | size_32 = *(reserve_map_32++); |
1255 | if (size_32 == 0) | 1293 | if (size_32 == 0) |
1256 | break; | 1294 | break; |
1295 | /* skip if the reservation is for the blob */ | ||
1296 | if (base_32 == self_base && size_32 == self_size) | ||
1297 | continue; | ||
1257 | DBG("reserving: %x -> %x\n", base_32, size_32); | 1298 | DBG("reserving: %x -> %x\n", base_32, size_32); |
1258 | lmb_reserve(base_32, size_32); | 1299 | lmb_reserve(base_32, size_32); |
1259 | } | 1300 | } |
@@ -1265,6 +1306,9 @@ static void __init early_reserve_mem(void) | |||
1265 | size = *(reserve_map++); | 1306 | size = *(reserve_map++); |
1266 | if (size == 0) | 1307 | if (size == 0) |
1267 | break; | 1308 | break; |
1309 | /* skip if the reservation is for the blob */ | ||
1310 | if (base == self_base && size == self_size) | ||
1311 | continue; | ||
1268 | DBG("reserving: %llx -> %llx\n", base, size); | 1312 | DBG("reserving: %llx -> %llx\n", base, size); |
1269 | lmb_reserve(base, size); | 1313 | lmb_reserve(base, size); |
1270 | } | 1314 | } |
@@ -1292,18 +1336,26 @@ void __init early_init_devtree(void *params) | |||
1292 | lmb_init(); | 1336 | lmb_init(); |
1293 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | 1337 | of_scan_flat_dt(early_init_dt_scan_root, NULL); |
1294 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | 1338 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); |
1295 | lmb_enforce_memory_limit(memory_limit); | ||
1296 | lmb_analyze(); | ||
1297 | 1339 | ||
1298 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | 1340 | /* Save command line for /proc/cmdline and then parse parameters */ |
1341 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | ||
1342 | parse_early_param(); | ||
1299 | 1343 | ||
1300 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ | 1344 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ |
1301 | lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); | 1345 | lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); |
1302 | #ifdef CONFIG_CRASH_DUMP | 1346 | reserve_kdump_trampoline(); |
1303 | lmb_reserve(0, KDUMP_RESERVE_LIMIT); | 1347 | reserve_crashkernel(); |
1304 | #endif | ||
1305 | early_reserve_mem(); | 1348 | early_reserve_mem(); |
1306 | 1349 | ||
1350 | lmb_enforce_memory_limit(memory_limit); | ||
1351 | lmb_analyze(); | ||
1352 | |||
1353 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | ||
1354 | |||
1355 | /* We may need to relocate the flat tree, do it now. | ||
1356 | * FIXME .. and the initrd too? */ | ||
1357 | move_device_tree(); | ||
1358 | |||
1307 | DBG("Scanning CPUs ...\n"); | 1359 | DBG("Scanning CPUs ...\n"); |
1308 | 1360 | ||
1309 | /* Retreive CPU related informations from the flat tree | 1361 | /* Retreive CPU related informations from the flat tree |
@@ -2053,29 +2105,46 @@ int prom_update_property(struct device_node *np, | |||
2053 | return 0; | 2105 | return 0; |
2054 | } | 2106 | } |
2055 | 2107 | ||
2056 | #ifdef CONFIG_KEXEC | ||
2057 | /* We may have allocated the flat device tree inside the crash kernel region | ||
2058 | * in prom_init. If so we need to move it out into regular memory. */ | ||
2059 | void kdump_move_device_tree(void) | ||
2060 | { | ||
2061 | unsigned long start, end; | ||
2062 | struct boot_param_header *new; | ||
2063 | |||
2064 | start = __pa((unsigned long)initial_boot_params); | ||
2065 | end = start + initial_boot_params->totalsize; | ||
2066 | |||
2067 | if (end < crashk_res.start || start > crashk_res.end) | ||
2068 | return; | ||
2069 | 2108 | ||
2070 | new = (struct boot_param_header*) | 2109 | /* Find the device node for a given logical cpu number, also returns the cpu |
2071 | __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE)); | 2110 | * local thread number (index in ibm,interrupt-server#s) if relevant and |
2072 | 2111 | * asked for (non NULL) | |
2073 | memcpy(new, initial_boot_params, initial_boot_params->totalsize); | 2112 | */ |
2113 | struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | ||
2114 | { | ||
2115 | int hardid; | ||
2116 | struct device_node *np; | ||
2074 | 2117 | ||
2075 | initial_boot_params = new; | 2118 | hardid = get_hard_smp_processor_id(cpu); |
2076 | 2119 | ||
2077 | DBG("Flat device tree blob moved to %p\n", initial_boot_params); | 2120 | for_each_node_by_type(np, "cpu") { |
2121 | u32 *intserv; | ||
2122 | unsigned int plen, t; | ||
2078 | 2123 | ||
2079 | /* XXX should we unreserve the old DT? */ | 2124 | /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist |
2125 | * fallback to "reg" property and assume no threads | ||
2126 | */ | ||
2127 | intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", | ||
2128 | &plen); | ||
2129 | if (intserv == NULL) { | ||
2130 | u32 *reg = (u32 *)get_property(np, "reg", NULL); | ||
2131 | if (reg == NULL) | ||
2132 | continue; | ||
2133 | if (*reg == hardid) { | ||
2134 | if (thread) | ||
2135 | *thread = 0; | ||
2136 | return np; | ||
2137 | } | ||
2138 | } else { | ||
2139 | plen /= sizeof(u32); | ||
2140 | for (t = 0; t < plen; t++) { | ||
2141 | if (hardid == intserv[t]) { | ||
2142 | if (thread) | ||
2143 | *thread = t; | ||
2144 | return np; | ||
2145 | } | ||
2146 | } | ||
2147 | } | ||
2148 | } | ||
2149 | return NULL; | ||
2080 | } | 2150 | } |
2081 | #endif /* CONFIG_KEXEC */ | ||