1c767a54bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2c767a54bSJoe Perches 34d022e35SMiguel Boton #include <linux/module.h> 44d022e35SMiguel Boton #include <linux/reboot.h> 54d022e35SMiguel Boton #include <linux/init.h> 64d022e35SMiguel Boton #include <linux/pm.h> 74d022e35SMiguel Boton #include <linux/efi.h> 86c6c51e4SPaul Mackerras #include <linux/dmi.h> 9d43c36dcSAlexey Dobriyan #include <linux/sched.h> 1069575d38SShane Wang #include <linux/tboot.h> 11ca444564SJean Delvare #include <linux/delay.h> 124d022e35SMiguel Boton #include <acpi/reboot.h> 134d022e35SMiguel Boton #include <asm/io.h> 144d022e35SMiguel Boton #include <asm/apic.h> 154d022e35SMiguel Boton #include <asm/desc.h> 164d022e35SMiguel Boton #include <asm/hpet.h> 1768db065cSJeremy Fitzhardinge #include <asm/pgtable.h> 184412620fSDmitri Vorobiev #include <asm/proto.h> 194d022e35SMiguel Boton #include <asm/reboot_fixups.h> 204d022e35SMiguel Boton #include <asm/reboot.h> 2182487711SJaswinder Singh Rajput #include <asm/pci_x86.h> 22d176720dSEduardo Habkost #include <asm/virtext.h> 2396b89dc6SJaswinder Singh Rajput #include <asm/cpu.h> 24c410b830SDon Zickus #include <asm/nmi.h> 2565051397SH. Peter Anvin #include <asm/smp.h> 264d022e35SMiguel Boton 274d022e35SMiguel Boton #include <linux/ctype.h> 284d022e35SMiguel Boton #include <linux/mc146818rtc.h> 295a8c9aebSJarkko Sakkinen #include <asm/realmode.h> 30338bac52SFUJITA Tomonori #include <asm/x86_init.h> 314d022e35SMiguel Boton 324d022e35SMiguel Boton /* 334d022e35SMiguel Boton * Power off function, if any 344d022e35SMiguel Boton */ 354d022e35SMiguel Boton void (*pm_power_off)(void); 364d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off); 374d022e35SMiguel Boton 38ebdd561aSJan Beulich static const struct desc_ptr no_idt = {}; 39*edf2b139SRobin Holt static enum reboot_mode reboot_mode; 40660e34ceSMatthew Garrett enum reboot_type reboot_type = BOOT_ACPI; 414d022e35SMiguel Boton int reboot_force; 424d022e35SMiguel Boton 43144d102bSMichael D Labriola /* 44144d102bSMichael D Labriola * This variable is used privately to keep track of whether or not 455955633eSMichael D Labriola * reboot_type is still set to its default value (i.e., reboot= hasn't 465955633eSMichael D Labriola * been set on the command line). This is needed so that we can 475955633eSMichael D Labriola * suppress DMI scanning for reboot quirks. Without it, it's 485955633eSMichael D Labriola * impossible to override a faulty reboot quirk without recompiling. 495955633eSMichael D Labriola */ 505955633eSMichael D Labriola static int reboot_default = 1; 515955633eSMichael D Labriola 5265051397SH. Peter Anvin #ifdef CONFIG_SMP 534d022e35SMiguel Boton static int reboot_cpu = -1; 544d022e35SMiguel Boton #endif 554d022e35SMiguel Boton 56144d102bSMichael D Labriola /* 57144d102bSMichael D Labriola * This is set if we need to go through the 'emergency' path. 58d176720dSEduardo Habkost * When machine_emergency_restart() is called, we may be on 59d176720dSEduardo Habkost * an inconsistent state and won't be able to do a clean cleanup 60d176720dSEduardo Habkost */ 61d176720dSEduardo Habkost static int reboot_emergency; 62d176720dSEduardo Habkost 6314d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 6414d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 6514d7ca5cSH. Peter Anvin 66144d102bSMichael D Labriola /* 67144d102bSMichael D Labriola * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] 68144d102bSMichael D Labriola * warm Don't set the cold reboot flag 69144d102bSMichael D Labriola * cold Set the cold reboot flag 7065051397SH. Peter Anvin * bios Reboot by jumping through the BIOS 7165051397SH. Peter Anvin * smp Reboot by executing reset on BSP or other CPU 72144d102bSMichael D Labriola * triple Force a triple fault (init) 73144d102bSMichael D Labriola * kbd Use the keyboard controller. cold reset (default) 74144d102bSMichael D Labriola * acpi Use the RESET_REG in the FADT 75144d102bSMichael D Labriola * efi Use efi reset_system runtime service 76144d102bSMichael D Labriola * pci Use the so-called "PCI reset register", CF9 77144d102bSMichael D Labriola * force Avoid anything that could hang. 784d022e35SMiguel Boton */ 794d022e35SMiguel Boton static int __init reboot_setup(char *str) 804d022e35SMiguel Boton { 814d022e35SMiguel Boton for (;;) { 82144d102bSMichael D Labriola /* 83144d102bSMichael D Labriola * Having anything passed on the command line via 845955633eSMichael D Labriola * reboot= will cause us to disable DMI checking 855955633eSMichael D Labriola * below. 865955633eSMichael D Labriola */ 875955633eSMichael D Labriola reboot_default = 0; 885955633eSMichael D Labriola 894d022e35SMiguel Boton switch (*str) { 904d022e35SMiguel Boton case 'w': 91*edf2b139SRobin Holt reboot_mode = REBOOT_WARM; 924d022e35SMiguel Boton break; 934d022e35SMiguel Boton 944d022e35SMiguel Boton case 'c': 95*edf2b139SRobin Holt reboot_mode = REBOOT_COLD; 964d022e35SMiguel Boton break; 974d022e35SMiguel Boton 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 } 105144d102bSMichael D Labriola /* 106144d102bSMichael D Labriola * We will leave sorting out the final value 107144d102bSMichael D Labriola * when we are ready to reboot, since we might not 108144d102bSMichael D Labriola * have detected BSP APIC ID or smp_num_cpu 109144d102bSMichael D Labriola */ 1104d022e35SMiguel Boton break; 1114d022e35SMiguel Boton #endif /* CONFIG_SMP */ 1124d022e35SMiguel Boton 1134d022e35SMiguel Boton case 'b': 1144d022e35SMiguel Boton case 'a': 1154d022e35SMiguel Boton case 'k': 1164d022e35SMiguel Boton case 't': 1174d022e35SMiguel Boton case 'e': 11814d7ca5cSH. Peter Anvin case 'p': 1194d022e35SMiguel Boton reboot_type = *str; 1204d022e35SMiguel Boton break; 1214d022e35SMiguel Boton 1224d022e35SMiguel Boton case 'f': 1234d022e35SMiguel Boton reboot_force = 1; 1244d022e35SMiguel Boton break; 1254d022e35SMiguel Boton } 1264d022e35SMiguel Boton 1274d022e35SMiguel Boton str = strchr(str, ','); 1284d022e35SMiguel Boton if (str) 1294d022e35SMiguel Boton str++; 1304d022e35SMiguel Boton else 1314d022e35SMiguel Boton break; 1324d022e35SMiguel Boton } 1334d022e35SMiguel Boton return 1; 1344d022e35SMiguel Boton } 1354d022e35SMiguel Boton 1364d022e35SMiguel Boton __setup("reboot=", reboot_setup); 1374d022e35SMiguel Boton 1384d022e35SMiguel Boton 1394d022e35SMiguel Boton /* 1404d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 1414d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 1424d022e35SMiguel Boton */ 1434d022e35SMiguel Boton 1444d022e35SMiguel Boton /* 1451ef03890SPeter Chubb * Some machines require the "reboot=b" or "reboot=k" commandline options, 1464d022e35SMiguel Boton * this quirk makes that automatic. 1474d022e35SMiguel Boton */ 1484d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 1494d022e35SMiguel Boton { 1504d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 1514d022e35SMiguel Boton reboot_type = BOOT_BIOS; 152c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 153c767a54bSJoe Perches "BIOS", d->ident); 1544d022e35SMiguel Boton } 1554d022e35SMiguel Boton return 0; 1564d022e35SMiguel Boton } 1574d022e35SMiguel Boton 15865051397SH. Peter Anvin void __noreturn machine_real_restart(unsigned int type) 15957b16594SMichael D Labriola { 16057b16594SMichael D Labriola local_irq_disable(); 16157b16594SMichael D Labriola 162144d102bSMichael D Labriola /* 163144d102bSMichael D Labriola * Write zero to CMOS register number 0x0f, which the BIOS POST 164144d102bSMichael D Labriola * routine will recognize as telling it to do a proper reboot. (Well 165144d102bSMichael D Labriola * that's what this book in front of me says -- it may only apply to 166144d102bSMichael D Labriola * the Phoenix BIOS though, it's not clear). At the same time, 167144d102bSMichael D Labriola * disable NMIs by setting the top bit in the CMOS address register, 168144d102bSMichael D Labriola * as we're about to do peculiar things to the CPU. I'm not sure if 169144d102bSMichael D Labriola * `outb_p' is needed instead of just `outb'. Use it to be on the 170144d102bSMichael D Labriola * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 17157b16594SMichael D Labriola */ 17257b16594SMichael D Labriola spin_lock(&rtc_lock); 17357b16594SMichael D Labriola CMOS_WRITE(0x00, 0x8f); 17457b16594SMichael D Labriola spin_unlock(&rtc_lock); 17557b16594SMichael D Labriola 17657b16594SMichael D Labriola /* 17757b16594SMichael D Labriola * Switch back to the initial page table. 17857b16594SMichael D Labriola */ 17965051397SH. Peter Anvin #ifdef CONFIG_X86_32 18057b16594SMichael D Labriola load_cr3(initial_page_table); 18165051397SH. Peter Anvin #else 18265051397SH. Peter Anvin write_cr3(real_mode_header->trampoline_pgd); 18365051397SH. Peter Anvin #endif 18457b16594SMichael D Labriola 18557b16594SMichael D Labriola /* Jump to the identity-mapped low memory code */ 18665051397SH. Peter Anvin #ifdef CONFIG_X86_32 18765051397SH. Peter Anvin asm volatile("jmpl *%0" : : 18865051397SH. Peter Anvin "rm" (real_mode_header->machine_real_restart_asm), 18965051397SH. Peter Anvin "a" (type)); 19065051397SH. Peter Anvin #else 19165051397SH. Peter Anvin asm volatile("ljmpl *%0" : : 19265051397SH. Peter Anvin "m" (real_mode_header->machine_real_restart_asm), 19365051397SH. Peter Anvin "D" (type)); 19465051397SH. Peter Anvin #endif 19565051397SH. Peter Anvin unreachable(); 19657b16594SMichael D Labriola } 19757b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE 19857b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart); 19957b16594SMichael D Labriola #endif 20057b16594SMichael D Labriola 20157b16594SMichael D Labriola /* 20257b16594SMichael D Labriola * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot 20357b16594SMichael D Labriola */ 20457b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d) 20557b16594SMichael D Labriola { 20657b16594SMichael D Labriola if (reboot_type != BOOT_CF9) { 20757b16594SMichael D Labriola reboot_type = BOOT_CF9; 208c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 209c767a54bSJoe Perches "PCI", d->ident); 21057b16594SMichael D Labriola } 21157b16594SMichael D Labriola return 0; 21257b16594SMichael D Labriola } 21357b16594SMichael D Labriola 2141ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d) 2151ef03890SPeter Chubb { 2161ef03890SPeter Chubb if (reboot_type != BOOT_KBD) { 2171ef03890SPeter Chubb reboot_type = BOOT_KBD; 218c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboot.\n", 219c767a54bSJoe Perches "KBD", d->ident); 2201ef03890SPeter Chubb } 2211ef03890SPeter Chubb return 0; 2221ef03890SPeter Chubb } 2231ef03890SPeter Chubb 224144d102bSMichael D Labriola /* 22565051397SH. Peter Anvin * This is a single dmi_table handling all reboot quirks. 22657b16594SMichael D Labriola */ 2274d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 2284d022e35SMiguel Boton { /* Handle problems with rebooting on Dell E520's */ 2294d022e35SMiguel Boton .callback = set_bios_reboot, 2304d022e35SMiguel Boton .ident = "Dell E520", 2314d022e35SMiguel Boton .matches = { 2324d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2334d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 2344d022e35SMiguel Boton }, 2354d022e35SMiguel Boton }, 2364d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 1300's */ 2374d022e35SMiguel Boton .callback = set_bios_reboot, 2384d022e35SMiguel Boton .ident = "Dell PowerEdge 1300", 2394d022e35SMiguel Boton .matches = { 2404d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 2414d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 2424d022e35SMiguel Boton }, 2434d022e35SMiguel Boton }, 2444d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 300's */ 2454d022e35SMiguel Boton .callback = set_bios_reboot, 2464d022e35SMiguel Boton .ident = "Dell PowerEdge 300", 2474d022e35SMiguel Boton .matches = { 2484d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 2494d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 2504d022e35SMiguel Boton }, 2514d022e35SMiguel Boton }, 2524d022e35SMiguel Boton { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ 2534d022e35SMiguel Boton .callback = set_bios_reboot, 2544d022e35SMiguel Boton .ident = "Dell OptiPlex 745", 2554d022e35SMiguel Boton .matches = { 2564d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2574d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 2584d022e35SMiguel Boton }, 2594d022e35SMiguel Boton }, 260fc115bf1SColeman Kane { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ 261fc115bf1SColeman Kane .callback = set_bios_reboot, 262fc115bf1SColeman Kane .ident = "Dell OptiPlex 745", 263fc115bf1SColeman Kane .matches = { 264fc115bf1SColeman Kane DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 265fc115bf1SColeman Kane DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 266fc115bf1SColeman Kane DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 267fc115bf1SColeman Kane }, 268fc115bf1SColeman Kane }, 269fc1c8925SHeinz-Ado Arnolds { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 270fc1c8925SHeinz-Ado Arnolds .callback = set_bios_reboot, 271fc1c8925SHeinz-Ado Arnolds .ident = "Dell OptiPlex 745", 272fc1c8925SHeinz-Ado Arnolds .matches = { 273fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 274fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 275fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 276fc1c8925SHeinz-Ado Arnolds }, 277fc1c8925SHeinz-Ado Arnolds }, 278093bac15SSteve Conklin { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 279093bac15SSteve Conklin .callback = set_bios_reboot, 280093bac15SSteve Conklin .ident = "Dell OptiPlex 330", 281093bac15SSteve Conklin .matches = { 282093bac15SSteve Conklin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 283093bac15SSteve Conklin DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 284093bac15SSteve Conklin DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 285093bac15SSteve Conklin }, 286093bac15SSteve Conklin }, 2874a4aca64SJean Delvare { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 2884a4aca64SJean Delvare .callback = set_bios_reboot, 2894a4aca64SJean Delvare .ident = "Dell OptiPlex 360", 2904a4aca64SJean Delvare .matches = { 2914a4aca64SJean Delvare DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2924a4aca64SJean Delvare DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 2934a4aca64SJean Delvare DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 2944a4aca64SJean Delvare }, 2954a4aca64SJean Delvare }, 29635ea63d7SLeann Ogasawara { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ 29735ea63d7SLeann Ogasawara .callback = set_bios_reboot, 29835ea63d7SLeann Ogasawara .ident = "Dell OptiPlex 760", 29935ea63d7SLeann Ogasawara .matches = { 30035ea63d7SLeann Ogasawara DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 30135ea63d7SLeann Ogasawara DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), 30235ea63d7SLeann Ogasawara DMI_MATCH(DMI_BOARD_NAME, "0G919G"), 30335ea63d7SLeann Ogasawara }, 30435ea63d7SLeann Ogasawara }, 3054d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 2400's */ 3064d022e35SMiguel Boton .callback = set_bios_reboot, 3074d022e35SMiguel Boton .ident = "Dell PowerEdge 2400", 3084d022e35SMiguel Boton .matches = { 3094d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 3104d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 3114d022e35SMiguel Boton }, 3124d022e35SMiguel Boton }, 313fab3b58dSIngo Molnar { /* Handle problems with rebooting on Dell T5400's */ 314fab3b58dSIngo Molnar .callback = set_bios_reboot, 315fab3b58dSIngo Molnar .ident = "Dell Precision T5400", 316fab3b58dSIngo Molnar .matches = { 317fab3b58dSIngo Molnar DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 318fab3b58dSIngo Molnar DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 319fab3b58dSIngo Molnar }, 320fab3b58dSIngo Molnar }, 321890ffedcSThomas Backlund { /* Handle problems with rebooting on Dell T7400's */ 322890ffedcSThomas Backlund .callback = set_bios_reboot, 323890ffedcSThomas Backlund .ident = "Dell Precision T7400", 324890ffedcSThomas Backlund .matches = { 325890ffedcSThomas Backlund DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 326890ffedcSThomas Backlund DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), 327890ffedcSThomas Backlund }, 328890ffedcSThomas Backlund }, 3294d022e35SMiguel Boton { /* Handle problems with rebooting on HP laptops */ 3304d022e35SMiguel Boton .callback = set_bios_reboot, 3314d022e35SMiguel Boton .ident = "HP Compaq Laptop", 3324d022e35SMiguel Boton .matches = { 3334d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 3344d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 3354d022e35SMiguel Boton }, 3364d022e35SMiguel Boton }, 337dd4124a8SLeann Ogasawara { /* Handle problems with rebooting on Dell XPS710 */ 338dd4124a8SLeann Ogasawara .callback = set_bios_reboot, 339dd4124a8SLeann Ogasawara .ident = "Dell XPS710", 340dd4124a8SLeann Ogasawara .matches = { 341dd4124a8SLeann Ogasawara DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 342dd4124a8SLeann Ogasawara DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 343dd4124a8SLeann Ogasawara }, 344dd4124a8SLeann Ogasawara }, 345c5da9a2bSAlan Cox { /* Handle problems with rebooting on Dell DXP061 */ 346c5da9a2bSAlan Cox .callback = set_bios_reboot, 347c5da9a2bSAlan Cox .ident = "Dell DXP061", 348c5da9a2bSAlan Cox .matches = { 349c5da9a2bSAlan Cox DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 350c5da9a2bSAlan Cox DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 351c5da9a2bSAlan Cox }, 352c5da9a2bSAlan Cox }, 35388dff493SZhang Rui { /* Handle problems with rebooting on Sony VGN-Z540N */ 35488dff493SZhang Rui .callback = set_bios_reboot, 35588dff493SZhang Rui .ident = "Sony VGN-Z540N", 35688dff493SZhang Rui .matches = { 35788dff493SZhang Rui DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 35888dff493SZhang Rui DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 35988dff493SZhang Rui }, 36088dff493SZhang Rui }, 3614832dddaSLeann Ogasawara { /* Handle problems with rebooting on ASUS P4S800 */ 3624832dddaSLeann Ogasawara .callback = set_bios_reboot, 3634832dddaSLeann Ogasawara .ident = "ASUS P4S800", 3644832dddaSLeann Ogasawara .matches = { 3654832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 3664832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 3674832dddaSLeann Ogasawara }, 3684832dddaSLeann Ogasawara }, 36957b16594SMichael D Labriola 370b49c78d4SPeter Chubb { /* Handle reboot issue on Acer Aspire one */ 3711ef03890SPeter Chubb .callback = set_kbd_reboot, 372b49c78d4SPeter Chubb .ident = "Acer Aspire One A110", 373b49c78d4SPeter Chubb .matches = { 374b49c78d4SPeter Chubb DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 375b49c78d4SPeter Chubb DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 376b49c78d4SPeter Chubb }, 377b49c78d4SPeter Chubb }, 3783e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBook5 */ 3796c6c51e4SPaul Mackerras .callback = set_pci_reboot, 3803e03bbeaSShunichi Fuji .ident = "Apple MacBook5", 3816c6c51e4SPaul Mackerras .matches = { 3826c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 3833e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), 3846c6c51e4SPaul Mackerras }, 3856c6c51e4SPaul Mackerras }, 3863e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBookPro5 */ 387498cdbfbSOzan Çağlayan .callback = set_pci_reboot, 3883e03bbeaSShunichi Fuji .ident = "Apple MacBookPro5", 389498cdbfbSOzan Çağlayan .matches = { 390498cdbfbSOzan Çağlayan DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 3913e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), 392498cdbfbSOzan Çağlayan }, 393498cdbfbSOzan Çağlayan }, 39405154752SGottfried Haider { /* Handle problems with rebooting on Apple Macmini3,1 */ 39505154752SGottfried Haider .callback = set_pci_reboot, 39605154752SGottfried Haider .ident = "Apple Macmini3,1", 39705154752SGottfried Haider .matches = { 39805154752SGottfried Haider DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 39905154752SGottfried Haider DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), 40005154752SGottfried Haider }, 40105154752SGottfried Haider }, 4020a832320SJustin P. Mattock { /* Handle problems with rebooting on the iMac9,1. */ 4030a832320SJustin P. Mattock .callback = set_pci_reboot, 4040a832320SJustin P. Mattock .ident = "Apple iMac9,1", 4050a832320SJustin P. Mattock .matches = { 4060a832320SJustin P. Mattock DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4070a832320SJustin P. Mattock DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), 4080a832320SJustin P. Mattock }, 4090a832320SJustin P. Mattock }, 4103628c3f5SMaxime Ripard { /* Handle problems with rebooting on the Latitude E6320. */ 4113628c3f5SMaxime Ripard .callback = set_pci_reboot, 4123628c3f5SMaxime Ripard .ident = "Dell Latitude E6320", 4133628c3f5SMaxime Ripard .matches = { 4143628c3f5SMaxime Ripard DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 4153628c3f5SMaxime Ripard DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), 4163628c3f5SMaxime Ripard }, 4173628c3f5SMaxime Ripard }, 418b7798d28SDaniel J Blueman { /* Handle problems with rebooting on the Latitude E5420. */ 419b7798d28SDaniel J Blueman .callback = set_pci_reboot, 420b7798d28SDaniel J Blueman .ident = "Dell Latitude E5420", 421b7798d28SDaniel J Blueman .matches = { 422b7798d28SDaniel J Blueman DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 423b7798d28SDaniel J Blueman DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), 424b7798d28SDaniel J Blueman }, 425b7798d28SDaniel J Blueman }, 426a536877eSH. Peter Anvin { /* Handle problems with rebooting on the Latitude E6420. */ 427a536877eSH. Peter Anvin .callback = set_pci_reboot, 428a536877eSH. Peter Anvin .ident = "Dell Latitude E6420", 429a536877eSH. Peter Anvin .matches = { 430a536877eSH. Peter Anvin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 431a536877eSH. Peter Anvin DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), 432a536877eSH. Peter Anvin }, 433a536877eSH. Peter Anvin }, 4346be30bb7SRafael J. Wysocki { /* Handle problems with rebooting on the OptiPlex 990. */ 4356be30bb7SRafael J. Wysocki .callback = set_pci_reboot, 4366be30bb7SRafael J. Wysocki .ident = "Dell OptiPlex 990", 4376be30bb7SRafael J. Wysocki .matches = { 4386be30bb7SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 4396be30bb7SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), 4406be30bb7SRafael J. Wysocki }, 4416be30bb7SRafael J. Wysocki }, 44276eb9a30SZhang Rui { /* Handle problems with rebooting on the Precision M6600. */ 44376eb9a30SZhang Rui .callback = set_pci_reboot, 44476eb9a30SZhang Rui .ident = "Dell OptiPlex 990", 44576eb9a30SZhang Rui .matches = { 44676eb9a30SZhang Rui DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 44776eb9a30SZhang Rui DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), 44876eb9a30SZhang Rui }, 44976eb9a30SZhang Rui }, 4506c6c51e4SPaul Mackerras { } 4516c6c51e4SPaul Mackerras }; 4526c6c51e4SPaul Mackerras 45357b16594SMichael D Labriola static int __init reboot_init(void) 4546c6c51e4SPaul Mackerras { 455144d102bSMichael D Labriola /* 456144d102bSMichael D Labriola * Only do the DMI check if reboot_type hasn't been overridden 4575955633eSMichael D Labriola * on the command line 4585955633eSMichael D Labriola */ 459144d102bSMichael D Labriola if (reboot_default) 46057b16594SMichael D Labriola dmi_check_system(reboot_dmi_table); 4616c6c51e4SPaul Mackerras return 0; 4626c6c51e4SPaul Mackerras } 46357b16594SMichael D Labriola core_initcall(reboot_init); 4646c6c51e4SPaul Mackerras 4654d022e35SMiguel Boton static inline void kb_wait(void) 4664d022e35SMiguel Boton { 4674d022e35SMiguel Boton int i; 4684d022e35SMiguel Boton 469c84d6af8SAlan Cox for (i = 0; i < 0x10000; i++) { 470c84d6af8SAlan Cox if ((inb(0x64) & 0x02) == 0) 4714d022e35SMiguel Boton break; 472c84d6af8SAlan Cox udelay(2); 473c84d6af8SAlan Cox } 4744d022e35SMiguel Boton } 4754d022e35SMiguel Boton 4769c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs) 477d176720dSEduardo Habkost { 478d176720dSEduardo Habkost cpu_emergency_vmxoff(); 479d176720dSEduardo Habkost } 480d176720dSEduardo Habkost 481144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ 482d176720dSEduardo Habkost static void emergency_vmx_disable_all(void) 483d176720dSEduardo Habkost { 484d176720dSEduardo Habkost /* Just make sure we won't change CPUs while doing this */ 485d176720dSEduardo Habkost local_irq_disable(); 486d176720dSEduardo Habkost 487144d102bSMichael D Labriola /* 488144d102bSMichael D Labriola * We need to disable VMX on all CPUs before rebooting, otherwise 489d176720dSEduardo Habkost * we risk hanging up the machine, because the CPU ignore INIT 490d176720dSEduardo Habkost * signals when VMX is enabled. 491d176720dSEduardo Habkost * 492d176720dSEduardo Habkost * We can't take any locks and we may be on an inconsistent 493d176720dSEduardo Habkost * state, so we use NMIs as IPIs to tell the other CPUs to disable 494d176720dSEduardo Habkost * VMX and halt. 495d176720dSEduardo Habkost * 496d176720dSEduardo Habkost * For safety, we will avoid running the nmi_shootdown_cpus() 497d176720dSEduardo Habkost * stuff unnecessarily, but we don't have a way to check 498d176720dSEduardo Habkost * if other CPUs have VMX enabled. So we will call it only if the 499d176720dSEduardo Habkost * CPU we are running on has VMX enabled. 500d176720dSEduardo Habkost * 501d176720dSEduardo Habkost * We will miss cases where VMX is not enabled on all CPUs. This 502d176720dSEduardo Habkost * shouldn't do much harm because KVM always enable VMX on all 503d176720dSEduardo Habkost * CPUs anyway. But we can miss it on the small window where KVM 504d176720dSEduardo Habkost * is still enabling VMX. 505d176720dSEduardo Habkost */ 506d176720dSEduardo Habkost if (cpu_has_vmx() && cpu_vmx_enabled()) { 507144d102bSMichael D Labriola /* Disable VMX on this CPU. */ 508d176720dSEduardo Habkost cpu_vmxoff(); 509d176720dSEduardo Habkost 510d176720dSEduardo Habkost /* Halt and disable VMX on the other CPUs */ 511d176720dSEduardo Habkost nmi_shootdown_cpus(vmxoff_nmi); 512d176720dSEduardo Habkost 513d176720dSEduardo Habkost } 514d176720dSEduardo Habkost } 515d176720dSEduardo Habkost 516d176720dSEduardo Habkost 5177432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 5187432d149SIngo Molnar { 5197432d149SIngo Molnar } 5207432d149SIngo Molnar 521660e34ceSMatthew Garrett /* 522660e34ceSMatthew Garrett * Windows compatible x86 hardware expects the following on reboot: 523660e34ceSMatthew Garrett * 524660e34ceSMatthew Garrett * 1) If the FADT has the ACPI reboot register flag set, try it 525660e34ceSMatthew Garrett * 2) If still alive, write to the keyboard controller 526660e34ceSMatthew Garrett * 3) If still alive, write to the ACPI reboot register again 527660e34ceSMatthew Garrett * 4) If still alive, write to the keyboard controller again 528660e34ceSMatthew Garrett * 529660e34ceSMatthew Garrett * If the machine is still alive at this stage, it gives up. We default to 530660e34ceSMatthew Garrett * following the same pattern, except that if we're still alive after (4) we'll 531660e34ceSMatthew Garrett * try to force a triple fault and then cycle between hitting the keyboard 532660e34ceSMatthew Garrett * controller and doing that 533660e34ceSMatthew Garrett */ 534416e2d63SJody Belka static void native_machine_emergency_restart(void) 5354d022e35SMiguel Boton { 5364d022e35SMiguel Boton int i; 537660e34ceSMatthew Garrett int attempt = 0; 538660e34ceSMatthew Garrett int orig_reboot_type = reboot_type; 539*edf2b139SRobin Holt unsigned short mode; 5404d022e35SMiguel Boton 541d176720dSEduardo Habkost if (reboot_emergency) 542d176720dSEduardo Habkost emergency_vmx_disable_all(); 543d176720dSEduardo Habkost 544840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 545840c2bafSJoseph Cihula 5464d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 547*edf2b139SRobin Holt mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; 548*edf2b139SRobin Holt *((unsigned short *)__va(0x472)) = mode; 5494d022e35SMiguel Boton 5504d022e35SMiguel Boton for (;;) { 5514d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 5524d022e35SMiguel Boton switch (reboot_type) { 5534d022e35SMiguel Boton case BOOT_KBD: 554144d102bSMichael D Labriola mach_reboot_fixups(); /* For board specific fixups */ 5557432d149SIngo Molnar 5564d022e35SMiguel Boton for (i = 0; i < 10; i++) { 5574d022e35SMiguel Boton kb_wait(); 5584d022e35SMiguel Boton udelay(50); 559144d102bSMichael D Labriola outb(0xfe, 0x64); /* Pulse reset low */ 5604d022e35SMiguel Boton udelay(50); 5614d022e35SMiguel Boton } 562660e34ceSMatthew Garrett if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { 563660e34ceSMatthew Garrett attempt = 1; 564660e34ceSMatthew Garrett reboot_type = BOOT_ACPI; 565660e34ceSMatthew Garrett } else { 566660e34ceSMatthew Garrett reboot_type = BOOT_TRIPLE; 567660e34ceSMatthew Garrett } 568660e34ceSMatthew Garrett break; 5694d022e35SMiguel Boton 5704d022e35SMiguel Boton case BOOT_TRIPLE: 571ebdd561aSJan Beulich load_idt(&no_idt); 5724d022e35SMiguel Boton __asm__ __volatile__("int3"); 5734d022e35SMiguel Boton 5744d022e35SMiguel Boton reboot_type = BOOT_KBD; 5754d022e35SMiguel Boton break; 5764d022e35SMiguel Boton 5774d022e35SMiguel Boton case BOOT_BIOS: 5783d35ac34SH. Peter Anvin machine_real_restart(MRR_BIOS); 5794d022e35SMiguel Boton 5804d022e35SMiguel Boton reboot_type = BOOT_KBD; 5814d022e35SMiguel Boton break; 5824d022e35SMiguel Boton 5834d022e35SMiguel Boton case BOOT_ACPI: 5844d022e35SMiguel Boton acpi_reboot(); 5854d022e35SMiguel Boton reboot_type = BOOT_KBD; 5864d022e35SMiguel Boton break; 5874d022e35SMiguel Boton 5884d022e35SMiguel Boton case BOOT_EFI: 58983e68189SMatt Fleming if (efi_enabled(EFI_RUNTIME_SERVICES)) 590*edf2b139SRobin Holt efi.reset_system(reboot_mode == REBOOT_WARM ? 59114d7ca5cSH. Peter Anvin EFI_RESET_WARM : 59214d7ca5cSH. Peter Anvin EFI_RESET_COLD, 5934d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 594b47b9288SH. Peter Anvin reboot_type = BOOT_KBD; 59514d7ca5cSH. Peter Anvin break; 5964d022e35SMiguel Boton 59714d7ca5cSH. Peter Anvin case BOOT_CF9: 59814d7ca5cSH. Peter Anvin port_cf9_safe = true; 599144d102bSMichael D Labriola /* Fall through */ 60014d7ca5cSH. Peter Anvin 60114d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 60214d7ca5cSH. Peter Anvin if (port_cf9_safe) { 60314d7ca5cSH. Peter Anvin u8 cf9 = inb(0xcf9) & ~6; 60414d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 60514d7ca5cSH. Peter Anvin udelay(50); 60614d7ca5cSH. Peter Anvin outb(cf9|6, 0xcf9); /* Actually do the reset */ 60714d7ca5cSH. Peter Anvin udelay(50); 60814d7ca5cSH. Peter Anvin } 6094d022e35SMiguel Boton reboot_type = BOOT_KBD; 6104d022e35SMiguel Boton break; 6114d022e35SMiguel Boton } 6124d022e35SMiguel Boton } 6134d022e35SMiguel Boton } 6144d022e35SMiguel Boton 6153c62c625SGlauber Costa void native_machine_shutdown(void) 6164d022e35SMiguel Boton { 6174d022e35SMiguel Boton /* Stop the cpus and apics */ 6184d022e35SMiguel Boton #ifdef CONFIG_SMP 6194d022e35SMiguel Boton 6204d022e35SMiguel Boton /* The boot cpu is always logical cpu 0 */ 62165c01184SMike Travis int reboot_cpu_id = 0; 6224d022e35SMiguel Boton 6234d022e35SMiguel Boton /* See if there has been given a command line override */ 6249628937dSMike Travis if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && 6250bc3cc03SMike Travis cpu_online(reboot_cpu)) 6264d022e35SMiguel Boton reboot_cpu_id = reboot_cpu; 6274d022e35SMiguel Boton 6284d022e35SMiguel Boton /* Make certain the cpu I'm about to reboot on is online */ 6290bc3cc03SMike Travis if (!cpu_online(reboot_cpu_id)) 6304d022e35SMiguel Boton reboot_cpu_id = smp_processor_id(); 6314d022e35SMiguel Boton 6324d022e35SMiguel Boton /* Make certain I only run on the appropriate processor */ 6339628937dSMike Travis set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); 6344d022e35SMiguel Boton 635144d102bSMichael D Labriola /* 63655c844a4SFeng Tang * O.K Now that I'm on the appropriate processor, stop all of the 63755c844a4SFeng Tang * others. Also disable the local irq to not receive the per-cpu 63855c844a4SFeng Tang * timer interrupt which may trigger scheduler's load balance. 6394d022e35SMiguel Boton */ 64055c844a4SFeng Tang local_irq_disable(); 64176fac077SAlok Kataria stop_other_cpus(); 6424d022e35SMiguel Boton #endif 6434d022e35SMiguel Boton 6444d022e35SMiguel Boton lapic_shutdown(); 6454d022e35SMiguel Boton 6464d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC 6474d022e35SMiguel Boton disable_IO_APIC(); 6484d022e35SMiguel Boton #endif 6494d022e35SMiguel Boton 6504d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 6514d022e35SMiguel Boton hpet_disable(); 6524d022e35SMiguel Boton #endif 6534d022e35SMiguel Boton 6544d022e35SMiguel Boton #ifdef CONFIG_X86_64 655338bac52SFUJITA Tomonori x86_platform.iommu_shutdown(); 6564d022e35SMiguel Boton #endif 6574d022e35SMiguel Boton } 6584d022e35SMiguel Boton 659d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 660d176720dSEduardo Habkost { 661d176720dSEduardo Habkost reboot_emergency = emergency; 662d176720dSEduardo Habkost machine_ops.emergency_restart(); 663d176720dSEduardo Habkost } 664d176720dSEduardo Habkost 665416e2d63SJody Belka static void native_machine_restart(char *__unused) 6664d022e35SMiguel Boton { 667c767a54bSJoe Perches pr_notice("machine restart\n"); 6684d022e35SMiguel Boton 6694d022e35SMiguel Boton if (!reboot_force) 6704d022e35SMiguel Boton machine_shutdown(); 671d176720dSEduardo Habkost __machine_emergency_restart(0); 6724d022e35SMiguel Boton } 6734d022e35SMiguel Boton 674416e2d63SJody Belka static void native_machine_halt(void) 6754d022e35SMiguel Boton { 676144d102bSMichael D Labriola /* Stop other cpus and apics */ 677d3ec5caeSIvan Vecera machine_shutdown(); 678d3ec5caeSIvan Vecera 679840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 680840c2bafSJoseph Cihula 681d3ec5caeSIvan Vecera stop_this_cpu(NULL); 6824d022e35SMiguel Boton } 6834d022e35SMiguel Boton 684416e2d63SJody Belka static void native_machine_power_off(void) 6854d022e35SMiguel Boton { 6864d022e35SMiguel Boton if (pm_power_off) { 6874d022e35SMiguel Boton if (!reboot_force) 6884d022e35SMiguel Boton machine_shutdown(); 6894d022e35SMiguel Boton pm_power_off(); 6904d022e35SMiguel Boton } 691144d102bSMichael D Labriola /* A fallback in case there is no PM info available */ 692840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 6934d022e35SMiguel Boton } 6944d022e35SMiguel Boton 6954d022e35SMiguel Boton struct machine_ops machine_ops = { 696416e2d63SJody Belka .power_off = native_machine_power_off, 697416e2d63SJody Belka .shutdown = native_machine_shutdown, 698416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 699416e2d63SJody Belka .restart = native_machine_restart, 700ed23dc6fSGlauber Costa .halt = native_machine_halt, 701ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 702ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 703ed23dc6fSGlauber Costa #endif 7044d022e35SMiguel Boton }; 705416e2d63SJody Belka 706416e2d63SJody Belka void machine_power_off(void) 707416e2d63SJody Belka { 708416e2d63SJody Belka machine_ops.power_off(); 709416e2d63SJody Belka } 710416e2d63SJody Belka 711416e2d63SJody Belka void machine_shutdown(void) 712416e2d63SJody Belka { 713416e2d63SJody Belka machine_ops.shutdown(); 714416e2d63SJody Belka } 715416e2d63SJody Belka 716416e2d63SJody Belka void machine_emergency_restart(void) 717416e2d63SJody Belka { 718d176720dSEduardo Habkost __machine_emergency_restart(1); 719416e2d63SJody Belka } 720416e2d63SJody Belka 721416e2d63SJody Belka void machine_restart(char *cmd) 722416e2d63SJody Belka { 723416e2d63SJody Belka machine_ops.restart(cmd); 724416e2d63SJody Belka } 725416e2d63SJody Belka 726416e2d63SJody Belka void machine_halt(void) 727416e2d63SJody Belka { 728416e2d63SJody Belka machine_ops.halt(); 729416e2d63SJody Belka } 730416e2d63SJody Belka 731ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 732ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 733ed23dc6fSGlauber Costa { 734ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 735ed23dc6fSGlauber Costa } 736ed23dc6fSGlauber Costa #endif 7372ddded21SEduardo Habkost 7382ddded21SEduardo Habkost 739bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 7402ddded21SEduardo Habkost 7412ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 7422ddded21SEduardo Habkost static int crashing_cpu; 7432ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 7442ddded21SEduardo Habkost 7452ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 7462ddded21SEduardo Habkost 7479c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) 7482ddded21SEduardo Habkost { 7492ddded21SEduardo Habkost int cpu; 7502ddded21SEduardo Habkost 7512ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 7522ddded21SEduardo Habkost 753144d102bSMichael D Labriola /* 754144d102bSMichael D Labriola * Don't do anything if this handler is invoked on crashing cpu. 7552ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 7562ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 7572ddded21SEduardo Habkost */ 7582ddded21SEduardo Habkost if (cpu == crashing_cpu) 7599c48f1c6SDon Zickus return NMI_HANDLED; 7602ddded21SEduardo Habkost local_irq_disable(); 7612ddded21SEduardo Habkost 7629c48f1c6SDon Zickus shootdown_callback(cpu, regs); 7632ddded21SEduardo Habkost 7642ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 7652ddded21SEduardo Habkost /* Assume hlt works */ 7662ddded21SEduardo Habkost halt(); 7672ddded21SEduardo Habkost for (;;) 7682ddded21SEduardo Habkost cpu_relax(); 7692ddded21SEduardo Habkost 7709c48f1c6SDon Zickus return NMI_HANDLED; 7712ddded21SEduardo Habkost } 7722ddded21SEduardo Habkost 7732ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 7742ddded21SEduardo Habkost { 775dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 7762ddded21SEduardo Habkost } 7772ddded21SEduardo Habkost 778144d102bSMichael D Labriola /* 779144d102bSMichael D Labriola * Halt all other CPUs, calling the specified function on each of them 780bb8dd270SEduardo Habkost * 781bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 782bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 783bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 784bb8dd270SEduardo Habkost */ 7852ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 7862ddded21SEduardo Habkost { 7872ddded21SEduardo Habkost unsigned long msecs; 788c415b3dcSEduardo Habkost local_irq_disable(); 7892ddded21SEduardo Habkost 7902ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback. */ 7912ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 7922ddded21SEduardo Habkost 7932ddded21SEduardo Habkost shootdown_callback = callback; 7942ddded21SEduardo Habkost 7952ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 7962ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 7979c48f1c6SDon Zickus if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, 7989c48f1c6SDon Zickus NMI_FLAG_FIRST, "crash")) 799144d102bSMichael D Labriola return; /* Return what? */ 800144d102bSMichael D Labriola /* 801144d102bSMichael D Labriola * Ensure the new callback function is set before sending 8022ddded21SEduardo Habkost * out the NMI 8032ddded21SEduardo Habkost */ 8042ddded21SEduardo Habkost wmb(); 8052ddded21SEduardo Habkost 8062ddded21SEduardo Habkost smp_send_nmi_allbutself(); 8072ddded21SEduardo Habkost 8082ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 8092ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 8102ddded21SEduardo Habkost mdelay(1); 8112ddded21SEduardo Habkost msecs--; 8122ddded21SEduardo Habkost } 8132ddded21SEduardo Habkost 8142ddded21SEduardo Habkost /* Leave the nmi callback set */ 8152ddded21SEduardo Habkost } 816bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 817bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 818bb8dd270SEduardo Habkost { 819bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 820bb8dd270SEduardo Habkost } 8212ddded21SEduardo Habkost #endif 822