diff options
Diffstat (limited to 'arch/s390/kernel/machine_kexec.c')
| -rw-r--r-- | arch/s390/kernel/machine_kexec.c | 105 |
1 files changed, 59 insertions, 46 deletions
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 47b168fb29c..719e27b2cf2 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -1,7 +1,5 @@ /* - * arch/s390/kernel/machine_kexec.c - * - * Copyright IBM Corp. 2005,2011 + * Copyright IBM Corp. 2005, 2011 * * Author(s): Rolf Adelsberger, * Heiko Carstens <heiko.carstens@de.ibm.com> @@ -14,16 +12,19 @@ #include <linux/delay.h> #include <linux/reboot.h> #include <linux/ftrace.h> +#include <linux/debug_locks.h> +#include <linux/suspend.h> #include <asm/cio.h> #include <asm/setup.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> -#include <asm/system.h> #include <asm/smp.h> #include <asm/reset.h> #include <asm/ipl.h> #include <asm/diag.h> +#include <asm/elf.h> #include <asm/asm-offsets.h> +#include <asm/os_info.h> typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); @@ -32,8 +33,6 @@ extern const unsigned long long relocate_kernel_len; #ifdef CONFIG_CRASH_DUMP -void *fill_cpu_elf_notes(void *ptr, struct save_area *sa); - /* * Create ELF notes for one CPU */ @@ -49,55 +48,55 @@ static void add_elf_notes(int cpu) } /* - * Store status of next available physical CPU + * Initialize CPU ELF notes */ -static int store_status_next(int start_cpu, int this_cpu) +static void setup_regs(void) { - struct save_area *sa = (void *) 4608 + store_prefix(); - int cpu, rc; + unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE; + int cpu, this_cpu; - for (cpu = start_cpu; cpu < 65536; cpu++) { + this_cpu = smp_find_processor_id(stap()); + add_elf_notes(this_cpu); + for_each_online_cpu(cpu) { if (cpu == this_cpu) continue; - do { - rc = raw_sigp(cpu, sigp_stop_and_store_status); - } while (rc == sigp_busy); - if (rc != sigp_order_code_accepted) + if (smp_store_status(cpu)) continue; - if (sa->pref_reg) - return cpu; + add_elf_notes(cpu); } - return -1; + /* Copy dump CPU store status info to absolute zero */ + memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area)); } /* - * Initialize CPU ELF notes + * PM notifier callback for kdump */ -void setup_regs(void) +static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, + void *ptr) { - unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE; - int cpu, this_cpu, phys_cpu = 0, first = 1; - - this_cpu = stap(); - - if (!S390_lowcore.prefixreg_save_area) - first = 0; - for_each_online_cpu(cpu) { - if (first) { - add_elf_notes(cpu); - first = 0; - continue; - } - phys_cpu = store_status_next(phys_cpu, this_cpu); - if (phys_cpu == -1) - break; - add_elf_notes(cpu); - phys_cpu++; + switch (action) { + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + if (crashk_res.start) + crash_map_reserved_pages(); + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + if (crashk_res.start) + crash_unmap_reserved_pages(); + break; + default: + return NOTIFY_DONE; } - /* Copy dump CPU store status info to absolute zero */ - memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area)); + return NOTIFY_OK; } +static int __init machine_kdump_pm_init(void) +{ + pm_notifier(machine_kdump_pm_cb, 0); + return 0; +} +arch_initcall(machine_kdump_pm_init); #endif /* @@ -108,8 +107,8 @@ static void __do_machine_kdump(void *image) #ifdef CONFIG_CRASH_DUMP int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; - __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); setup_regs(); + __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); start_kdump(1); #endif } @@ -143,8 +142,13 @@ static void crash_map_pages(int enable) size % KEXEC_CRASH_MEM_ALIGN); if (enable) vmem_add_mapping(crashk_res.start, size); - else + else { vmem_remove_mapping(crashk_res.start, size); + if (size) + os_info_crashkernel_add(crashk_res.start, size); + else + os_info_crashkernel_add(0, 0); + } } /* @@ -184,7 +188,7 @@ int machine_kexec_prepare(struct kimage *image) /* Can't replace kernel image since it is read-only. */ if (ipl_flags & IPL_NSS_VALID) - return -ENOSYS; + return -EOPNOTSUPP; if (image->type == KEXEC_TYPE_CRASH) return machine_kexec_prepare_kdump(); @@ -216,6 +220,10 @@ void machine_shutdown(void) { } +void machine_crash_shutdown(struct pt_regs *regs) +{ +} + /* * Do normal kexec */ @@ -237,11 +245,16 @@ static void __machine_kexec(void *data) { struct kimage *image = data; + __arch_local_irq_stosm(0x04); /* enable DAT */ pfault_fini(); - if (image->type == KEXEC_TYPE_CRASH) + tracing_off(); + debug_locks_off(); + if (image->type == KEXEC_TYPE_CRASH) { + lgr_info_log(); s390_reset_system(__do_machine_kdump, data); - else + } else { s390_reset_system(__do_machine_kexec, data); + } disabled_wait((unsigned long) __builtin_return_address(0)); } @@ -255,5 +268,5 @@ void machine_kexec(struct kimage *image) return; tracer_disable(); smp_send_stop(); - smp_switch_to_ipl_cpu(__machine_kexec, image); + smp_call_ipl_cpu(__machine_kexec, image); } |
