Linux 2.6.39-rc2
[deliverable/linux.git] / arch / x86 / kernel / reboot.c
CommitLineData
1da177e4 1#include <linux/module.h>
cd6ed525 2#include <linux/reboot.h>
4d022e35
MB
3#include <linux/init.h>
4#include <linux/pm.h>
5#include <linux/efi.h>
6c6c51e4 6#include <linux/dmi.h>
d43c36dc 7#include <linux/sched.h>
69575d38 8#include <linux/tboot.h>
ca444564 9#include <linux/delay.h>
4d022e35
MB
10#include <acpi/reboot.h>
11#include <asm/io.h>
1da177e4 12#include <asm/apic.h>
4d37e7e3 13#include <asm/desc.h>
4d022e35 14#include <asm/hpet.h>
68db065c 15#include <asm/pgtable.h>
4412620f 16#include <asm/proto.h>
973efae2 17#include <asm/reboot_fixups.h>
07f3331c 18#include <asm/reboot.h>
82487711 19#include <asm/pci_x86.h>
d176720d 20#include <asm/virtext.h>
96b89dc6 21#include <asm/cpu.h>
c410b830 22#include <asm/nmi.h>
1da177e4 23
4d022e35 24#ifdef CONFIG_X86_32
4d022e35
MB
25# include <linux/ctype.h>
26# include <linux/mc146818rtc.h>
4d022e35 27#else
338bac52 28# include <asm/x86_init.h>
4d022e35
MB
29#endif
30
1da177e4
LT
31/*
32 * Power off function, if any
33 */
34void (*pm_power_off)(void);
129f6946 35EXPORT_SYMBOL(pm_power_off);
1da177e4 36
ebdd561a 37static const struct desc_ptr no_idt = {};
1da177e4 38static int reboot_mode;
8d00450d 39enum reboot_type reboot_type = BOOT_KBD;
4d022e35 40int reboot_force;
1da177e4 41
4d022e35 42#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
1da177e4 43static int reboot_cpu = -1;
1da177e4 44#endif
4d022e35 45
d176720d
EH
46/* This is set if we need to go through the 'emergency' path.
47 * When machine_emergency_restart() is called, we may be on
48 * an inconsistent state and won't be able to do a clean cleanup
49 */
50static int reboot_emergency;
51
14d7ca5c
PA
52/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
53bool port_cf9_safe = false;
54
55/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
4d022e35
MB
56 warm Don't set the cold reboot flag
57 cold Set the cold reboot flag
58 bios Reboot by jumping through the BIOS (only for X86_32)
59 smp Reboot by executing reset on BSP or other CPU (only for X86_32)
60 triple Force a triple fault (init)
61 kbd Use the keyboard controller. cold reset (default)
62 acpi Use the RESET_REG in the FADT
63 efi Use efi reset_system runtime service
14d7ca5c 64 pci Use the so-called "PCI reset register", CF9
4d022e35
MB
65 force Avoid anything that could hang.
66 */
1da177e4
LT
67static int __init reboot_setup(char *str)
68{
4d022e35 69 for (;;) {
1da177e4 70 switch (*str) {
4d022e35 71 case 'w':
1da177e4
LT
72 reboot_mode = 0x1234;
73 break;
4d022e35
MB
74
75 case 'c':
76 reboot_mode = 0;
1da177e4 77 break;
4d022e35
MB
78
79#ifdef CONFIG_X86_32
1da177e4 80#ifdef CONFIG_SMP
4d022e35 81 case 's':
6f673d83 82 if (isdigit(*(str+1))) {
1da177e4 83 reboot_cpu = (int) (*(str+1) - '0');
6f673d83 84 if (isdigit(*(str+2)))
1da177e4
LT
85 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
86 }
4d022e35
MB
87 /* we will leave sorting out the final value
88 when we are ready to reboot, since we might not
f6e9456c 89 have detected BSP APIC ID or smp_num_cpu */
1da177e4 90 break;
4d022e35
MB
91#endif /* CONFIG_SMP */
92
93 case 'b':
1da177e4 94#endif
4d022e35
MB
95 case 'a':
96 case 'k':
97 case 't':
98 case 'e':
14d7ca5c 99 case 'p':
4d022e35
MB
100 reboot_type = *str;
101 break;
102
103 case 'f':
104 reboot_force = 1;
105 break;
1da177e4 106 }
4d022e35
MB
107
108 str = strchr(str, ',');
109 if (str)
1da177e4
LT
110 str++;
111 else
112 break;
113 }
114 return 1;
115}
116
117__setup("reboot=", reboot_setup);
118
4d022e35
MB
119
120#ifdef CONFIG_X86_32
1da177e4
LT
121/*
122 * Reboot options and system auto-detection code provided by
123 * Dell Inc. so their systems "just work". :-)
124 */
125
126/*
4d022e35
MB
127 * Some machines require the "reboot=b" commandline option,
128 * this quirk makes that automatic.
1da177e4 129 */
1855256c 130static int __init set_bios_reboot(const struct dmi_system_id *d)
1da177e4 131{
4d022e35
MB
132 if (reboot_type != BOOT_BIOS) {
133 reboot_type = BOOT_BIOS;
1da177e4
LT
134 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
135 }
136 return 0;
137}
138
1da177e4 139static struct dmi_system_id __initdata reboot_dmi_table[] = {
b9e82af8
TG
140 { /* Handle problems with rebooting on Dell E520's */
141 .callback = set_bios_reboot,
142 .ident = "Dell E520",
143 .matches = {
144 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
145 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
146 },
147 },
1da177e4 148 { /* Handle problems with rebooting on Dell 1300's */
dd2a1305 149 .callback = set_bios_reboot,
1da177e4
LT
150 .ident = "Dell PowerEdge 1300",
151 .matches = {
152 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
153 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
154 },
155 },
156 { /* Handle problems with rebooting on Dell 300's */
157 .callback = set_bios_reboot,
158 .ident = "Dell PowerEdge 300",
159 .matches = {
160 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
161 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
162 },
163 },
df2edcf3
JJ
164 { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
165 .callback = set_bios_reboot,
166 .ident = "Dell OptiPlex 745",
167 .matches = {
168 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
169 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
df2edcf3
JJ
170 },
171 },
fc115bf1
CK
172 { /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
173 .callback = set_bios_reboot,
174 .ident = "Dell OptiPlex 745",
175 .matches = {
176 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
177 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
178 DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
179 },
180 },
fc1c8925
HAA
181 { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
182 .callback = set_bios_reboot,
183 .ident = "Dell OptiPlex 745",
184 .matches = {
185 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
186 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
187 DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
188 },
189 },
093bac15
SC
190 { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
191 .callback = set_bios_reboot,
192 .ident = "Dell OptiPlex 330",
193 .matches = {
194 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
195 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
196 DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
197 },
198 },
4a4aca64
JD
199 { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
200 .callback = set_bios_reboot,
201 .ident = "Dell OptiPlex 360",
202 .matches = {
203 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
204 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
205 DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
206 },
207 },
35ea63d7
LO
208 { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
209 .callback = set_bios_reboot,
210 .ident = "Dell OptiPlex 760",
211 .matches = {
212 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
213 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
214 DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
215 },
216 },
1da177e4
LT
217 { /* Handle problems with rebooting on Dell 2400's */
218 .callback = set_bios_reboot,
219 .ident = "Dell PowerEdge 2400",
220 .matches = {
221 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
222 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
223 },
224 },
fab3b58d
IM
225 { /* Handle problems with rebooting on Dell T5400's */
226 .callback = set_bios_reboot,
227 .ident = "Dell Precision T5400",
228 .matches = {
229 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
230 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
231 },
232 },
890ffedc
TB
233 { /* Handle problems with rebooting on Dell T7400's */
234 .callback = set_bios_reboot,
235 .ident = "Dell Precision T7400",
236 .matches = {
237 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
238 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
239 },
240 },
766c3f94 241 { /* Handle problems with rebooting on HP laptops */
d91b14c4 242 .callback = set_bios_reboot,
766c3f94 243 .ident = "HP Compaq Laptop",
d91b14c4
TV
244 .matches = {
245 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
766c3f94 246 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
d91b14c4
TV
247 },
248 },
dd4124a8
LO
249 { /* Handle problems with rebooting on Dell XPS710 */
250 .callback = set_bios_reboot,
251 .ident = "Dell XPS710",
252 .matches = {
253 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
254 DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
255 },
256 },
c5da9a2b
AC
257 { /* Handle problems with rebooting on Dell DXP061 */
258 .callback = set_bios_reboot,
259 .ident = "Dell DXP061",
260 .matches = {
261 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
262 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
263 },
264 },
88dff493
ZR
265 { /* Handle problems with rebooting on Sony VGN-Z540N */
266 .callback = set_bios_reboot,
267 .ident = "Sony VGN-Z540N",
268 .matches = {
269 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
270 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
271 },
272 },
77f32dfd
DT
273 { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */
274 .callback = set_bios_reboot,
275 .ident = "CompuLab SBC-FITPC2",
276 .matches = {
277 DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
278 DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
279 },
280 },
4832ddda
LO
281 { /* Handle problems with rebooting on ASUS P4S800 */
282 .callback = set_bios_reboot,
283 .ident = "ASUS P4S800",
284 .matches = {
285 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
286 DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
287 },
288 },
e19e074b
KK
289 { /* Handle problems with rebooting on VersaLogic Menlow boards */
290 .callback = set_bios_reboot,
291 .ident = "VersaLogic Menlow based board",
292 .matches = {
293 DMI_MATCH(DMI_BOARD_VENDOR, "VersaLogic Corporation"),
294 DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"),
295 },
296 },
1da177e4
LT
297 { }
298};
299
300static int __init reboot_init(void)
301{
302 dmi_check_system(reboot_dmi_table);
303 return 0;
304}
1da177e4
LT
305core_initcall(reboot_init);
306
3d35ac34
PA
307extern const unsigned char machine_real_restart_asm[];
308extern const u64 machine_real_restart_gdt[3];
1da177e4 309
3d35ac34 310void machine_real_restart(unsigned int type)
1da177e4 311{
3d35ac34
PA
312 void *restart_va;
313 unsigned long restart_pa;
314 void (*restart_lowmem)(unsigned int);
315 u64 *lowmem_gdt;
1da177e4 316
1da177e4
LT
317 local_irq_disable();
318
319 /* Write zero to CMOS register number 0x0f, which the BIOS POST
320 routine will recognize as telling it to do a proper reboot. (Well
321 that's what this book in front of me says -- it may only apply to
322 the Phoenix BIOS though, it's not clear). At the same time,
323 disable NMIs by setting the top bit in the CMOS address register,
324 as we're about to do peculiar things to the CPU. I'm not sure if
325 `outb_p' is needed instead of just `outb'. Use it to be on the
326 safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
327 */
62dbc210 328 spin_lock(&rtc_lock);
1da177e4 329 CMOS_WRITE(0x00, 0x8f);
62dbc210 330 spin_unlock(&rtc_lock);
1da177e4 331
1da177e4 332 /*
b40827fa 333 * Switch back to the initial page table.
1da177e4 334 */
b40827fa 335 load_cr3(initial_page_table);
1da177e4
LT
336
337 /* Write 0x1234 to absolute memory location 0x472. The BIOS reads
338 this on booting to tell it to "Bypass memory test (also warm
339 boot)". This seems like a fairly standard thing that gets set by
340 REBOOT.COM programs, and the previous reset routine did this
341 too. */
1da177e4
LT
342 *((unsigned short *)0x472) = reboot_mode;
343
3d35ac34
PA
344 /* Patch the GDT in the low memory trampoline */
345 lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
346
347 restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
348 restart_pa = virt_to_phys(restart_va);
349 restart_lowmem = (void (*)(unsigned int))restart_pa;
350
351 /* GDT[0]: GDT self-pointer */
352 lowmem_gdt[0] =
353 (u64)(sizeof(machine_real_restart_gdt) - 1) +
354 ((u64)virt_to_phys(lowmem_gdt) << 16);
355 /* GDT[1]: 64K real mode code segment */
356 lowmem_gdt[1] =
357 GDT_ENTRY(0x009b, restart_pa, 0xffff);
358
359 /* Jump to the identity-mapped low memory code */
360 restart_lowmem(type);
1da177e4 361}
129f6946
AD
362#ifdef CONFIG_APM_MODULE
363EXPORT_SYMBOL(machine_real_restart);
364#endif
1da177e4 365
4d022e35
MB
366#endif /* CONFIG_X86_32 */
367
6c6c51e4 368/*
498cdbfb 369 * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
6c6c51e4
PM
370 */
371static int __init set_pci_reboot(const struct dmi_system_id *d)
372{
373 if (reboot_type != BOOT_CF9) {
374 reboot_type = BOOT_CF9;
375 printk(KERN_INFO "%s series board detected. "
376 "Selecting PCI-method for reboots.\n", d->ident);
377 }
378 return 0;
379}
380
381static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
3e03bbea 382 { /* Handle problems with rebooting on Apple MacBook5 */
6c6c51e4 383 .callback = set_pci_reboot,
3e03bbea 384 .ident = "Apple MacBook5",
6c6c51e4
PM
385 .matches = {
386 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
3e03bbea 387 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
6c6c51e4
PM
388 },
389 },
3e03bbea 390 { /* Handle problems with rebooting on Apple MacBookPro5 */
498cdbfb 391 .callback = set_pci_reboot,
3e03bbea 392 .ident = "Apple MacBookPro5",
498cdbfb
OÇ
393 .matches = {
394 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
3e03bbea 395 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
498cdbfb
OÇ
396 },
397 },
05154752
GH
398 { /* Handle problems with rebooting on Apple Macmini3,1 */
399 .callback = set_pci_reboot,
400 .ident = "Apple Macmini3,1",
401 .matches = {
402 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
403 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
404 },
405 },
0a832320
JM
406 { /* Handle problems with rebooting on the iMac9,1. */
407 .callback = set_pci_reboot,
408 .ident = "Apple iMac9,1",
409 .matches = {
410 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
411 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
412 },
413 },
6c6c51e4
PM
414 { }
415};
416
417static int __init pci_reboot_init(void)
418{
419 dmi_check_system(pci_reboot_dmi_table);
420 return 0;
421}
422core_initcall(pci_reboot_init);
423
4d022e35
MB
424static inline void kb_wait(void)
425{
426 int i;
427
c84d6af8
AC
428 for (i = 0; i < 0x10000; i++) {
429 if ((inb(0x64) & 0x02) == 0)
4d022e35 430 break;
c84d6af8
AC
431 udelay(2);
432 }
4d022e35
MB
433}
434
d176720d
EH
435static void vmxoff_nmi(int cpu, struct die_args *args)
436{
437 cpu_emergency_vmxoff();
438}
439
440/* Use NMIs as IPIs to tell all CPUs to disable virtualization
441 */
442static void emergency_vmx_disable_all(void)
443{
444 /* Just make sure we won't change CPUs while doing this */
445 local_irq_disable();
446
447 /* We need to disable VMX on all CPUs before rebooting, otherwise
448 * we risk hanging up the machine, because the CPU ignore INIT
449 * signals when VMX is enabled.
450 *
451 * We can't take any locks and we may be on an inconsistent
452 * state, so we use NMIs as IPIs to tell the other CPUs to disable
453 * VMX and halt.
454 *
455 * For safety, we will avoid running the nmi_shootdown_cpus()
456 * stuff unnecessarily, but we don't have a way to check
457 * if other CPUs have VMX enabled. So we will call it only if the
458 * CPU we are running on has VMX enabled.
459 *
460 * We will miss cases where VMX is not enabled on all CPUs. This
461 * shouldn't do much harm because KVM always enable VMX on all
462 * CPUs anyway. But we can miss it on the small window where KVM
463 * is still enabling VMX.
464 */
465 if (cpu_has_vmx() && cpu_vmx_enabled()) {
466 /* Disable VMX on this CPU.
467 */
468 cpu_vmxoff();
469
470 /* Halt and disable VMX on the other CPUs */
471 nmi_shootdown_cpus(vmxoff_nmi);
472
473 }
474}
475
476
7432d149
IM
477void __attribute__((weak)) mach_reboot_fixups(void)
478{
479}
480
416e2d63 481static void native_machine_emergency_restart(void)
1da177e4 482{
4d022e35
MB
483 int i;
484
d176720d
EH
485 if (reboot_emergency)
486 emergency_vmx_disable_all();
487
840c2baf
JC
488 tboot_shutdown(TB_SHUTDOWN_REBOOT);
489
4d022e35
MB
490 /* Tell the BIOS if we want cold or warm reboot */
491 *((unsigned short *)__va(0x472)) = reboot_mode;
492
493 for (;;) {
494 /* Could also try the reset bit in the Hammer NB */
495 switch (reboot_type) {
496 case BOOT_KBD:
7432d149
IM
497 mach_reboot_fixups(); /* for board specific fixups */
498
4d022e35
MB
499 for (i = 0; i < 10; i++) {
500 kb_wait();
501 udelay(50);
502 outb(0xfe, 0x64); /* pulse reset low */
503 udelay(50);
504 }
505
506 case BOOT_TRIPLE:
ebdd561a 507 load_idt(&no_idt);
4d022e35
MB
508 __asm__ __volatile__("int3");
509
510 reboot_type = BOOT_KBD;
511 break;
512
513#ifdef CONFIG_X86_32
514 case BOOT_BIOS:
3d35ac34 515 machine_real_restart(MRR_BIOS);
4d022e35
MB
516
517 reboot_type = BOOT_KBD;
518 break;
519#endif
520
521 case BOOT_ACPI:
522 acpi_reboot();
523 reboot_type = BOOT_KBD;
524 break;
525
4d022e35
MB
526 case BOOT_EFI:
527 if (efi_enabled)
14d7ca5c
PA
528 efi.reset_system(reboot_mode ?
529 EFI_RESET_WARM :
530 EFI_RESET_COLD,
4d022e35 531 EFI_SUCCESS, 0, NULL);
b47b9288 532 reboot_type = BOOT_KBD;
14d7ca5c 533 break;
4d022e35 534
14d7ca5c
PA
535 case BOOT_CF9:
536 port_cf9_safe = true;
537 /* fall through */
4d022e35 538
14d7ca5c
PA
539 case BOOT_CF9_COND:
540 if (port_cf9_safe) {
541 u8 cf9 = inb(0xcf9) & ~6;
542 outb(cf9|2, 0xcf9); /* Request hard reset */
543 udelay(50);
544 outb(cf9|6, 0xcf9); /* Actually do the reset */
545 udelay(50);
546 }
4d022e35
MB
547 reboot_type = BOOT_KBD;
548 break;
549 }
550 }
551}
552
3c62c625 553void native_machine_shutdown(void)
4d022e35
MB
554{
555 /* Stop the cpus and apics */
1da177e4 556#ifdef CONFIG_SMP
dd2a1305
EB
557
558 /* The boot cpu is always logical cpu 0 */
65c01184 559 int reboot_cpu_id = 0;
dd2a1305 560
4d022e35 561#ifdef CONFIG_X86_32
dd2a1305 562 /* See if there has been given a command line override */
9628937d 563 if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
0bc3cc03 564 cpu_online(reboot_cpu))
dd2a1305 565 reboot_cpu_id = reboot_cpu;
4d022e35 566#endif
1da177e4 567
4d022e35 568 /* Make certain the cpu I'm about to reboot on is online */
0bc3cc03 569 if (!cpu_online(reboot_cpu_id))
dd2a1305 570 reboot_cpu_id = smp_processor_id();
dd2a1305
EB
571
572 /* Make certain I only run on the appropriate processor */
9628937d 573 set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
dd2a1305 574
4d022e35
MB
575 /* O.K Now that I'm on the appropriate processor,
576 * stop all of the others.
1da177e4 577 */
76fac077 578 stop_other_cpus();
4d022e35 579#endif
1da177e4
LT
580
581 lapic_shutdown();
582
583#ifdef CONFIG_X86_IO_APIC
584 disable_IO_APIC();
585#endif
4d022e35 586
c86c7fbc
OH
587#ifdef CONFIG_HPET_TIMER
588 hpet_disable();
589#endif
dd2a1305 590
4d022e35 591#ifdef CONFIG_X86_64
338bac52 592 x86_platform.iommu_shutdown();
4d022e35 593#endif
973efae2
JF
594}
595
d176720d
EH
596static void __machine_emergency_restart(int emergency)
597{
598 reboot_emergency = emergency;
599 machine_ops.emergency_restart();
600}
601
416e2d63 602static void native_machine_restart(char *__unused)
dd2a1305 603{
4d022e35 604 printk("machine restart\n");
1da177e4 605
4d022e35
MB
606 if (!reboot_force)
607 machine_shutdown();
d176720d 608 __machine_emergency_restart(0);
4a1421f8
EB
609}
610
416e2d63 611static void native_machine_halt(void)
1da177e4 612{
d3ec5cae
IV
613 /* stop other cpus and apics */
614 machine_shutdown();
615
840c2baf
JC
616 tboot_shutdown(TB_SHUTDOWN_HALT);
617
d3ec5cae
IV
618 /* stop this cpu */
619 stop_this_cpu(NULL);
1da177e4
LT
620}
621
416e2d63 622static void native_machine_power_off(void)
1da177e4 623{
6e3fbee5 624 if (pm_power_off) {
4d022e35
MB
625 if (!reboot_force)
626 machine_shutdown();
1da177e4 627 pm_power_off();
6e3fbee5 628 }
840c2baf
JC
629 /* a fallback in case there is no PM info available */
630 tboot_shutdown(TB_SHUTDOWN_HALT);
1da177e4
LT
631}
632
07f3331c 633struct machine_ops machine_ops = {
416e2d63
JB
634 .power_off = native_machine_power_off,
635 .shutdown = native_machine_shutdown,
636 .emergency_restart = native_machine_emergency_restart,
637 .restart = native_machine_restart,
ed23dc6f
GC
638 .halt = native_machine_halt,
639#ifdef CONFIG_KEXEC
640 .crash_shutdown = native_machine_crash_shutdown,
641#endif
07f3331c 642};
416e2d63
JB
643
644void machine_power_off(void)
645{
646 machine_ops.power_off();
647}
648
649void machine_shutdown(void)
650{
651 machine_ops.shutdown();
652}
653
654void machine_emergency_restart(void)
655{
d176720d 656 __machine_emergency_restart(1);
416e2d63
JB
657}
658
659void machine_restart(char *cmd)
660{
661 machine_ops.restart(cmd);
662}
663
664void machine_halt(void)
665{
666 machine_ops.halt();
667}
668
ed23dc6f
GC
669#ifdef CONFIG_KEXEC
670void machine_crash_shutdown(struct pt_regs *regs)
671{
672 machine_ops.crash_shutdown(regs);
673}
674#endif
2ddded21
EH
675
676
bb8dd270 677#if defined(CONFIG_SMP)
2ddded21
EH
678
679/* This keeps a track of which one is crashing cpu. */
680static int crashing_cpu;
681static nmi_shootdown_cb shootdown_callback;
682
683static atomic_t waiting_for_crash_ipi;
684
685static int crash_nmi_callback(struct notifier_block *self,
686 unsigned long val, void *data)
687{
688 int cpu;
689
c410b830 690 if (val != DIE_NMI)
2ddded21
EH
691 return NOTIFY_OK;
692
693 cpu = raw_smp_processor_id();
694
695 /* Don't do anything if this handler is invoked on crashing cpu.
696 * Otherwise, system will completely hang. Crashing cpu can get
697 * an NMI if system was initially booted with nmi_watchdog parameter.
698 */
699 if (cpu == crashing_cpu)
700 return NOTIFY_STOP;
701 local_irq_disable();
702
703 shootdown_callback(cpu, (struct die_args *)data);
704
705 atomic_dec(&waiting_for_crash_ipi);
706 /* Assume hlt works */
707 halt();
708 for (;;)
709 cpu_relax();
710
711 return 1;
712}
713
714static void smp_send_nmi_allbutself(void)
715{
dac5f412 716 apic->send_IPI_allbutself(NMI_VECTOR);
2ddded21
EH
717}
718
719static struct notifier_block crash_nmi_nb = {
720 .notifier_call = crash_nmi_callback,
166d7514
DZ
721 /* we want to be the first one called */
722 .priority = NMI_LOCAL_HIGH_PRIOR+1,
2ddded21
EH
723};
724
bb8dd270
EH
725/* Halt all other CPUs, calling the specified function on each of them
726 *
727 * This function can be used to halt all other CPUs on crash
728 * or emergency reboot time. The function passed as parameter
729 * will be called inside a NMI handler on all CPUs.
730 */
2ddded21
EH
731void nmi_shootdown_cpus(nmi_shootdown_cb callback)
732{
733 unsigned long msecs;
c415b3dc 734 local_irq_disable();
2ddded21
EH
735
736 /* Make a note of crashing cpu. Will be used in NMI callback.*/
737 crashing_cpu = safe_smp_processor_id();
738
739 shootdown_callback = callback;
740
741 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
742 /* Would it be better to replace the trap vector here? */
743 if (register_die_notifier(&crash_nmi_nb))
744 return; /* return what? */
745 /* Ensure the new callback function is set before sending
746 * out the NMI
747 */
748 wmb();
749
750 smp_send_nmi_allbutself();
751
752 msecs = 1000; /* Wait at most a second for the other cpus to stop */
753 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
754 mdelay(1);
755 msecs--;
756 }
757
758 /* Leave the nmi callback set */
759}
bb8dd270
EH
760#else /* !CONFIG_SMP */
761void nmi_shootdown_cpus(nmi_shootdown_cb callback)
762{
763 /* No other CPUs to shoot down */
764}
2ddded21 765#endif
This page took 0.690889 seconds and 5 git commands to generate.