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 = {}; 394d022e35SMiguel Boton 40144d102bSMichael D Labriola /* 41144d102bSMichael D Labriola * This is set if we need to go through the 'emergency' path. 42d176720dSEduardo Habkost * When machine_emergency_restart() is called, we may be on 43d176720dSEduardo Habkost * an inconsistent state and won't be able to do a clean cleanup 44d176720dSEduardo Habkost */ 45d176720dSEduardo Habkost static int reboot_emergency; 46d176720dSEduardo Habkost 4714d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 4814d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 4914d7ca5cSH. Peter Anvin 50144d102bSMichael D Labriola /* 514d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 524d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 534d022e35SMiguel Boton */ 544d022e35SMiguel Boton 554d022e35SMiguel Boton /* 561ef03890SPeter Chubb * Some machines require the "reboot=b" or "reboot=k" commandline options, 574d022e35SMiguel Boton * this quirk makes that automatic. 584d022e35SMiguel Boton */ 594d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 604d022e35SMiguel Boton { 614d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 624d022e35SMiguel Boton reboot_type = BOOT_BIOS; 63c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 646d9153bbSLan Tianyu d->ident, "BIOS"); 654d022e35SMiguel Boton } 664d022e35SMiguel Boton return 0; 674d022e35SMiguel Boton } 684d022e35SMiguel Boton 6965051397SH. Peter Anvin void __noreturn machine_real_restart(unsigned int type) 7057b16594SMichael D Labriola { 7157b16594SMichael D Labriola local_irq_disable(); 7257b16594SMichael D Labriola 73144d102bSMichael D Labriola /* 74144d102bSMichael D Labriola * Write zero to CMOS register number 0x0f, which the BIOS POST 75144d102bSMichael D Labriola * routine will recognize as telling it to do a proper reboot. (Well 76144d102bSMichael D Labriola * that's what this book in front of me says -- it may only apply to 77144d102bSMichael D Labriola * the Phoenix BIOS though, it's not clear). At the same time, 78144d102bSMichael D Labriola * disable NMIs by setting the top bit in the CMOS address register, 79144d102bSMichael D Labriola * as we're about to do peculiar things to the CPU. I'm not sure if 80144d102bSMichael D Labriola * `outb_p' is needed instead of just `outb'. Use it to be on the 81144d102bSMichael D Labriola * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 8257b16594SMichael D Labriola */ 8357b16594SMichael D Labriola spin_lock(&rtc_lock); 8457b16594SMichael D Labriola CMOS_WRITE(0x00, 0x8f); 8557b16594SMichael D Labriola spin_unlock(&rtc_lock); 8657b16594SMichael D Labriola 8757b16594SMichael D Labriola /* 8857b16594SMichael D Labriola * Switch back to the initial page table. 8957b16594SMichael D Labriola */ 9065051397SH. Peter Anvin #ifdef CONFIG_X86_32 9157b16594SMichael D Labriola load_cr3(initial_page_table); 9265051397SH. Peter Anvin #else 9365051397SH. Peter Anvin write_cr3(real_mode_header->trampoline_pgd); 9465051397SH. Peter Anvin #endif 9557b16594SMichael D Labriola 9657b16594SMichael D Labriola /* Jump to the identity-mapped low memory code */ 9765051397SH. Peter Anvin #ifdef CONFIG_X86_32 9865051397SH. Peter Anvin asm volatile("jmpl *%0" : : 9965051397SH. Peter Anvin "rm" (real_mode_header->machine_real_restart_asm), 10065051397SH. Peter Anvin "a" (type)); 10165051397SH. Peter Anvin #else 10265051397SH. Peter Anvin asm volatile("ljmpl *%0" : : 10365051397SH. Peter Anvin "m" (real_mode_header->machine_real_restart_asm), 10465051397SH. Peter Anvin "D" (type)); 10565051397SH. Peter Anvin #endif 10665051397SH. Peter Anvin unreachable(); 10757b16594SMichael D Labriola } 10857b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE 10957b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart); 11057b16594SMichael D Labriola #endif 11157b16594SMichael D Labriola 11257b16594SMichael D Labriola /* 11357b16594SMichael D Labriola * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot 11457b16594SMichael D Labriola */ 11557b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d) 11657b16594SMichael D Labriola { 11757b16594SMichael D Labriola if (reboot_type != BOOT_CF9) { 11857b16594SMichael D Labriola reboot_type = BOOT_CF9; 119c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 1206d9153bbSLan Tianyu d->ident, "PCI"); 12157b16594SMichael D Labriola } 12257b16594SMichael D Labriola return 0; 12357b16594SMichael D Labriola } 12457b16594SMichael D Labriola 1251ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d) 1261ef03890SPeter Chubb { 1271ef03890SPeter Chubb if (reboot_type != BOOT_KBD) { 1281ef03890SPeter Chubb reboot_type = BOOT_KBD; 129c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboot.\n", 1306d9153bbSLan Tianyu d->ident, "KBD"); 1311ef03890SPeter Chubb } 1321ef03890SPeter Chubb return 0; 1331ef03890SPeter Chubb } 1341ef03890SPeter Chubb 135144d102bSMichael D Labriola /* 13665051397SH. Peter Anvin * This is a single dmi_table handling all reboot quirks. 13757b16594SMichael D Labriola */ 1384d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 13957b16594SMichael D Labriola 140e56e57f6SDave Jones /* Acer */ 141b49c78d4SPeter Chubb { /* Handle reboot issue on Acer Aspire one */ 1421ef03890SPeter Chubb .callback = set_kbd_reboot, 143b49c78d4SPeter Chubb .ident = "Acer Aspire One A110", 144b49c78d4SPeter Chubb .matches = { 145b49c78d4SPeter Chubb DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 146b49c78d4SPeter Chubb DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 147b49c78d4SPeter Chubb }, 148b49c78d4SPeter Chubb }, 149e56e57f6SDave Jones 150e56e57f6SDave Jones /* Apple */ 1513e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBook5 */ 1526c6c51e4SPaul Mackerras .callback = set_pci_reboot, 1533e03bbeaSShunichi Fuji .ident = "Apple MacBook5", 1546c6c51e4SPaul Mackerras .matches = { 1556c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1563e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), 1576c6c51e4SPaul Mackerras }, 1586c6c51e4SPaul Mackerras }, 1593e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBookPro5 */ 160498cdbfbSOzan Çağlayan .callback = set_pci_reboot, 1613e03bbeaSShunichi Fuji .ident = "Apple MacBookPro5", 162498cdbfbSOzan Çağlayan .matches = { 163498cdbfbSOzan Çağlayan DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1643e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), 165498cdbfbSOzan Çağlayan }, 166498cdbfbSOzan Çağlayan }, 16705154752SGottfried Haider { /* Handle problems with rebooting on Apple Macmini3,1 */ 16805154752SGottfried Haider .callback = set_pci_reboot, 16905154752SGottfried Haider .ident = "Apple Macmini3,1", 17005154752SGottfried Haider .matches = { 17105154752SGottfried Haider DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 17205154752SGottfried Haider DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), 17305154752SGottfried Haider }, 17405154752SGottfried Haider }, 1750a832320SJustin P. Mattock { /* Handle problems with rebooting on the iMac9,1. */ 1760a832320SJustin P. Mattock .callback = set_pci_reboot, 1770a832320SJustin P. Mattock .ident = "Apple iMac9,1", 1780a832320SJustin P. Mattock .matches = { 1790a832320SJustin P. Mattock DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1800a832320SJustin P. Mattock DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), 1810a832320SJustin P. Mattock }, 1820a832320SJustin P. Mattock }, 183e56e57f6SDave Jones 184e56e57f6SDave Jones /* ASUS */ 185e56e57f6SDave Jones { /* Handle problems with rebooting on ASUS P4S800 */ 186e56e57f6SDave Jones .callback = set_bios_reboot, 187e56e57f6SDave Jones .ident = "ASUS P4S800", 188e56e57f6SDave Jones .matches = { 189e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 190e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 191e56e57f6SDave Jones }, 192e56e57f6SDave Jones }, 193e56e57f6SDave Jones 194e56e57f6SDave Jones /* Dell */ 195e56e57f6SDave Jones { /* Handle problems with rebooting on Dell DXP061 */ 196e56e57f6SDave Jones .callback = set_bios_reboot, 197e56e57f6SDave Jones .ident = "Dell DXP061", 1983628c3f5SMaxime Ripard .matches = { 1993628c3f5SMaxime Ripard DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 200e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 201e56e57f6SDave Jones }, 202e56e57f6SDave Jones }, 203e56e57f6SDave Jones { /* Handle problems with rebooting on Dell E520's */ 204e56e57f6SDave Jones .callback = set_bios_reboot, 205e56e57f6SDave Jones .ident = "Dell E520", 206e56e57f6SDave Jones .matches = { 207e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 208e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 2093628c3f5SMaxime Ripard }, 2103628c3f5SMaxime Ripard }, 2118412da75SVille Syrjälä { /* Handle problems with rebooting on the Latitude E5410. */ 2128412da75SVille Syrjälä .callback = set_pci_reboot, 2138412da75SVille Syrjälä .ident = "Dell Latitude E5410", 2148412da75SVille Syrjälä .matches = { 2158412da75SVille Syrjälä DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2168412da75SVille Syrjälä DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"), 2178412da75SVille Syrjälä }, 2188412da75SVille Syrjälä }, 219b7798d28SDaniel J Blueman { /* Handle problems with rebooting on the Latitude E5420. */ 220b7798d28SDaniel J Blueman .callback = set_pci_reboot, 221b7798d28SDaniel J Blueman .ident = "Dell Latitude E5420", 222b7798d28SDaniel J Blueman .matches = { 223b7798d28SDaniel J Blueman DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 224b7798d28SDaniel J Blueman DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), 225b7798d28SDaniel J Blueman }, 226b7798d28SDaniel J Blueman }, 227e56e57f6SDave Jones { /* Handle problems with rebooting on the Latitude E6320. */ 228e56e57f6SDave Jones .callback = set_pci_reboot, 229e56e57f6SDave Jones .ident = "Dell Latitude E6320", 230e56e57f6SDave Jones .matches = { 231e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 232e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), 233e56e57f6SDave Jones }, 234e56e57f6SDave Jones }, 235a536877eSH. Peter Anvin { /* Handle problems with rebooting on the Latitude E6420. */ 236a536877eSH. Peter Anvin .callback = set_pci_reboot, 237a536877eSH. Peter Anvin .ident = "Dell Latitude E6420", 238a536877eSH. Peter Anvin .matches = { 239a536877eSH. Peter Anvin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 240a536877eSH. Peter Anvin DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), 241a536877eSH. Peter Anvin }, 242a536877eSH. Peter Anvin }, 243e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 244e56e57f6SDave Jones .callback = set_bios_reboot, 245e56e57f6SDave Jones .ident = "Dell OptiPlex 330", 246e56e57f6SDave Jones .matches = { 247e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 248e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 249e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 250e56e57f6SDave Jones }, 251e56e57f6SDave Jones }, 252e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 253e56e57f6SDave Jones .callback = set_bios_reboot, 254e56e57f6SDave Jones .ident = "Dell OptiPlex 360", 255e56e57f6SDave Jones .matches = { 256e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 257e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 258e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 259e56e57f6SDave Jones }, 260e56e57f6SDave Jones }, 261e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ 262e56e57f6SDave Jones .callback = set_bios_reboot, 263e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 264e56e57f6SDave Jones .matches = { 265e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 266e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 267e56e57f6SDave Jones }, 268e56e57f6SDave Jones }, 269e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ 270e56e57f6SDave Jones .callback = set_bios_reboot, 271e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 272e56e57f6SDave Jones .matches = { 273e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 274e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 275e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 276e56e57f6SDave Jones }, 277e56e57f6SDave Jones }, 278e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 279e56e57f6SDave Jones .callback = set_bios_reboot, 280e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 281e56e57f6SDave Jones .matches = { 282e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 283e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 284e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 285e56e57f6SDave Jones }, 286e56e57f6SDave Jones }, 287e56e57f6SDave Jones { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ 288e56e57f6SDave Jones .callback = set_bios_reboot, 289e56e57f6SDave Jones .ident = "Dell OptiPlex 760", 290e56e57f6SDave Jones .matches = { 291e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 292e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), 293e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0G919G"), 294e56e57f6SDave Jones }, 295e56e57f6SDave Jones }, 2966be30bb7SRafael J. Wysocki { /* Handle problems with rebooting on the OptiPlex 990. */ 2976be30bb7SRafael J. Wysocki .callback = set_pci_reboot, 2986be30bb7SRafael J. Wysocki .ident = "Dell OptiPlex 990", 2996be30bb7SRafael J. Wysocki .matches = { 3006be30bb7SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 3016be30bb7SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), 3026be30bb7SRafael J. Wysocki }, 3036be30bb7SRafael J. Wysocki }, 304e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 300's */ 305e56e57f6SDave Jones .callback = set_bios_reboot, 306e56e57f6SDave Jones .ident = "Dell PowerEdge 300", 30776eb9a30SZhang Rui .matches = { 308e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 309e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 310e56e57f6SDave Jones }, 311e56e57f6SDave Jones }, 312e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 1300's */ 313e56e57f6SDave Jones .callback = set_bios_reboot, 314e56e57f6SDave Jones .ident = "Dell PowerEdge 1300", 315e56e57f6SDave Jones .matches = { 316e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 317e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 318e56e57f6SDave Jones }, 319e56e57f6SDave Jones }, 320e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 2400's */ 321e56e57f6SDave Jones .callback = set_bios_reboot, 322e56e57f6SDave Jones .ident = "Dell PowerEdge 2400", 323e56e57f6SDave Jones .matches = { 324e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 325e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 32676eb9a30SZhang Rui }, 32776eb9a30SZhang Rui }, 3284f0acd31SMasoud Sharbiani { /* Handle problems with rebooting on the Dell PowerEdge C6100. */ 3294f0acd31SMasoud Sharbiani .callback = set_pci_reboot, 3304f0acd31SMasoud Sharbiani .ident = "Dell PowerEdge C6100", 3314f0acd31SMasoud Sharbiani .matches = { 3324f0acd31SMasoud Sharbiani DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 3334f0acd31SMasoud Sharbiani DMI_MATCH(DMI_PRODUCT_NAME, "C6100"), 3344f0acd31SMasoud Sharbiani }, 3354f0acd31SMasoud Sharbiani }, 3366c6c51e4SPaul Mackerras { /* Handle problems with rebooting on the Precision M6600. */ 3376c6c51e4SPaul Mackerras .callback = set_pci_reboot, 3386c6c51e4SPaul Mackerras .ident = "Dell Precision M6600", 3396c6c51e4SPaul Mackerras .matches = { 3406c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 3416c6c51e4SPaul Mackerras DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), 3426c6c51e4SPaul Mackerras }, 3436c6c51e4SPaul Mackerras }, 344e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T5400's */ 345e56e57f6SDave Jones .callback = set_bios_reboot, 346e56e57f6SDave Jones .ident = "Dell Precision T5400", 34757b16594SMichael D Labriola .matches = { 3486c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 349e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 350144d102bSMichael D Labriola }, 3515955633eSMichael D Labriola }, 352e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T7400's */ 353e56e57f6SDave Jones .callback = set_bios_reboot, 354e56e57f6SDave Jones .ident = "Dell Precision T7400", 3556c6c51e4SPaul Mackerras .matches = { 356e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 357e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), 3586c6c51e4SPaul Mackerras }, 3594d022e35SMiguel Boton }, 360e56e57f6SDave Jones { /* Handle problems with rebooting on Dell XPS710 */ 361e56e57f6SDave Jones .callback = set_bios_reboot, 362e56e57f6SDave Jones .ident = "Dell XPS710", 363e56e57f6SDave Jones .matches = { 364e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 365e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 366e56e57f6SDave Jones }, 367e56e57f6SDave Jones }, 368e56e57f6SDave Jones 369e56e57f6SDave Jones /* Hewlett-Packard */ 370e56e57f6SDave Jones { /* Handle problems with rebooting on HP laptops */ 371e56e57f6SDave Jones .callback = set_bios_reboot, 372e56e57f6SDave Jones .ident = "HP Compaq Laptop", 373e56e57f6SDave Jones .matches = { 374e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 375e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 376e56e57f6SDave Jones }, 377e56e57f6SDave Jones }, 378e56e57f6SDave Jones 379e56e57f6SDave Jones /* Sony */ 380e56e57f6SDave Jones { /* Handle problems with rebooting on Sony VGN-Z540N */ 381e56e57f6SDave Jones .callback = set_bios_reboot, 382e56e57f6SDave Jones .ident = "Sony VGN-Z540N", 383e56e57f6SDave Jones .matches = { 384e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 385e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 386e56e57f6SDave Jones }, 387e56e57f6SDave Jones }, 388e56e57f6SDave Jones 3894d022e35SMiguel Boton { } 3904d022e35SMiguel Boton }; 3919c48f1c6SDon Zickus 392d176720dSEduardo Habkost static int __init reboot_init(void) 393d176720dSEduardo Habkost { 394d176720dSEduardo Habkost /* 395d176720dSEduardo Habkost * Only do the DMI check if reboot_type hasn't been overridden 396d176720dSEduardo Habkost * on the command line 397d176720dSEduardo Habkost */ 398d176720dSEduardo Habkost if (reboot_default) 399d176720dSEduardo Habkost dmi_check_system(reboot_dmi_table); 400d176720dSEduardo Habkost return 0; 401d176720dSEduardo Habkost } 402d176720dSEduardo Habkost core_initcall(reboot_init); 403d176720dSEduardo Habkost 404d176720dSEduardo Habkost static inline void kb_wait(void) 405d176720dSEduardo Habkost { 406d176720dSEduardo Habkost int i; 407d176720dSEduardo Habkost 408d176720dSEduardo Habkost for (i = 0; i < 0x10000; i++) { 409d176720dSEduardo Habkost if ((inb(0x64) & 0x02) == 0) 410d176720dSEduardo Habkost break; 411d176720dSEduardo Habkost udelay(2); 412d176720dSEduardo Habkost } 413d176720dSEduardo Habkost } 414d176720dSEduardo Habkost 415d176720dSEduardo Habkost static void vmxoff_nmi(int cpu, struct pt_regs *regs) 416d176720dSEduardo Habkost { 417d176720dSEduardo Habkost cpu_emergency_vmxoff(); 418d176720dSEduardo Habkost } 419d176720dSEduardo Habkost 420144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ 421d176720dSEduardo Habkost static void emergency_vmx_disable_all(void) 422d176720dSEduardo Habkost { 423d176720dSEduardo Habkost /* Just make sure we won't change CPUs while doing this */ 424d176720dSEduardo Habkost local_irq_disable(); 425d176720dSEduardo Habkost 426144d102bSMichael D Labriola /* 427144d102bSMichael D Labriola * We need to disable VMX on all CPUs before rebooting, otherwise 428d176720dSEduardo Habkost * we risk hanging up the machine, because the CPU ignore INIT 429d176720dSEduardo Habkost * signals when VMX is enabled. 430d176720dSEduardo Habkost * 431d176720dSEduardo Habkost * We can't take any locks and we may be on an inconsistent 432d176720dSEduardo Habkost * state, so we use NMIs as IPIs to tell the other CPUs to disable 433d176720dSEduardo Habkost * VMX and halt. 434d176720dSEduardo Habkost * 435d176720dSEduardo Habkost * For safety, we will avoid running the nmi_shootdown_cpus() 436d176720dSEduardo Habkost * stuff unnecessarily, but we don't have a way to check 437d176720dSEduardo Habkost * if other CPUs have VMX enabled. So we will call it only if the 438d176720dSEduardo Habkost * CPU we are running on has VMX enabled. 439d176720dSEduardo Habkost * 440d176720dSEduardo Habkost * We will miss cases where VMX is not enabled on all CPUs. This 441d176720dSEduardo Habkost * shouldn't do much harm because KVM always enable VMX on all 442d176720dSEduardo Habkost * CPUs anyway. But we can miss it on the small window where KVM 443d176720dSEduardo Habkost * is still enabling VMX. 444d176720dSEduardo Habkost */ 445d176720dSEduardo Habkost if (cpu_has_vmx() && cpu_vmx_enabled()) { 446144d102bSMichael D Labriola /* Disable VMX on this CPU. */ 447d176720dSEduardo Habkost cpu_vmxoff(); 448d176720dSEduardo Habkost 449d176720dSEduardo Habkost /* Halt and disable VMX on the other CPUs */ 450d176720dSEduardo Habkost nmi_shootdown_cpus(vmxoff_nmi); 451d176720dSEduardo Habkost 452d176720dSEduardo Habkost } 453d176720dSEduardo Habkost } 454d176720dSEduardo Habkost 455d176720dSEduardo Habkost 4567432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 4577432d149SIngo Molnar { 4587432d149SIngo Molnar } 4597432d149SIngo Molnar 460660e34ceSMatthew Garrett /* 461660e34ceSMatthew Garrett * Windows compatible x86 hardware expects the following on reboot: 462660e34ceSMatthew Garrett * 463660e34ceSMatthew Garrett * 1) If the FADT has the ACPI reboot register flag set, try it 464660e34ceSMatthew Garrett * 2) If still alive, write to the keyboard controller 465660e34ceSMatthew Garrett * 3) If still alive, write to the ACPI reboot register again 466660e34ceSMatthew Garrett * 4) If still alive, write to the keyboard controller again 467*a4f1987eSLi, Aubrey * 5) If still alive, call the EFI runtime service to reboot 468*a4f1987eSLi, Aubrey * 6) If still alive, write to the PCI IO port 0xCF9 to reboot 469*a4f1987eSLi, Aubrey * 7) If still alive, inform BIOS to do a proper reboot 470660e34ceSMatthew Garrett * 471660e34ceSMatthew Garrett * If the machine is still alive at this stage, it gives up. We default to 472*a4f1987eSLi, Aubrey * following the same pattern, except that if we're still alive after (7) we'll 473660e34ceSMatthew Garrett * try to force a triple fault and then cycle between hitting the keyboard 474660e34ceSMatthew Garrett * controller and doing that 475660e34ceSMatthew Garrett */ 476416e2d63SJody Belka static void native_machine_emergency_restart(void) 4774d022e35SMiguel Boton { 4784d022e35SMiguel Boton int i; 479660e34ceSMatthew Garrett int attempt = 0; 480660e34ceSMatthew Garrett int orig_reboot_type = reboot_type; 481edf2b139SRobin Holt unsigned short mode; 4824d022e35SMiguel Boton 483d176720dSEduardo Habkost if (reboot_emergency) 484d176720dSEduardo Habkost emergency_vmx_disable_all(); 485d176720dSEduardo Habkost 486840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 487840c2bafSJoseph Cihula 4884d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 489edf2b139SRobin Holt mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; 490edf2b139SRobin Holt *((unsigned short *)__va(0x472)) = mode; 4914d022e35SMiguel Boton 4924d022e35SMiguel Boton for (;;) { 4934d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 4944d022e35SMiguel Boton switch (reboot_type) { 4954d022e35SMiguel Boton case BOOT_KBD: 496144d102bSMichael D Labriola mach_reboot_fixups(); /* For board specific fixups */ 4977432d149SIngo Molnar 4984d022e35SMiguel Boton for (i = 0; i < 10; i++) { 4994d022e35SMiguel Boton kb_wait(); 5004d022e35SMiguel Boton udelay(50); 501144d102bSMichael D Labriola outb(0xfe, 0x64); /* Pulse reset low */ 5024d022e35SMiguel Boton udelay(50); 5034d022e35SMiguel Boton } 504660e34ceSMatthew Garrett if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { 505660e34ceSMatthew Garrett attempt = 1; 506660e34ceSMatthew Garrett reboot_type = BOOT_ACPI; 507660e34ceSMatthew Garrett } else { 508*a4f1987eSLi, Aubrey reboot_type = BOOT_EFI; 509660e34ceSMatthew Garrett } 510660e34ceSMatthew Garrett break; 5114d022e35SMiguel Boton 5124d022e35SMiguel Boton case BOOT_TRIPLE: 513ebdd561aSJan Beulich load_idt(&no_idt); 5144d022e35SMiguel Boton __asm__ __volatile__("int3"); 5154d022e35SMiguel Boton 516*a4f1987eSLi, Aubrey /* We're probably dead after this, but... */ 5174d022e35SMiguel Boton reboot_type = BOOT_KBD; 5184d022e35SMiguel Boton break; 5194d022e35SMiguel Boton 5204d022e35SMiguel Boton case BOOT_BIOS: 5213d35ac34SH. Peter Anvin machine_real_restart(MRR_BIOS); 5224d022e35SMiguel Boton 523*a4f1987eSLi, Aubrey /* We're probably dead after this, but... */ 524*a4f1987eSLi, Aubrey reboot_type = BOOT_TRIPLE; 5254d022e35SMiguel Boton break; 5264d022e35SMiguel Boton 5274d022e35SMiguel Boton case BOOT_ACPI: 5284d022e35SMiguel Boton acpi_reboot(); 5294d022e35SMiguel Boton reboot_type = BOOT_KBD; 5304d022e35SMiguel Boton break; 5314d022e35SMiguel Boton 5324d022e35SMiguel Boton case BOOT_EFI: 53383e68189SMatt Fleming if (efi_enabled(EFI_RUNTIME_SERVICES)) 534edf2b139SRobin Holt efi.reset_system(reboot_mode == REBOOT_WARM ? 53514d7ca5cSH. Peter Anvin EFI_RESET_WARM : 53614d7ca5cSH. Peter Anvin EFI_RESET_COLD, 5374d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 538*a4f1987eSLi, Aubrey reboot_type = BOOT_CF9; 53914d7ca5cSH. Peter Anvin break; 5404d022e35SMiguel Boton 54114d7ca5cSH. Peter Anvin case BOOT_CF9: 54214d7ca5cSH. Peter Anvin port_cf9_safe = true; 543144d102bSMichael D Labriola /* Fall through */ 54414d7ca5cSH. Peter Anvin 54514d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 54614d7ca5cSH. Peter Anvin if (port_cf9_safe) { 54716c21ae5SLi Fei u8 reboot_code = reboot_mode == REBOOT_WARM ? 54816c21ae5SLi Fei 0x06 : 0x0E; 54916c21ae5SLi Fei u8 cf9 = inb(0xcf9) & ~reboot_code; 55014d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 55114d7ca5cSH. Peter Anvin udelay(50); 55216c21ae5SLi Fei /* Actually do the reset */ 55316c21ae5SLi Fei outb(cf9|reboot_code, 0xcf9); 55414d7ca5cSH. Peter Anvin udelay(50); 55514d7ca5cSH. Peter Anvin } 556*a4f1987eSLi, Aubrey reboot_type = BOOT_BIOS; 5574d022e35SMiguel Boton break; 5584d022e35SMiguel Boton } 5594d022e35SMiguel Boton } 5604d022e35SMiguel Boton } 5614d022e35SMiguel Boton 5623c62c625SGlauber Costa void native_machine_shutdown(void) 5634d022e35SMiguel Boton { 5644d022e35SMiguel Boton /* Stop the cpus and apics */ 565522e6646SFenghua Yu #ifdef CONFIG_X86_IO_APIC 5662885432aSFenghua Yu /* 5672885432aSFenghua Yu * Disabling IO APIC before local APIC is a workaround for 5682885432aSFenghua Yu * erratum AVR31 in "Intel Atom Processor C2000 Product Family 5692885432aSFenghua Yu * Specification Update". In this situation, interrupts that target 5702885432aSFenghua Yu * a Logical Processor whose Local APIC is either in the process of 5712885432aSFenghua Yu * being hardware disabled or software disabled are neither delivered 5722885432aSFenghua Yu * nor discarded. When this erratum occurs, the processor may hang. 5732885432aSFenghua Yu * 5742885432aSFenghua Yu * Even without the erratum, it still makes sense to quiet IO APIC 5752885432aSFenghua Yu * before disabling Local APIC. 5762885432aSFenghua Yu */ 577522e6646SFenghua Yu disable_IO_APIC(); 578522e6646SFenghua Yu #endif 579522e6646SFenghua Yu 5804d022e35SMiguel Boton #ifdef CONFIG_SMP 581144d102bSMichael D Labriola /* 5821b3a5d02SRobin Holt * Stop all of the others. Also disable the local irq to 5831b3a5d02SRobin Holt * not receive the per-cpu timer interrupt which may trigger 5841b3a5d02SRobin Holt * scheduler's load balance. 5854d022e35SMiguel Boton */ 58655c844a4SFeng Tang local_irq_disable(); 58776fac077SAlok Kataria stop_other_cpus(); 5884d022e35SMiguel Boton #endif 5894d022e35SMiguel Boton 5904d022e35SMiguel Boton lapic_shutdown(); 5914d022e35SMiguel Boton 5924d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 5934d022e35SMiguel Boton hpet_disable(); 5944d022e35SMiguel Boton #endif 5954d022e35SMiguel Boton 5964d022e35SMiguel Boton #ifdef CONFIG_X86_64 597338bac52SFUJITA Tomonori x86_platform.iommu_shutdown(); 5984d022e35SMiguel Boton #endif 5994d022e35SMiguel Boton } 6004d022e35SMiguel Boton 601d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 602d176720dSEduardo Habkost { 603d176720dSEduardo Habkost reboot_emergency = emergency; 604d176720dSEduardo Habkost machine_ops.emergency_restart(); 605d176720dSEduardo Habkost } 606d176720dSEduardo Habkost 607416e2d63SJody Belka static void native_machine_restart(char *__unused) 6084d022e35SMiguel Boton { 609c767a54bSJoe Perches pr_notice("machine restart\n"); 6104d022e35SMiguel Boton 6114d022e35SMiguel Boton if (!reboot_force) 6124d022e35SMiguel Boton machine_shutdown(); 613d176720dSEduardo Habkost __machine_emergency_restart(0); 6144d022e35SMiguel Boton } 6154d022e35SMiguel Boton 616416e2d63SJody Belka static void native_machine_halt(void) 6174d022e35SMiguel Boton { 618144d102bSMichael D Labriola /* Stop other cpus and apics */ 619d3ec5caeSIvan Vecera machine_shutdown(); 620d3ec5caeSIvan Vecera 621840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 622840c2bafSJoseph Cihula 623d3ec5caeSIvan Vecera stop_this_cpu(NULL); 6244d022e35SMiguel Boton } 6254d022e35SMiguel Boton 626416e2d63SJody Belka static void native_machine_power_off(void) 6274d022e35SMiguel Boton { 6284d022e35SMiguel Boton if (pm_power_off) { 6294d022e35SMiguel Boton if (!reboot_force) 6304d022e35SMiguel Boton machine_shutdown(); 6314d022e35SMiguel Boton pm_power_off(); 6324d022e35SMiguel Boton } 633144d102bSMichael D Labriola /* A fallback in case there is no PM info available */ 634840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 6354d022e35SMiguel Boton } 6364d022e35SMiguel Boton 6374d022e35SMiguel Boton struct machine_ops machine_ops = { 638416e2d63SJody Belka .power_off = native_machine_power_off, 639416e2d63SJody Belka .shutdown = native_machine_shutdown, 640416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 641416e2d63SJody Belka .restart = native_machine_restart, 642ed23dc6fSGlauber Costa .halt = native_machine_halt, 643ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 644ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 645ed23dc6fSGlauber Costa #endif 6464d022e35SMiguel Boton }; 647416e2d63SJody Belka 648416e2d63SJody Belka void machine_power_off(void) 649416e2d63SJody Belka { 650416e2d63SJody Belka machine_ops.power_off(); 651416e2d63SJody Belka } 652416e2d63SJody Belka 653416e2d63SJody Belka void machine_shutdown(void) 654416e2d63SJody Belka { 655416e2d63SJody Belka machine_ops.shutdown(); 656416e2d63SJody Belka } 657416e2d63SJody Belka 658416e2d63SJody Belka void machine_emergency_restart(void) 659416e2d63SJody Belka { 660d176720dSEduardo Habkost __machine_emergency_restart(1); 661416e2d63SJody Belka } 662416e2d63SJody Belka 663416e2d63SJody Belka void machine_restart(char *cmd) 664416e2d63SJody Belka { 665416e2d63SJody Belka machine_ops.restart(cmd); 666416e2d63SJody Belka } 667416e2d63SJody Belka 668416e2d63SJody Belka void machine_halt(void) 669416e2d63SJody Belka { 670416e2d63SJody Belka machine_ops.halt(); 671416e2d63SJody Belka } 672416e2d63SJody Belka 673ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 674ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 675ed23dc6fSGlauber Costa { 676ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 677ed23dc6fSGlauber Costa } 678ed23dc6fSGlauber Costa #endif 6792ddded21SEduardo Habkost 6802ddded21SEduardo Habkost 681bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 6822ddded21SEduardo Habkost 6832ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 6842ddded21SEduardo Habkost static int crashing_cpu; 6852ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 6862ddded21SEduardo Habkost 6872ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 6882ddded21SEduardo Habkost 6899c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) 6902ddded21SEduardo Habkost { 6912ddded21SEduardo Habkost int cpu; 6922ddded21SEduardo Habkost 6932ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 6942ddded21SEduardo Habkost 695144d102bSMichael D Labriola /* 696144d102bSMichael D Labriola * Don't do anything if this handler is invoked on crashing cpu. 6972ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 6982ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 6992ddded21SEduardo Habkost */ 7002ddded21SEduardo Habkost if (cpu == crashing_cpu) 7019c48f1c6SDon Zickus return NMI_HANDLED; 7022ddded21SEduardo Habkost local_irq_disable(); 7032ddded21SEduardo Habkost 7049c48f1c6SDon Zickus shootdown_callback(cpu, regs); 7052ddded21SEduardo Habkost 7062ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 7072ddded21SEduardo Habkost /* Assume hlt works */ 7082ddded21SEduardo Habkost halt(); 7092ddded21SEduardo Habkost for (;;) 7102ddded21SEduardo Habkost cpu_relax(); 7112ddded21SEduardo Habkost 7129c48f1c6SDon Zickus return NMI_HANDLED; 7132ddded21SEduardo Habkost } 7142ddded21SEduardo Habkost 7152ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 7162ddded21SEduardo Habkost { 717dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 7182ddded21SEduardo Habkost } 7192ddded21SEduardo Habkost 720144d102bSMichael D Labriola /* 721144d102bSMichael D Labriola * Halt all other CPUs, calling the specified function on each of them 722bb8dd270SEduardo Habkost * 723bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 724bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 725bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 726bb8dd270SEduardo Habkost */ 7272ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 7282ddded21SEduardo Habkost { 7292ddded21SEduardo Habkost unsigned long msecs; 730c415b3dcSEduardo Habkost local_irq_disable(); 7312ddded21SEduardo Habkost 7322ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback. */ 7332ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 7342ddded21SEduardo Habkost 7352ddded21SEduardo Habkost shootdown_callback = callback; 7362ddded21SEduardo Habkost 7372ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 7382ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 7399c48f1c6SDon Zickus if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, 7409c48f1c6SDon Zickus NMI_FLAG_FIRST, "crash")) 741144d102bSMichael D Labriola return; /* Return what? */ 742144d102bSMichael D Labriola /* 743144d102bSMichael D Labriola * Ensure the new callback function is set before sending 7442ddded21SEduardo Habkost * out the NMI 7452ddded21SEduardo Habkost */ 7462ddded21SEduardo Habkost wmb(); 7472ddded21SEduardo Habkost 7482ddded21SEduardo Habkost smp_send_nmi_allbutself(); 7492ddded21SEduardo Habkost 7502ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 7512ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 7522ddded21SEduardo Habkost mdelay(1); 7532ddded21SEduardo Habkost msecs--; 7542ddded21SEduardo Habkost } 7552ddded21SEduardo Habkost 7562ddded21SEduardo Habkost /* Leave the nmi callback set */ 7572ddded21SEduardo Habkost } 758bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 759bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 760bb8dd270SEduardo Habkost { 761bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 762bb8dd270SEduardo Habkost } 7632ddded21SEduardo Habkost #endif 764