diff options
Diffstat (limited to 'arch/powerpc/kernel/machine_kexec_64.c')
-rw-r--r-- | arch/powerpc/kernel/machine_kexec_64.c | 75 |
1 files changed, 23 insertions, 52 deletions
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 4c780a342282..a205fa3d9bf3 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -23,6 +23,7 @@ #include <asm/current.h> #include <asm/machdep.h> #include <asm/cacheflush.h> +#include <asm/firmware.h> #include <asm/paca.h> #include <asm/mmu.h> #include <asm/sections.h> /* _end */ @@ -31,21 +32,6 @@ #include <asm/hw_breakpoint.h> #include <asm/asm-prototypes.h> -#ifdef CONFIG_PPC_BOOK3E -int default_machine_kexec_prepare(struct kimage *image) -{ - int i; - /* - * Since we use the kernel fault handlers and paging code to - * handle the virtual mode, we must make sure no destination - * overlaps kernel static data or bss. - */ - for (i = 0; i < image->nr_segments; i++) - if (image->segment[i].mem < __pa(_end)) - return -ETXTBSY; - return 0; -} -#else int default_machine_kexec_prepare(struct kimage *image) { int i; @@ -55,9 +41,6 @@ int default_machine_kexec_prepare(struct kimage *image) const unsigned long *basep; const unsigned int *sizep; - if (!mmu_hash_ops.hpte_clear_all) - return -ENOENT; - /* * Since we use the kernel fault handlers and paging code to * handle the virtual mode, we must make sure no destination @@ -67,31 +50,6 @@ int default_machine_kexec_prepare(struct kimage *image) if (image->segment[i].mem < __pa(_end)) return -ETXTBSY; - /* - * For non-LPAR, we absolutely can not overwrite the mmu hash - * table, since we are still using the bolted entries in it to - * do the copy. Check that here. - * - * It is safe if the end is below the start of the blocked - * region (end <= low), or if the beginning is after the - * end of the blocked region (begin >= high). Use the - * boolean identity !(a || b) === (!a && !b). - */ -#ifdef CONFIG_PPC_STD_MMU_64 - if (htab_address) { - low = __pa(htab_address); - high = low + htab_size_bytes; - - for (i = 0; i < image->nr_segments; i++) { - begin = image->segment[i].mem; - end = begin + image->segment[i].memsz; - - if ((begin < high) && (end > low)) - return -ETXTBSY; - } - } -#endif /* CONFIG_PPC_STD_MMU_64 */ - /* We also should not overwrite the tce tables */ for_each_node_by_type(node, "pci") { basep = of_get_property(node, "linux,tce-base", NULL); @@ -113,7 +71,6 @@ int default_machine_kexec_prepare(struct kimage *image) return 0; } -#endif /* !CONFIG_PPC_BOOK3E */ static void copy_segments(unsigned long ind) { @@ -332,11 +289,14 @@ struct paca_struct kexec_paca; /* Our assembly helper, in misc_64.S */ extern void kexec_sequence(void *newstack, unsigned long start, void *image, void *control, - void (*clear_all)(void)) __noreturn; + void (*clear_all)(void), + bool copy_with_mmu_off) __noreturn; /* too late to fail here */ void default_machine_kexec(struct kimage *image) { + bool copy_with_mmu_off; + /* prepare control code if any */ /* @@ -374,18 +334,29 @@ void default_machine_kexec(struct kimage *image) /* XXX: If anyone does 'dynamic lppacas' this will also need to be * switched to a static version! */ + /* + * On Book3S, the copy must happen with the MMU off if we are either + * using Radix page tables or we are not in an LPAR since we can + * overwrite the page tables while copying. + * + * In an LPAR, we keep the MMU on otherwise we can't access beyond + * the RMA. On BookE there is no real MMU off mode, so we have to + * keep it enabled as well (but then we have bolted TLB entries). + */ +#ifdef CONFIG_PPC_BOOK3E + copy_with_mmu_off = false; +#else + copy_with_mmu_off = radix_enabled() || + !(firmware_has_feature(FW_FEATURE_LPAR) || + firmware_has_feature(FW_FEATURE_PS3_LV1)); +#endif /* Some things are best done in assembly. Finding globals with * a toc is easier in C, so pass in what we can. */ kexec_sequence(&kexec_stack, image->start, image, - page_address(image->control_code_page), -#ifdef CONFIG_PPC_STD_MMU - mmu_hash_ops.hpte_clear_all -#else - NULL -#endif - ); + page_address(image->control_code_page), + mmu_cleanup_all, copy_with_mmu_off); /* NOTREACHED */ } |