14d022e35SMiguel Boton #include <linux/module.h> 24d022e35SMiguel Boton #include <linux/reboot.h> 34d022e35SMiguel Boton #include <linux/init.h> 44d022e35SMiguel Boton #include <linux/pm.h> 54d022e35SMiguel Boton #include <linux/efi.h> 66c6c51e4SPaul Mackerras #include <linux/dmi.h> 7d43c36dcSAlexey Dobriyan #include <linux/sched.h> 869575d38SShane Wang #include <linux/tboot.h> 9ca444564SJean Delvare #include <linux/delay.h> 104d022e35SMiguel Boton #include <acpi/reboot.h> 114d022e35SMiguel Boton #include <asm/io.h> 124d022e35SMiguel Boton #include <asm/apic.h> 134d022e35SMiguel Boton #include <asm/desc.h> 144d022e35SMiguel Boton #include <asm/hpet.h> 1568db065cSJeremy Fitzhardinge #include <asm/pgtable.h> 164412620fSDmitri Vorobiev #include <asm/proto.h> 174d022e35SMiguel Boton #include <asm/reboot_fixups.h> 184d022e35SMiguel Boton #include <asm/reboot.h> 1982487711SJaswinder Singh Rajput #include <asm/pci_x86.h> 20d176720dSEduardo Habkost #include <asm/virtext.h> 2196b89dc6SJaswinder Singh Rajput #include <asm/cpu.h> 22c410b830SDon Zickus #include <asm/nmi.h> 234d022e35SMiguel Boton 244d022e35SMiguel Boton #ifdef CONFIG_X86_32 254d022e35SMiguel Boton # include <linux/ctype.h> 264d022e35SMiguel Boton # include <linux/mc146818rtc.h> 274d022e35SMiguel Boton #else 28338bac52SFUJITA Tomonori # include <asm/x86_init.h> 294d022e35SMiguel Boton #endif 304d022e35SMiguel Boton 314d022e35SMiguel Boton /* 324d022e35SMiguel Boton * Power off function, if any 334d022e35SMiguel Boton */ 344d022e35SMiguel Boton void (*pm_power_off)(void); 354d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off); 364d022e35SMiguel Boton 37ebdd561aSJan Beulich static const struct desc_ptr no_idt = {}; 384d022e35SMiguel Boton static int reboot_mode; 39660e34ceSMatthew Garrett enum reboot_type reboot_type = BOOT_ACPI; 404d022e35SMiguel Boton int reboot_force; 414d022e35SMiguel Boton 42*144d102bSMichael D Labriola /* 43*144d102bSMichael D Labriola * This variable is used privately to keep track of whether or not 445955633eSMichael D Labriola * reboot_type is still set to its default value (i.e., reboot= hasn't 455955633eSMichael D Labriola * been set on the command line). This is needed so that we can 465955633eSMichael D Labriola * suppress DMI scanning for reboot quirks. Without it, it's 475955633eSMichael D Labriola * impossible to override a faulty reboot quirk without recompiling. 485955633eSMichael D Labriola */ 495955633eSMichael D Labriola static int reboot_default = 1; 505955633eSMichael D Labriola 514d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 524d022e35SMiguel Boton static int reboot_cpu = -1; 534d022e35SMiguel Boton #endif 544d022e35SMiguel Boton 55*144d102bSMichael D Labriola /* 56*144d102bSMichael D Labriola * This is set if we need to go through the 'emergency' path. 57d176720dSEduardo Habkost * When machine_emergency_restart() is called, we may be on 58d176720dSEduardo Habkost * an inconsistent state and won't be able to do a clean cleanup 59d176720dSEduardo Habkost */ 60d176720dSEduardo Habkost static int reboot_emergency; 61d176720dSEduardo Habkost 6214d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 6314d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 6414d7ca5cSH. Peter Anvin 65*144d102bSMichael D Labriola /* 66*144d102bSMichael D Labriola * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] 67*144d102bSMichael D Labriola * warm Don't set the cold reboot flag 68*144d102bSMichael D Labriola * cold Set the cold reboot flag 69*144d102bSMichael D Labriola * bios Reboot by jumping through the BIOS (only for X86_32) 70*144d102bSMichael D Labriola * smp Reboot by executing reset on BSP or other CPU (only for X86_32) 71*144d102bSMichael D Labriola * triple Force a triple fault (init) 72*144d102bSMichael D Labriola * kbd Use the keyboard controller. cold reset (default) 73*144d102bSMichael D Labriola * acpi Use the RESET_REG in the FADT 74*144d102bSMichael D Labriola * efi Use efi reset_system runtime service 75*144d102bSMichael D Labriola * pci Use the so-called "PCI reset register", CF9 76*144d102bSMichael D Labriola * force Avoid anything that could hang. 774d022e35SMiguel Boton */ 784d022e35SMiguel Boton static int __init reboot_setup(char *str) 794d022e35SMiguel Boton { 804d022e35SMiguel Boton for (;;) { 81*144d102bSMichael D Labriola /* 82*144d102bSMichael D Labriola * Having anything passed on the command line via 835955633eSMichael D Labriola * reboot= will cause us to disable DMI checking 845955633eSMichael D Labriola * below. 855955633eSMichael D Labriola */ 865955633eSMichael D Labriola reboot_default = 0; 875955633eSMichael D Labriola 884d022e35SMiguel Boton switch (*str) { 894d022e35SMiguel Boton case 'w': 904d022e35SMiguel Boton reboot_mode = 0x1234; 914d022e35SMiguel Boton break; 924d022e35SMiguel Boton 934d022e35SMiguel Boton case 'c': 944d022e35SMiguel Boton reboot_mode = 0; 954d022e35SMiguel Boton break; 964d022e35SMiguel Boton 974d022e35SMiguel Boton #ifdef CONFIG_X86_32 984d022e35SMiguel Boton #ifdef CONFIG_SMP 994d022e35SMiguel Boton case 's': 1004d022e35SMiguel Boton if (isdigit(*(str+1))) { 1014d022e35SMiguel Boton reboot_cpu = (int) (*(str+1) - '0'); 1024d022e35SMiguel Boton if (isdigit(*(str+2))) 1034d022e35SMiguel Boton reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); 1044d022e35SMiguel Boton } 105*144d102bSMichael D Labriola /* 106*144d102bSMichael D Labriola * We will leave sorting out the final value 107*144d102bSMichael D Labriola * when we are ready to reboot, since we might not 108*144d102bSMichael D Labriola * have detected BSP APIC ID or smp_num_cpu 109*144d102bSMichael D Labriola */ 1104d022e35SMiguel Boton break; 1114d022e35SMiguel Boton #endif /* CONFIG_SMP */ 1124d022e35SMiguel Boton 1134d022e35SMiguel Boton case 'b': 1144d022e35SMiguel Boton #endif 1154d022e35SMiguel Boton case 'a': 1164d022e35SMiguel Boton case 'k': 1174d022e35SMiguel Boton case 't': 1184d022e35SMiguel Boton case 'e': 11914d7ca5cSH. Peter Anvin case 'p': 1204d022e35SMiguel Boton reboot_type = *str; 1214d022e35SMiguel Boton break; 1224d022e35SMiguel Boton 1234d022e35SMiguel Boton case 'f': 1244d022e35SMiguel Boton reboot_force = 1; 1254d022e35SMiguel Boton break; 1264d022e35SMiguel Boton } 1274d022e35SMiguel Boton 1284d022e35SMiguel Boton str = strchr(str, ','); 1294d022e35SMiguel Boton if (str) 1304d022e35SMiguel Boton str++; 1314d022e35SMiguel Boton else 1324d022e35SMiguel Boton break; 1334d022e35SMiguel Boton } 1344d022e35SMiguel Boton return 1; 1354d022e35SMiguel Boton } 1364d022e35SMiguel Boton 1374d022e35SMiguel Boton __setup("reboot=", reboot_setup); 1384d022e35SMiguel Boton 1394d022e35SMiguel Boton 1404d022e35SMiguel Boton #ifdef CONFIG_X86_32 1414d022e35SMiguel Boton /* 1424d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 1434d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 1444d022e35SMiguel Boton */ 1454d022e35SMiguel Boton 1464d022e35SMiguel Boton /* 1471ef03890SPeter Chubb * Some machines require the "reboot=b" or "reboot=k" commandline options, 1484d022e35SMiguel Boton * this quirk makes that automatic. 1494d022e35SMiguel Boton */ 1504d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 1514d022e35SMiguel Boton { 1524d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 1534d022e35SMiguel Boton reboot_type = BOOT_BIOS; 1544d022e35SMiguel Boton printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); 1554d022e35SMiguel Boton } 1564d022e35SMiguel Boton return 0; 1574d022e35SMiguel Boton } 1584d022e35SMiguel Boton 15957b16594SMichael D Labriola extern const unsigned char machine_real_restart_asm[]; 16057b16594SMichael D Labriola extern const u64 machine_real_restart_gdt[3]; 16157b16594SMichael D Labriola 16257b16594SMichael D Labriola void machine_real_restart(unsigned int type) 16357b16594SMichael D Labriola { 16457b16594SMichael D Labriola void *restart_va; 16557b16594SMichael D Labriola unsigned long restart_pa; 16657b16594SMichael D Labriola void (*restart_lowmem)(unsigned int); 16757b16594SMichael D Labriola u64 *lowmem_gdt; 16857b16594SMichael D Labriola 16957b16594SMichael D Labriola local_irq_disable(); 17057b16594SMichael D Labriola 171*144d102bSMichael D Labriola /* 172*144d102bSMichael D Labriola * Write zero to CMOS register number 0x0f, which the BIOS POST 173*144d102bSMichael D Labriola * routine will recognize as telling it to do a proper reboot. (Well 174*144d102bSMichael D Labriola * that's what this book in front of me says -- it may only apply to 175*144d102bSMichael D Labriola * the Phoenix BIOS though, it's not clear). At the same time, 176*144d102bSMichael D Labriola * disable NMIs by setting the top bit in the CMOS address register, 177*144d102bSMichael D Labriola * as we're about to do peculiar things to the CPU. I'm not sure if 178*144d102bSMichael D Labriola * `outb_p' is needed instead of just `outb'. Use it to be on the 179*144d102bSMichael D Labriola * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 18057b16594SMichael D Labriola */ 18157b16594SMichael D Labriola spin_lock(&rtc_lock); 18257b16594SMichael D Labriola CMOS_WRITE(0x00, 0x8f); 18357b16594SMichael D Labriola spin_unlock(&rtc_lock); 18457b16594SMichael D Labriola 18557b16594SMichael D Labriola /* 18657b16594SMichael D Labriola * Switch back to the initial page table. 18757b16594SMichael D Labriola */ 18857b16594SMichael D Labriola load_cr3(initial_page_table); 18957b16594SMichael D Labriola 190*144d102bSMichael D Labriola /* 191*144d102bSMichael D Labriola * Write 0x1234 to absolute memory location 0x472. The BIOS reads 192*144d102bSMichael D Labriola * this on booting to tell it to "Bypass memory test (also warm 193*144d102bSMichael D Labriola * boot)". This seems like a fairly standard thing that gets set by 194*144d102bSMichael D Labriola * REBOOT.COM programs, and the previous reset routine did this 195*144d102bSMichael D Labriola * too. */ 19657b16594SMichael D Labriola *((unsigned short *)0x472) = reboot_mode; 19757b16594SMichael D Labriola 19857b16594SMichael D Labriola /* Patch the GDT in the low memory trampoline */ 19957b16594SMichael D Labriola lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); 20057b16594SMichael D Labriola 20157b16594SMichael D Labriola restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); 20257b16594SMichael D Labriola restart_pa = virt_to_phys(restart_va); 20357b16594SMichael D Labriola restart_lowmem = (void (*)(unsigned int))restart_pa; 20457b16594SMichael D Labriola 20557b16594SMichael D Labriola /* GDT[0]: GDT self-pointer */ 20657b16594SMichael D Labriola lowmem_gdt[0] = 20757b16594SMichael D Labriola (u64)(sizeof(machine_real_restart_gdt) - 1) + 20857b16594SMichael D Labriola ((u64)virt_to_phys(lowmem_gdt) << 16); 20957b16594SMichael D Labriola /* GDT[1]: 64K real mode code segment */ 21057b16594SMichael D Labriola lowmem_gdt[1] = 21157b16594SMichael D Labriola GDT_ENTRY(0x009b, restart_pa, 0xffff); 21257b16594SMichael D Labriola 21357b16594SMichael D Labriola /* Jump to the identity-mapped low memory code */ 21457b16594SMichael D Labriola restart_lowmem(type); 21557b16594SMichael D Labriola } 21657b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE 21757b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart); 21857b16594SMichael D Labriola #endif 21957b16594SMichael D Labriola 22057b16594SMichael D Labriola #endif /* CONFIG_X86_32 */ 22157b16594SMichael D Labriola 22257b16594SMichael D Labriola /* 22357b16594SMichael D Labriola * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot 22457b16594SMichael D Labriola */ 22557b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d) 22657b16594SMichael D Labriola { 22757b16594SMichael D Labriola if (reboot_type != BOOT_CF9) { 22857b16594SMichael D Labriola reboot_type = BOOT_CF9; 22957b16594SMichael D Labriola printk(KERN_INFO "%s series board detected. " 23057b16594SMichael D Labriola "Selecting PCI-method for reboots.\n", d->ident); 23157b16594SMichael D Labriola } 23257b16594SMichael D Labriola return 0; 23357b16594SMichael D Labriola } 23457b16594SMichael D Labriola 2351ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d) 2361ef03890SPeter Chubb { 2371ef03890SPeter Chubb if (reboot_type != BOOT_KBD) { 2381ef03890SPeter Chubb reboot_type = BOOT_KBD; 2391ef03890SPeter Chubb printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident); 2401ef03890SPeter Chubb } 2411ef03890SPeter Chubb return 0; 2421ef03890SPeter Chubb } 2431ef03890SPeter Chubb 244*144d102bSMichael D Labriola /* 245*144d102bSMichael D Labriola * This is a single dmi_table handling all reboot quirks. Note that 24657b16594SMichael D Labriola * REBOOT_BIOS is only available for 32bit 24757b16594SMichael D Labriola */ 2484d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 24957b16594SMichael D Labriola #ifdef CONFIG_X86_32 2504d022e35SMiguel Boton { /* Handle problems with rebooting on Dell E520's */ 2514d022e35SMiguel Boton .callback = set_bios_reboot, 2524d022e35SMiguel Boton .ident = "Dell E520", 2534d022e35SMiguel Boton .matches = { 2544d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2554d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 2564d022e35SMiguel Boton }, 2574d022e35SMiguel Boton }, 2584d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 1300's */ 2594d022e35SMiguel Boton .callback = set_bios_reboot, 2604d022e35SMiguel Boton .ident = "Dell PowerEdge 1300", 2614d022e35SMiguel Boton .matches = { 2624d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 2634d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 2644d022e35SMiguel Boton }, 2654d022e35SMiguel Boton }, 2664d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 300's */ 2674d022e35SMiguel Boton .callback = set_bios_reboot, 2684d022e35SMiguel Boton .ident = "Dell PowerEdge 300", 2694d022e35SMiguel Boton .matches = { 2704d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 2714d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 2724d022e35SMiguel Boton }, 2734d022e35SMiguel Boton }, 2744d022e35SMiguel Boton { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ 2754d022e35SMiguel Boton .callback = set_bios_reboot, 2764d022e35SMiguel Boton .ident = "Dell OptiPlex 745", 2774d022e35SMiguel Boton .matches = { 2784d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2794d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 2804d022e35SMiguel Boton }, 2814d022e35SMiguel Boton }, 282fc115bf1SColeman Kane { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ 283fc115bf1SColeman Kane .callback = set_bios_reboot, 284fc115bf1SColeman Kane .ident = "Dell OptiPlex 745", 285fc115bf1SColeman Kane .matches = { 286fc115bf1SColeman Kane DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 287fc115bf1SColeman Kane DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 288fc115bf1SColeman Kane DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 289fc115bf1SColeman Kane }, 290fc115bf1SColeman Kane }, 291fc1c8925SHeinz-Ado Arnolds { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 292fc1c8925SHeinz-Ado Arnolds .callback = set_bios_reboot, 293fc1c8925SHeinz-Ado Arnolds .ident = "Dell OptiPlex 745", 294fc1c8925SHeinz-Ado Arnolds .matches = { 295fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 296fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 297fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 298fc1c8925SHeinz-Ado Arnolds }, 299fc1c8925SHeinz-Ado Arnolds }, 300093bac15SSteve Conklin { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 301093bac15SSteve Conklin .callback = set_bios_reboot, 302093bac15SSteve Conklin .ident = "Dell OptiPlex 330", 303093bac15SSteve Conklin .matches = { 304093bac15SSteve Conklin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 305093bac15SSteve Conklin DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 306093bac15SSteve Conklin DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 307093bac15SSteve Conklin }, 308093bac15SSteve Conklin }, 3094a4aca64SJean Delvare { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 3104a4aca64SJean Delvare .callback = set_bios_reboot, 3114a4aca64SJean Delvare .ident = "Dell OptiPlex 360", 3124a4aca64SJean Delvare .matches = { 3134a4aca64SJean Delvare DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 3144a4aca64SJean Delvare DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 3154a4aca64SJean Delvare DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 3164a4aca64SJean Delvare }, 3174a4aca64SJean Delvare }, 31835ea63d7SLeann Ogasawara { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ 31935ea63d7SLeann Ogasawara .callback = set_bios_reboot, 32035ea63d7SLeann Ogasawara .ident = "Dell OptiPlex 760", 32135ea63d7SLeann Ogasawara .matches = { 32235ea63d7SLeann Ogasawara DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 32335ea63d7SLeann Ogasawara DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), 32435ea63d7SLeann Ogasawara DMI_MATCH(DMI_BOARD_NAME, "0G919G"), 32535ea63d7SLeann Ogasawara }, 32635ea63d7SLeann Ogasawara }, 3274d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 2400's */ 3284d022e35SMiguel Boton .callback = set_bios_reboot, 3294d022e35SMiguel Boton .ident = "Dell PowerEdge 2400", 3304d022e35SMiguel Boton .matches = { 3314d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 3324d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 3334d022e35SMiguel Boton }, 3344d022e35SMiguel Boton }, 335fab3b58dSIngo Molnar { /* Handle problems with rebooting on Dell T5400's */ 336fab3b58dSIngo Molnar .callback = set_bios_reboot, 337fab3b58dSIngo Molnar .ident = "Dell Precision T5400", 338fab3b58dSIngo Molnar .matches = { 339fab3b58dSIngo Molnar DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 340fab3b58dSIngo Molnar DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 341fab3b58dSIngo Molnar }, 342fab3b58dSIngo Molnar }, 343890ffedcSThomas Backlund { /* Handle problems with rebooting on Dell T7400's */ 344890ffedcSThomas Backlund .callback = set_bios_reboot, 345890ffedcSThomas Backlund .ident = "Dell Precision T7400", 346890ffedcSThomas Backlund .matches = { 347890ffedcSThomas Backlund DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 348890ffedcSThomas Backlund DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), 349890ffedcSThomas Backlund }, 350890ffedcSThomas Backlund }, 3514d022e35SMiguel Boton { /* Handle problems with rebooting on HP laptops */ 3524d022e35SMiguel Boton .callback = set_bios_reboot, 3534d022e35SMiguel Boton .ident = "HP Compaq Laptop", 3544d022e35SMiguel Boton .matches = { 3554d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 3564d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 3574d022e35SMiguel Boton }, 3584d022e35SMiguel Boton }, 359dd4124a8SLeann Ogasawara { /* Handle problems with rebooting on Dell XPS710 */ 360dd4124a8SLeann Ogasawara .callback = set_bios_reboot, 361dd4124a8SLeann Ogasawara .ident = "Dell XPS710", 362dd4124a8SLeann Ogasawara .matches = { 363dd4124a8SLeann Ogasawara DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 364dd4124a8SLeann Ogasawara DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 365dd4124a8SLeann Ogasawara }, 366dd4124a8SLeann Ogasawara }, 367c5da9a2bSAlan Cox { /* Handle problems with rebooting on Dell DXP061 */ 368c5da9a2bSAlan Cox .callback = set_bios_reboot, 369c5da9a2bSAlan Cox .ident = "Dell DXP061", 370c5da9a2bSAlan Cox .matches = { 371c5da9a2bSAlan Cox DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 372c5da9a2bSAlan Cox DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 373c5da9a2bSAlan Cox }, 374c5da9a2bSAlan Cox }, 37588dff493SZhang Rui { /* Handle problems with rebooting on Sony VGN-Z540N */ 37688dff493SZhang Rui .callback = set_bios_reboot, 37788dff493SZhang Rui .ident = "Sony VGN-Z540N", 37888dff493SZhang Rui .matches = { 37988dff493SZhang Rui DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 38088dff493SZhang Rui DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 38188dff493SZhang Rui }, 38288dff493SZhang Rui }, 38377f32dfdSDenis Turischev { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */ 38477f32dfdSDenis Turischev .callback = set_bios_reboot, 38577f32dfdSDenis Turischev .ident = "CompuLab SBC-FITPC2", 38677f32dfdSDenis Turischev .matches = { 38777f32dfdSDenis Turischev DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"), 38877f32dfdSDenis Turischev DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), 38977f32dfdSDenis Turischev }, 39077f32dfdSDenis Turischev }, 3914832dddaSLeann Ogasawara { /* Handle problems with rebooting on ASUS P4S800 */ 3924832dddaSLeann Ogasawara .callback = set_bios_reboot, 3934832dddaSLeann Ogasawara .ident = "ASUS P4S800", 3944832dddaSLeann Ogasawara .matches = { 3954832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 3964832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 3974832dddaSLeann Ogasawara }, 3984832dddaSLeann Ogasawara }, 39957b16594SMichael D Labriola #endif /* CONFIG_X86_32 */ 40057b16594SMichael D Labriola 401b49c78d4SPeter Chubb { /* Handle reboot issue on Acer Aspire one */ 4021ef03890SPeter Chubb .callback = set_kbd_reboot, 403b49c78d4SPeter Chubb .ident = "Acer Aspire One A110", 404b49c78d4SPeter Chubb .matches = { 405b49c78d4SPeter Chubb DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 406b49c78d4SPeter Chubb DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 407b49c78d4SPeter Chubb }, 408b49c78d4SPeter Chubb }, 4093e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBook5 */ 4106c6c51e4SPaul Mackerras .callback = set_pci_reboot, 4113e03bbeaSShunichi Fuji .ident = "Apple MacBook5", 4126c6c51e4SPaul Mackerras .matches = { 4136c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4143e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), 4156c6c51e4SPaul Mackerras }, 4166c6c51e4SPaul Mackerras }, 4173e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBookPro5 */ 418498cdbfbSOzan Çağlayan .callback = set_pci_reboot, 4193e03bbeaSShunichi Fuji .ident = "Apple MacBookPro5", 420498cdbfbSOzan Çağlayan .matches = { 421498cdbfbSOzan Çağlayan DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4223e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), 423498cdbfbSOzan Çağlayan }, 424498cdbfbSOzan Çağlayan }, 42505154752SGottfried Haider { /* Handle problems with rebooting on Apple Macmini3,1 */ 42605154752SGottfried Haider .callback = set_pci_reboot, 42705154752SGottfried Haider .ident = "Apple Macmini3,1", 42805154752SGottfried Haider .matches = { 42905154752SGottfried Haider DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 43005154752SGottfried Haider DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), 43105154752SGottfried Haider }, 43205154752SGottfried Haider }, 4330a832320SJustin P. Mattock { /* Handle problems with rebooting on the iMac9,1. */ 4340a832320SJustin P. Mattock .callback = set_pci_reboot, 4350a832320SJustin P. Mattock .ident = "Apple iMac9,1", 4360a832320SJustin P. Mattock .matches = { 4370a832320SJustin P. Mattock DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4380a832320SJustin P. Mattock DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), 4390a832320SJustin P. Mattock }, 4400a832320SJustin P. Mattock }, 4413628c3f5SMaxime Ripard { /* Handle problems with rebooting on the Latitude E6320. */ 4423628c3f5SMaxime Ripard .callback = set_pci_reboot, 4433628c3f5SMaxime Ripard .ident = "Dell Latitude E6320", 4443628c3f5SMaxime Ripard .matches = { 4453628c3f5SMaxime Ripard DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 4463628c3f5SMaxime Ripard DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), 4473628c3f5SMaxime Ripard }, 4483628c3f5SMaxime Ripard }, 449b7798d28SDaniel J Blueman { /* Handle problems with rebooting on the Latitude E5420. */ 450b7798d28SDaniel J Blueman .callback = set_pci_reboot, 451b7798d28SDaniel J Blueman .ident = "Dell Latitude E5420", 452b7798d28SDaniel J Blueman .matches = { 453b7798d28SDaniel J Blueman DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 454b7798d28SDaniel J Blueman DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), 455b7798d28SDaniel J Blueman }, 456b7798d28SDaniel J Blueman }, 457a536877eSH. Peter Anvin { /* Handle problems with rebooting on the Latitude E6420. */ 458a536877eSH. Peter Anvin .callback = set_pci_reboot, 459a536877eSH. Peter Anvin .ident = "Dell Latitude E6420", 460a536877eSH. Peter Anvin .matches = { 461a536877eSH. Peter Anvin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 462a536877eSH. Peter Anvin DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), 463a536877eSH. Peter Anvin }, 464a536877eSH. Peter Anvin }, 4656be30bb7SRafael J. Wysocki { /* Handle problems with rebooting on the OptiPlex 990. */ 4666be30bb7SRafael J. Wysocki .callback = set_pci_reboot, 4676be30bb7SRafael J. Wysocki .ident = "Dell OptiPlex 990", 4686be30bb7SRafael J. Wysocki .matches = { 4696be30bb7SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 4706be30bb7SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), 4716be30bb7SRafael J. Wysocki }, 4726be30bb7SRafael J. Wysocki }, 4736c6c51e4SPaul Mackerras { } 4746c6c51e4SPaul Mackerras }; 4756c6c51e4SPaul Mackerras 47657b16594SMichael D Labriola static int __init reboot_init(void) 4776c6c51e4SPaul Mackerras { 478*144d102bSMichael D Labriola /* 479*144d102bSMichael D Labriola * Only do the DMI check if reboot_type hasn't been overridden 4805955633eSMichael D Labriola * on the command line 4815955633eSMichael D Labriola */ 482*144d102bSMichael D Labriola if (reboot_default) 48357b16594SMichael D Labriola dmi_check_system(reboot_dmi_table); 4846c6c51e4SPaul Mackerras return 0; 4856c6c51e4SPaul Mackerras } 48657b16594SMichael D Labriola core_initcall(reboot_init); 4876c6c51e4SPaul Mackerras 4884d022e35SMiguel Boton static inline void kb_wait(void) 4894d022e35SMiguel Boton { 4904d022e35SMiguel Boton int i; 4914d022e35SMiguel Boton 492c84d6af8SAlan Cox for (i = 0; i < 0x10000; i++) { 493c84d6af8SAlan Cox if ((inb(0x64) & 0x02) == 0) 4944d022e35SMiguel Boton break; 495c84d6af8SAlan Cox udelay(2); 496c84d6af8SAlan Cox } 4974d022e35SMiguel Boton } 4984d022e35SMiguel Boton 4999c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs) 500d176720dSEduardo Habkost { 501d176720dSEduardo Habkost cpu_emergency_vmxoff(); 502d176720dSEduardo Habkost } 503d176720dSEduardo Habkost 504*144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ 505d176720dSEduardo Habkost static void emergency_vmx_disable_all(void) 506d176720dSEduardo Habkost { 507d176720dSEduardo Habkost /* Just make sure we won't change CPUs while doing this */ 508d176720dSEduardo Habkost local_irq_disable(); 509d176720dSEduardo Habkost 510*144d102bSMichael D Labriola /* 511*144d102bSMichael D Labriola * We need to disable VMX on all CPUs before rebooting, otherwise 512d176720dSEduardo Habkost * we risk hanging up the machine, because the CPU ignore INIT 513d176720dSEduardo Habkost * signals when VMX is enabled. 514d176720dSEduardo Habkost * 515d176720dSEduardo Habkost * We can't take any locks and we may be on an inconsistent 516d176720dSEduardo Habkost * state, so we use NMIs as IPIs to tell the other CPUs to disable 517d176720dSEduardo Habkost * VMX and halt. 518d176720dSEduardo Habkost * 519d176720dSEduardo Habkost * For safety, we will avoid running the nmi_shootdown_cpus() 520d176720dSEduardo Habkost * stuff unnecessarily, but we don't have a way to check 521d176720dSEduardo Habkost * if other CPUs have VMX enabled. So we will call it only if the 522d176720dSEduardo Habkost * CPU we are running on has VMX enabled. 523d176720dSEduardo Habkost * 524d176720dSEduardo Habkost * We will miss cases where VMX is not enabled on all CPUs. This 525d176720dSEduardo Habkost * shouldn't do much harm because KVM always enable VMX on all 526d176720dSEduardo Habkost * CPUs anyway. But we can miss it on the small window where KVM 527d176720dSEduardo Habkost * is still enabling VMX. 528d176720dSEduardo Habkost */ 529d176720dSEduardo Habkost if (cpu_has_vmx() && cpu_vmx_enabled()) { 530*144d102bSMichael D Labriola /* Disable VMX on this CPU. */ 531d176720dSEduardo Habkost cpu_vmxoff(); 532d176720dSEduardo Habkost 533d176720dSEduardo Habkost /* Halt and disable VMX on the other CPUs */ 534d176720dSEduardo Habkost nmi_shootdown_cpus(vmxoff_nmi); 535d176720dSEduardo Habkost 536d176720dSEduardo Habkost } 537d176720dSEduardo Habkost } 538d176720dSEduardo Habkost 539d176720dSEduardo Habkost 5407432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 5417432d149SIngo Molnar { 5427432d149SIngo Molnar } 5437432d149SIngo Molnar 544660e34ceSMatthew Garrett /* 545660e34ceSMatthew Garrett * Windows compatible x86 hardware expects the following on reboot: 546660e34ceSMatthew Garrett * 547660e34ceSMatthew Garrett * 1) If the FADT has the ACPI reboot register flag set, try it 548660e34ceSMatthew Garrett * 2) If still alive, write to the keyboard controller 549660e34ceSMatthew Garrett * 3) If still alive, write to the ACPI reboot register again 550660e34ceSMatthew Garrett * 4) If still alive, write to the keyboard controller again 551660e34ceSMatthew Garrett * 552660e34ceSMatthew Garrett * If the machine is still alive at this stage, it gives up. We default to 553660e34ceSMatthew Garrett * following the same pattern, except that if we're still alive after (4) we'll 554660e34ceSMatthew Garrett * try to force a triple fault and then cycle between hitting the keyboard 555660e34ceSMatthew Garrett * controller and doing that 556660e34ceSMatthew Garrett */ 557416e2d63SJody Belka static void native_machine_emergency_restart(void) 5584d022e35SMiguel Boton { 5594d022e35SMiguel Boton int i; 560660e34ceSMatthew Garrett int attempt = 0; 561660e34ceSMatthew Garrett int orig_reboot_type = reboot_type; 5624d022e35SMiguel Boton 563d176720dSEduardo Habkost if (reboot_emergency) 564d176720dSEduardo Habkost emergency_vmx_disable_all(); 565d176720dSEduardo Habkost 566840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 567840c2bafSJoseph Cihula 5684d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 5694d022e35SMiguel Boton *((unsigned short *)__va(0x472)) = reboot_mode; 5704d022e35SMiguel Boton 5714d022e35SMiguel Boton for (;;) { 5724d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 5734d022e35SMiguel Boton switch (reboot_type) { 5744d022e35SMiguel Boton case BOOT_KBD: 575*144d102bSMichael D Labriola mach_reboot_fixups(); /* For board specific fixups */ 5767432d149SIngo Molnar 5774d022e35SMiguel Boton for (i = 0; i < 10; i++) { 5784d022e35SMiguel Boton kb_wait(); 5794d022e35SMiguel Boton udelay(50); 580*144d102bSMichael D Labriola outb(0xfe, 0x64); /* Pulse reset low */ 5814d022e35SMiguel Boton udelay(50); 5824d022e35SMiguel Boton } 583660e34ceSMatthew Garrett if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { 584660e34ceSMatthew Garrett attempt = 1; 585660e34ceSMatthew Garrett reboot_type = BOOT_ACPI; 586660e34ceSMatthew Garrett } else { 587660e34ceSMatthew Garrett reboot_type = BOOT_TRIPLE; 588660e34ceSMatthew Garrett } 589660e34ceSMatthew Garrett break; 5904d022e35SMiguel Boton 5914d022e35SMiguel Boton case BOOT_TRIPLE: 592ebdd561aSJan Beulich load_idt(&no_idt); 5934d022e35SMiguel Boton __asm__ __volatile__("int3"); 5944d022e35SMiguel Boton 5954d022e35SMiguel Boton reboot_type = BOOT_KBD; 5964d022e35SMiguel Boton break; 5974d022e35SMiguel Boton 5984d022e35SMiguel Boton #ifdef CONFIG_X86_32 5994d022e35SMiguel Boton case BOOT_BIOS: 6003d35ac34SH. Peter Anvin machine_real_restart(MRR_BIOS); 6014d022e35SMiguel Boton 6024d022e35SMiguel Boton reboot_type = BOOT_KBD; 6034d022e35SMiguel Boton break; 6044d022e35SMiguel Boton #endif 6054d022e35SMiguel Boton 6064d022e35SMiguel Boton case BOOT_ACPI: 6074d022e35SMiguel Boton acpi_reboot(); 6084d022e35SMiguel Boton reboot_type = BOOT_KBD; 6094d022e35SMiguel Boton break; 6104d022e35SMiguel Boton 6114d022e35SMiguel Boton case BOOT_EFI: 6124d022e35SMiguel Boton if (efi_enabled) 61314d7ca5cSH. Peter Anvin efi.reset_system(reboot_mode ? 61414d7ca5cSH. Peter Anvin EFI_RESET_WARM : 61514d7ca5cSH. Peter Anvin EFI_RESET_COLD, 6164d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 617b47b9288SH. Peter Anvin reboot_type = BOOT_KBD; 61814d7ca5cSH. Peter Anvin break; 6194d022e35SMiguel Boton 62014d7ca5cSH. Peter Anvin case BOOT_CF9: 62114d7ca5cSH. Peter Anvin port_cf9_safe = true; 622*144d102bSMichael D Labriola /* Fall through */ 62314d7ca5cSH. Peter Anvin 62414d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 62514d7ca5cSH. Peter Anvin if (port_cf9_safe) { 62614d7ca5cSH. Peter Anvin u8 cf9 = inb(0xcf9) & ~6; 62714d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 62814d7ca5cSH. Peter Anvin udelay(50); 62914d7ca5cSH. Peter Anvin outb(cf9|6, 0xcf9); /* Actually do the reset */ 63014d7ca5cSH. Peter Anvin udelay(50); 63114d7ca5cSH. Peter Anvin } 6324d022e35SMiguel Boton reboot_type = BOOT_KBD; 6334d022e35SMiguel Boton break; 6344d022e35SMiguel Boton } 6354d022e35SMiguel Boton } 6364d022e35SMiguel Boton } 6374d022e35SMiguel Boton 6383c62c625SGlauber Costa void native_machine_shutdown(void) 6394d022e35SMiguel Boton { 6404d022e35SMiguel Boton /* Stop the cpus and apics */ 6414d022e35SMiguel Boton #ifdef CONFIG_SMP 6424d022e35SMiguel Boton 6434d022e35SMiguel Boton /* The boot cpu is always logical cpu 0 */ 64465c01184SMike Travis int reboot_cpu_id = 0; 6454d022e35SMiguel Boton 6464d022e35SMiguel Boton #ifdef CONFIG_X86_32 6474d022e35SMiguel Boton /* See if there has been given a command line override */ 6489628937dSMike Travis if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && 6490bc3cc03SMike Travis cpu_online(reboot_cpu)) 6504d022e35SMiguel Boton reboot_cpu_id = reboot_cpu; 6514d022e35SMiguel Boton #endif 6524d022e35SMiguel Boton 6534d022e35SMiguel Boton /* Make certain the cpu I'm about to reboot on is online */ 6540bc3cc03SMike Travis if (!cpu_online(reboot_cpu_id)) 6554d022e35SMiguel Boton reboot_cpu_id = smp_processor_id(); 6564d022e35SMiguel Boton 6574d022e35SMiguel Boton /* Make certain I only run on the appropriate processor */ 6589628937dSMike Travis set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); 6594d022e35SMiguel Boton 660*144d102bSMichael D Labriola /* 661*144d102bSMichael D Labriola * O.K Now that I'm on the appropriate processor, 6624d022e35SMiguel Boton * stop all of the others. 6634d022e35SMiguel Boton */ 66476fac077SAlok Kataria stop_other_cpus(); 6654d022e35SMiguel Boton #endif 6664d022e35SMiguel Boton 6674d022e35SMiguel Boton lapic_shutdown(); 6684d022e35SMiguel Boton 6694d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC 6704d022e35SMiguel Boton disable_IO_APIC(); 6714d022e35SMiguel Boton #endif 6724d022e35SMiguel Boton 6734d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 6744d022e35SMiguel Boton hpet_disable(); 6754d022e35SMiguel Boton #endif 6764d022e35SMiguel Boton 6774d022e35SMiguel Boton #ifdef CONFIG_X86_64 678338bac52SFUJITA Tomonori x86_platform.iommu_shutdown(); 6794d022e35SMiguel Boton #endif 6804d022e35SMiguel Boton } 6814d022e35SMiguel Boton 682d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 683d176720dSEduardo Habkost { 684d176720dSEduardo Habkost reboot_emergency = emergency; 685d176720dSEduardo Habkost machine_ops.emergency_restart(); 686d176720dSEduardo Habkost } 687d176720dSEduardo Habkost 688416e2d63SJody Belka static void native_machine_restart(char *__unused) 6894d022e35SMiguel Boton { 6904d022e35SMiguel Boton printk("machine restart\n"); 6914d022e35SMiguel Boton 6924d022e35SMiguel Boton if (!reboot_force) 6934d022e35SMiguel Boton machine_shutdown(); 694d176720dSEduardo Habkost __machine_emergency_restart(0); 6954d022e35SMiguel Boton } 6964d022e35SMiguel Boton 697416e2d63SJody Belka static void native_machine_halt(void) 6984d022e35SMiguel Boton { 699*144d102bSMichael D Labriola /* Stop other cpus and apics */ 700d3ec5caeSIvan Vecera machine_shutdown(); 701d3ec5caeSIvan Vecera 702840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 703840c2bafSJoseph Cihula 704d3ec5caeSIvan Vecera stop_this_cpu(NULL); 7054d022e35SMiguel Boton } 7064d022e35SMiguel Boton 707416e2d63SJody Belka static void native_machine_power_off(void) 7084d022e35SMiguel Boton { 7094d022e35SMiguel Boton if (pm_power_off) { 7104d022e35SMiguel Boton if (!reboot_force) 7114d022e35SMiguel Boton machine_shutdown(); 7124d022e35SMiguel Boton pm_power_off(); 7134d022e35SMiguel Boton } 714*144d102bSMichael D Labriola /* A fallback in case there is no PM info available */ 715840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 7164d022e35SMiguel Boton } 7174d022e35SMiguel Boton 7184d022e35SMiguel Boton struct machine_ops machine_ops = { 719416e2d63SJody Belka .power_off = native_machine_power_off, 720416e2d63SJody Belka .shutdown = native_machine_shutdown, 721416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 722416e2d63SJody Belka .restart = native_machine_restart, 723ed23dc6fSGlauber Costa .halt = native_machine_halt, 724ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 725ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 726ed23dc6fSGlauber Costa #endif 7274d022e35SMiguel Boton }; 728416e2d63SJody Belka 729416e2d63SJody Belka void machine_power_off(void) 730416e2d63SJody Belka { 731416e2d63SJody Belka machine_ops.power_off(); 732416e2d63SJody Belka } 733416e2d63SJody Belka 734416e2d63SJody Belka void machine_shutdown(void) 735416e2d63SJody Belka { 736416e2d63SJody Belka machine_ops.shutdown(); 737416e2d63SJody Belka } 738416e2d63SJody Belka 739416e2d63SJody Belka void machine_emergency_restart(void) 740416e2d63SJody Belka { 741d176720dSEduardo Habkost __machine_emergency_restart(1); 742416e2d63SJody Belka } 743416e2d63SJody Belka 744416e2d63SJody Belka void machine_restart(char *cmd) 745416e2d63SJody Belka { 746416e2d63SJody Belka machine_ops.restart(cmd); 747416e2d63SJody Belka } 748416e2d63SJody Belka 749416e2d63SJody Belka void machine_halt(void) 750416e2d63SJody Belka { 751416e2d63SJody Belka machine_ops.halt(); 752416e2d63SJody Belka } 753416e2d63SJody Belka 754ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 755ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 756ed23dc6fSGlauber Costa { 757ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 758ed23dc6fSGlauber Costa } 759ed23dc6fSGlauber Costa #endif 7602ddded21SEduardo Habkost 7612ddded21SEduardo Habkost 762bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 7632ddded21SEduardo Habkost 7642ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 7652ddded21SEduardo Habkost static int crashing_cpu; 7662ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 7672ddded21SEduardo Habkost 7682ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 7692ddded21SEduardo Habkost 7709c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) 7712ddded21SEduardo Habkost { 7722ddded21SEduardo Habkost int cpu; 7732ddded21SEduardo Habkost 7742ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 7752ddded21SEduardo Habkost 776*144d102bSMichael D Labriola /* 777*144d102bSMichael D Labriola * Don't do anything if this handler is invoked on crashing cpu. 7782ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 7792ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 7802ddded21SEduardo Habkost */ 7812ddded21SEduardo Habkost if (cpu == crashing_cpu) 7829c48f1c6SDon Zickus return NMI_HANDLED; 7832ddded21SEduardo Habkost local_irq_disable(); 7842ddded21SEduardo Habkost 7859c48f1c6SDon Zickus shootdown_callback(cpu, regs); 7862ddded21SEduardo Habkost 7872ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 7882ddded21SEduardo Habkost /* Assume hlt works */ 7892ddded21SEduardo Habkost halt(); 7902ddded21SEduardo Habkost for (;;) 7912ddded21SEduardo Habkost cpu_relax(); 7922ddded21SEduardo Habkost 7939c48f1c6SDon Zickus return NMI_HANDLED; 7942ddded21SEduardo Habkost } 7952ddded21SEduardo Habkost 7962ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 7972ddded21SEduardo Habkost { 798dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 7992ddded21SEduardo Habkost } 8002ddded21SEduardo Habkost 801*144d102bSMichael D Labriola /* 802*144d102bSMichael D Labriola * Halt all other CPUs, calling the specified function on each of them 803bb8dd270SEduardo Habkost * 804bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 805bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 806bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 807bb8dd270SEduardo Habkost */ 8082ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 8092ddded21SEduardo Habkost { 8102ddded21SEduardo Habkost unsigned long msecs; 811c415b3dcSEduardo Habkost local_irq_disable(); 8122ddded21SEduardo Habkost 8132ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback. */ 8142ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 8152ddded21SEduardo Habkost 8162ddded21SEduardo Habkost shootdown_callback = callback; 8172ddded21SEduardo Habkost 8182ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 8192ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 8209c48f1c6SDon Zickus if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, 8219c48f1c6SDon Zickus NMI_FLAG_FIRST, "crash")) 822*144d102bSMichael D Labriola return; /* Return what? */ 823*144d102bSMichael D Labriola /* 824*144d102bSMichael D Labriola * Ensure the new callback function is set before sending 8252ddded21SEduardo Habkost * out the NMI 8262ddded21SEduardo Habkost */ 8272ddded21SEduardo Habkost wmb(); 8282ddded21SEduardo Habkost 8292ddded21SEduardo Habkost smp_send_nmi_allbutself(); 8302ddded21SEduardo Habkost 8312ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 8322ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 8332ddded21SEduardo Habkost mdelay(1); 8342ddded21SEduardo Habkost msecs--; 8352ddded21SEduardo Habkost } 8362ddded21SEduardo Habkost 8372ddded21SEduardo Habkost /* Leave the nmi callback set */ 8382ddded21SEduardo Habkost } 839bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 840bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 841bb8dd270SEduardo Habkost { 842bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 843bb8dd270SEduardo Habkost } 8442ddded21SEduardo Habkost #endif 845