Merge branch 'akpm'
[linux-2.6/next.git] / arch / s390 / kernel / machine_kexec.c
blob76b557d8f0c7745ca0866f36ffe91358e370c253
1 /*
2 * arch/s390/kernel/machine_kexec.c
4 * Copyright IBM Corp. 2005,2006
6 * Author(s): Rolf Adelsberger,
7 * Heiko Carstens <heiko.carstens@de.ibm.com>
8 */
10 #include <linux/device.h>
11 #include <linux/mm.h>
12 #include <linux/kexec.h>
13 #include <linux/delay.h>
14 #include <linux/reboot.h>
15 #include <linux/ftrace.h>
16 #include <asm/cio.h>
17 #include <asm/setup.h>
18 #include <asm/pgtable.h>
19 #include <asm/pgalloc.h>
20 #include <asm/system.h>
21 #include <asm/smp.h>
22 #include <asm/reset.h>
23 #include <asm/ipl.h>
24 #include <asm/diag.h>
26 typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
28 extern const unsigned char relocate_kernel[];
29 extern const unsigned long long relocate_kernel_len;
31 #ifdef CONFIG_CRASH_DUMP
33 #define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
34 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
36 #ifndef NT_FPREGSET
37 #define NT_FPREGSET 2
38 #endif
41 * fpregset ELF Note
43 struct nt_fpregset_64 {
44 u32 fpc;
45 u32 pad;
46 u64 fprs[16];
47 } __packed;
50 * Initialize ELF note
52 static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
53 const char *name)
55 Elf64_Nhdr *note;
56 u64 len;
58 note = (Elf64_Nhdr *)buf;
59 note->n_namesz = strlen(name) + 1;
60 note->n_descsz = d_len;
61 note->n_type = type;
62 len = sizeof(Elf64_Nhdr);
64 memcpy(buf + len, name, note->n_namesz);
65 len = ROUNDUP(len + note->n_namesz, 4);
67 memcpy(buf + len, desc, note->n_descsz);
68 len = ROUNDUP(len + note->n_descsz, 4);
70 return PTR_ADD(buf, len);
74 * Initialize prstatus note
76 static void *nt_prstatus(void *ptr, struct save_area *sa)
78 struct elf_prstatus nt_prstatus;
79 static int cpu_nr = 1;
81 memset(&nt_prstatus, 0, sizeof(nt_prstatus));
82 memcpy(&nt_prstatus.pr_reg.gprs, sa->gp_regs, sizeof(sa->gp_regs));
83 memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
84 memcpy(&nt_prstatus.pr_reg.acrs, sa->acc_regs, sizeof(sa->acc_regs));
85 nt_prstatus.pr_pid = cpu_nr;
86 cpu_nr++;
88 return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
89 "CORE");
93 * Initialize fpregset (floating point) note
95 static void *nt_fpregset(void *ptr, struct save_area *sa)
97 struct nt_fpregset_64 nt_fpregset;
99 memset(&nt_fpregset, 0, sizeof(nt_fpregset));
100 memcpy(&nt_fpregset.fpc, &sa->fp_ctrl_reg, sizeof(sa->fp_ctrl_reg));
101 memcpy(&nt_fpregset.fprs, &sa->fp_regs, sizeof(sa->fp_regs));
103 return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
104 "CORE");
108 * Initialize timer note
110 static void *nt_s390_timer(void *ptr, struct save_area *sa)
112 return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
113 KEXEC_CORE_NOTE_NAME);
117 * Initialize TOD clock comparator note
119 static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
121 return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
122 sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
126 * Initialize TOD programmable register note
128 static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
130 return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
131 sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
135 * Initialize control register note
137 static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
139 return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
140 sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
144 * Initialize prefix register note
146 static void *nt_s390_prefix(void *ptr, struct save_area *sa)
148 return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
149 sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
153 * Final empty node
155 static void nt_final(void *ptr)
157 memset(ptr, 0, sizeof(struct elf_note));
161 * Add create ELF notes for CPU
163 static void add_elf_notes(int cpu)
165 struct save_area *sa = (void *) 4608 + store_prefix();
166 void *ptr;
168 memcpy((void *) (4608UL + sa->pref_reg), sa, sizeof(*sa));
169 ptr = (u64 *) per_cpu_ptr(crash_notes, cpu);
170 ptr = nt_prstatus(ptr, sa);
171 ptr = nt_fpregset(ptr, sa);
172 ptr = nt_s390_timer(ptr, sa);
173 ptr = nt_s390_tod_cmp(ptr, sa);
174 ptr = nt_s390_tod_preg(ptr, sa);
175 ptr = nt_s390_ctrs(ptr, sa);
176 ptr = nt_s390_prefix(ptr, sa);
177 nt_final(ptr);
181 * Store status of next available physical CPU
183 static int store_status_next(int start_cpu, int this_cpu)
185 struct save_area *sa = (void *) 4608 + store_prefix();
186 int cpu, rc;
188 for (cpu = start_cpu; cpu < 65536; cpu++) {
189 if (cpu == this_cpu)
190 continue;
191 do {
192 rc = raw_sigp(cpu, sigp_stop_and_store_status);
193 } while (rc == sigp_busy);
194 if (rc != sigp_order_code_accepted)
195 continue;
196 if (sa->pref_reg)
197 return cpu;
199 return -1;
203 * Initialize CPU ELF notes
205 void setup_regs(void)
207 int cpu, this_cpu, phys_cpu = 0, first = 1;
209 this_cpu = stap();
211 store_status();
212 if (!S390_lowcore.prefixreg_save_area)
213 first = 0;
214 for_each_online_cpu(cpu) {
215 if (first) {
216 add_elf_notes(cpu);
217 first = 0;
218 continue;
220 phys_cpu = store_status_next(phys_cpu, this_cpu);
221 if (phys_cpu == -1)
222 return;
223 add_elf_notes(cpu);
224 phys_cpu++;
229 * Start kdump
231 static void __machine_kdump(void *image)
233 int (*start_kdump)(int) = (void *)((struct kimage *) image)->start;
235 pfault_fini();
236 s390_reset_system();
237 __load_psw_mask(PSW_BASE_BITS | PSW_DEFAULT_KEY);
238 setup_regs();
239 start_kdump(1);
240 disabled_wait((unsigned long) __builtin_return_address(0));
243 #endif
246 * Give back memory to hypervisor before new kdump is loaded
248 static int machine_kexec_prepare_kdump(void)
250 #ifdef CONFIG_CRASH_DUMP
251 if (MACHINE_IS_VM)
252 diag10_range(PFN_DOWN(crashk_res.start),
253 PFN_DOWN(crashk_res.end - crashk_res.start + 1));
254 return 0;
255 #else
256 return -EINVAL;
257 #endif
260 int machine_kexec_prepare(struct kimage *image)
262 void *reboot_code_buffer;
264 /* Can't replace kernel image since it is read-only. */
265 if (ipl_flags & IPL_NSS_VALID)
266 return -ENOSYS;
268 if (image->type == KEXEC_TYPE_CRASH)
269 return machine_kexec_prepare_kdump();
271 /* We don't support anything but the default image type for now. */
272 if (image->type != KEXEC_TYPE_DEFAULT)
273 return -EINVAL;
275 /* Get the destination where the assembler code should be copied to.*/
276 reboot_code_buffer = (void *) page_to_phys(image->control_code_page);
278 /* Then copy it */
279 memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len);
280 return 0;
283 void machine_kexec_cleanup(struct kimage *image)
287 void machine_shutdown(void)
291 static void __machine_kexec(void *data)
293 relocate_kernel_t data_mover;
294 struct kimage *image = data;
296 pfault_fini();
297 s390_reset_system();
299 data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page);
301 /* Call the moving routine */
302 (*data_mover)(&image->head, image->start);
303 for (;;);
306 void machine_kexec(struct kimage *image)
308 tracer_disable();
309 #ifdef CONFIG_CRASH_DUMP
310 if (image->type == KEXEC_TYPE_CRASH) {
311 int (*start_kdump)(int) = (void *)image->start;
312 int rc;
313 __arch_local_irq_stnsm(0xfb); /* disable DAT */
314 rc = start_kdump(0);
315 __arch_local_irq_stosm(0x04); /* enable DAT */
316 if (rc)
317 return;
318 smp_switch_to_ipl_cpu(__machine_kdump, image);
320 #endif
321 smp_send_stop();
322 smp_switch_to_ipl_cpu(__machine_kexec, image);