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> 94d022e35SMiguel Boton #include <acpi/reboot.h> 104d022e35SMiguel Boton #include <asm/io.h> 114d022e35SMiguel Boton #include <asm/apic.h> 124d022e35SMiguel Boton #include <asm/desc.h> 134d022e35SMiguel Boton #include <asm/hpet.h> 1468db065cSJeremy Fitzhardinge #include <asm/pgtable.h> 154412620fSDmitri Vorobiev #include <asm/proto.h> 164d022e35SMiguel Boton #include <asm/reboot_fixups.h> 174d022e35SMiguel Boton #include <asm/reboot.h> 1882487711SJaswinder Singh Rajput #include <asm/pci_x86.h> 19d176720dSEduardo Habkost #include <asm/virtext.h> 2096b89dc6SJaswinder Singh Rajput #include <asm/cpu.h> 214d022e35SMiguel Boton 224d022e35SMiguel Boton #ifdef CONFIG_X86_32 234d022e35SMiguel Boton # include <linux/ctype.h> 244d022e35SMiguel Boton # include <linux/mc146818rtc.h> 254d022e35SMiguel Boton #else 264d022e35SMiguel Boton # include <asm/iommu.h> 274d022e35SMiguel Boton #endif 284d022e35SMiguel Boton 294d022e35SMiguel Boton /* 304d022e35SMiguel Boton * Power off function, if any 314d022e35SMiguel Boton */ 324d022e35SMiguel Boton void (*pm_power_off)(void); 334d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off); 344d022e35SMiguel Boton 35ebdd561aSJan Beulich static const struct desc_ptr no_idt = {}; 364d022e35SMiguel Boton static int reboot_mode; 378d00450dSEduardo Habkost enum reboot_type reboot_type = BOOT_KBD; 384d022e35SMiguel Boton int reboot_force; 394d022e35SMiguel Boton 404d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 414d022e35SMiguel Boton static int reboot_cpu = -1; 424d022e35SMiguel Boton #endif 434d022e35SMiguel Boton 44d176720dSEduardo Habkost /* This is set if we need to go through the 'emergency' path. 45d176720dSEduardo Habkost * When machine_emergency_restart() is called, we may be on 46d176720dSEduardo Habkost * an inconsistent state and won't be able to do a clean cleanup 47d176720dSEduardo Habkost */ 48d176720dSEduardo Habkost static int reboot_emergency; 49d176720dSEduardo Habkost 5014d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 5114d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 5214d7ca5cSH. Peter Anvin 5314d7ca5cSH. Peter Anvin /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] 544d022e35SMiguel Boton warm Don't set the cold reboot flag 554d022e35SMiguel Boton cold Set the cold reboot flag 564d022e35SMiguel Boton bios Reboot by jumping through the BIOS (only for X86_32) 574d022e35SMiguel Boton smp Reboot by executing reset on BSP or other CPU (only for X86_32) 584d022e35SMiguel Boton triple Force a triple fault (init) 594d022e35SMiguel Boton kbd Use the keyboard controller. cold reset (default) 604d022e35SMiguel Boton acpi Use the RESET_REG in the FADT 614d022e35SMiguel Boton efi Use efi reset_system runtime service 6214d7ca5cSH. Peter Anvin pci Use the so-called "PCI reset register", CF9 634d022e35SMiguel Boton force Avoid anything that could hang. 644d022e35SMiguel Boton */ 654d022e35SMiguel Boton static int __init reboot_setup(char *str) 664d022e35SMiguel Boton { 674d022e35SMiguel Boton for (;;) { 684d022e35SMiguel Boton switch (*str) { 694d022e35SMiguel Boton case 'w': 704d022e35SMiguel Boton reboot_mode = 0x1234; 714d022e35SMiguel Boton break; 724d022e35SMiguel Boton 734d022e35SMiguel Boton case 'c': 744d022e35SMiguel Boton reboot_mode = 0; 754d022e35SMiguel Boton break; 764d022e35SMiguel Boton 774d022e35SMiguel Boton #ifdef CONFIG_X86_32 784d022e35SMiguel Boton #ifdef CONFIG_SMP 794d022e35SMiguel Boton case 's': 804d022e35SMiguel Boton if (isdigit(*(str+1))) { 814d022e35SMiguel Boton reboot_cpu = (int) (*(str+1) - '0'); 824d022e35SMiguel Boton if (isdigit(*(str+2))) 834d022e35SMiguel Boton reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); 844d022e35SMiguel Boton } 854d022e35SMiguel Boton /* we will leave sorting out the final value 864d022e35SMiguel Boton when we are ready to reboot, since we might not 874d022e35SMiguel Boton have set up boot_cpu_id or smp_num_cpu */ 884d022e35SMiguel Boton break; 894d022e35SMiguel Boton #endif /* CONFIG_SMP */ 904d022e35SMiguel Boton 914d022e35SMiguel Boton case 'b': 924d022e35SMiguel Boton #endif 934d022e35SMiguel Boton case 'a': 944d022e35SMiguel Boton case 'k': 954d022e35SMiguel Boton case 't': 964d022e35SMiguel Boton case 'e': 9714d7ca5cSH. Peter Anvin case 'p': 984d022e35SMiguel Boton reboot_type = *str; 994d022e35SMiguel Boton break; 1004d022e35SMiguel Boton 1014d022e35SMiguel Boton case 'f': 1024d022e35SMiguel Boton reboot_force = 1; 1034d022e35SMiguel Boton break; 1044d022e35SMiguel Boton } 1054d022e35SMiguel Boton 1064d022e35SMiguel Boton str = strchr(str, ','); 1074d022e35SMiguel Boton if (str) 1084d022e35SMiguel Boton str++; 1094d022e35SMiguel Boton else 1104d022e35SMiguel Boton break; 1114d022e35SMiguel Boton } 1124d022e35SMiguel Boton return 1; 1134d022e35SMiguel Boton } 1144d022e35SMiguel Boton 1154d022e35SMiguel Boton __setup("reboot=", reboot_setup); 1164d022e35SMiguel Boton 1174d022e35SMiguel Boton 1184d022e35SMiguel Boton #ifdef CONFIG_X86_32 1194d022e35SMiguel Boton /* 1204d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 1214d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 1224d022e35SMiguel Boton */ 1234d022e35SMiguel Boton 1244d022e35SMiguel Boton /* 1254d022e35SMiguel Boton * Some machines require the "reboot=b" commandline option, 1264d022e35SMiguel Boton * this quirk makes that automatic. 1274d022e35SMiguel Boton */ 1284d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 1294d022e35SMiguel Boton { 1304d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 1314d022e35SMiguel Boton reboot_type = BOOT_BIOS; 1324d022e35SMiguel Boton printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); 1334d022e35SMiguel Boton } 1344d022e35SMiguel Boton return 0; 1354d022e35SMiguel Boton } 1364d022e35SMiguel Boton 1374d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 1384d022e35SMiguel Boton { /* Handle problems with rebooting on Dell E520's */ 1394d022e35SMiguel Boton .callback = set_bios_reboot, 1404d022e35SMiguel Boton .ident = "Dell E520", 1414d022e35SMiguel Boton .matches = { 1424d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1434d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 1444d022e35SMiguel Boton }, 1454d022e35SMiguel Boton }, 1464d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 1300's */ 1474d022e35SMiguel Boton .callback = set_bios_reboot, 1484d022e35SMiguel Boton .ident = "Dell PowerEdge 1300", 1494d022e35SMiguel Boton .matches = { 1504d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 1514d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 1524d022e35SMiguel Boton }, 1534d022e35SMiguel Boton }, 1544d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 300's */ 1554d022e35SMiguel Boton .callback = set_bios_reboot, 1564d022e35SMiguel Boton .ident = "Dell PowerEdge 300", 1574d022e35SMiguel Boton .matches = { 1584d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 1594d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 1604d022e35SMiguel Boton }, 1614d022e35SMiguel Boton }, 1624d022e35SMiguel Boton { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/ 1634d022e35SMiguel Boton .callback = set_bios_reboot, 1644d022e35SMiguel Boton .ident = "Dell OptiPlex 745", 1654d022e35SMiguel Boton .matches = { 1664d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1674d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 1684d022e35SMiguel Boton }, 1694d022e35SMiguel Boton }, 170fc115bf1SColeman Kane { /* Handle problems with rebooting on Dell Optiplex 745's DFF*/ 171fc115bf1SColeman Kane .callback = set_bios_reboot, 172fc115bf1SColeman Kane .ident = "Dell OptiPlex 745", 173fc115bf1SColeman Kane .matches = { 174fc115bf1SColeman Kane DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 175fc115bf1SColeman Kane DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 176fc115bf1SColeman Kane DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 177fc115bf1SColeman Kane }, 178fc115bf1SColeman Kane }, 179fc1c8925SHeinz-Ado Arnolds { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 180fc1c8925SHeinz-Ado Arnolds .callback = set_bios_reboot, 181fc1c8925SHeinz-Ado Arnolds .ident = "Dell OptiPlex 745", 182fc1c8925SHeinz-Ado Arnolds .matches = { 183fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 184fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 185fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 186fc1c8925SHeinz-Ado Arnolds }, 187fc1c8925SHeinz-Ado Arnolds }, 188093bac15SSteve Conklin { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 189093bac15SSteve Conklin .callback = set_bios_reboot, 190093bac15SSteve Conklin .ident = "Dell OptiPlex 330", 191093bac15SSteve Conklin .matches = { 192093bac15SSteve Conklin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 193093bac15SSteve Conklin DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 194093bac15SSteve Conklin DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 195093bac15SSteve Conklin }, 196093bac15SSteve Conklin }, 1974a4aca64SJean Delvare { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 1984a4aca64SJean Delvare .callback = set_bios_reboot, 1994a4aca64SJean Delvare .ident = "Dell OptiPlex 360", 2004a4aca64SJean Delvare .matches = { 2014a4aca64SJean Delvare DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2024a4aca64SJean Delvare DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 2034a4aca64SJean Delvare DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 2044a4aca64SJean Delvare }, 2054a4aca64SJean Delvare }, 2064d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 2400's */ 2074d022e35SMiguel Boton .callback = set_bios_reboot, 2084d022e35SMiguel Boton .ident = "Dell PowerEdge 2400", 2094d022e35SMiguel Boton .matches = { 2104d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 2114d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 2124d022e35SMiguel Boton }, 2134d022e35SMiguel Boton }, 214fab3b58dSIngo Molnar { /* Handle problems with rebooting on Dell T5400's */ 215fab3b58dSIngo Molnar .callback = set_bios_reboot, 216fab3b58dSIngo Molnar .ident = "Dell Precision T5400", 217fab3b58dSIngo Molnar .matches = { 218fab3b58dSIngo Molnar DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 219fab3b58dSIngo Molnar DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 220fab3b58dSIngo Molnar }, 221fab3b58dSIngo Molnar }, 2224d022e35SMiguel Boton { /* Handle problems with rebooting on HP laptops */ 2234d022e35SMiguel Boton .callback = set_bios_reboot, 2244d022e35SMiguel Boton .ident = "HP Compaq Laptop", 2254d022e35SMiguel Boton .matches = { 2264d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 2274d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 2284d022e35SMiguel Boton }, 2294d022e35SMiguel Boton }, 230dd4124a8SLeann Ogasawara { /* Handle problems with rebooting on Dell XPS710 */ 231dd4124a8SLeann Ogasawara .callback = set_bios_reboot, 232dd4124a8SLeann Ogasawara .ident = "Dell XPS710", 233dd4124a8SLeann Ogasawara .matches = { 234dd4124a8SLeann Ogasawara DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 235dd4124a8SLeann Ogasawara DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 236dd4124a8SLeann Ogasawara }, 237dd4124a8SLeann Ogasawara }, 238c5da9a2bSAlan Cox { /* Handle problems with rebooting on Dell DXP061 */ 239c5da9a2bSAlan Cox .callback = set_bios_reboot, 240c5da9a2bSAlan Cox .ident = "Dell DXP061", 241c5da9a2bSAlan Cox .matches = { 242c5da9a2bSAlan Cox DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 243c5da9a2bSAlan Cox DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 244c5da9a2bSAlan Cox }, 245c5da9a2bSAlan Cox }, 24688dff493SZhang Rui { /* Handle problems with rebooting on Sony VGN-Z540N */ 24788dff493SZhang Rui .callback = set_bios_reboot, 24888dff493SZhang Rui .ident = "Sony VGN-Z540N", 24988dff493SZhang Rui .matches = { 25088dff493SZhang Rui DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 25188dff493SZhang Rui DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 25288dff493SZhang Rui }, 25388dff493SZhang Rui }, 25477f32dfdSDenis Turischev { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */ 25577f32dfdSDenis Turischev .callback = set_bios_reboot, 25677f32dfdSDenis Turischev .ident = "CompuLab SBC-FITPC2", 25777f32dfdSDenis Turischev .matches = { 25877f32dfdSDenis Turischev DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"), 25977f32dfdSDenis Turischev DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), 26077f32dfdSDenis Turischev }, 26177f32dfdSDenis Turischev }, 262*4832dddaSLeann Ogasawara { /* Handle problems with rebooting on ASUS P4S800 */ 263*4832dddaSLeann Ogasawara .callback = set_bios_reboot, 264*4832dddaSLeann Ogasawara .ident = "ASUS P4S800", 265*4832dddaSLeann Ogasawara .matches = { 266*4832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 267*4832dddaSLeann Ogasawara DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 268*4832dddaSLeann Ogasawara }, 269*4832dddaSLeann Ogasawara }, 2704d022e35SMiguel Boton { } 2714d022e35SMiguel Boton }; 2724d022e35SMiguel Boton 2734d022e35SMiguel Boton static int __init reboot_init(void) 2744d022e35SMiguel Boton { 2754d022e35SMiguel Boton dmi_check_system(reboot_dmi_table); 2764d022e35SMiguel Boton return 0; 2774d022e35SMiguel Boton } 2784d022e35SMiguel Boton core_initcall(reboot_init); 2794d022e35SMiguel Boton 2804d022e35SMiguel Boton /* The following code and data reboots the machine by switching to real 2814d022e35SMiguel Boton mode and jumping to the BIOS reset entry point, as if the CPU has 2824d022e35SMiguel Boton really been reset. The previous version asked the keyboard 2834d022e35SMiguel Boton controller to pulse the CPU reset line, which is more thorough, but 2844d022e35SMiguel Boton doesn't work with at least one type of 486 motherboard. It is easy 2854d022e35SMiguel Boton to stop this code working; hence the copious comments. */ 286ebdd561aSJan Beulich static const unsigned long long 2874d022e35SMiguel Boton real_mode_gdt_entries [3] = 2884d022e35SMiguel Boton { 2894d022e35SMiguel Boton 0x0000000000000000ULL, /* Null descriptor */ 290ebdd561aSJan Beulich 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ 291ebdd561aSJan Beulich 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ 2924d022e35SMiguel Boton }; 2934d022e35SMiguel Boton 294ebdd561aSJan Beulich static const struct desc_ptr 2954d022e35SMiguel Boton real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, 2964d022e35SMiguel Boton real_mode_idt = { 0x3ff, 0 }; 2974d022e35SMiguel Boton 2984d022e35SMiguel Boton /* This is 16-bit protected mode code to disable paging and the cache, 2994d022e35SMiguel Boton switch to real mode and jump to the BIOS reset code. 3004d022e35SMiguel Boton 3014d022e35SMiguel Boton The instruction that switches to real mode by writing to CR0 must be 3024d022e35SMiguel Boton followed immediately by a far jump instruction, which set CS to a 3034d022e35SMiguel Boton valid value for real mode, and flushes the prefetch queue to avoid 3044d022e35SMiguel Boton running instructions that have already been decoded in protected 3054d022e35SMiguel Boton mode. 3064d022e35SMiguel Boton 3074d022e35SMiguel Boton Clears all the flags except ET, especially PG (paging), PE 3084d022e35SMiguel Boton (protected-mode enable) and TS (task switch for coprocessor state 3094d022e35SMiguel Boton save). Flushes the TLB after paging has been disabled. Sets CD and 3104d022e35SMiguel Boton NW, to disable the cache on a 486, and invalidates the cache. This 3114d022e35SMiguel Boton is more like the state of a 486 after reset. I don't know if 3124d022e35SMiguel Boton something else should be done for other chips. 3134d022e35SMiguel Boton 3144d022e35SMiguel Boton More could be done here to set up the registers as if a CPU reset had 3154d022e35SMiguel Boton occurred; hopefully real BIOSs don't assume much. */ 316ebdd561aSJan Beulich static const unsigned char real_mode_switch [] = 3174d022e35SMiguel Boton { 3184d022e35SMiguel Boton 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ 3194d022e35SMiguel Boton 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ 3204d022e35SMiguel Boton 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ 3214d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ 3224d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ 3234d022e35SMiguel Boton 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ 3244d022e35SMiguel Boton 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ 3254d022e35SMiguel Boton 0x74, 0x02, /* jz f */ 3264d022e35SMiguel Boton 0x0f, 0x09, /* wbinvd */ 3274d022e35SMiguel Boton 0x24, 0x10, /* f: andb $0x10,al */ 3284d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ 3294d022e35SMiguel Boton }; 330ebdd561aSJan Beulich static const unsigned char jump_to_bios [] = 3314d022e35SMiguel Boton { 3324d022e35SMiguel Boton 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ 3334d022e35SMiguel Boton }; 3344d022e35SMiguel Boton 3354d022e35SMiguel Boton /* 3364d022e35SMiguel Boton * Switch to real mode and then execute the code 3374d022e35SMiguel Boton * specified by the code and length parameters. 3384d022e35SMiguel Boton * We assume that length will aways be less that 100! 3394d022e35SMiguel Boton */ 340ebdd561aSJan Beulich void machine_real_restart(const unsigned char *code, int length) 3414d022e35SMiguel Boton { 3424d022e35SMiguel Boton local_irq_disable(); 3434d022e35SMiguel Boton 3444d022e35SMiguel Boton /* Write zero to CMOS register number 0x0f, which the BIOS POST 3454d022e35SMiguel Boton routine will recognize as telling it to do a proper reboot. (Well 3464d022e35SMiguel Boton that's what this book in front of me says -- it may only apply to 3474d022e35SMiguel Boton the Phoenix BIOS though, it's not clear). At the same time, 3484d022e35SMiguel Boton disable NMIs by setting the top bit in the CMOS address register, 3494d022e35SMiguel Boton as we're about to do peculiar things to the CPU. I'm not sure if 3504d022e35SMiguel Boton `outb_p' is needed instead of just `outb'. Use it to be on the 3514d022e35SMiguel Boton safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 3524d022e35SMiguel Boton */ 3534d022e35SMiguel Boton spin_lock(&rtc_lock); 3544d022e35SMiguel Boton CMOS_WRITE(0x00, 0x8f); 3554d022e35SMiguel Boton spin_unlock(&rtc_lock); 3564d022e35SMiguel Boton 3574d022e35SMiguel Boton /* Remap the kernel at virtual address zero, as well as offset zero 3584d022e35SMiguel Boton from the kernel segment. This assumes the kernel segment starts at 3594d022e35SMiguel Boton virtual address PAGE_OFFSET. */ 36068db065cSJeremy Fitzhardinge memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, 3614d022e35SMiguel Boton sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); 3624d022e35SMiguel Boton 3634d022e35SMiguel Boton /* 3644d022e35SMiguel Boton * Use `swapper_pg_dir' as our page directory. 3654d022e35SMiguel Boton */ 3664d022e35SMiguel Boton load_cr3(swapper_pg_dir); 3674d022e35SMiguel Boton 3684d022e35SMiguel Boton /* Write 0x1234 to absolute memory location 0x472. The BIOS reads 3694d022e35SMiguel Boton this on booting to tell it to "Bypass memory test (also warm 3704d022e35SMiguel Boton boot)". This seems like a fairly standard thing that gets set by 3714d022e35SMiguel Boton REBOOT.COM programs, and the previous reset routine did this 3724d022e35SMiguel Boton too. */ 3734d022e35SMiguel Boton *((unsigned short *)0x472) = reboot_mode; 3744d022e35SMiguel Boton 3754d022e35SMiguel Boton /* For the switch to real mode, copy some code to low memory. It has 3764d022e35SMiguel Boton to be in the first 64k because it is running in 16-bit mode, and it 3774d022e35SMiguel Boton has to have the same physical and virtual address, because it turns 3784d022e35SMiguel Boton off paging. Copy it near the end of the first page, out of the way 3794d022e35SMiguel Boton of BIOS variables. */ 3804d022e35SMiguel Boton memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100), 3814d022e35SMiguel Boton real_mode_switch, sizeof (real_mode_switch)); 3824d022e35SMiguel Boton memcpy((void *)(0x1000 - 100), code, length); 3834d022e35SMiguel Boton 3844d022e35SMiguel Boton /* Set up the IDT for real mode. */ 3854d022e35SMiguel Boton load_idt(&real_mode_idt); 3864d022e35SMiguel Boton 3874d022e35SMiguel Boton /* Set up a GDT from which we can load segment descriptors for real 3884d022e35SMiguel Boton mode. The GDT is not used in real mode; it is just needed here to 3894d022e35SMiguel Boton prepare the descriptors. */ 3904d022e35SMiguel Boton load_gdt(&real_mode_gdt); 3914d022e35SMiguel Boton 3924d022e35SMiguel Boton /* Load the data segment registers, and thus the descriptors ready for 3934d022e35SMiguel Boton real mode. The base address of each segment is 0x100, 16 times the 3944d022e35SMiguel Boton selector value being loaded here. This is so that the segment 3954d022e35SMiguel Boton registers don't have to be reloaded after switching to real mode: 3964d022e35SMiguel Boton the values are consistent for real mode operation already. */ 3974d022e35SMiguel Boton __asm__ __volatile__ ("movl $0x0010,%%eax\n" 3984d022e35SMiguel Boton "\tmovl %%eax,%%ds\n" 3994d022e35SMiguel Boton "\tmovl %%eax,%%es\n" 4004d022e35SMiguel Boton "\tmovl %%eax,%%fs\n" 4014d022e35SMiguel Boton "\tmovl %%eax,%%gs\n" 4024d022e35SMiguel Boton "\tmovl %%eax,%%ss" : : : "eax"); 4034d022e35SMiguel Boton 4044d022e35SMiguel Boton /* Jump to the 16-bit code that we copied earlier. It disables paging 4054d022e35SMiguel Boton and the cache, switches to real mode, and jumps to the BIOS reset 4064d022e35SMiguel Boton entry point. */ 4074d022e35SMiguel Boton __asm__ __volatile__ ("ljmp $0x0008,%0" 4084d022e35SMiguel Boton : 4094d022e35SMiguel Boton : "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100))); 4104d022e35SMiguel Boton } 4114d022e35SMiguel Boton #ifdef CONFIG_APM_MODULE 4124d022e35SMiguel Boton EXPORT_SYMBOL(machine_real_restart); 4134d022e35SMiguel Boton #endif 4144d022e35SMiguel Boton 4154d022e35SMiguel Boton #endif /* CONFIG_X86_32 */ 4164d022e35SMiguel Boton 4176c6c51e4SPaul Mackerras /* 418498cdbfbSOzan Çağlayan * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot 4196c6c51e4SPaul Mackerras */ 4206c6c51e4SPaul Mackerras static int __init set_pci_reboot(const struct dmi_system_id *d) 4216c6c51e4SPaul Mackerras { 4226c6c51e4SPaul Mackerras if (reboot_type != BOOT_CF9) { 4236c6c51e4SPaul Mackerras reboot_type = BOOT_CF9; 4246c6c51e4SPaul Mackerras printk(KERN_INFO "%s series board detected. " 4256c6c51e4SPaul Mackerras "Selecting PCI-method for reboots.\n", d->ident); 4266c6c51e4SPaul Mackerras } 4276c6c51e4SPaul Mackerras return 0; 4286c6c51e4SPaul Mackerras } 4296c6c51e4SPaul Mackerras 4306c6c51e4SPaul Mackerras static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { 4313e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBook5 */ 4326c6c51e4SPaul Mackerras .callback = set_pci_reboot, 4333e03bbeaSShunichi Fuji .ident = "Apple MacBook5", 4346c6c51e4SPaul Mackerras .matches = { 4356c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4363e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), 4376c6c51e4SPaul Mackerras }, 4386c6c51e4SPaul Mackerras }, 4393e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBookPro5 */ 440498cdbfbSOzan Çağlayan .callback = set_pci_reboot, 4413e03bbeaSShunichi Fuji .ident = "Apple MacBookPro5", 442498cdbfbSOzan Çağlayan .matches = { 443498cdbfbSOzan Çağlayan DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 4443e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), 445498cdbfbSOzan Çağlayan }, 446498cdbfbSOzan Çağlayan }, 44705154752SGottfried Haider { /* Handle problems with rebooting on Apple Macmini3,1 */ 44805154752SGottfried Haider .callback = set_pci_reboot, 44905154752SGottfried Haider .ident = "Apple Macmini3,1", 45005154752SGottfried Haider .matches = { 45105154752SGottfried Haider DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 45205154752SGottfried Haider DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), 45305154752SGottfried Haider }, 45405154752SGottfried Haider }, 4556c6c51e4SPaul Mackerras { } 4566c6c51e4SPaul Mackerras }; 4576c6c51e4SPaul Mackerras 4586c6c51e4SPaul Mackerras static int __init pci_reboot_init(void) 4596c6c51e4SPaul Mackerras { 4606c6c51e4SPaul Mackerras dmi_check_system(pci_reboot_dmi_table); 4616c6c51e4SPaul Mackerras return 0; 4626c6c51e4SPaul Mackerras } 4636c6c51e4SPaul Mackerras core_initcall(pci_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 476d176720dSEduardo Habkost static void vmxoff_nmi(int cpu, struct die_args *args) 477d176720dSEduardo Habkost { 478d176720dSEduardo Habkost cpu_emergency_vmxoff(); 479d176720dSEduardo Habkost } 480d176720dSEduardo Habkost 481d176720dSEduardo Habkost /* Use NMIs as IPIs to tell all CPUs to disable virtualization 482d176720dSEduardo Habkost */ 483d176720dSEduardo Habkost static void emergency_vmx_disable_all(void) 484d176720dSEduardo Habkost { 485d176720dSEduardo Habkost /* Just make sure we won't change CPUs while doing this */ 486d176720dSEduardo Habkost local_irq_disable(); 487d176720dSEduardo Habkost 488d176720dSEduardo Habkost /* 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()) { 507d176720dSEduardo Habkost /* Disable VMX on this CPU. 508d176720dSEduardo Habkost */ 509d176720dSEduardo Habkost cpu_vmxoff(); 510d176720dSEduardo Habkost 511d176720dSEduardo Habkost /* Halt and disable VMX on the other CPUs */ 512d176720dSEduardo Habkost nmi_shootdown_cpus(vmxoff_nmi); 513d176720dSEduardo Habkost 514d176720dSEduardo Habkost } 515d176720dSEduardo Habkost } 516d176720dSEduardo Habkost 517d176720dSEduardo Habkost 5187432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 5197432d149SIngo Molnar { 5207432d149SIngo Molnar } 5217432d149SIngo Molnar 522416e2d63SJody Belka static void native_machine_emergency_restart(void) 5234d022e35SMiguel Boton { 5244d022e35SMiguel Boton int i; 5254d022e35SMiguel Boton 526d176720dSEduardo Habkost if (reboot_emergency) 527d176720dSEduardo Habkost emergency_vmx_disable_all(); 528d176720dSEduardo Habkost 529840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 530840c2bafSJoseph Cihula 5314d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 5324d022e35SMiguel Boton *((unsigned short *)__va(0x472)) = reboot_mode; 5334d022e35SMiguel Boton 5344d022e35SMiguel Boton for (;;) { 5354d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 5364d022e35SMiguel Boton switch (reboot_type) { 5374d022e35SMiguel Boton case BOOT_KBD: 5387432d149SIngo Molnar mach_reboot_fixups(); /* for board specific fixups */ 5397432d149SIngo Molnar 5404d022e35SMiguel Boton for (i = 0; i < 10; i++) { 5414d022e35SMiguel Boton kb_wait(); 5424d022e35SMiguel Boton udelay(50); 5434d022e35SMiguel Boton outb(0xfe, 0x64); /* pulse reset low */ 5444d022e35SMiguel Boton udelay(50); 5454d022e35SMiguel Boton } 5464d022e35SMiguel Boton 5474d022e35SMiguel Boton case BOOT_TRIPLE: 548ebdd561aSJan Beulich load_idt(&no_idt); 5494d022e35SMiguel Boton __asm__ __volatile__("int3"); 5504d022e35SMiguel Boton 5514d022e35SMiguel Boton reboot_type = BOOT_KBD; 5524d022e35SMiguel Boton break; 5534d022e35SMiguel Boton 5544d022e35SMiguel Boton #ifdef CONFIG_X86_32 5554d022e35SMiguel Boton case BOOT_BIOS: 5564d022e35SMiguel Boton machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); 5574d022e35SMiguel Boton 5584d022e35SMiguel Boton reboot_type = BOOT_KBD; 5594d022e35SMiguel Boton break; 5604d022e35SMiguel Boton #endif 5614d022e35SMiguel Boton 5624d022e35SMiguel Boton case BOOT_ACPI: 5634d022e35SMiguel Boton acpi_reboot(); 5644d022e35SMiguel Boton reboot_type = BOOT_KBD; 5654d022e35SMiguel Boton break; 5664d022e35SMiguel Boton 5674d022e35SMiguel Boton case BOOT_EFI: 5684d022e35SMiguel Boton if (efi_enabled) 56914d7ca5cSH. Peter Anvin efi.reset_system(reboot_mode ? 57014d7ca5cSH. Peter Anvin EFI_RESET_WARM : 57114d7ca5cSH. Peter Anvin EFI_RESET_COLD, 5724d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 573b47b9288SH. Peter Anvin reboot_type = BOOT_KBD; 57414d7ca5cSH. Peter Anvin break; 5754d022e35SMiguel Boton 57614d7ca5cSH. Peter Anvin case BOOT_CF9: 57714d7ca5cSH. Peter Anvin port_cf9_safe = true; 57814d7ca5cSH. Peter Anvin /* fall through */ 57914d7ca5cSH. Peter Anvin 58014d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 58114d7ca5cSH. Peter Anvin if (port_cf9_safe) { 58214d7ca5cSH. Peter Anvin u8 cf9 = inb(0xcf9) & ~6; 58314d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 58414d7ca5cSH. Peter Anvin udelay(50); 58514d7ca5cSH. Peter Anvin outb(cf9|6, 0xcf9); /* Actually do the reset */ 58614d7ca5cSH. Peter Anvin udelay(50); 58714d7ca5cSH. Peter Anvin } 5884d022e35SMiguel Boton reboot_type = BOOT_KBD; 5894d022e35SMiguel Boton break; 5904d022e35SMiguel Boton } 5914d022e35SMiguel Boton } 5924d022e35SMiguel Boton } 5934d022e35SMiguel Boton 5943c62c625SGlauber Costa void native_machine_shutdown(void) 5954d022e35SMiguel Boton { 5964d022e35SMiguel Boton /* Stop the cpus and apics */ 5974d022e35SMiguel Boton #ifdef CONFIG_SMP 5984d022e35SMiguel Boton 5994d022e35SMiguel Boton /* The boot cpu is always logical cpu 0 */ 60065c01184SMike Travis int reboot_cpu_id = 0; 6014d022e35SMiguel Boton 6024d022e35SMiguel Boton #ifdef CONFIG_X86_32 6034d022e35SMiguel Boton /* See if there has been given a command line override */ 6049628937dSMike Travis if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && 6050bc3cc03SMike Travis cpu_online(reboot_cpu)) 6064d022e35SMiguel Boton reboot_cpu_id = reboot_cpu; 6074d022e35SMiguel Boton #endif 6084d022e35SMiguel Boton 6094d022e35SMiguel Boton /* Make certain the cpu I'm about to reboot on is online */ 6100bc3cc03SMike Travis if (!cpu_online(reboot_cpu_id)) 6114d022e35SMiguel Boton reboot_cpu_id = smp_processor_id(); 6124d022e35SMiguel Boton 6134d022e35SMiguel Boton /* Make certain I only run on the appropriate processor */ 6149628937dSMike Travis set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); 6154d022e35SMiguel Boton 6164d022e35SMiguel Boton /* O.K Now that I'm on the appropriate processor, 6174d022e35SMiguel Boton * stop all of the others. 6184d022e35SMiguel Boton */ 6194d022e35SMiguel Boton smp_send_stop(); 6204d022e35SMiguel Boton #endif 6214d022e35SMiguel Boton 6224d022e35SMiguel Boton lapic_shutdown(); 6234d022e35SMiguel Boton 6244d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC 6254d022e35SMiguel Boton disable_IO_APIC(); 6264d022e35SMiguel Boton #endif 6274d022e35SMiguel Boton 6284d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 6294d022e35SMiguel Boton hpet_disable(); 6304d022e35SMiguel Boton #endif 6314d022e35SMiguel Boton 6324d022e35SMiguel Boton #ifdef CONFIG_X86_64 6334d022e35SMiguel Boton pci_iommu_shutdown(); 6344d022e35SMiguel Boton #endif 6354d022e35SMiguel Boton } 6364d022e35SMiguel Boton 637d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 638d176720dSEduardo Habkost { 639d176720dSEduardo Habkost reboot_emergency = emergency; 640d176720dSEduardo Habkost machine_ops.emergency_restart(); 641d176720dSEduardo Habkost } 642d176720dSEduardo Habkost 643416e2d63SJody Belka static void native_machine_restart(char *__unused) 6444d022e35SMiguel Boton { 6454d022e35SMiguel Boton printk("machine restart\n"); 6464d022e35SMiguel Boton 6474d022e35SMiguel Boton if (!reboot_force) 6484d022e35SMiguel Boton machine_shutdown(); 649d176720dSEduardo Habkost __machine_emergency_restart(0); 6504d022e35SMiguel Boton } 6514d022e35SMiguel Boton 652416e2d63SJody Belka static void native_machine_halt(void) 6534d022e35SMiguel Boton { 654d3ec5caeSIvan Vecera /* stop other cpus and apics */ 655d3ec5caeSIvan Vecera machine_shutdown(); 656d3ec5caeSIvan Vecera 657840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 658840c2bafSJoseph Cihula 659d3ec5caeSIvan Vecera /* stop this cpu */ 660d3ec5caeSIvan Vecera stop_this_cpu(NULL); 6614d022e35SMiguel Boton } 6624d022e35SMiguel Boton 663416e2d63SJody Belka static void native_machine_power_off(void) 6644d022e35SMiguel Boton { 6654d022e35SMiguel Boton if (pm_power_off) { 6664d022e35SMiguel Boton if (!reboot_force) 6674d022e35SMiguel Boton machine_shutdown(); 6684d022e35SMiguel Boton pm_power_off(); 6694d022e35SMiguel Boton } 670840c2bafSJoseph Cihula /* a fallback in case there is no PM info available */ 671840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 6724d022e35SMiguel Boton } 6734d022e35SMiguel Boton 6744d022e35SMiguel Boton struct machine_ops machine_ops = { 675416e2d63SJody Belka .power_off = native_machine_power_off, 676416e2d63SJody Belka .shutdown = native_machine_shutdown, 677416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 678416e2d63SJody Belka .restart = native_machine_restart, 679ed23dc6fSGlauber Costa .halt = native_machine_halt, 680ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 681ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 682ed23dc6fSGlauber Costa #endif 6834d022e35SMiguel Boton }; 684416e2d63SJody Belka 685416e2d63SJody Belka void machine_power_off(void) 686416e2d63SJody Belka { 687416e2d63SJody Belka machine_ops.power_off(); 688416e2d63SJody Belka } 689416e2d63SJody Belka 690416e2d63SJody Belka void machine_shutdown(void) 691416e2d63SJody Belka { 692416e2d63SJody Belka machine_ops.shutdown(); 693416e2d63SJody Belka } 694416e2d63SJody Belka 695416e2d63SJody Belka void machine_emergency_restart(void) 696416e2d63SJody Belka { 697d176720dSEduardo Habkost __machine_emergency_restart(1); 698416e2d63SJody Belka } 699416e2d63SJody Belka 700416e2d63SJody Belka void machine_restart(char *cmd) 701416e2d63SJody Belka { 702416e2d63SJody Belka machine_ops.restart(cmd); 703416e2d63SJody Belka } 704416e2d63SJody Belka 705416e2d63SJody Belka void machine_halt(void) 706416e2d63SJody Belka { 707416e2d63SJody Belka machine_ops.halt(); 708416e2d63SJody Belka } 709416e2d63SJody Belka 710ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 711ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 712ed23dc6fSGlauber Costa { 713ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 714ed23dc6fSGlauber Costa } 715ed23dc6fSGlauber Costa #endif 7162ddded21SEduardo Habkost 7172ddded21SEduardo Habkost 718bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 7192ddded21SEduardo Habkost 7202ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 7212ddded21SEduardo Habkost static int crashing_cpu; 7222ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 7232ddded21SEduardo Habkost 7242ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 7252ddded21SEduardo Habkost 7262ddded21SEduardo Habkost static int crash_nmi_callback(struct notifier_block *self, 7272ddded21SEduardo Habkost unsigned long val, void *data) 7282ddded21SEduardo Habkost { 7292ddded21SEduardo Habkost int cpu; 7302ddded21SEduardo Habkost 7312ddded21SEduardo Habkost if (val != DIE_NMI_IPI) 7322ddded21SEduardo Habkost return NOTIFY_OK; 7332ddded21SEduardo Habkost 7342ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 7352ddded21SEduardo Habkost 7362ddded21SEduardo Habkost /* Don't do anything if this handler is invoked on crashing cpu. 7372ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 7382ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 7392ddded21SEduardo Habkost */ 7402ddded21SEduardo Habkost if (cpu == crashing_cpu) 7412ddded21SEduardo Habkost return NOTIFY_STOP; 7422ddded21SEduardo Habkost local_irq_disable(); 7432ddded21SEduardo Habkost 7442ddded21SEduardo Habkost shootdown_callback(cpu, (struct die_args *)data); 7452ddded21SEduardo Habkost 7462ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 7472ddded21SEduardo Habkost /* Assume hlt works */ 7482ddded21SEduardo Habkost halt(); 7492ddded21SEduardo Habkost for (;;) 7502ddded21SEduardo Habkost cpu_relax(); 7512ddded21SEduardo Habkost 7522ddded21SEduardo Habkost return 1; 7532ddded21SEduardo Habkost } 7542ddded21SEduardo Habkost 7552ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 7562ddded21SEduardo Habkost { 757dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 7582ddded21SEduardo Habkost } 7592ddded21SEduardo Habkost 7602ddded21SEduardo Habkost static struct notifier_block crash_nmi_nb = { 7612ddded21SEduardo Habkost .notifier_call = crash_nmi_callback, 7622ddded21SEduardo Habkost }; 7632ddded21SEduardo Habkost 764bb8dd270SEduardo Habkost /* Halt all other CPUs, calling the specified function on each of them 765bb8dd270SEduardo Habkost * 766bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 767bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 768bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 769bb8dd270SEduardo Habkost */ 7702ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 7712ddded21SEduardo Habkost { 7722ddded21SEduardo Habkost unsigned long msecs; 773c415b3dcSEduardo Habkost local_irq_disable(); 7742ddded21SEduardo Habkost 7752ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback.*/ 7762ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 7772ddded21SEduardo Habkost 7782ddded21SEduardo Habkost shootdown_callback = callback; 7792ddded21SEduardo Habkost 7802ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 7812ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 7822ddded21SEduardo Habkost if (register_die_notifier(&crash_nmi_nb)) 7832ddded21SEduardo Habkost return; /* return what? */ 7842ddded21SEduardo Habkost /* Ensure the new callback function is set before sending 7852ddded21SEduardo Habkost * out the NMI 7862ddded21SEduardo Habkost */ 7872ddded21SEduardo Habkost wmb(); 7882ddded21SEduardo Habkost 7892ddded21SEduardo Habkost smp_send_nmi_allbutself(); 7902ddded21SEduardo Habkost 7912ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 7922ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 7932ddded21SEduardo Habkost mdelay(1); 7942ddded21SEduardo Habkost msecs--; 7952ddded21SEduardo Habkost } 7962ddded21SEduardo Habkost 7972ddded21SEduardo Habkost /* Leave the nmi callback set */ 7982ddded21SEduardo Habkost } 799bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 800bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 801bb8dd270SEduardo Habkost { 802bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 803bb8dd270SEduardo Habkost } 8042ddded21SEduardo Habkost #endif 805