aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/reboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r--arch/x86/kernel/reboot.c141
1 files changed, 133 insertions, 8 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index f4c93f1cfc19..61f718df6eec 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -21,6 +21,9 @@
21# include <asm/iommu.h> 21# include <asm/iommu.h>
22#endif 22#endif
23 23
24#include <mach_ipi.h>
25
26
24/* 27/*
25 * Power off function, if any 28 * Power off function, if any
26 */ 29 */
@@ -29,18 +32,17 @@ EXPORT_SYMBOL(pm_power_off);
29 32
30static const struct desc_ptr no_idt = {}; 33static const struct desc_ptr no_idt = {};
31static int reboot_mode; 34static int reboot_mode;
32/* 35enum reboot_type reboot_type = BOOT_KBD;
33 * Keyboard reset and triple fault may result in INIT, not RESET, which
34 * doesn't work when we're in vmx root mode. Try ACPI first.
35 */
36enum reboot_type reboot_type = BOOT_ACPI;
37int reboot_force; 36int reboot_force;
38 37
39#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 38#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
40static int reboot_cpu = -1; 39static int reboot_cpu = -1;
41#endif 40#endif
42 41
43/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] 42/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
43bool port_cf9_safe = false;
44
45/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
44 warm Don't set the cold reboot flag 46 warm Don't set the cold reboot flag
45 cold Set the cold reboot flag 47 cold Set the cold reboot flag
46 bios Reboot by jumping through the BIOS (only for X86_32) 48 bios Reboot by jumping through the BIOS (only for X86_32)
@@ -49,6 +51,7 @@ static int reboot_cpu = -1;
49 kbd Use the keyboard controller. cold reset (default) 51 kbd Use the keyboard controller. cold reset (default)
50 acpi Use the RESET_REG in the FADT 52 acpi Use the RESET_REG in the FADT
51 efi Use efi reset_system runtime service 53 efi Use efi reset_system runtime service
54 pci Use the so-called "PCI reset register", CF9
52 force Avoid anything that could hang. 55 force Avoid anything that could hang.
53 */ 56 */
54static int __init reboot_setup(char *str) 57static int __init reboot_setup(char *str)
@@ -83,6 +86,7 @@ static int __init reboot_setup(char *str)
83 case 'k': 86 case 'k':
84 case 't': 87 case 't':
85 case 'e': 88 case 'e':
89 case 'p':
86 reboot_type = *str; 90 reboot_type = *str;
87 break; 91 break;
88 92
@@ -173,6 +177,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
173 DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 177 DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
174 }, 178 },
175 }, 179 },
180 { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
181 .callback = set_bios_reboot,
182 .ident = "Dell OptiPlex 330",
183 .matches = {
184 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
185 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
186 DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
187 },
188 },
176 { /* Handle problems with rebooting on Dell 2400's */ 189 { /* Handle problems with rebooting on Dell 2400's */
177 .callback = set_bios_reboot, 190 .callback = set_bios_reboot,
178 .ident = "Dell PowerEdge 2400", 191 .ident = "Dell PowerEdge 2400",
@@ -399,12 +412,27 @@ static void native_machine_emergency_restart(void)
399 reboot_type = BOOT_KBD; 412 reboot_type = BOOT_KBD;
400 break; 413 break;
401 414
402
403 case BOOT_EFI: 415 case BOOT_EFI:
404 if (efi_enabled) 416 if (efi_enabled)
405 efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, 417 efi.reset_system(reboot_mode ?
418 EFI_RESET_WARM :
419 EFI_RESET_COLD,
406 EFI_SUCCESS, 0, NULL); 420 EFI_SUCCESS, 0, NULL);
421 reboot_type = BOOT_KBD;
422 break;
423
424 case BOOT_CF9:
425 port_cf9_safe = true;
426 /* fall through */
407 427
428 case BOOT_CF9_COND:
429 if (port_cf9_safe) {
430 u8 cf9 = inb(0xcf9) & ~6;
431 outb(cf9|2, 0xcf9); /* Request hard reset */
432 udelay(50);
433 outb(cf9|6, 0xcf9); /* Actually do the reset */
434 udelay(50);
435 }
408 reboot_type = BOOT_KBD; 436 reboot_type = BOOT_KBD;
409 break; 437 break;
410 } 438 }
@@ -465,6 +493,11 @@ static void native_machine_restart(char *__unused)
465 493
466static void native_machine_halt(void) 494static void native_machine_halt(void)
467{ 495{
496 /* stop other cpus and apics */
497 machine_shutdown();
498
499 /* stop this cpu */
500 stop_this_cpu(NULL);
468} 501}
469 502
470static void native_machine_power_off(void) 503static void native_machine_power_off(void)
@@ -518,3 +551,95 @@ void machine_crash_shutdown(struct pt_regs *regs)
518 machine_ops.crash_shutdown(regs); 551 machine_ops.crash_shutdown(regs);
519} 552}
520#endif 553#endif
554
555
556#if defined(CONFIG_SMP)
557
558/* This keeps a track of which one is crashing cpu. */
559static int crashing_cpu;
560static nmi_shootdown_cb shootdown_callback;
561
562static atomic_t waiting_for_crash_ipi;
563
564static int crash_nmi_callback(struct notifier_block *self,
565 unsigned long val, void *data)
566{
567 int cpu;
568
569 if (val != DIE_NMI_IPI)
570 return NOTIFY_OK;
571
572 cpu = raw_smp_processor_id();
573
574 /* Don't do anything if this handler is invoked on crashing cpu.
575 * Otherwise, system will completely hang. Crashing cpu can get
576 * an NMI if system was initially booted with nmi_watchdog parameter.
577 */
578 if (cpu == crashing_cpu)
579 return NOTIFY_STOP;
580 local_irq_disable();
581
582 shootdown_callback(cpu, (struct die_args *)data);
583
584 atomic_dec(&waiting_for_crash_ipi);
585 /* Assume hlt works */
586 halt();
587 for (;;)
588 cpu_relax();
589
590 return 1;
591}
592
593static void smp_send_nmi_allbutself(void)
594{
595 cpumask_t mask = cpu_online_map;
596 cpu_clear(safe_smp_processor_id(), mask);
597 if (!cpus_empty(mask))
598 send_IPI_mask(mask, NMI_VECTOR);
599}
600
601static struct notifier_block crash_nmi_nb = {
602 .notifier_call = crash_nmi_callback,
603};
604
605/* Halt all other CPUs, calling the specified function on each of them
606 *
607 * This function can be used to halt all other CPUs on crash
608 * or emergency reboot time. The function passed as parameter
609 * will be called inside a NMI handler on all CPUs.
610 */
611void nmi_shootdown_cpus(nmi_shootdown_cb callback)
612{
613 unsigned long msecs;
614 local_irq_disable();
615
616 /* Make a note of crashing cpu. Will be used in NMI callback.*/
617 crashing_cpu = safe_smp_processor_id();
618
619 shootdown_callback = callback;
620
621 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
622 /* Would it be better to replace the trap vector here? */
623 if (register_die_notifier(&crash_nmi_nb))
624 return; /* return what? */
625 /* Ensure the new callback function is set before sending
626 * out the NMI
627 */
628 wmb();
629
630 smp_send_nmi_allbutself();
631
632 msecs = 1000; /* Wait at most a second for the other cpus to stop */
633 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
634 mdelay(1);
635 msecs--;
636 }
637
638 /* Leave the nmi callback set */
639}
640#else /* !CONFIG_SMP */
641void nmi_shootdown_cpus(nmi_shootdown_cb callback)
642{
643 /* No other CPUs to shoot down */
644}
645#endif