diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r-- | arch/powerpc/kernel/prom.c | 118 |
1 files changed, 78 insertions, 40 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fed9bf6187d1..8c3112a57cf2 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -66,7 +66,9 @@ | |||
66 | int __initdata iommu_is_off; | 66 | int __initdata iommu_is_off; |
67 | int __initdata iommu_force_on; | 67 | int __initdata iommu_force_on; |
68 | unsigned long tce_alloc_start, tce_alloc_end; | 68 | unsigned long tce_alloc_start, tce_alloc_end; |
69 | u64 ppc64_rma_size; | ||
69 | #endif | 70 | #endif |
71 | static phys_addr_t first_memblock_size; | ||
70 | 72 | ||
71 | static int __init early_parse_mem(char *p) | 73 | static int __init early_parse_mem(char *p) |
72 | { | 74 | { |
@@ -80,11 +82,29 @@ static int __init early_parse_mem(char *p) | |||
80 | } | 82 | } |
81 | early_param("mem", early_parse_mem); | 83 | early_param("mem", early_parse_mem); |
82 | 84 | ||
85 | /* | ||
86 | * overlaps_initrd - check for overlap with page aligned extension of | ||
87 | * initrd. | ||
88 | */ | ||
89 | static inline int overlaps_initrd(unsigned long start, unsigned long size) | ||
90 | { | ||
91 | #ifdef CONFIG_BLK_DEV_INITRD | ||
92 | if (!initrd_start) | ||
93 | return 0; | ||
94 | |||
95 | return (start + size) > _ALIGN_DOWN(initrd_start, PAGE_SIZE) && | ||
96 | start <= _ALIGN_UP(initrd_end, PAGE_SIZE); | ||
97 | #else | ||
98 | return 0; | ||
99 | #endif | ||
100 | } | ||
101 | |||
83 | /** | 102 | /** |
84 | * move_device_tree - move tree to an unused area, if needed. | 103 | * move_device_tree - move tree to an unused area, if needed. |
85 | * | 104 | * |
86 | * The device tree may be allocated beyond our memory limit, or inside the | 105 | * The device tree may be allocated beyond our memory limit, or inside the |
87 | * crash kernel region for kdump. If so, move it out of the way. | 106 | * crash kernel region for kdump, or within the page aligned range of initrd. |
107 | * If so, move it out of the way. | ||
88 | */ | 108 | */ |
89 | static void __init move_device_tree(void) | 109 | static void __init move_device_tree(void) |
90 | { | 110 | { |
@@ -96,9 +116,10 @@ static void __init move_device_tree(void) | |||
96 | start = __pa(initial_boot_params); | 116 | start = __pa(initial_boot_params); |
97 | size = be32_to_cpu(initial_boot_params->totalsize); | 117 | size = be32_to_cpu(initial_boot_params->totalsize); |
98 | 118 | ||
99 | if ((memory_limit && (start + size) > memory_limit) || | 119 | if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) || |
100 | overlaps_crashkernel(start, size)) { | 120 | overlaps_crashkernel(start, size) || |
101 | p = __va(memblock_alloc_base(size, PAGE_SIZE, memblock.rmo_size)); | 121 | overlaps_initrd(start, size)) { |
122 | p = __va(memblock_alloc(size, PAGE_SIZE)); | ||
102 | memcpy(p, initial_boot_params, size); | 123 | memcpy(p, initial_boot_params, size); |
103 | initial_boot_params = (struct boot_param_header *)p; | 124 | initial_boot_params = (struct boot_param_header *)p; |
104 | DBG("Moved device tree to 0x%p\n", p); | 125 | DBG("Moved device tree to 0x%p\n", p); |
@@ -122,18 +143,19 @@ static void __init move_device_tree(void) | |||
122 | */ | 143 | */ |
123 | static struct ibm_pa_feature { | 144 | static struct ibm_pa_feature { |
124 | unsigned long cpu_features; /* CPU_FTR_xxx bit */ | 145 | unsigned long cpu_features; /* CPU_FTR_xxx bit */ |
146 | unsigned long mmu_features; /* MMU_FTR_xxx bit */ | ||
125 | unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ | 147 | unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ |
126 | unsigned char pabyte; /* byte number in ibm,pa-features */ | 148 | unsigned char pabyte; /* byte number in ibm,pa-features */ |
127 | unsigned char pabit; /* bit number (big-endian) */ | 149 | unsigned char pabit; /* bit number (big-endian) */ |
128 | unsigned char invert; /* if 1, pa bit set => clear feature */ | 150 | unsigned char invert; /* if 1, pa bit set => clear feature */ |
129 | } ibm_pa_features[] __initdata = { | 151 | } ibm_pa_features[] __initdata = { |
130 | {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, | 152 | {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, |
131 | {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, | 153 | {0, 0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, |
132 | {CPU_FTR_SLB, 0, 0, 2, 0}, | 154 | {0, MMU_FTR_SLB, 0, 0, 2, 0}, |
133 | {CPU_FTR_CTRL, 0, 0, 3, 0}, | 155 | {CPU_FTR_CTRL, 0, 0, 0, 3, 0}, |
134 | {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, | 156 | {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0}, |
135 | {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, | 157 | {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1}, |
136 | {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, | 158 | {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, |
137 | {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, | 159 | {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, |
138 | }; | 160 | }; |
139 | 161 | ||
@@ -165,9 +187,11 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs, | |||
165 | if (bit ^ fp->invert) { | 187 | if (bit ^ fp->invert) { |
166 | cur_cpu_spec->cpu_features |= fp->cpu_features; | 188 | cur_cpu_spec->cpu_features |= fp->cpu_features; |
167 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; | 189 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; |
190 | cur_cpu_spec->mmu_features |= fp->mmu_features; | ||
168 | } else { | 191 | } else { |
169 | cur_cpu_spec->cpu_features &= ~fp->cpu_features; | 192 | cur_cpu_spec->cpu_features &= ~fp->cpu_features; |
170 | cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; | 193 | cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; |
194 | cur_cpu_spec->mmu_features &= ~fp->mmu_features; | ||
171 | } | 195 | } |
172 | } | 196 | } |
173 | } | 197 | } |
@@ -267,13 +291,13 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
267 | const char *uname, int depth, | 291 | const char *uname, int depth, |
268 | void *data) | 292 | void *data) |
269 | { | 293 | { |
270 | static int logical_cpuid = 0; | ||
271 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 294 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
272 | const u32 *prop; | 295 | const u32 *prop; |
273 | const u32 *intserv; | 296 | const u32 *intserv; |
274 | int i, nthreads; | 297 | int i, nthreads; |
275 | unsigned long len; | 298 | unsigned long len; |
276 | int found = 0; | 299 | int found = -1; |
300 | int found_thread = 0; | ||
277 | 301 | ||
278 | /* We are scanning "cpu" nodes only */ | 302 | /* We are scanning "cpu" nodes only */ |
279 | if (type == NULL || strcmp(type, "cpu") != 0) | 303 | if (type == NULL || strcmp(type, "cpu") != 0) |
@@ -297,11 +321,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
297 | * version 2 of the kexec param format adds the phys cpuid of | 321 | * version 2 of the kexec param format adds the phys cpuid of |
298 | * booted proc. | 322 | * booted proc. |
299 | */ | 323 | */ |
300 | if (initial_boot_params && initial_boot_params->version >= 2) { | 324 | if (initial_boot_params->version >= 2) { |
301 | if (intserv[i] == | 325 | if (intserv[i] == initial_boot_params->boot_cpuid_phys) { |
302 | initial_boot_params->boot_cpuid_phys) { | 326 | found = boot_cpu_count; |
303 | found = 1; | 327 | found_thread = i; |
304 | break; | ||
305 | } | 328 | } |
306 | } else { | 329 | } else { |
307 | /* | 330 | /* |
@@ -310,23 +333,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
310 | * off secondary threads. | 333 | * off secondary threads. |
311 | */ | 334 | */ |
312 | if (of_get_flat_dt_prop(node, | 335 | if (of_get_flat_dt_prop(node, |
313 | "linux,boot-cpu", NULL) != NULL) { | 336 | "linux,boot-cpu", NULL) != NULL) |
314 | found = 1; | 337 | found = boot_cpu_count; |
315 | break; | ||
316 | } | ||
317 | } | 338 | } |
318 | |||
319 | #ifdef CONFIG_SMP | 339 | #ifdef CONFIG_SMP |
320 | /* logical cpu id is always 0 on UP kernels */ | 340 | /* logical cpu id is always 0 on UP kernels */ |
321 | logical_cpuid++; | 341 | boot_cpu_count++; |
322 | #endif | 342 | #endif |
323 | } | 343 | } |
324 | 344 | ||
325 | if (found) { | 345 | if (found >= 0) { |
326 | DBG("boot cpu: logical %d physical %d\n", logical_cpuid, | 346 | DBG("boot cpu: logical %d physical %d\n", found, |
327 | intserv[i]); | 347 | intserv[found_thread]); |
328 | boot_cpuid = logical_cpuid; | 348 | boot_cpuid = found; |
329 | set_hard_smp_processor_id(boot_cpuid, intserv[i]); | 349 | set_hard_smp_processor_id(found, intserv[found_thread]); |
330 | 350 | ||
331 | /* | 351 | /* |
332 | * PAPR defines "logical" PVR values for cpus that | 352 | * PAPR defines "logical" PVR values for cpus that |
@@ -363,10 +383,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
363 | return 0; | 383 | return 0; |
364 | } | 384 | } |
365 | 385 | ||
366 | void __init early_init_dt_scan_chosen_arch(unsigned long node) | 386 | int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname, |
387 | int depth, void *data) | ||
367 | { | 388 | { |
368 | unsigned long *lprop; | 389 | unsigned long *lprop; |
369 | 390 | ||
391 | /* Use common scan routine to determine if this is the chosen node */ | ||
392 | if (early_init_dt_scan_chosen(node, uname, depth, data) == 0) | ||
393 | return 0; | ||
394 | |||
370 | #ifdef CONFIG_PPC64 | 395 | #ifdef CONFIG_PPC64 |
371 | /* check if iommu is forced on or off */ | 396 | /* check if iommu is forced on or off */ |
372 | if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) | 397 | if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) |
@@ -398,6 +423,9 @@ void __init early_init_dt_scan_chosen_arch(unsigned long node) | |||
398 | if (lprop) | 423 | if (lprop) |
399 | crashk_res.end = crashk_res.start + *lprop - 1; | 424 | crashk_res.end = crashk_res.start + *lprop - 1; |
400 | #endif | 425 | #endif |
426 | |||
427 | /* break now */ | ||
428 | return 1; | ||
401 | } | 429 | } |
402 | 430 | ||
403 | #ifdef CONFIG_PPC_PSERIES | 431 | #ifdef CONFIG_PPC_PSERIES |
@@ -492,7 +520,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node, | |||
492 | 520 | ||
493 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | 521 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) |
494 | { | 522 | { |
495 | #if defined(CONFIG_PPC64) | 523 | #ifdef CONFIG_PPC64 |
496 | if (iommu_is_off) { | 524 | if (iommu_is_off) { |
497 | if (base >= 0x80000000ul) | 525 | if (base >= 0x80000000ul) |
498 | return; | 526 | return; |
@@ -500,15 +528,22 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) | |||
500 | size = 0x80000000ul - base; | 528 | size = 0x80000000ul - base; |
501 | } | 529 | } |
502 | #endif | 530 | #endif |
531 | /* Keep track of the beginning of memory -and- the size of | ||
532 | * the very first block in the device-tree as it represents | ||
533 | * the RMA on ppc64 server | ||
534 | */ | ||
535 | if (base < memstart_addr) { | ||
536 | memstart_addr = base; | ||
537 | first_memblock_size = size; | ||
538 | } | ||
503 | 539 | ||
540 | /* Add the chunk to the MEMBLOCK list */ | ||
504 | memblock_add(base, size); | 541 | memblock_add(base, size); |
505 | |||
506 | memstart_addr = min((u64)memstart_addr, base); | ||
507 | } | 542 | } |
508 | 543 | ||
509 | u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | 544 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) |
510 | { | 545 | { |
511 | return memblock_alloc(size, align); | 546 | return __va(memblock_alloc(size, align)); |
512 | } | 547 | } |
513 | 548 | ||
514 | #ifdef CONFIG_BLK_DEV_INITRD | 549 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -539,7 +574,9 @@ static void __init early_reserve_mem(void) | |||
539 | #ifdef CONFIG_BLK_DEV_INITRD | 574 | #ifdef CONFIG_BLK_DEV_INITRD |
540 | /* then reserve the initrd, if any */ | 575 | /* then reserve the initrd, if any */ |
541 | if (initrd_start && (initrd_end > initrd_start)) | 576 | if (initrd_start && (initrd_end > initrd_start)) |
542 | memblock_reserve(__pa(initrd_start), initrd_end - initrd_start); | 577 | memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE), |
578 | _ALIGN_UP(initrd_end, PAGE_SIZE) - | ||
579 | _ALIGN_DOWN(initrd_start, PAGE_SIZE)); | ||
543 | #endif /* CONFIG_BLK_DEV_INITRD */ | 580 | #endif /* CONFIG_BLK_DEV_INITRD */ |
544 | 581 | ||
545 | #ifdef CONFIG_PPC32 | 582 | #ifdef CONFIG_PPC32 |
@@ -655,7 +692,6 @@ static void __init phyp_dump_reserve_mem(void) | |||
655 | static inline void __init phyp_dump_reserve_mem(void) {} | 692 | static inline void __init phyp_dump_reserve_mem(void) {} |
656 | #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ | 693 | #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ |
657 | 694 | ||
658 | |||
659 | void __init early_init_devtree(void *params) | 695 | void __init early_init_devtree(void *params) |
660 | { | 696 | { |
661 | phys_addr_t limit; | 697 | phys_addr_t limit; |
@@ -671,7 +707,7 @@ void __init early_init_devtree(void *params) | |||
671 | #endif | 707 | #endif |
672 | 708 | ||
673 | #ifdef CONFIG_PHYP_DUMP | 709 | #ifdef CONFIG_PHYP_DUMP |
674 | /* scan tree to see if dump occured during last boot */ | 710 | /* scan tree to see if dump occurred during last boot */ |
675 | of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); | 711 | of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); |
676 | #endif | 712 | #endif |
677 | 713 | ||
@@ -679,12 +715,14 @@ void __init early_init_devtree(void *params) | |||
679 | * device-tree, including the platform type, initrd location and | 715 | * device-tree, including the platform type, initrd location and |
680 | * size, TCE reserve, and more ... | 716 | * size, TCE reserve, and more ... |
681 | */ | 717 | */ |
682 | of_scan_flat_dt(early_init_dt_scan_chosen, NULL); | 718 | of_scan_flat_dt(early_init_dt_scan_chosen_ppc, cmd_line); |
683 | 719 | ||
684 | /* Scan memory nodes and rebuild MEMBLOCKs */ | 720 | /* Scan memory nodes and rebuild MEMBLOCKs */ |
685 | memblock_init(); | 721 | memblock_init(); |
722 | |||
686 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | 723 | of_scan_flat_dt(early_init_dt_scan_root, NULL); |
687 | of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); | 724 | of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); |
725 | setup_initial_memory_limit(memstart_addr, first_memblock_size); | ||
688 | 726 | ||
689 | /* Save command line for /proc/cmdline and then parse parameters */ | 727 | /* Save command line for /proc/cmdline and then parse parameters */ |
690 | strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); | 728 | strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); |
@@ -726,7 +764,7 @@ void __init early_init_devtree(void *params) | |||
726 | 764 | ||
727 | DBG("Scanning CPUs ...\n"); | 765 | DBG("Scanning CPUs ...\n"); |
728 | 766 | ||
729 | /* Retreive CPU related informations from the flat tree | 767 | /* Retrieve CPU related informations from the flat tree |
730 | * (altivec support, boot CPU ID, ...) | 768 | * (altivec support, boot CPU ID, ...) |
731 | */ | 769 | */ |
732 | of_scan_flat_dt(early_init_dt_scan_cpus, NULL); | 770 | of_scan_flat_dt(early_init_dt_scan_cpus, NULL); |