aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorZou Nan hai <nanhai.zou@intel.com>2006-12-07 12:51:35 -0500
committerTony Luck <tony.luck@intel.com>2006-12-07 12:51:35 -0500
commita79561134f38de12dce14ed72138f38e55ef53fc (patch)
treeabe109dbe85e5b0085ba9b9a7eed7cc623d67eec /arch
parent620034c84d1d939717bdfbe02c51a3fee43541c3 (diff)
[IA64] IA64 Kexec/kdump
Changes and updates. 1. Remove fake rendz path and related code according to discuss with Khalid Aziz. 2. fc.i offset fix in relocate_kernel.S. 3. iospic shutdown code eoi and mask race fix from Fujitsu. 4. Warm boot hook in machine_kexec to SN SAL code from Jack Steiner. 5. Send slave to SAL slave loop patch from Jay Lan. 6. Kdump on non-recoverable MCA event patch from Jay Lan 7. Use CTL_UNNUMBERED in kdump_on_init sysctl. Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/Kconfig23
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/crash.c245
-rw-r--r--arch/ia64/kernel/efi.c65
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/ia64/kernel/iosapic.c21
-rw-r--r--arch/ia64/kernel/machine_kexec.c133
-rw-r--r--arch/ia64/kernel/mca.c5
-rw-r--r--arch/ia64/kernel/relocate_kernel.S334
-rw-r--r--arch/ia64/kernel/setup.c38
-rw-r--r--arch/ia64/kernel/smp.c28
-rw-r--r--arch/ia64/sn/kernel/setup.c8
12 files changed, 898 insertions, 5 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 683b12c6f76c..75d839715b2f 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -434,6 +434,29 @@ config IA64_ESI
434 434
435source "drivers/sn/Kconfig" 435source "drivers/sn/Kconfig"
436 436
437config KEXEC
438 bool "kexec system call (EXPERIMENTAL)"
439 depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
440 help
441 kexec is a system call that implements the ability to shutdown your
442 current kernel, and to start another kernel. It is like a reboot
443 but it is indepedent of the system firmware. And like a reboot
444 you can start any kernel with it, not just Linux.
445
446 The name comes from the similiarity to the exec system call.
447
448 It is an ongoing process to be certain the hardware in a machine
449 is properly shutdown, so do not be surprised if this code does not
450 initially work for you. It may help to enable device hotplugging
451 support. As of this writing the exact hardware interface is
452 strongly in flux, so no good recommendation can be made.
453
454config CRASH_DUMP
455 bool "kernel crash dumps (EXPERIMENTAL)"
456 depends on EXPERIMENTAL && IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
457 help
458 Generate crash dump after being started by kexec.
459
437source "drivers/firmware/Kconfig" 460source "drivers/firmware/Kconfig"
438 461
439source "fs/Kconfig.binfmt" 462source "fs/Kconfig.binfmt"
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index cfa099b04cda..8ae384eb5357 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
28obj-$(CONFIG_CPU_FREQ) += cpufreq/ 28obj-$(CONFIG_CPU_FREQ) += cpufreq/
29obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o 29obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
30obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o 30obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
31obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
31obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o 32obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
32obj-$(CONFIG_AUDIT) += audit.o 33obj-$(CONFIG_AUDIT) += audit.o
33obj-$(CONFIG_PCI_MSI) += msi_ia64.o 34obj-$(CONFIG_PCI_MSI) += msi_ia64.o
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
new file mode 100644
index 000000000000..0aabedf95dad
--- /dev/null
+++ b/arch/ia64/kernel/crash.c
@@ -0,0 +1,245 @@
1/*
2 * arch/ia64/kernel/crash.c
3 *
4 * Architecture specific (ia64) functions for kexec based crash dumps.
5 *
6 * Created by: Khalid Aziz <khalid.aziz@hp.com>
7 * Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
8 * Copyright (C) 2005 Intel Corp Zou Nan hai <nanhai.zou@intel.com>
9 *
10 */
11#include <linux/smp.h>
12#include <linux/delay.h>
13#include <linux/crash_dump.h>
14#include <linux/bootmem.h>
15#include <linux/kexec.h>
16#include <linux/elfcore.h>
17#include <linux/sysctl.h>
18#include <linux/init.h>
19
20#include <asm/kdebug.h>
21#include <asm/mca.h>
22#include <asm/uaccess.h>
23
24int kdump_status[NR_CPUS];
25atomic_t kdump_cpu_freezed;
26atomic_t kdump_in_progress;
27int kdump_on_init = 1;
28ssize_t
29copy_oldmem_page(unsigned long pfn, char *buf,
30 size_t csize, unsigned long offset, int userbuf)
31{
32 void *vaddr;
33
34 if (!csize)
35 return 0;
36 vaddr = __va(pfn<<PAGE_SHIFT);
37 if (userbuf) {
38 if (copy_to_user(buf, (vaddr + offset), csize)) {
39 return -EFAULT;
40 }
41 } else
42 memcpy(buf, (vaddr + offset), csize);
43 return csize;
44}
45
46static inline Elf64_Word
47*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
48 size_t data_len)
49{
50 struct elf_note *note = (struct elf_note *)buf;
51 note->n_namesz = strlen(name) + 1;
52 note->n_descsz = data_len;
53 note->n_type = type;
54 buf += (sizeof(*note) + 3)/4;
55 memcpy(buf, name, note->n_namesz);
56 buf += (note->n_namesz + 3)/4;
57 memcpy(buf, data, data_len);
58 buf += (data_len + 3)/4;
59 return buf;
60}
61
62static void
63final_note(void *buf)
64{
65 memset(buf, 0, sizeof(struct elf_note));
66}
67
68extern void ia64_dump_cpu_regs(void *);
69
70static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus);
71
72void
73crash_save_this_cpu()
74{
75 void *buf;
76 unsigned long cfm, sof, sol;
77
78 int cpu = smp_processor_id();
79 struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu);
80
81 elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg);
82 memset(prstatus, 0, sizeof(*prstatus));
83 prstatus->pr_pid = current->pid;
84
85 ia64_dump_cpu_regs(dst);
86 cfm = dst[43];
87 sol = (cfm >> 7) & 0x7f;
88 sof = cfm & 0x7f;
89 dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46],
90 sof - sol);
91
92 buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
93 if (!buf)
94 return;
95 buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus,
96 sizeof(*prstatus));
97 final_note(buf);
98}
99
100static int
101kdump_wait_cpu_freeze(void)
102{
103 int cpu_num = num_online_cpus() - 1;
104 int timeout = 1000;
105 while(timeout-- > 0) {
106 if (atomic_read(&kdump_cpu_freezed) == cpu_num)
107 return 0;
108 udelay(1000);
109 }
110 return 1;
111}
112
113void
114machine_crash_shutdown(struct pt_regs *pt)
115{
116 /* This function is only called after the system
117 * has paniced or is otherwise in a critical state.
118 * The minimum amount of code to allow a kexec'd kernel
119 * to run successfully needs to happen here.
120 *
121 * In practice this means shooting down the other cpus in
122 * an SMP system.
123 */
124 kexec_disable_iosapic();
125#ifdef CONFIG_SMP
126 kdump_smp_send_stop();
127 if (kdump_wait_cpu_freeze() && kdump_on_init) {
128 //not all cpu response to IPI, send INIT to freeze them
129 kdump_smp_send_init();
130 }
131#endif
132}
133
134static void
135machine_kdump_on_init(void)
136{
137 local_irq_disable();
138 kexec_disable_iosapic();
139 machine_kexec(ia64_kimage);
140}
141
142void
143kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
144{
145 int cpuid;
146 local_irq_disable();
147 cpuid = smp_processor_id();
148 crash_save_this_cpu();
149 current->thread.ksp = (__u64)info->sw - 16;
150 atomic_inc(&kdump_cpu_freezed);
151 kdump_status[cpuid] = 1;
152 mb();
153 if (cpuid == 0) {
154 for (;;)
155 cpu_relax();
156 } else
157 ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
158}
159
160static int
161kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
162{
163 struct ia64_mca_notify_die *nd;
164 struct die_args *args = data;
165
166 if (!kdump_on_init)
167 return NOTIFY_DONE;
168
169 if (val != DIE_INIT_MONARCH_ENTER &&
170 val != DIE_INIT_SLAVE_ENTER &&
171 val != DIE_MCA_RENDZVOUS_LEAVE &&
172 val != DIE_MCA_MONARCH_LEAVE)
173 return NOTIFY_DONE;
174
175 nd = (struct ia64_mca_notify_die *)args->err;
176 /* Reason code 1 means machine check rendezous*/
177 if ((val == DIE_INIT_MONARCH_ENTER || DIE_INIT_SLAVE_ENTER) &&
178 nd->sos->rv_rc == 1)
179 return NOTIFY_DONE;
180
181 switch (val) {
182 case DIE_INIT_MONARCH_ENTER:
183 machine_kdump_on_init();
184 break;
185 case DIE_INIT_SLAVE_ENTER:
186 unw_init_running(kdump_cpu_freeze, NULL);
187 break;
188 case DIE_MCA_RENDZVOUS_LEAVE:
189 if (atomic_read(&kdump_in_progress))
190 unw_init_running(kdump_cpu_freeze, NULL);
191 break;
192 case DIE_MCA_MONARCH_LEAVE:
193 /* die_register->signr indicate if MCA is recoverable */
194 if (!args->signr)
195 machine_kdump_on_init();
196 break;
197 }
198 return NOTIFY_DONE;
199}
200
201#ifdef CONFIG_SYSCTL
202static ctl_table kdump_on_init_table[] = {
203 {
204 .ctl_name = CTL_UNNUMBERED,
205 .procname = "kdump_on_init",
206 .data = &kdump_on_init,
207 .maxlen = sizeof(int),
208 .mode = 0644,
209 .proc_handler = &proc_dointvec,
210 },
211 { .ctl_name = 0 }
212};
213
214static ctl_table sys_table[] = {
215 {
216 .ctl_name = CTL_KERN,
217 .procname = "kernel",
218 .mode = 0555,
219 .child = kdump_on_init_table,
220 },
221 { .ctl_name = 0 }
222};
223#endif
224
225static int
226machine_crash_setup(void)
227{
228 char *from = strstr(saved_command_line, "elfcorehdr=");
229 static struct notifier_block kdump_init_notifier_nb = {
230 .notifier_call = kdump_init_notifier,
231 };
232 int ret;
233 if (from)
234 elfcorehdr_addr = memparse(from+11, &from);
235 saved_max_pfn = (unsigned long)-1;
236 if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
237 return ret;
238#ifdef CONFIG_SYSCTL
239 register_sysctl_table(sys_table, 0);
240#endif
241 return 0;
242}
243
244__initcall(machine_crash_setup);
245
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index bb8770a177b5..9b96e7dbaf67 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -26,6 +26,7 @@
26#include <linux/types.h> 26#include <linux/types.h>
27#include <linux/time.h> 27#include <linux/time.h>
28#include <linux/efi.h> 28#include <linux/efi.h>
29#include <linux/kexec.h>
29 30
30#include <asm/io.h> 31#include <asm/io.h>
31#include <asm/kregs.h> 32#include <asm/kregs.h>
@@ -41,7 +42,7 @@ extern efi_status_t efi_call_phys (void *, ...);
41struct efi efi; 42struct efi efi;
42EXPORT_SYMBOL(efi); 43EXPORT_SYMBOL(efi);
43static efi_runtime_services_t *runtime; 44static efi_runtime_services_t *runtime;
44static unsigned long mem_limit = ~0UL, max_addr = ~0UL; 45static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
45 46
46#define efi_call_virt(f, args...) (*(f))(args) 47#define efi_call_virt(f, args...) (*(f))(args)
47 48
@@ -421,6 +422,8 @@ efi_init (void)
421 mem_limit = memparse(cp + 4, &cp); 422 mem_limit = memparse(cp + 4, &cp);
422 } else if (memcmp(cp, "max_addr=", 9) == 0) { 423 } else if (memcmp(cp, "max_addr=", 9) == 0) {
423 max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); 424 max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
425 } else if (memcmp(cp, "min_addr=", 9) == 0) {
426 min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
424 } else { 427 } else {
425 while (*cp != ' ' && *cp) 428 while (*cp != ' ' && *cp)
426 ++cp; 429 ++cp;
@@ -428,6 +431,8 @@ efi_init (void)
428 ++cp; 431 ++cp;
429 } 432 }
430 } 433 }
434 if (min_addr != 0UL)
435 printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20);
431 if (max_addr != ~0UL) 436 if (max_addr != ~0UL)
432 printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20); 437 printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20);
433 438
@@ -894,7 +899,8 @@ find_memmap_space (void)
894 as = max(contig_low, md->phys_addr); 899 as = max(contig_low, md->phys_addr);
895 ae = min(contig_high, efi_md_end(md)); 900 ae = min(contig_high, efi_md_end(md));
896 901
897 /* keep within max_addr= command line arg */ 902 /* keep within max_addr= and min_addr= command line arg */
903 as = max(as, min_addr);
898 ae = min(ae, max_addr); 904 ae = min(ae, max_addr);
899 if (ae <= as) 905 if (ae <= as)
900 continue; 906 continue;
@@ -1004,7 +1010,8 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
1004 } else 1010 } else
1005 ae = efi_md_end(md); 1011 ae = efi_md_end(md);
1006 1012
1007 /* keep within max_addr= command line arg */ 1013 /* keep within max_addr= and min_addr= command line arg */
1014 as = max(as, min_addr);
1008 ae = min(ae, max_addr); 1015 ae = min(ae, max_addr);
1009 if (ae <= as) 1016 if (ae <= as)
1010 continue; 1017 continue;
@@ -1116,6 +1123,58 @@ efi_initialize_iomem_resources(struct resource *code_resource,
1116 */ 1123 */
1117 insert_resource(res, code_resource); 1124 insert_resource(res, code_resource);
1118 insert_resource(res, data_resource); 1125 insert_resource(res, data_resource);
1126#ifdef CONFIG_KEXEC
1127 insert_resource(res, &efi_memmap_res);
1128 insert_resource(res, &boot_param_res);
1129 if (crashk_res.end > crashk_res.start)
1130 insert_resource(res, &crashk_res);
1131#endif
1119 } 1132 }
1120 } 1133 }
1121} 1134}
1135
1136#ifdef CONFIG_KEXEC
1137/* find a block of memory aligned to 64M exclude reserved regions
1138 rsvd_regions are sorted
1139 */
1140unsigned long
1141kdump_find_rsvd_region (unsigned long size,
1142 struct rsvd_region *r, int n)
1143{
1144 int i;
1145 u64 start, end;
1146 u64 alignment = 1UL << _PAGE_SIZE_64M;
1147 void *efi_map_start, *efi_map_end, *p;
1148 efi_memory_desc_t *md;
1149 u64 efi_desc_size;
1150
1151 efi_map_start = __va(ia64_boot_param->efi_memmap);
1152 efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
1153 efi_desc_size = ia64_boot_param->efi_memdesc_size;
1154
1155 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
1156 md = p;
1157 if (!efi_wb(md))
1158 continue;
1159 start = ALIGN(md->phys_addr, alignment);
1160 end = efi_md_end(md);
1161 for (i = 0; i < n; i++) {
1162 if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
1163 if (__pa(r[i].start) > start + size)
1164 return start;
1165 start = ALIGN(__pa(r[i].end), alignment);
1166 if (i < n-1 && __pa(r[i+1].start) < start + size)
1167 continue;
1168 else
1169 break;
1170 }
1171 }
1172 if (end > start + size)
1173 return start;
1174 }
1175
1176 printk(KERN_WARNING "Cannot reserve 0x%lx byte of memory for crashdump\n",
1177 size);
1178 return ~0UL;
1179}
1180#endif
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 3390b7c5a63f..15234ed3a341 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1575,7 +1575,7 @@ sys_call_table:
1575 data8 sys_mq_timedreceive // 1265 1575 data8 sys_mq_timedreceive // 1265
1576 data8 sys_mq_notify 1576 data8 sys_mq_notify
1577 data8 sys_mq_getsetattr 1577 data8 sys_mq_getsetattr
1578 data8 sys_ni_syscall // reserved for kexec_load 1578 data8 sys_kexec_load
1579 data8 sys_ni_syscall // reserved for vserver 1579 data8 sys_ni_syscall // reserved for vserver
1580 data8 sys_waitid // 1270 1580 data8 sys_waitid // 1270
1581 data8 sys_add_key 1581 data8 sys_add_key
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 60d64950e3c2..0fc5fb7865cf 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -288,6 +288,27 @@ nop (unsigned int irq)
288 /* do nothing... */ 288 /* do nothing... */
289} 289}
290 290
291
292#ifdef CONFIG_KEXEC
293void
294kexec_disable_iosapic(void)
295{
296 struct iosapic_intr_info *info;
297 struct iosapic_rte_info *rte;
298 u8 vec = 0;
299 for (info = iosapic_intr_info; info <
300 iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
301 list_for_each_entry(rte, &info->rtes,
302 rte_list) {
303 iosapic_write(rte->addr,
304 IOSAPIC_RTE_LOW(rte->rte_index),
305 IOSAPIC_MASK|vec);
306 iosapic_eoi(rte->addr, vec);
307 }
308 }
309}
310#endif
311
291static void 312static void
292mask_irq (unsigned int irq) 313mask_irq (unsigned int irq)
293{ 314{
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
new file mode 100644
index 000000000000..468233fa2cee
--- /dev/null
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -0,0 +1,133 @@
1/*
2 * arch/ia64/kernel/machine_kexec.c
3 *
4 * Handle transition of Linux booting another kernel
5 * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P.
6 * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com>
7 * Copyright (C) 2006 Intel Corp, Zou Nan hai <nanhai.zou@intel.com>
8 *
9 * This source code is licensed under the GNU General Public License,
10 * Version 2. See the file COPYING for more details.
11 */
12
13#include <linux/mm.h>
14#include <linux/kexec.h>
15#include <linux/cpu.h>
16#include <linux/irq.h>
17#include <asm/mmu_context.h>
18#include <asm/setup.h>
19#include <asm/delay.h>
20#include <asm/meminit.h>
21
22typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long,
23 struct ia64_boot_param *, unsigned long);
24
25struct kimage *ia64_kimage;
26
27struct resource efi_memmap_res = {
28 .name = "EFI Memory Map",
29 .start = 0,
30 .end = 0,
31 .flags = IORESOURCE_BUSY | IORESOURCE_MEM
32};
33
34struct resource boot_param_res = {
35 .name = "Boot parameter",
36 .start = 0,
37 .end = 0,
38 .flags = IORESOURCE_BUSY | IORESOURCE_MEM
39};
40
41
42/*
43 * Do what every setup is needed on image and the
44 * reboot code buffer to allow us to avoid allocations
45 * later.
46 */
47int machine_kexec_prepare(struct kimage *image)
48{
49 void *control_code_buffer;
50 const unsigned long *func;
51
52 func = (unsigned long *)&relocate_new_kernel;
53 /* Pre-load control code buffer to minimize work in kexec path */
54 control_code_buffer = page_address(image->control_code_page);
55 memcpy((void *)control_code_buffer, (const void *)func[0],
56 relocate_new_kernel_size);
57 flush_icache_range((unsigned long)control_code_buffer,
58 (unsigned long)control_code_buffer + relocate_new_kernel_size);
59 ia64_kimage = image;
60
61 return 0;
62}
63
64void machine_kexec_cleanup(struct kimage *image)
65{
66}
67
68void machine_shutdown(void)
69{
70 int cpu;
71
72 for_each_online_cpu(cpu) {
73 if (cpu != smp_processor_id())
74 cpu_down(cpu);
75 }
76 kexec_disable_iosapic();
77}
78
79/*
80 * Do not allocate memory (or fail in any way) in machine_kexec().
81 * We are past the point of no return, committed to rebooting now.
82 */
83extern void *efi_get_pal_addr(void);
84static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
85{
86 struct kimage *image = arg;
87 relocate_new_kernel_t rnk;
88 void *pal_addr = efi_get_pal_addr();
89 unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
90 unsigned long vector;
91 int ii;
92
93 if (image->type == KEXEC_TYPE_CRASH) {
94 crash_save_this_cpu();
95 current->thread.ksp = (__u64)info->sw - 16;
96 }
97
98 /* Interrupts aren't acceptable while we reboot */
99 local_irq_disable();
100
101 /* Mask CMC and Performance Monitor interrupts */
102 ia64_setreg(_IA64_REG_CR_PMV, 1 << 16);
103 ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16);
104
105 /* Mask ITV and Local Redirect Registers */
106 ia64_set_itv(1 << 16);
107 ia64_set_lrr0(1 << 16);
108 ia64_set_lrr1(1 << 16);
109
110 /* terminate possible nested in-service interrupts */
111 for (ii = 0; ii < 16; ii++)
112 ia64_eoi();
113
114 /* unmask TPR and clear any pending interrupts */
115 ia64_setreg(_IA64_REG_CR_TPR, 0);
116 ia64_srlz_d();
117 vector = ia64_get_ivr();
118 while (vector != IA64_SPURIOUS_INT_VECTOR) {
119 ia64_eoi();
120 vector = ia64_get_ivr();
121 }
122 platform_kernel_launch_event();
123 rnk = (relocate_new_kernel_t)&code_addr;
124 (*rnk)(image->head, image->start, ia64_boot_param,
125 GRANULEROUNDDOWN((unsigned long) pal_addr));
126 BUG();
127}
128
129void machine_kexec(struct kimage *image)
130{
131 unw_init_running(ia64_machine_kexec, image);
132 for(;;);
133}
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 6bedd97570ca..87c1c4f42872 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -82,6 +82,7 @@
82#include <asm/system.h> 82#include <asm/system.h>
83#include <asm/sal.h> 83#include <asm/sal.h>
84#include <asm/mca.h> 84#include <asm/mca.h>
85#include <asm/kexec.h>
85 86
86#include <asm/irq.h> 87#include <asm/irq.h>
87#include <asm/hw_irq.h> 88#include <asm/hw_irq.h>
@@ -1238,6 +1239,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
1238 } else { 1239 } else {
1239 /* Dump buffered message to console */ 1240 /* Dump buffered message to console */
1240 ia64_mlogbuf_finish(1); 1241 ia64_mlogbuf_finish(1);
1242#ifdef CONFIG_CRASH_DUMP
1243 atomic_set(&kdump_in_progress, 1);
1244 monarch_cpu = -1;
1245#endif
1241 } 1246 }
1242 if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) 1247 if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover)
1243 == NOTIFY_STOP) 1248 == NOTIFY_STOP)
diff --git a/arch/ia64/kernel/relocate_kernel.S b/arch/ia64/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..ae473e3f2a0d
--- /dev/null
+++ b/arch/ia64/kernel/relocate_kernel.S
@@ -0,0 +1,334 @@
1/*
2 * arch/ia64/kernel/relocate_kernel.S
3 *
4 * Relocate kexec'able kernel and start it
5 *
6 * Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
7 * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com>
8 * Copyright (C) 2005 Intel Corp, Zou Nan hai <nanhai.zou@intel.com>
9 *
10 * This source code is licensed under the GNU General Public License,
11 * Version 2. See the file COPYING for more details.
12 */
13#include <asm/asmmacro.h>
14#include <asm/kregs.h>
15#include <asm/page.h>
16#include <asm/pgtable.h>
17#include <asm/mca_asm.h>
18
19 /* Must be relocatable PIC code callable as a C function
20 */
21GLOBAL_ENTRY(relocate_new_kernel)
22 .prologue
23 alloc r31=ar.pfs,4,0,0,0
24 .body
25.reloc_entry:
26{
27 rsm psr.i| psr.ic
28 mov r2=ip
29}
30 ;;
31{
32 flushrs // must be first insn in group
33 srlz.i
34}
35 ;;
36 dep r2=0,r2,61,3 //to physical address
37 ;;
38 //first switch to physical mode
39 add r3=1f-.reloc_entry, r2
40 movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC
41 mov ar.rsc=0 // put RSE in enforced lazy mode
42 ;;
43 add sp=(memory_stack_end - 16 - .reloc_entry),r2
44 add r8=(register_stack - .reloc_entry),r2
45 ;;
46 mov r18=ar.rnat
47 mov ar.bspstore=r8
48 ;;
49 mov cr.ipsr=r16
50 mov cr.iip=r3
51 mov cr.ifs=r0
52 srlz.i
53 ;;
54 mov ar.rnat=r18
55 rfi
56 ;;
571:
58 //physical mode code begin
59 mov b6=in1
60 dep r28=0,in2,61,3 //to physical address
61
62 // purge all TC entries
63#define O(member) IA64_CPUINFO_##member##_OFFSET
64 GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2
65 ;;
66 addl r17=O(PTCE_STRIDE),r2
67 addl r2=O(PTCE_BASE),r2
68 ;;
69 ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base
70 ld4 r19=[r2],4 // r19=ptce_count[0]
71 ld4 r21=[r17],4 // r21=ptce_stride[0]
72 ;;
73 ld4 r20=[r2] // r20=ptce_count[1]
74 ld4 r22=[r17] // r22=ptce_stride[1]
75 mov r24=r0
76 ;;
77 adds r20=-1,r20
78 ;;
79#undef O
802:
81 cmp.ltu p6,p7=r24,r19
82(p7) br.cond.dpnt.few 4f
83 mov ar.lc=r20
843:
85 ptc.e r18
86 ;;
87 add r18=r22,r18
88 br.cloop.sptk.few 3b
89 ;;
90 add r18=r21,r18
91 add r24=1,r24
92 ;;
93 br.sptk.few 2b
944:
95 srlz.i
96 ;;
97 //purge TR entry for kernel text and data
98 movl r16=KERNEL_START
99 mov r18=KERNEL_TR_PAGE_SHIFT<<2
100 ;;
101 ptr.i r16, r18
102 ptr.d r16, r18
103 ;;
104 srlz.i
105 ;;
106
107 // purge TR entry for percpu data
108 movl r16=PERCPU_ADDR
109 mov r18=PERCPU_PAGE_SHIFT<<2
110 ;;
111 ptr.d r16,r18
112 ;;
113 srlz.d
114 ;;
115
116 // purge TR entry for pal code
117 mov r16=in3
118 mov r18=IA64_GRANULE_SHIFT<<2
119 ;;
120 ptr.i r16,r18
121 ;;
122 srlz.i
123 ;;
124
125 // purge TR entry for stack
126 mov r16=IA64_KR(CURRENT_STACK)
127 ;;
128 shl r16=r16,IA64_GRANULE_SHIFT
129 movl r19=PAGE_OFFSET
130 ;;
131 add r16=r19,r16
132 mov r18=IA64_GRANULE_SHIFT<<2
133 ;;
134 ptr.d r16,r18
135 ;;
136 srlz.i
137 ;;
138
139 //copy segments
140 movl r16=PAGE_MASK
141 mov r30=in0 // in0 is page_list
142 br.sptk.few .dest_page
143 ;;
144.loop:
145 ld8 r30=[in0], 8;;
146.dest_page:
147 tbit.z p0, p6=r30, 0;; // 0x1 dest page
148(p6) and r17=r30, r16
149(p6) br.cond.sptk.few .loop;;
150
151 tbit.z p0, p6=r30, 1;; // 0x2 indirect page
152(p6) and in0=r30, r16
153(p6) br.cond.sptk.few .loop;;
154
155 tbit.z p0, p6=r30, 2;; // 0x4 end flag
156(p6) br.cond.sptk.few .end_loop;;
157
158 tbit.z p6, p0=r30, 3;; // 0x8 source page
159(p6) br.cond.sptk.few .loop
160
161 and r18=r30, r16
162
163 // simple copy page, may optimize later
164 movl r14=PAGE_SIZE/8 - 1;;
165 mov ar.lc=r14;;
1661:
167 ld8 r14=[r18], 8;;
168 st8 [r17]=r14;;
169 fc.i r17
170 add r17=8, r17
171 br.ctop.sptk.few 1b
172 br.sptk.few .loop
173 ;;
174
175.end_loop:
176 sync.i // for fc.i
177 ;;
178 srlz.i
179 ;;
180 srlz.d
181 ;;
182 br.call.sptk.many b0=b6;;
183
184.align 32
185memory_stack:
186 .fill 8192, 1, 0
187memory_stack_end:
188register_stack:
189 .fill 8192, 1, 0
190register_stack_end:
191relocate_new_kernel_end:
192END(relocate_new_kernel)
193
194.global relocate_new_kernel_size
195relocate_new_kernel_size:
196 data8 relocate_new_kernel_end - relocate_new_kernel
197
198GLOBAL_ENTRY(ia64_dump_cpu_regs)
199 .prologue
200 alloc loc0=ar.pfs,1,2,0,0
201 .body
202 mov ar.rsc=0 // put RSE in enforced lazy mode
203 add loc1=4*8, in0 // save r4 and r5 first
204 ;;
205{
206 flushrs // flush dirty regs to backing store
207 srlz.i
208}
209 st8 [loc1]=r4, 8
210 ;;
211 st8 [loc1]=r5, 8
212 ;;
213 add loc1=32*8, in0
214 mov r4=ar.rnat
215 ;;
216 st8 [in0]=r0, 8 // r0
217 st8 [loc1]=r4, 8 // rnat
218 mov r5=pr
219 ;;
220 st8 [in0]=r1, 8 // r1
221 st8 [loc1]=r5, 8 // pr
222 mov r4=b0
223 ;;
224 st8 [in0]=r2, 8 // r2
225 st8 [loc1]=r4, 8 // b0
226 mov r5=b1;
227 ;;
228 st8 [in0]=r3, 24 // r3
229 st8 [loc1]=r5, 8 // b1
230 mov r4=b2
231 ;;
232 st8 [in0]=r6, 8 // r6
233 st8 [loc1]=r4, 8 // b2
234 mov r5=b3
235 ;;
236 st8 [in0]=r7, 8 // r7
237 st8 [loc1]=r5, 8 // b3
238 mov r4=b4
239 ;;
240 st8 [in0]=r8, 8 // r8
241 st8 [loc1]=r4, 8 // b4
242 mov r5=b5
243 ;;
244 st8 [in0]=r9, 8 // r9
245 st8 [loc1]=r5, 8 // b5
246 mov r4=b6
247 ;;
248 st8 [in0]=r10, 8 // r10
249 st8 [loc1]=r5, 8 // b6
250 mov r5=b7
251 ;;
252 st8 [in0]=r11, 8 // r11
253 st8 [loc1]=r5, 8 // b7
254 mov r4=b0
255 ;;
256 st8 [in0]=r12, 8 // r12
257 st8 [loc1]=r4, 8 // ip
258 mov r5=loc0
259 ;;
260 st8 [in0]=r13, 8 // r13
261 extr.u r5=r5, 0, 38 // ar.pfs.pfm
262 mov r4=r0 // user mask
263 ;;
264 st8 [in0]=r14, 8 // r14
265 st8 [loc1]=r5, 8 // cfm
266 ;;
267 st8 [in0]=r15, 8 // r15
268 st8 [loc1]=r4, 8 // user mask
269 mov r5=ar.rsc
270 ;;
271 st8 [in0]=r16, 8 // r16
272 st8 [loc1]=r5, 8 // ar.rsc
273 mov r4=ar.bsp
274 ;;
275 st8 [in0]=r17, 8 // r17
276 st8 [loc1]=r4, 8 // ar.bsp
277 mov r5=ar.bspstore
278 ;;
279 st8 [in0]=r18, 8 // r18
280 st8 [loc1]=r5, 8 // ar.bspstore
281 mov r4=ar.rnat
282 ;;
283 st8 [in0]=r19, 8 // r19
284 st8 [loc1]=r4, 8 // ar.rnat
285 mov r5=ar.ccv
286 ;;
287 st8 [in0]=r20, 8 // r20
288 st8 [loc1]=r5, 8 // ar.ccv
289 mov r4=ar.unat
290 ;;
291 st8 [in0]=r21, 8 // r21
292 st8 [loc1]=r4, 8 // ar.unat
293 mov r5 = ar.fpsr
294 ;;
295 st8 [in0]=r22, 8 // r22
296 st8 [loc1]=r5, 8 // ar.fpsr
297 mov r4 = ar.unat
298 ;;
299 st8 [in0]=r23, 8 // r23
300 st8 [loc1]=r4, 8 // unat
301 mov r5 = ar.fpsr
302 ;;
303 st8 [in0]=r24, 8 // r24
304 st8 [loc1]=r5, 8 // fpsr
305 mov r4 = ar.pfs
306 ;;
307 st8 [in0]=r25, 8 // r25
308 st8 [loc1]=r4, 8 // ar.pfs
309 mov r5 = ar.lc
310 ;;
311 st8 [in0]=r26, 8 // r26
312 st8 [loc1]=r5, 8 // ar.lc
313 mov r4 = ar.ec
314 ;;
315 st8 [in0]=r27, 8 // r27
316 st8 [loc1]=r4, 8 // ar.ec
317 mov r5 = ar.csd
318 ;;
319 st8 [in0]=r28, 8 // r28
320 st8 [loc1]=r5, 8 // ar.csd
321 mov r4 = ar.ssd
322 ;;
323 st8 [in0]=r29, 8 // r29
324 st8 [loc1]=r4, 8 // ar.ssd
325 ;;
326 st8 [in0]=r30, 8 // r30
327 ;;
328 st8 [in0]=r31, 8 // r31
329 mov ar.pfs=loc0
330 ;;
331 br.ret.sptk.many rp
332END(ia64_dump_cpu_regs)
333
334
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index d10404a41756..14e1200376a9 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -43,6 +43,8 @@
43#include <linux/initrd.h> 43#include <linux/initrd.h>
44#include <linux/pm.h> 44#include <linux/pm.h>
45#include <linux/cpufreq.h> 45#include <linux/cpufreq.h>
46#include <linux/kexec.h>
47#include <linux/crash_dump.h>
46 48
47#include <asm/ia32.h> 49#include <asm/ia32.h>
48#include <asm/machvec.h> 50#include <asm/machvec.h>
@@ -252,6 +254,41 @@ reserve_memory (void)
252 efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); 254 efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
253 n++; 255 n++;
254 256
257#ifdef CONFIG_KEXEC
258 /* crashkernel=size@offset specifies the size to reserve for a crash
259 * kernel.(offset is ingored for keep compatibility with other archs)
260 * By reserving this memory we guarantee that linux never set's it
261 * up as a DMA target.Useful for holding code to do something
262 * appropriate after a kernel panic.
263 */
264 {
265 char *from = strstr(saved_command_line, "crashkernel=");
266 unsigned long base, size;
267 if (from) {
268 size = memparse(from + 12, &from);
269 if (size) {
270 sort_regions(rsvd_region, n);
271 base = kdump_find_rsvd_region(size,
272 rsvd_region, n);
273 if (base != ~0UL) {
274 rsvd_region[n].start =
275 (unsigned long)__va(base);
276 rsvd_region[n].end =
277 (unsigned long)__va(base + size);
278 n++;
279 crashk_res.start = base;
280 crashk_res.end = base + size - 1;
281 }
282 }
283 }
284 efi_memmap_res.start = ia64_boot_param->efi_memmap;
285 efi_memmap_res.end = efi_memmap_res.start +
286 ia64_boot_param->efi_memmap_size;
287 boot_param_res.start = __pa(ia64_boot_param);
288 boot_param_res.end = boot_param_res.start +
289 sizeof(*ia64_boot_param);
290 }
291#endif
255 /* end of memory marker */ 292 /* end of memory marker */
256 rsvd_region[n].start = ~0UL; 293 rsvd_region[n].start = ~0UL;
257 rsvd_region[n].end = ~0UL; 294 rsvd_region[n].end = ~0UL;
@@ -263,6 +300,7 @@ reserve_memory (void)
263 sort_regions(rsvd_region, num_rsvd_regions); 300 sort_regions(rsvd_region, num_rsvd_regions);
264} 301}
265 302
303
266/** 304/**
267 * find_initrd - get initrd parameters from the boot parameter structure 305 * find_initrd - get initrd parameters from the boot parameter structure
268 * 306 *
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 6ab95ceaf9d4..b1b9aa4364b9 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -30,6 +30,7 @@
30#include <linux/delay.h> 30#include <linux/delay.h>
31#include <linux/efi.h> 31#include <linux/efi.h>
32#include <linux/bitops.h> 32#include <linux/bitops.h>
33#include <linux/kexec.h>
33 34
34#include <asm/atomic.h> 35#include <asm/atomic.h>
35#include <asm/current.h> 36#include <asm/current.h>
@@ -66,6 +67,7 @@ static volatile struct call_data_struct *call_data;
66 67
67#define IPI_CALL_FUNC 0 68#define IPI_CALL_FUNC 0
68#define IPI_CPU_STOP 1 69#define IPI_CPU_STOP 1
70#define IPI_KDUMP_CPU_STOP 3
69 71
70/* This needs to be cacheline aligned because it is written to by *other* CPUs. */ 72/* This needs to be cacheline aligned because it is written to by *other* CPUs. */
71static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; 73static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -155,7 +157,11 @@ handle_IPI (int irq, void *dev_id)
155 case IPI_CPU_STOP: 157 case IPI_CPU_STOP:
156 stop_this_cpu(); 158 stop_this_cpu();
157 break; 159 break;
158 160#ifdef CONFIG_CRASH_DUMP
161 case IPI_KDUMP_CPU_STOP:
162 unw_init_running(kdump_cpu_freeze, NULL);
163 break;
164#endif
159 default: 165 default:
160 printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); 166 printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
161 break; 167 break;
@@ -213,6 +219,26 @@ send_IPI_self (int op)
213 send_IPI_single(smp_processor_id(), op); 219 send_IPI_single(smp_processor_id(), op);
214} 220}
215 221
222#ifdef CONFIG_CRASH_DUMP
223void
224kdump_smp_send_stop()
225{
226 send_IPI_allbutself(IPI_KDUMP_CPU_STOP);
227}
228
229void
230kdump_smp_send_init()
231{
232 unsigned int cpu, self_cpu;
233 self_cpu = smp_processor_id();
234 for_each_online_cpu(cpu) {
235 if (cpu != self_cpu) {
236 if(kdump_status[cpu] == 0)
237 platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
238 }
239 }
240}
241#endif
216/* 242/*
217 * Called with preeemption disabled. 243 * Called with preeemption disabled.
218 */ 244 */
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 1d009f93244d..a934ad069425 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -769,5 +769,13 @@ int sn_prom_feature_available(int id)
769 return 0; 769 return 0;
770 return test_bit(id, sn_prom_features); 770 return test_bit(id, sn_prom_features);
771} 771}
772
773void
774sn_kernel_launch_event(void)
775{
776 /* ignore status until we understand possible failure, if any*/
777 if (ia64_sn_kernel_launch_event())
778 printk(KERN_ERR "KEXEC is not supported in this PROM, Please update the PROM.\n");
779}
772EXPORT_SYMBOL(sn_prom_feature_available); 780EXPORT_SYMBOL(sn_prom_feature_available);
773 781