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", 64c767a54bSJoe Perches "BIOS", d->ident); 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", 120c767a54bSJoe Perches "PCI", d->ident); 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", 130c767a54bSJoe Perches "KBD", d->ident); 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 140*e56e57f6SDave 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 }, 149*e56e57f6SDave Jones 150*e56e57f6SDave 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 }, 183*e56e57f6SDave Jones 184*e56e57f6SDave Jones /* ASUS */ 185*e56e57f6SDave Jones { /* Handle problems with rebooting on ASUS P4S800 */ 186*e56e57f6SDave Jones .callback = set_bios_reboot, 187*e56e57f6SDave Jones .ident = "ASUS P4S800", 188*e56e57f6SDave Jones .matches = { 189*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 190*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "P4S800"), 191*e56e57f6SDave Jones }, 192*e56e57f6SDave Jones }, 193*e56e57f6SDave Jones 194*e56e57f6SDave Jones /* Dell */ 195*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell DXP061 */ 196*e56e57f6SDave Jones .callback = set_bios_reboot, 197*e56e57f6SDave Jones .ident = "Dell DXP061", 1983628c3f5SMaxime Ripard .matches = { 1993628c3f5SMaxime Ripard DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 200*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), 201*e56e57f6SDave Jones }, 202*e56e57f6SDave Jones }, 203*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell E520's */ 204*e56e57f6SDave Jones .callback = set_bios_reboot, 205*e56e57f6SDave Jones .ident = "Dell E520", 206*e56e57f6SDave Jones .matches = { 207*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 208*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 2093628c3f5SMaxime Ripard }, 2103628c3f5SMaxime Ripard }, 211b7798d28SDaniel J Blueman { /* Handle problems with rebooting on the Latitude E5420. */ 212b7798d28SDaniel J Blueman .callback = set_pci_reboot, 213b7798d28SDaniel J Blueman .ident = "Dell Latitude E5420", 214b7798d28SDaniel J Blueman .matches = { 215b7798d28SDaniel J Blueman DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 216b7798d28SDaniel J Blueman DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), 217b7798d28SDaniel J Blueman }, 218b7798d28SDaniel J Blueman }, 219*e56e57f6SDave Jones { /* Handle problems with rebooting on the Latitude E6320. */ 220*e56e57f6SDave Jones .callback = set_pci_reboot, 221*e56e57f6SDave Jones .ident = "Dell Latitude E6320", 222*e56e57f6SDave Jones .matches = { 223*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 224*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), 225*e56e57f6SDave Jones }, 226*e56e57f6SDave Jones }, 227a536877eSH. Peter Anvin { /* Handle problems with rebooting on the Latitude E6420. */ 228a536877eSH. Peter Anvin .callback = set_pci_reboot, 229a536877eSH. Peter Anvin .ident = "Dell Latitude E6420", 230a536877eSH. Peter Anvin .matches = { 231a536877eSH. Peter Anvin DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 232a536877eSH. Peter Anvin DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), 233a536877eSH. Peter Anvin }, 234a536877eSH. Peter Anvin }, 235*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ 236*e56e57f6SDave Jones .callback = set_bios_reboot, 237*e56e57f6SDave Jones .ident = "Dell OptiPlex 330", 238*e56e57f6SDave Jones .matches = { 239*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 240*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), 241*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KP561"), 242*e56e57f6SDave Jones }, 243*e56e57f6SDave Jones }, 244*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ 245*e56e57f6SDave Jones .callback = set_bios_reboot, 246*e56e57f6SDave Jones .ident = "Dell OptiPlex 360", 247*e56e57f6SDave Jones .matches = { 248*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 249*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), 250*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0T656F"), 251*e56e57f6SDave Jones }, 252*e56e57f6SDave Jones }, 253*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ 254*e56e57f6SDave Jones .callback = set_bios_reboot, 255*e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 256*e56e57f6SDave Jones .matches = { 257*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 258*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 259*e56e57f6SDave Jones }, 260*e56e57f6SDave Jones }, 261*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ 262*e56e57f6SDave Jones .callback = set_bios_reboot, 263*e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 264*e56e57f6SDave Jones .matches = { 265*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 266*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 267*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 268*e56e57f6SDave Jones }, 269*e56e57f6SDave Jones }, 270*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 271*e56e57f6SDave Jones .callback = set_bios_reboot, 272*e56e57f6SDave Jones .ident = "Dell OptiPlex 745", 273*e56e57f6SDave Jones .matches = { 274*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 275*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 276*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 277*e56e57f6SDave Jones }, 278*e56e57f6SDave Jones }, 279*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ 280*e56e57f6SDave Jones .callback = set_bios_reboot, 281*e56e57f6SDave Jones .ident = "Dell OptiPlex 760", 282*e56e57f6SDave Jones .matches = { 283*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 284*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), 285*e56e57f6SDave Jones DMI_MATCH(DMI_BOARD_NAME, "0G919G"), 286*e56e57f6SDave Jones }, 287*e56e57f6SDave Jones }, 2886be30bb7SRafael J. Wysocki { /* Handle problems with rebooting on the OptiPlex 990. */ 2896be30bb7SRafael J. Wysocki .callback = set_pci_reboot, 2906be30bb7SRafael J. Wysocki .ident = "Dell OptiPlex 990", 2916be30bb7SRafael J. Wysocki .matches = { 2926be30bb7SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 2936be30bb7SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), 2946be30bb7SRafael J. Wysocki }, 2956be30bb7SRafael J. Wysocki }, 296*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 300's */ 297*e56e57f6SDave Jones .callback = set_bios_reboot, 298*e56e57f6SDave Jones .ident = "Dell PowerEdge 300", 29976eb9a30SZhang Rui .matches = { 300*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 301*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 302*e56e57f6SDave Jones }, 303*e56e57f6SDave Jones }, 304*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 1300's */ 305*e56e57f6SDave Jones .callback = set_bios_reboot, 306*e56e57f6SDave Jones .ident = "Dell PowerEdge 1300", 307*e56e57f6SDave Jones .matches = { 308*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 309*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 310*e56e57f6SDave Jones }, 311*e56e57f6SDave Jones }, 312*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell 2400's */ 313*e56e57f6SDave Jones .callback = set_bios_reboot, 314*e56e57f6SDave Jones .ident = "Dell PowerEdge 2400", 315*e56e57f6SDave Jones .matches = { 316*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 317*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 31876eb9a30SZhang Rui }, 31976eb9a30SZhang Rui }, 3204f0acd31SMasoud Sharbiani { /* Handle problems with rebooting on the Dell PowerEdge C6100. */ 3214f0acd31SMasoud Sharbiani .callback = set_pci_reboot, 3224f0acd31SMasoud Sharbiani .ident = "Dell PowerEdge C6100", 3234f0acd31SMasoud Sharbiani .matches = { 3244f0acd31SMasoud Sharbiani DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 3254f0acd31SMasoud Sharbiani DMI_MATCH(DMI_PRODUCT_NAME, "C6100"), 3264f0acd31SMasoud Sharbiani }, 3274f0acd31SMasoud Sharbiani }, 328*e56e57f6SDave Jones { /* Handle problems with rebooting on the Precision M6600. */ 329*e56e57f6SDave Jones .callback = set_pci_reboot, 330*e56e57f6SDave Jones .ident = "Dell Precision M6600", 331*e56e57f6SDave Jones .matches = { 332*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 333*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), 334*e56e57f6SDave Jones }, 335*e56e57f6SDave Jones }, 336*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T5400's */ 337*e56e57f6SDave Jones .callback = set_bios_reboot, 338*e56e57f6SDave Jones .ident = "Dell Precision T5400", 339*e56e57f6SDave Jones .matches = { 340*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 341*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 342*e56e57f6SDave Jones }, 343*e56e57f6SDave Jones }, 344*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell T7400's */ 345*e56e57f6SDave Jones .callback = set_bios_reboot, 346*e56e57f6SDave Jones .ident = "Dell Precision T7400", 347*e56e57f6SDave Jones .matches = { 348*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 349*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), 350*e56e57f6SDave Jones }, 351*e56e57f6SDave Jones }, 352*e56e57f6SDave Jones { /* Handle problems with rebooting on Dell XPS710 */ 353*e56e57f6SDave Jones .callback = set_bios_reboot, 354*e56e57f6SDave Jones .ident = "Dell XPS710", 355*e56e57f6SDave Jones .matches = { 356*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 357*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), 358*e56e57f6SDave Jones }, 359*e56e57f6SDave Jones }, 360*e56e57f6SDave Jones 361*e56e57f6SDave Jones /* Hewlett-Packard */ 362*e56e57f6SDave Jones { /* Handle problems with rebooting on HP laptops */ 363*e56e57f6SDave Jones .callback = set_bios_reboot, 364*e56e57f6SDave Jones .ident = "HP Compaq Laptop", 365*e56e57f6SDave Jones .matches = { 366*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 367*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 368*e56e57f6SDave Jones }, 369*e56e57f6SDave Jones }, 370*e56e57f6SDave Jones 371*e56e57f6SDave Jones /* Sony */ 372*e56e57f6SDave Jones { /* Handle problems with rebooting on Sony VGN-Z540N */ 373*e56e57f6SDave Jones .callback = set_bios_reboot, 374*e56e57f6SDave Jones .ident = "Sony VGN-Z540N", 375*e56e57f6SDave Jones .matches = { 376*e56e57f6SDave Jones DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 377*e56e57f6SDave Jones DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), 378*e56e57f6SDave Jones }, 379*e56e57f6SDave Jones }, 380*e56e57f6SDave Jones 3816c6c51e4SPaul Mackerras { } 3826c6c51e4SPaul Mackerras }; 3836c6c51e4SPaul Mackerras 38457b16594SMichael D Labriola static int __init reboot_init(void) 3856c6c51e4SPaul Mackerras { 386144d102bSMichael D Labriola /* 387144d102bSMichael D Labriola * Only do the DMI check if reboot_type hasn't been overridden 3885955633eSMichael D Labriola * on the command line 3895955633eSMichael D Labriola */ 390144d102bSMichael D Labriola if (reboot_default) 39157b16594SMichael D Labriola dmi_check_system(reboot_dmi_table); 3926c6c51e4SPaul Mackerras return 0; 3936c6c51e4SPaul Mackerras } 39457b16594SMichael D Labriola core_initcall(reboot_init); 3956c6c51e4SPaul Mackerras 3964d022e35SMiguel Boton static inline void kb_wait(void) 3974d022e35SMiguel Boton { 3984d022e35SMiguel Boton int i; 3994d022e35SMiguel Boton 400c84d6af8SAlan Cox for (i = 0; i < 0x10000; i++) { 401c84d6af8SAlan Cox if ((inb(0x64) & 0x02) == 0) 4024d022e35SMiguel Boton break; 403c84d6af8SAlan Cox udelay(2); 404c84d6af8SAlan Cox } 4054d022e35SMiguel Boton } 4064d022e35SMiguel Boton 4079c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs) 408d176720dSEduardo Habkost { 409d176720dSEduardo Habkost cpu_emergency_vmxoff(); 410d176720dSEduardo Habkost } 411d176720dSEduardo Habkost 412144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ 413d176720dSEduardo Habkost static void emergency_vmx_disable_all(void) 414d176720dSEduardo Habkost { 415d176720dSEduardo Habkost /* Just make sure we won't change CPUs while doing this */ 416d176720dSEduardo Habkost local_irq_disable(); 417d176720dSEduardo Habkost 418144d102bSMichael D Labriola /* 419144d102bSMichael D Labriola * We need to disable VMX on all CPUs before rebooting, otherwise 420d176720dSEduardo Habkost * we risk hanging up the machine, because the CPU ignore INIT 421d176720dSEduardo Habkost * signals when VMX is enabled. 422d176720dSEduardo Habkost * 423d176720dSEduardo Habkost * We can't take any locks and we may be on an inconsistent 424d176720dSEduardo Habkost * state, so we use NMIs as IPIs to tell the other CPUs to disable 425d176720dSEduardo Habkost * VMX and halt. 426d176720dSEduardo Habkost * 427d176720dSEduardo Habkost * For safety, we will avoid running the nmi_shootdown_cpus() 428d176720dSEduardo Habkost * stuff unnecessarily, but we don't have a way to check 429d176720dSEduardo Habkost * if other CPUs have VMX enabled. So we will call it only if the 430d176720dSEduardo Habkost * CPU we are running on has VMX enabled. 431d176720dSEduardo Habkost * 432d176720dSEduardo Habkost * We will miss cases where VMX is not enabled on all CPUs. This 433d176720dSEduardo Habkost * shouldn't do much harm because KVM always enable VMX on all 434d176720dSEduardo Habkost * CPUs anyway. But we can miss it on the small window where KVM 435d176720dSEduardo Habkost * is still enabling VMX. 436d176720dSEduardo Habkost */ 437d176720dSEduardo Habkost if (cpu_has_vmx() && cpu_vmx_enabled()) { 438144d102bSMichael D Labriola /* Disable VMX on this CPU. */ 439d176720dSEduardo Habkost cpu_vmxoff(); 440d176720dSEduardo Habkost 441d176720dSEduardo Habkost /* Halt and disable VMX on the other CPUs */ 442d176720dSEduardo Habkost nmi_shootdown_cpus(vmxoff_nmi); 443d176720dSEduardo Habkost 444d176720dSEduardo Habkost } 445d176720dSEduardo Habkost } 446d176720dSEduardo Habkost 447d176720dSEduardo Habkost 4487432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 4497432d149SIngo Molnar { 4507432d149SIngo Molnar } 4517432d149SIngo Molnar 452660e34ceSMatthew Garrett /* 453660e34ceSMatthew Garrett * Windows compatible x86 hardware expects the following on reboot: 454660e34ceSMatthew Garrett * 455660e34ceSMatthew Garrett * 1) If the FADT has the ACPI reboot register flag set, try it 456660e34ceSMatthew Garrett * 2) If still alive, write to the keyboard controller 457660e34ceSMatthew Garrett * 3) If still alive, write to the ACPI reboot register again 458660e34ceSMatthew Garrett * 4) If still alive, write to the keyboard controller again 459660e34ceSMatthew Garrett * 460660e34ceSMatthew Garrett * If the machine is still alive at this stage, it gives up. We default to 461660e34ceSMatthew Garrett * following the same pattern, except that if we're still alive after (4) we'll 462660e34ceSMatthew Garrett * try to force a triple fault and then cycle between hitting the keyboard 463660e34ceSMatthew Garrett * controller and doing that 464660e34ceSMatthew Garrett */ 465416e2d63SJody Belka static void native_machine_emergency_restart(void) 4664d022e35SMiguel Boton { 4674d022e35SMiguel Boton int i; 468660e34ceSMatthew Garrett int attempt = 0; 469660e34ceSMatthew Garrett int orig_reboot_type = reboot_type; 470edf2b139SRobin Holt unsigned short mode; 4714d022e35SMiguel Boton 472d176720dSEduardo Habkost if (reboot_emergency) 473d176720dSEduardo Habkost emergency_vmx_disable_all(); 474d176720dSEduardo Habkost 475840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_REBOOT); 476840c2bafSJoseph Cihula 4774d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 478edf2b139SRobin Holt mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; 479edf2b139SRobin Holt *((unsigned short *)__va(0x472)) = mode; 4804d022e35SMiguel Boton 4814d022e35SMiguel Boton for (;;) { 4824d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 4834d022e35SMiguel Boton switch (reboot_type) { 4844d022e35SMiguel Boton case BOOT_KBD: 485144d102bSMichael D Labriola mach_reboot_fixups(); /* For board specific fixups */ 4867432d149SIngo Molnar 4874d022e35SMiguel Boton for (i = 0; i < 10; i++) { 4884d022e35SMiguel Boton kb_wait(); 4894d022e35SMiguel Boton udelay(50); 490144d102bSMichael D Labriola outb(0xfe, 0x64); /* Pulse reset low */ 4914d022e35SMiguel Boton udelay(50); 4924d022e35SMiguel Boton } 493660e34ceSMatthew Garrett if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { 494660e34ceSMatthew Garrett attempt = 1; 495660e34ceSMatthew Garrett reboot_type = BOOT_ACPI; 496660e34ceSMatthew Garrett } else { 497660e34ceSMatthew Garrett reboot_type = BOOT_TRIPLE; 498660e34ceSMatthew Garrett } 499660e34ceSMatthew Garrett break; 5004d022e35SMiguel Boton 5014d022e35SMiguel Boton case BOOT_TRIPLE: 502ebdd561aSJan Beulich load_idt(&no_idt); 5034d022e35SMiguel Boton __asm__ __volatile__("int3"); 5044d022e35SMiguel Boton 5054d022e35SMiguel Boton reboot_type = BOOT_KBD; 5064d022e35SMiguel Boton break; 5074d022e35SMiguel Boton 5084d022e35SMiguel Boton case BOOT_BIOS: 5093d35ac34SH. Peter Anvin machine_real_restart(MRR_BIOS); 5104d022e35SMiguel Boton 5114d022e35SMiguel Boton reboot_type = BOOT_KBD; 5124d022e35SMiguel Boton break; 5134d022e35SMiguel Boton 5144d022e35SMiguel Boton case BOOT_ACPI: 5154d022e35SMiguel Boton acpi_reboot(); 5164d022e35SMiguel Boton reboot_type = BOOT_KBD; 5174d022e35SMiguel Boton break; 5184d022e35SMiguel Boton 5194d022e35SMiguel Boton case BOOT_EFI: 52083e68189SMatt Fleming if (efi_enabled(EFI_RUNTIME_SERVICES)) 521edf2b139SRobin Holt efi.reset_system(reboot_mode == REBOOT_WARM ? 52214d7ca5cSH. Peter Anvin EFI_RESET_WARM : 52314d7ca5cSH. Peter Anvin EFI_RESET_COLD, 5244d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 525b47b9288SH. Peter Anvin reboot_type = BOOT_KBD; 52614d7ca5cSH. Peter Anvin break; 5274d022e35SMiguel Boton 52814d7ca5cSH. Peter Anvin case BOOT_CF9: 52914d7ca5cSH. Peter Anvin port_cf9_safe = true; 530144d102bSMichael D Labriola /* Fall through */ 53114d7ca5cSH. Peter Anvin 53214d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 53314d7ca5cSH. Peter Anvin if (port_cf9_safe) { 53416c21ae5SLi Fei u8 reboot_code = reboot_mode == REBOOT_WARM ? 53516c21ae5SLi Fei 0x06 : 0x0E; 53616c21ae5SLi Fei u8 cf9 = inb(0xcf9) & ~reboot_code; 53714d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 53814d7ca5cSH. Peter Anvin udelay(50); 53916c21ae5SLi Fei /* Actually do the reset */ 54016c21ae5SLi Fei outb(cf9|reboot_code, 0xcf9); 54114d7ca5cSH. Peter Anvin udelay(50); 54214d7ca5cSH. Peter Anvin } 5434d022e35SMiguel Boton reboot_type = BOOT_KBD; 5444d022e35SMiguel Boton break; 5454d022e35SMiguel Boton } 5464d022e35SMiguel Boton } 5474d022e35SMiguel Boton } 5484d022e35SMiguel Boton 5493c62c625SGlauber Costa void native_machine_shutdown(void) 5504d022e35SMiguel Boton { 5514d022e35SMiguel Boton /* Stop the cpus and apics */ 5524d022e35SMiguel Boton #ifdef CONFIG_SMP 553144d102bSMichael D Labriola /* 5541b3a5d02SRobin Holt * Stop all of the others. Also disable the local irq to 5551b3a5d02SRobin Holt * not receive the per-cpu timer interrupt which may trigger 5561b3a5d02SRobin Holt * scheduler's load balance. 5574d022e35SMiguel Boton */ 55855c844a4SFeng Tang local_irq_disable(); 55976fac077SAlok Kataria stop_other_cpus(); 5604d022e35SMiguel Boton #endif 5614d022e35SMiguel Boton 5624d022e35SMiguel Boton lapic_shutdown(); 5634d022e35SMiguel Boton 5644d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC 5654d022e35SMiguel Boton disable_IO_APIC(); 5664d022e35SMiguel Boton #endif 5674d022e35SMiguel Boton 5684d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 5694d022e35SMiguel Boton hpet_disable(); 5704d022e35SMiguel Boton #endif 5714d022e35SMiguel Boton 5724d022e35SMiguel Boton #ifdef CONFIG_X86_64 573338bac52SFUJITA Tomonori x86_platform.iommu_shutdown(); 5744d022e35SMiguel Boton #endif 5754d022e35SMiguel Boton } 5764d022e35SMiguel Boton 577d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency) 578d176720dSEduardo Habkost { 579d176720dSEduardo Habkost reboot_emergency = emergency; 580d176720dSEduardo Habkost machine_ops.emergency_restart(); 581d176720dSEduardo Habkost } 582d176720dSEduardo Habkost 583416e2d63SJody Belka static void native_machine_restart(char *__unused) 5844d022e35SMiguel Boton { 585c767a54bSJoe Perches pr_notice("machine restart\n"); 5864d022e35SMiguel Boton 5874d022e35SMiguel Boton if (!reboot_force) 5884d022e35SMiguel Boton machine_shutdown(); 589d176720dSEduardo Habkost __machine_emergency_restart(0); 5904d022e35SMiguel Boton } 5914d022e35SMiguel Boton 592416e2d63SJody Belka static void native_machine_halt(void) 5934d022e35SMiguel Boton { 594144d102bSMichael D Labriola /* Stop other cpus and apics */ 595d3ec5caeSIvan Vecera machine_shutdown(); 596d3ec5caeSIvan Vecera 597840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 598840c2bafSJoseph Cihula 599d3ec5caeSIvan Vecera stop_this_cpu(NULL); 6004d022e35SMiguel Boton } 6014d022e35SMiguel Boton 602416e2d63SJody Belka static void native_machine_power_off(void) 6034d022e35SMiguel Boton { 6044d022e35SMiguel Boton if (pm_power_off) { 6054d022e35SMiguel Boton if (!reboot_force) 6064d022e35SMiguel Boton machine_shutdown(); 6074d022e35SMiguel Boton pm_power_off(); 6084d022e35SMiguel Boton } 609144d102bSMichael D Labriola /* A fallback in case there is no PM info available */ 610840c2bafSJoseph Cihula tboot_shutdown(TB_SHUTDOWN_HALT); 6114d022e35SMiguel Boton } 6124d022e35SMiguel Boton 6134d022e35SMiguel Boton struct machine_ops machine_ops = { 614416e2d63SJody Belka .power_off = native_machine_power_off, 615416e2d63SJody Belka .shutdown = native_machine_shutdown, 616416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 617416e2d63SJody Belka .restart = native_machine_restart, 618ed23dc6fSGlauber Costa .halt = native_machine_halt, 619ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 620ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 621ed23dc6fSGlauber Costa #endif 6224d022e35SMiguel Boton }; 623416e2d63SJody Belka 624416e2d63SJody Belka void machine_power_off(void) 625416e2d63SJody Belka { 626416e2d63SJody Belka machine_ops.power_off(); 627416e2d63SJody Belka } 628416e2d63SJody Belka 629416e2d63SJody Belka void machine_shutdown(void) 630416e2d63SJody Belka { 631416e2d63SJody Belka machine_ops.shutdown(); 632416e2d63SJody Belka } 633416e2d63SJody Belka 634416e2d63SJody Belka void machine_emergency_restart(void) 635416e2d63SJody Belka { 636d176720dSEduardo Habkost __machine_emergency_restart(1); 637416e2d63SJody Belka } 638416e2d63SJody Belka 639416e2d63SJody Belka void machine_restart(char *cmd) 640416e2d63SJody Belka { 641416e2d63SJody Belka machine_ops.restart(cmd); 642416e2d63SJody Belka } 643416e2d63SJody Belka 644416e2d63SJody Belka void machine_halt(void) 645416e2d63SJody Belka { 646416e2d63SJody Belka machine_ops.halt(); 647416e2d63SJody Belka } 648416e2d63SJody Belka 649ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 650ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 651ed23dc6fSGlauber Costa { 652ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 653ed23dc6fSGlauber Costa } 654ed23dc6fSGlauber Costa #endif 6552ddded21SEduardo Habkost 6562ddded21SEduardo Habkost 657bb8dd270SEduardo Habkost #if defined(CONFIG_SMP) 6582ddded21SEduardo Habkost 6592ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */ 6602ddded21SEduardo Habkost static int crashing_cpu; 6612ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback; 6622ddded21SEduardo Habkost 6632ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi; 6642ddded21SEduardo Habkost 6659c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) 6662ddded21SEduardo Habkost { 6672ddded21SEduardo Habkost int cpu; 6682ddded21SEduardo Habkost 6692ddded21SEduardo Habkost cpu = raw_smp_processor_id(); 6702ddded21SEduardo Habkost 671144d102bSMichael D Labriola /* 672144d102bSMichael D Labriola * Don't do anything if this handler is invoked on crashing cpu. 6732ddded21SEduardo Habkost * Otherwise, system will completely hang. Crashing cpu can get 6742ddded21SEduardo Habkost * an NMI if system was initially booted with nmi_watchdog parameter. 6752ddded21SEduardo Habkost */ 6762ddded21SEduardo Habkost if (cpu == crashing_cpu) 6779c48f1c6SDon Zickus return NMI_HANDLED; 6782ddded21SEduardo Habkost local_irq_disable(); 6792ddded21SEduardo Habkost 6809c48f1c6SDon Zickus shootdown_callback(cpu, regs); 6812ddded21SEduardo Habkost 6822ddded21SEduardo Habkost atomic_dec(&waiting_for_crash_ipi); 6832ddded21SEduardo Habkost /* Assume hlt works */ 6842ddded21SEduardo Habkost halt(); 6852ddded21SEduardo Habkost for (;;) 6862ddded21SEduardo Habkost cpu_relax(); 6872ddded21SEduardo Habkost 6889c48f1c6SDon Zickus return NMI_HANDLED; 6892ddded21SEduardo Habkost } 6902ddded21SEduardo Habkost 6912ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void) 6922ddded21SEduardo Habkost { 693dac5f412SIngo Molnar apic->send_IPI_allbutself(NMI_VECTOR); 6942ddded21SEduardo Habkost } 6952ddded21SEduardo Habkost 696144d102bSMichael D Labriola /* 697144d102bSMichael D Labriola * Halt all other CPUs, calling the specified function on each of them 698bb8dd270SEduardo Habkost * 699bb8dd270SEduardo Habkost * This function can be used to halt all other CPUs on crash 700bb8dd270SEduardo Habkost * or emergency reboot time. The function passed as parameter 701bb8dd270SEduardo Habkost * will be called inside a NMI handler on all CPUs. 702bb8dd270SEduardo Habkost */ 7032ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 7042ddded21SEduardo Habkost { 7052ddded21SEduardo Habkost unsigned long msecs; 706c415b3dcSEduardo Habkost local_irq_disable(); 7072ddded21SEduardo Habkost 7082ddded21SEduardo Habkost /* Make a note of crashing cpu. Will be used in NMI callback. */ 7092ddded21SEduardo Habkost crashing_cpu = safe_smp_processor_id(); 7102ddded21SEduardo Habkost 7112ddded21SEduardo Habkost shootdown_callback = callback; 7122ddded21SEduardo Habkost 7132ddded21SEduardo Habkost atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 7142ddded21SEduardo Habkost /* Would it be better to replace the trap vector here? */ 7159c48f1c6SDon Zickus if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, 7169c48f1c6SDon Zickus NMI_FLAG_FIRST, "crash")) 717144d102bSMichael D Labriola return; /* Return what? */ 718144d102bSMichael D Labriola /* 719144d102bSMichael D Labriola * Ensure the new callback function is set before sending 7202ddded21SEduardo Habkost * out the NMI 7212ddded21SEduardo Habkost */ 7222ddded21SEduardo Habkost wmb(); 7232ddded21SEduardo Habkost 7242ddded21SEduardo Habkost smp_send_nmi_allbutself(); 7252ddded21SEduardo Habkost 7262ddded21SEduardo Habkost msecs = 1000; /* Wait at most a second for the other cpus to stop */ 7272ddded21SEduardo Habkost while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { 7282ddded21SEduardo Habkost mdelay(1); 7292ddded21SEduardo Habkost msecs--; 7302ddded21SEduardo Habkost } 7312ddded21SEduardo Habkost 7322ddded21SEduardo Habkost /* Leave the nmi callback set */ 7332ddded21SEduardo Habkost } 734bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */ 735bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback) 736bb8dd270SEduardo Habkost { 737bb8dd270SEduardo Habkost /* No other CPUs to shoot down */ 738bb8dd270SEduardo Habkost } 7392ddded21SEduardo Habkost #endif 740