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> 31*44be28e9SMatt Fleming #include <asm/efi.h> 324d022e35SMiguel Boton 334d022e35SMiguel Boton /* 344d022e35SMiguel Boton * Power off function, if any 354d022e35SMiguel Boton */ 364d022e35SMiguel Boton void (*pm_power_off)(void); 374d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off); 384d022e35SMiguel Boton 39ebdd561aSJan Beulich static const struct desc_ptr no_idt = {}; 404d022e35SMiguel Boton 41144d102bSMichael D Labriola /* 42144d102bSMichael D Labriola * This is set if we need to go through the 'emergency' path. 43d176720dSEduardo Habkost * When machine_emergency_restart() is called, we may be on 44d176720dSEduardo Habkost * an inconsistent state and won't be able to do a clean cleanup 45d176720dSEduardo Habkost */ 46d176720dSEduardo Habkost static int reboot_emergency; 47d176720dSEduardo Habkost 4814d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 4914d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 5014d7ca5cSH. Peter Anvin 51144d102bSMichael D Labriola /* 524d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 534d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 544d022e35SMiguel Boton */ 554d022e35SMiguel Boton 564d022e35SMiguel Boton /* 571ef03890SPeter Chubb * Some machines require the "reboot=b" or "reboot=k" commandline options, 584d022e35SMiguel Boton * this quirk makes that automatic. 594d022e35SMiguel Boton */ 604d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 614d022e35SMiguel Boton { 624d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 634d022e35SMiguel Boton reboot_type = BOOT_BIOS; 64c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 656d9153bbSLan Tianyu d->ident, "BIOS"); 664d022e35SMiguel Boton } 674d022e35SMiguel Boton return 0; 684d022e35SMiguel Boton } 694d022e35SMiguel Boton 7065051397SH. Peter Anvin void __noreturn machine_real_restart(unsigned int type) 7157b16594SMichael D Labriola { 7257b16594SMichael D Labriola local_irq_disable(); 7357b16594SMichael D Labriola 74144d102bSMichael D Labriola /* 75144d102bSMichael D Labriola * Write zero to CMOS register number 0x0f, which the BIOS POST 76144d102bSMichael D Labriola * routine will recognize as telling it to do a proper reboot. (Well 77144d102bSMichael D Labriola * that's what this book in front of me says -- it may only apply to 78144d102bSMichael D Labriola * the Phoenix BIOS though, it's not clear). At the same time, 79144d102bSMichael D Labriola * disable NMIs by setting the top bit in the CMOS address register, 80144d102bSMichael D Labriola * as we're about to do peculiar things to the CPU. I'm not sure if 81144d102bSMichael D Labriola * `outb_p' is needed instead of just `outb'. Use it to be on the 82144d102bSMichael D Labriola * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 8357b16594SMichael D Labriola */ 8457b16594SMichael D Labriola spin_lock(&rtc_lock); 8557b16594SMichael D Labriola CMOS_WRITE(0x00, 0x8f); 8657b16594SMichael D Labriola spin_unlock(&rtc_lock); 8757b16594SMichael D Labriola 8857b16594SMichael D Labriola /* 8957b16594SMichael D Labriola * Switch back to the initial page table. 9057b16594SMichael D Labriola */ 9165051397SH. Peter Anvin #ifdef CONFIG_X86_32 9257b16594SMichael D Labriola load_cr3(initial_page_table); 9365051397SH. Peter Anvin #else 9465051397SH. Peter Anvin write_cr3(real_mode_header->trampoline_pgd); 9565051397SH. Peter Anvin #endif 9657b16594SMichael D Labriola 9757b16594SMichael D Labriola /* Jump to the identity-mapped low memory code */ 9865051397SH. Peter Anvin #ifdef CONFIG_X86_32 9965051397SH. Peter Anvin asm volatile("jmpl *%0" : : 10065051397SH. Peter Anvin "rm" (real_mode_header->machine_real_restart_asm), 10165051397SH. Peter Anvin "a" (type)); 10265051397SH. Peter Anvin #else 10365051397SH. Peter Anvin asm volatile("ljmpl *%0" : : 10465051397SH. Peter Anvin "m" (real_mode_header->machine_real_restart_asm), 10565051397SH. Peter Anvin "D" (type)); 10665051397SH. Peter Anvin #endif 10765051397SH. Peter Anvin unreachable(); 10857b16594SMichael D Labriola } 10957b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE 11057b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart); 11157b16594SMichael D Labriola #endif 11257b16594SMichael D Labriola 11357b16594SMichael D Labriola /* 11457b16594SMichael D Labriola * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot 11557b16594SMichael D Labriola */ 11657b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d) 11757b16594SMichael D Labriola { 1185be44a6fSIngo Molnar if (reboot_type != BOOT_CF9_FORCE) { 1195be44a6fSIngo Molnar reboot_type = BOOT_CF9_FORCE; 120c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboots.\n", 1216d9153bbSLan Tianyu d->ident, "PCI"); 12257b16594SMichael D Labriola } 12357b16594SMichael D Labriola return 0; 12457b16594SMichael D Labriola } 12557b16594SMichael D Labriola 1261ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d) 1271ef03890SPeter Chubb { 1281ef03890SPeter Chubb if (reboot_type != BOOT_KBD) { 1291ef03890SPeter Chubb reboot_type = BOOT_KBD; 130c767a54bSJoe Perches pr_info("%s series board detected. Selecting %s-method for reboot.\n", 1316d9153bbSLan Tianyu d->ident, "KBD"); 1321ef03890SPeter Chubb } 1331ef03890SPeter Chubb return 0; 1341ef03890SPeter Chubb } 1351ef03890SPeter Chubb 136144d102bSMichael D Labriola /* 13765051397SH. Peter Anvin * This is a single dmi_table handling all reboot quirks. 13857b16594SMichael D Labriola */ 1394d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 14057b16594SMichael D Labriola 141e56e57f6SDave Jones /* Acer */ 142b49c78d4SPeter Chubb { /* Handle reboot issue on Acer Aspire one */ 1431ef03890SPeter Chubb .callback = set_kbd_reboot, 144b49c78d4SPeter Chubb .ident = "Acer Aspire One A110", 145b49c78d4SPeter Chubb .matches = { 146b49c78d4SPeter Chubb DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 147b49c78d4SPeter Chubb DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 148b49c78d4SPeter Chubb }, 149b49c78d4SPeter Chubb }, 150e56e57f6SDave Jones 151e56e57f6SDave Jones /* Apple */ 1523e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBook5 */ 1536c6c51e4SPaul Mackerras .callback = set_pci_reboot, 1543e03bbeaSShunichi Fuji .ident = "Apple MacBook5", 1556c6c51e4SPaul Mackerras .matches = { 1566c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1573e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), 1586c6c51e4SPaul Mackerras }, 1596c6c51e4SPaul Mackerras }, 1603e03bbeaSShunichi Fuji { /* Handle problems with rebooting on Apple MacBookPro5 */ 161498cdbfbSOzan Çağlayan .callback = set_pci_reboot, 1623e03bbeaSShunichi Fuji .ident = "Apple MacBookPro5", 163498cdbfbSOzan Çağlayan .matches = { 164498cdbfbSOzan Çağlayan DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1653e03bbeaSShunichi Fuji DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), 166498cdbfbSOzan Çağlayan }, 167498cdbfbSOzan Çağlayan }, 16805154752SGottfried Haider { /* Handle problems with rebooting on Apple Macmini3,1 */ 16905154752SGottfried Haider .callback = set_pci_reboot, 17005154752SGottfried Haider .ident = "Apple Macmini3,1", 17105154752SGottfried Haider .matches = { 17205154752SGottfried Haider DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 17305154752SGottfried Haider DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), 17405154752SGottfried Haider }, 17505154752SGottfried Haider }, 1760a832320SJustin P. Mattock { /* Handle problems with rebooting on the iMac9,1. */ 1770a832320SJustin P. Mattock .callback = set_pci_reboot, 1780a832320SJustin P. Mattock .ident = "Apple iMac9,1", 1790a832320SJustin P. Mattock .matches = { 1800a832320SJustin P. Mattock DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 1810a832320SJustin P. Mattock DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), 1820a832320SJustin P. Mattock }, 1830a832320SJustin P. Mattock }, 184e56e57f6SDave Jones 185e56e57f6SDave Jones /* ASUS */ 186e56e57f6SDave Jones { /* Handle problems with rebooting on ASUS P4S800 */ 187e56e57f6SDave Jones .callback = set_bios_reboot, 188e56e57f6SDave Jones .ident = "ASUS P4S800", 189e56e57f6SDave Jones .matches = { 190e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 191e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 192e56e57f6SDave Jones }, 193e56e57f6SDave Jones }, 194e56e57f6SDave Jones 195aadca6faSChristian Gmeiner /* Certec */ 196aadca6faSChristian Gmeiner { /* Handle problems with rebooting on Certec BPC600 */ 197aadca6faSChristian Gmeiner .callback = set_pci_reboot, 198aadca6faSChristian Gmeiner .ident = "Certec BPC600", 199aadca6faSChristian Gmeiner .matches = { 200aadca6faSChristian Gmeiner DMI_MATCH(DMI_SYS_VENDOR, "Certec"), 201aadca6faSChristian Gmeiner DMI_MATCH(DMI_PRODUCT_NAME, "BPC600"), 202aadca6faSChristian Gmeiner }, 203aadca6faSChristian Gmeiner }, 204aadca6faSChristian Gmeiner 205e56e57f6SDave Jones /* Dell */ 206e56e57f6SDave Jones { /* Handle problems with rebooting on Dell DXP061 */ 207e56e57f6SDave Jones .callback = set_bios_reboot, 208e56e57f6SDave Jones .ident = "Dell DXP061", 2093628c3f5SMaxime Ripard .matches = { 2103628c3f5SMaxime Ripard DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 211e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 212e56e57f6SDave Jones }, 213e56e57f6SDave Jones }, 214e56e57f6SDave Jones { /* Handle problems with rebooting on Dell E520's */ 215e56e57f6SDave Jones .callback = set_bios_reboot, 216e56e57f6SDave Jones .ident = "Dell E520", 217e56e57f6SDave Jones .matches = { 218e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 219e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 2203628c3f5SMaxime Ripard }, 2213628c3f5SMaxime Ripard }, 2228412da75SVille Syrjälä { /* Handle problems with rebooting on the Latitude E5410. */ 2238412da75SVille Syrjälä .callback = set_pci_reboot, 2248412da75SVille Syrjälä .ident = "Dell Latitude E5410", 2258412da75SVille Syrjälä .matches = { 2268412da75SVille Syrjälä DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2278412da75SVille Syrjälä DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"), 2288412da75SVille Syrjälä }, 2298412da75SVille Syrjälä }, 230b7798d28SDaniel J Blueman { /* Handle problems with rebooting on the Latitude E5420. */ 231b7798d28SDaniel J Blueman .callback = set_pci_reboot, 232b7798d28SDaniel J Blueman .ident = "Dell Latitude E5420", 233b7798d28SDaniel J Blueman .matches = { 234b7798d28SDaniel J Blueman DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 235b7798d28SDaniel J Blueman DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), 236b7798d28SDaniel J Blueman }, 237b7798d28SDaniel J Blueman }, 238e56e57f6SDave Jones { /* Handle problems with rebooting on the Latitude E6320. */ 239e56e57f6SDave Jones .callback = set_pci_reboot, 240e56e57f6SDave Jones .ident = "Dell Latitude E6320", 241e56e57f6SDave Jones .matches = { 242e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 243e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), 244e56e57f6SDave Jones }, 245e56e57f6SDave Jones }, 246a536877eSH. Peter Anvin { /* Handle problems with rebooting on the Latitude E6420. */ 247a536877eSH. Peter Anvin .callback = set_pci_reboot, 248a536877eSH. Peter Anvin .ident = "Dell Latitude E6420", 249a536877eSH. Peter Anvin .matches = { 250a536877eSH. Peter Anvin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 251a536877eSH. Peter Anvin DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), 252a536877eSH. Peter Anvin }, 253a536877eSH. Peter Anvin }, 254e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 255e56e57f6SDave Jones .callback = set_bios_reboot, 256e56e57f6SDave Jones .ident = "Dell OptiPlex 330", 257e56e57f6SDave Jones .matches = { 258e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 259e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 260e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 261e56e57f6SDave Jones }, 262e56e57f6SDave Jones }, 263e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 264e56e57f6SDave Jones .callback = set_bios_reboot, 265e56e57f6SDave Jones .ident = "Dell OptiPlex 360", 266e56e57f6SDave Jones .matches = { 267e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 268e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 269e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 270e56e57f6SDave Jones }, 271e56e57f6SDave Jones }, 272e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ 273e56e57f6SDave Jones .callback = set_bios_reboot, 274e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 275e56e57f6SDave Jones .matches = { 276e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 277e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 278e56e57f6SDave Jones }, 279e56e57f6SDave Jones }, 280e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ 281e56e57f6SDave Jones .callback = set_bios_reboot, 282e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 283e56e57f6SDave Jones .matches = { 284e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 285e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 286e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 287e56e57f6SDave Jones }, 288e56e57f6SDave Jones }, 289e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 290e56e57f6SDave Jones .callback = set_bios_reboot, 291e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 292e56e57f6SDave Jones .matches = { 293e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 294e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 295e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 296e56e57f6SDave Jones }, 297e56e57f6SDave Jones }, 298e56e57f6SDave Jones { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ 299e56e57f6SDave Jones .callback = set_bios_reboot, 300e56e57f6SDave Jones .ident = "Dell OptiPlex 760", 301e56e57f6SDave Jones .matches = { 302e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 303e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), 304e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0G919G"), 305e56e57f6SDave Jones }, 306e56e57f6SDave Jones }, 3076be30bb7SRafael J. Wysocki { /* Handle problems with rebooting on the OptiPlex 990. */ 3086be30bb7SRafael J. Wysocki .callback = set_pci_reboot, 3096be30bb7SRafael J. Wysocki .ident = "Dell OptiPlex 990", 3106be30bb7SRafael J. Wysocki .matches = { 3116be30bb7SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 3126be30bb7SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), 3136be30bb7SRafael J. Wysocki }, 3146be30bb7SRafael J. Wysocki }, 315e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 300's */ 316e56e57f6SDave Jones .callback = set_bios_reboot, 317e56e57f6SDave Jones .ident = "Dell PowerEdge 300", 31876eb9a30SZhang Rui .matches = { 319e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 320e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 321e56e57f6SDave Jones }, 322e56e57f6SDave Jones }, 323e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 1300's */ 324e56e57f6SDave Jones .callback = set_bios_reboot, 325e56e57f6SDave Jones .ident = "Dell PowerEdge 1300", 326e56e57f6SDave Jones .matches = { 327e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 328e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 329e56e57f6SDave Jones }, 330e56e57f6SDave Jones }, 331e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 2400's */ 332e56e57f6SDave Jones .callback = set_bios_reboot, 333e56e57f6SDave Jones .ident = "Dell PowerEdge 2400", 334e56e57f6SDave Jones .matches = { 335e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 336e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 33776eb9a30SZhang Rui }, 33876eb9a30SZhang Rui }, 3394f0acd31SMasoud Sharbiani { /* Handle problems with rebooting on the Dell PowerEdge C6100. */ 3404f0acd31SMasoud Sharbiani .callback = set_pci_reboot, 3414f0acd31SMasoud Sharbiani .ident = "Dell PowerEdge C6100", 3424f0acd31SMasoud Sharbiani .matches = { 3434f0acd31SMasoud Sharbiani DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 3444f0acd31SMasoud Sharbiani DMI_MATCH(DMI_PRODUCT_NAME, "C6100"), 3454f0acd31SMasoud Sharbiani }, 3464f0acd31SMasoud Sharbiani }, 3476c6c51e4SPaul Mackerras { /* Handle problems with rebooting on the Precision M6600. */ 3486c6c51e4SPaul Mackerras .callback = set_pci_reboot, 3496c6c51e4SPaul Mackerras .ident = "Dell Precision M6600", 3506c6c51e4SPaul Mackerras .matches = { 3516c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 3526c6c51e4SPaul Mackerras DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), 3536c6c51e4SPaul Mackerras }, 3546c6c51e4SPaul Mackerras }, 355e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T5400's */ 356e56e57f6SDave Jones .callback = set_bios_reboot, 357e56e57f6SDave Jones .ident = "Dell Precision T5400", 35857b16594SMichael D Labriola .matches = { 3596c6c51e4SPaul Mackerras DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 360e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 361144d102bSMichael D Labriola }, 3625955633eSMichael D Labriola }, 363e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T7400's */ 364e56e57f6SDave Jones .callback = set_bios_reboot, 365e56e57f6SDave Jones .ident = "Dell Precision T7400", 3666c6c51e4SPaul Mackerras .matches = { 367e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 368e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), 3696c6c51e4SPaul Mackerras }, 3704d022e35SMiguel Boton }, 371e56e57f6SDave Jones { /* Handle problems with rebooting on Dell XPS710 */ 372e56e57f6SDave Jones .callback = set_bios_reboot, 373e56e57f6SDave Jones .ident = "Dell XPS710", 374e56e57f6SDave Jones .matches = { 375e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 376e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 377e56e57f6SDave Jones }, 378e56e57f6SDave Jones }, 379e56e57f6SDave Jones 380e56e57f6SDave Jones /* Hewlett-Packard */ 381e56e57f6SDave Jones { /* Handle problems with rebooting on HP laptops */ 382e56e57f6SDave Jones .callback = set_bios_reboot, 383e56e57f6SDave Jones .ident = "HP Compaq Laptop", 384e56e57f6SDave Jones .matches = { 385e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 386e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 387e56e57f6SDave Jones }, 388e56e57f6SDave Jones }, 389e56e57f6SDave Jones 390e56e57f6SDave Jones /* Sony */ 391e56e57f6SDave Jones { /* Handle problems with rebooting on Sony VGN-Z540N */ 392e56e57f6SDave Jones .callback = set_bios_reboot, 393e56e57f6SDave Jones .ident = "Sony VGN-Z540N", 394e56e57f6SDave Jones .matches = { 395e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 396e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 397e56e57f6SDave Jones }, 398e56e57f6SDave Jones }, 399e56e57f6SDave Jones 4004d022e35SMiguel Boton { } 4014d022e35SMiguel Boton }; 4029c48f1c6SDon Zickus 403d176720dSEduardo Habkost static int __init reboot_init(void) 404d176720dSEduardo Habkost { 405*44be28e9SMatt Fleming int rv; 406*44be28e9SMatt Fleming 407d176720dSEduardo Habkost /* 408d176720dSEduardo Habkost * Only do the DMI check if reboot_type hasn't been overridden 409d176720dSEduardo Habkost * on the command line 410d176720dSEduardo Habkost */ 411*44be28e9SMatt Fleming if (!reboot_default) 412*44be28e9SMatt Fleming return 0; 413*44be28e9SMatt Fleming 414*44be28e9SMatt Fleming /* 415*44be28e9SMatt Fleming * The DMI quirks table takes precedence. If no quirks entry 416*44be28e9SMatt Fleming * matches and the ACPI Hardware Reduced bit is set, force EFI 417*44be28e9SMatt Fleming * reboot. 418*44be28e9SMatt Fleming */ 419*44be28e9SMatt Fleming rv = dmi_check_system(reboot_dmi_table); 420*44be28e9SMatt Fleming 421*44be28e9SMatt Fleming if (!rv && efi_reboot_required()) 422*44be28e9SMatt Fleming reboot_type = BOOT_EFI; 423*44be28e9SMatt Fleming 424d176720dSEduardo Habkost return 0; 425d176720dSEduardo Habkost } 426d176720dSEduardo Habkost core_initcall(reboot_init); 427d176720dSEduardo Habkost 428d176720dSEduardo Habkost static inline void kb_wait(void) 429d176720dSEduardo Habkost { 430d176720dSEduardo Habkost int i; 431d176720dSEduardo Habkost 432d176720dSEduardo Habkost for (i = 0; i < 0x10000; i++) { 4337432d149SIngo Molnar if ((inb(0x64) & 0x02) == 0) 4347432d149SIngo Molnar break; 4357432d149SIngo Molnar udelay(2); 4367432d149SIngo Molnar } 437416e2d63SJody Belka } 4384d022e35SMiguel Boton 4394d022e35SMiguel Boton static void vmxoff_nmi(int cpu, struct pt_regs *regs) 4404d022e35SMiguel Boton { 441d176720dSEduardo Habkost cpu_emergency_vmxoff(); 442d176720dSEduardo Habkost } 443d176720dSEduardo Habkost 444144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ 4454d022e35SMiguel Boton static void emergency_vmx_disable_all(void) 4464d022e35SMiguel Boton { 4474d022e35SMiguel Boton /* Just make sure we won't change CPUs while doing this */ 4484d022e35SMiguel Boton local_irq_disable(); 4494d022e35SMiguel Boton 450144d102bSMichael D Labriola /* 451144d102bSMichael D Labriola * We need to disable VMX on all CPUs before rebooting, otherwise 4524d022e35SMiguel Boton * we risk hanging up the machine, because the CPU ignore INIT 4534d022e35SMiguel Boton * signals when VMX is enabled. 4544d022e35SMiguel Boton * 4554d022e35SMiguel Boton * We can't take any locks and we may be on an inconsistent 4564d022e35SMiguel Boton * state, so we use NMIs as IPIs to tell the other CPUs to disable 4574d022e35SMiguel Boton * VMX and halt. 4584d022e35SMiguel Boton * 4594d022e35SMiguel Boton * For safety, we will avoid running the nmi_shootdown_cpus() 4604d022e35SMiguel Boton * stuff unnecessarily, but we don't have a way to check 4614d022e35SMiguel Boton * if other CPUs have VMX enabled. So we will call it only if the 4624d022e35SMiguel Boton * CPU we are running on has VMX enabled. 4634d022e35SMiguel Boton * 4644d022e35SMiguel Boton * We will miss cases where VMX is not enabled on all CPUs. This 4654d022e35SMiguel Boton * shouldn't do much harm because KVM always enable VMX on all 4664d022e35SMiguel Boton * CPUs anyway. But we can miss it on the small window where KVM 4674d022e35SMiguel Boton * is still enabling VMX. 4684d022e35SMiguel Boton */ 4694d022e35SMiguel Boton if (cpu_has_vmx() && cpu_vmx_enabled()) { 470144d102bSMichael D Labriola /* Disable VMX on this CPU. */ 4714d022e35SMiguel Boton cpu_vmxoff(); 4724d022e35SMiguel Boton 4734d022e35SMiguel Boton /* Halt and disable VMX on the other CPUs */ 4744d022e35SMiguel Boton nmi_shootdown_cpus(vmxoff_nmi); 4754d022e35SMiguel Boton 4764d022e35SMiguel Boton } 4774d022e35SMiguel Boton } 4784d022e35SMiguel Boton 4794d022e35SMiguel Boton 4804d022e35SMiguel Boton void __attribute__((weak)) mach_reboot_fixups(void) 4814d022e35SMiguel Boton { 4824d022e35SMiguel Boton } 4834d022e35SMiguel Boton 484660e34ceSMatthew Garrett /* 4855be44a6fSIngo Molnar * To the best of our knowledge Windows compatible x86 hardware expects 4865be44a6fSIngo Molnar * the following on reboot: 487660e34ceSMatthew Garrett * 488660e34ceSMatthew Garrett * 1) If the FADT has the ACPI reboot register flag set, try it 489660e34ceSMatthew Garrett * 2) If still alive, write to the keyboard controller 490660e34ceSMatthew Garrett * 3) If still alive, write to the ACPI reboot register again 491660e34ceSMatthew Garrett * 4) If still alive, write to the keyboard controller again 492a4f1987eSLi, Aubrey * 5) If still alive, call the EFI runtime service to reboot 4935be44a6fSIngo Molnar * 6) If no EFI runtime service, call the BIOS to do a reboot 494660e34ceSMatthew Garrett * 4955be44a6fSIngo Molnar * We default to following the same pattern. We also have 4965be44a6fSIngo Molnar * two other reboot methods: 'triple fault' and 'PCI', which 4975be44a6fSIngo Molnar * can be triggered via the reboot= kernel boot option or 4985be44a6fSIngo Molnar * via quirks. 4995be44a6fSIngo Molnar * 5005be44a6fSIngo Molnar * This means that this function can never return, it can misbehave 5015be44a6fSIngo Molnar * by not rebooting properly and hanging. 502660e34ceSMatthew Garrett */ 5034d022e35SMiguel Boton static void native_machine_emergency_restart(void) 5044d022e35SMiguel Boton { 5054d022e35SMiguel Boton int i; 506660e34ceSMatthew Garrett int attempt = 0; 507660e34ceSMatthew Garrett int orig_reboot_type = reboot_type; 508edf2b139SRobin Holt unsigned short mode; 5094d022e35SMiguel Boton 5104d022e35SMiguel Boton if (reboot_emergency) 5114d022e35SMiguel Boton emergency_vmx_disable_all(); 5124d022e35SMiguel Boton 513840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 514840c2bafSJoseph Cihula 5154d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 516edf2b139SRobin Holt mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; 517edf2b139SRobin Holt *((unsigned short *)__va(0x472)) = mode; 5184d022e35SMiguel Boton 5194d022e35SMiguel Boton for (;;) { 5204d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 5214d022e35SMiguel Boton switch (reboot_type) { 5225be44a6fSIngo Molnar case BOOT_ACPI: 5235be44a6fSIngo Molnar acpi_reboot(); 5245be44a6fSIngo Molnar reboot_type = BOOT_KBD; 5255be44a6fSIngo Molnar break; 5265be44a6fSIngo Molnar 5274d022e35SMiguel Boton case BOOT_KBD: 528144d102bSMichael D Labriola mach_reboot_fixups(); /* For board specific fixups */ 5297432d149SIngo Molnar 5304d022e35SMiguel Boton for (i = 0; i < 10; i++) { 5314d022e35SMiguel Boton kb_wait(); 5324d022e35SMiguel Boton udelay(50); 533144d102bSMichael D Labriola outb(0xfe, 0x64); /* Pulse reset low */ 5344d022e35SMiguel Boton udelay(50); 5354d022e35SMiguel Boton } 536660e34ceSMatthew Garrett if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { 537660e34ceSMatthew Garrett attempt = 1; 538660e34ceSMatthew Garrett reboot_type = BOOT_ACPI; 539660e34ceSMatthew Garrett } else { 540a4f1987eSLi, Aubrey reboot_type = BOOT_EFI; 541660e34ceSMatthew Garrett } 542660e34ceSMatthew Garrett break; 5434d022e35SMiguel Boton 5444d022e35SMiguel Boton case BOOT_EFI: 5458562c99cSMatt Fleming efi_reboot(reboot_mode, NULL); 5465be44a6fSIngo Molnar reboot_type = BOOT_BIOS; 54714d7ca5cSH. Peter Anvin break; 5484d022e35SMiguel Boton 5495be44a6fSIngo Molnar case BOOT_BIOS: 5505be44a6fSIngo Molnar machine_real_restart(MRR_BIOS); 5515be44a6fSIngo Molnar 5525be44a6fSIngo Molnar /* We're probably dead after this, but... */ 5535be44a6fSIngo Molnar reboot_type = BOOT_CF9_SAFE; 5545be44a6fSIngo Molnar break; 5555be44a6fSIngo Molnar 5565be44a6fSIngo Molnar case BOOT_CF9_FORCE: 55714d7ca5cSH. Peter Anvin port_cf9_safe = true; 558144d102bSMichael D Labriola /* Fall through */ 55914d7ca5cSH. Peter Anvin 5605be44a6fSIngo Molnar case BOOT_CF9_SAFE: 56114d7ca5cSH. Peter Anvin if (port_cf9_safe) { 5625be44a6fSIngo Molnar u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; 56316c21ae5SLi Fei u8 cf9 = inb(0xcf9) & ~reboot_code; 56414d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 56514d7ca5cSH. Peter Anvin udelay(50); 56616c21ae5SLi Fei /* Actually do the reset */ 56716c21ae5SLi Fei outb(cf9|reboot_code, 0xcf9); 56814d7ca5cSH. Peter Anvin udelay(50); 56914d7ca5cSH. Peter Anvin } 5705be44a6fSIngo Molnar reboot_type = BOOT_TRIPLE; 5715be44a6fSIngo Molnar break; 5725be44a6fSIngo Molnar 5735be44a6fSIngo Molnar case BOOT_TRIPLE: 5745be44a6fSIngo Molnar load_idt(&no_idt); 5755be44a6fSIngo Molnar __asm__ __volatile__("int3"); 5765be44a6fSIngo Molnar 5775be44a6fSIngo Molnar /* We're probably dead after this, but... */ 5785be44a6fSIngo Molnar reboot_type = BOOT_KBD; 5794d022e35SMiguel Boton break; 5804d022e35SMiguel Boton } 5814d022e35SMiguel Boton } 5824d022e35SMiguel Boton } 5834d022e35SMiguel Boton 5843c62c625SGlauber Costa void native_machine_shutdown(void) 5854d022e35SMiguel Boton { 5864d022e35SMiguel Boton /* Stop the cpus and apics */ 587522e6646SFenghua Yu #ifdef CONFIG_X86_IO_APIC 5882885432aSFenghua Yu /* 5892885432aSFenghua Yu * Disabling IO APIC before local APIC is a workaround for 5902885432aSFenghua Yu * erratum AVR31 in "Intel Atom Processor C2000 Product Family 5912885432aSFenghua Yu * Specification Update". In this situation, interrupts that target 5922885432aSFenghua Yu * a Logical Processor whose Local APIC is either in the process of 5932885432aSFenghua Yu * being hardware disabled or software disabled are neither delivered 5942885432aSFenghua Yu * nor discarded. When this erratum occurs, the processor may hang. 5952885432aSFenghua Yu * 5962885432aSFenghua Yu * Even without the erratum, it still makes sense to quiet IO APIC 5972885432aSFenghua Yu * before disabling Local APIC. 5982885432aSFenghua Yu */ 599522e6646SFenghua Yu disable_IO_APIC(); 600522e6646SFenghua Yu #endif 601522e6646SFenghua Yu 6024d022e35SMiguel Boton #ifdef CONFIG_SMP 603144d102bSMichael D Labriola /* 6041b3a5d02SRobin Holt * Stop all of the others. Also disable the local irq to 6051b3a5d02SRobin Holt * not receive the per-cpu timer interrupt which may trigger 6061b3a5d02SRobin Holt * scheduler's load balance. 6074d022e35SMiguel Boton */ 60855c844a4SFeng Tang local_irq_disable(); 60976fac077SAlok Kataria stop_other_cpus(); 6104d022e35SMiguel Boton #endif 6114d022e35SMiguel Boton 6124d022e35SMiguel Boton lapic_shutdown(); 6134d022e35SMiguel Boton 6144d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 6154d022e35SMiguel Boton hpet_disable(); 6164d022e35SMiguel Boton #endif 6174d022e35SMiguel Boton 6184d022e35SMiguel Boton #ifdef CONFIG_X86_64 619338bac52SFUJITA Tomonori x86_platform.iommu_shutdown(); 6204d022e35SMiguel Boton #endif 6214d022e35SMiguel Boton } 6224d022e35SMiguel Boton 623d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 624d176720dSEduardo Habkost { 625d176720dSEduardo Habkost reboot_emergency = emergency; 626d176720dSEduardo Habkost machine_ops.emergency_restart(); 627d176720dSEduardo Habkost } 628d176720dSEduardo Habkost 629416e2d63SJody Belka static void native_machine_restart(char *__unused) 6304d022e35SMiguel Boton { 631c767a54bSJoe Perches pr_notice("machine restart\n"); 6324d022e35SMiguel Boton 6334d022e35SMiguel Boton if (!reboot_force) 6344d022e35SMiguel Boton machine_shutdown(); 635d176720dSEduardo Habkost __machine_emergency_restart(0); 6364d022e35SMiguel Boton } 6374d022e35SMiguel Boton 638416e2d63SJody Belka static void native_machine_halt(void) 6394d022e35SMiguel Boton { 640144d102bSMichael D Labriola /* Stop other cpus and apics */ 641d3ec5caeSIvan Vecera machine_shutdown(); 642d3ec5caeSIvan Vecera 643840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 644840c2bafSJoseph Cihula 645d3ec5caeSIvan Vecera stop_this_cpu(NULL); 6464d022e35SMiguel Boton } 6474d022e35SMiguel Boton 648416e2d63SJody Belka static void native_machine_power_off(void) 6494d022e35SMiguel Boton { 6504d022e35SMiguel Boton if (pm_power_off) { 6514d022e35SMiguel Boton if (!reboot_force) 6524d022e35SMiguel Boton machine_shutdown(); 6534d022e35SMiguel Boton pm_power_off(); 6544d022e35SMiguel Boton } 655144d102bSMichael D Labriola /* A fallback in case there is no PM info available */ 656840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 6574d022e35SMiguel Boton } 6584d022e35SMiguel Boton 6594d022e35SMiguel Boton struct machine_ops machine_ops = { 660416e2d63SJody Belka .power_off = native_machine_power_off, 661416e2d63SJody Belka .shutdown = native_machine_shutdown, 662416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 663416e2d63SJody Belka .restart = native_machine_restart, 664ed23dc6fSGlauber Costa .halt = native_machine_halt, 665ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 666ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 667ed23dc6fSGlauber Costa #endif 6684d022e35SMiguel Boton }; 669416e2d63SJody Belka 670416e2d63SJody Belka void machine_power_off(void) 671416e2d63SJody Belka { 672416e2d63SJody Belka machine_ops.power_off(); 673416e2d63SJody Belka } 674416e2d63SJody Belka 675416e2d63SJody Belka void machine_shutdown(void) 676416e2d63SJody Belka { 677416e2d63SJody Belka machine_ops.shutdown(); 678416e2d63SJody Belka } 679416e2d63SJody Belka 680416e2d63SJody Belka void machine_emergency_restart(void) 681416e2d63SJody Belka { 682d176720dSEduardo Habkost __machine_emergency_restart(1); 683416e2d63SJody Belka } 684416e2d63SJody Belka 685416e2d63SJody Belka void machine_restart(char *cmd) 686416e2d63SJody Belka { 687416e2d63SJody Belka machine_ops.restart(cmd); 688416e2d63SJody Belka } 689416e2d63SJody Belka 690416e2d63SJody Belka void machine_halt(void) 691416e2d63SJody Belka { 692416e2d63SJody Belka machine_ops.halt(); 693416e2d63SJody Belka } 694416e2d63SJody Belka 695ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 696ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 697ed23dc6fSGlauber Costa { 698ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 699ed23dc6fSGlauber Costa } 700ed23dc6fSGlauber Costa #endif 7012ddded21SEduardo Habkost 7022ddded21SEduardo Habkost 703bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 7042ddded21SEduardo Habkost 7052ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 7062ddded21SEduardo Habkost static int crashing_cpu; 7072ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 7082ddded21SEduardo Habkost 7092ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 7102ddded21SEduardo Habkost 7119c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) 7122ddded21SEduardo Habkost { 7132ddded21SEduardo Habkost int cpu; 7142ddded21SEduardo Habkost 7152ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 7162ddded21SEduardo Habkost 717144d102bSMichael D Labriola /* 718144d102bSMichael D Labriola * Don't do anything if this handler is invoked on crashing cpu. 7192ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 7202ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 7212ddded21SEduardo Habkost */ 7222ddded21SEduardo Habkost if (cpu == crashing_cpu) 7239c48f1c6SDon Zickus return NMI_HANDLED; 7242ddded21SEduardo Habkost local_irq_disable(); 7252ddded21SEduardo Habkost 7269c48f1c6SDon Zickus shootdown_callback(cpu, regs); 7272ddded21SEduardo Habkost 7282ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 7292ddded21SEduardo Habkost /* Assume hlt works */ 7302ddded21SEduardo Habkost halt(); 7312ddded21SEduardo Habkost for (;;) 7322ddded21SEduardo Habkost cpu_relax(); 7332ddded21SEduardo Habkost 7349c48f1c6SDon Zickus return NMI_HANDLED; 7352ddded21SEduardo Habkost } 7362ddded21SEduardo Habkost 7372ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 7382ddded21SEduardo Habkost { 739dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 7402ddded21SEduardo Habkost } 7412ddded21SEduardo Habkost 742144d102bSMichael D Labriola /* 743144d102bSMichael D Labriola * Halt all other CPUs, calling the specified function on each of them 744bb8dd270SEduardo Habkost * 745bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 746bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 747bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 748bb8dd270SEduardo Habkost */ 7492ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 7502ddded21SEduardo Habkost { 7512ddded21SEduardo Habkost unsigned long msecs; 752c415b3dcSEduardo Habkost local_irq_disable(); 7532ddded21SEduardo Habkost 7542ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback. */ 7552ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 7562ddded21SEduardo Habkost 7572ddded21SEduardo Habkost shootdown_callback = callback; 7582ddded21SEduardo Habkost 7592ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 7602ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 7619c48f1c6SDon Zickus if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, 7629c48f1c6SDon Zickus NMI_FLAG_FIRST, "crash")) 763144d102bSMichael D Labriola return; /* Return what? */ 764144d102bSMichael D Labriola /* 765144d102bSMichael D Labriola * Ensure the new callback function is set before sending 7662ddded21SEduardo Habkost * out the NMI 7672ddded21SEduardo Habkost */ 7682ddded21SEduardo Habkost wmb(); 7692ddded21SEduardo Habkost 7702ddded21SEduardo Habkost smp_send_nmi_allbutself(); 7712ddded21SEduardo Habkost 7722ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 7732ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 7742ddded21SEduardo Habkost mdelay(1); 7752ddded21SEduardo Habkost msecs--; 7762ddded21SEduardo Habkost } 7772ddded21SEduardo Habkost 7782ddded21SEduardo Habkost /* Leave the nmi callback set */ 7792ddded21SEduardo Habkost } 780bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 781bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 782bb8dd270SEduardo Habkost { 783bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 784bb8dd270SEduardo Habkost } 7852ddded21SEduardo Habkost #endif 786