xref: /linux/arch/x86/kernel/reboot.c (revision 5a8c9aebe04a78b069828d364798d5f24c5a42bd)
14d022e35SMiguel Boton #include <linux/module.h>
24d022e35SMiguel Boton #include <linux/reboot.h>
34d022e35SMiguel Boton #include <linux/init.h>
44d022e35SMiguel Boton #include <linux/pm.h>
54d022e35SMiguel Boton #include <linux/efi.h>
66c6c51e4SPaul Mackerras #include <linux/dmi.h>
7d43c36dcSAlexey Dobriyan #include <linux/sched.h>
869575d38SShane Wang #include <linux/tboot.h>
9ca444564SJean Delvare #include <linux/delay.h>
104d022e35SMiguel Boton #include <acpi/reboot.h>
114d022e35SMiguel Boton #include <asm/io.h>
124d022e35SMiguel Boton #include <asm/apic.h>
134d022e35SMiguel Boton #include <asm/desc.h>
144d022e35SMiguel Boton #include <asm/hpet.h>
1568db065cSJeremy Fitzhardinge #include <asm/pgtable.h>
164412620fSDmitri Vorobiev #include <asm/proto.h>
174d022e35SMiguel Boton #include <asm/reboot_fixups.h>
184d022e35SMiguel Boton #include <asm/reboot.h>
1982487711SJaswinder Singh Rajput #include <asm/pci_x86.h>
20d176720dSEduardo Habkost #include <asm/virtext.h>
2196b89dc6SJaswinder Singh Rajput #include <asm/cpu.h>
22c410b830SDon Zickus #include <asm/nmi.h>
234d022e35SMiguel Boton 
244d022e35SMiguel Boton #ifdef CONFIG_X86_32
254d022e35SMiguel Boton # include <linux/ctype.h>
264d022e35SMiguel Boton # include <linux/mc146818rtc.h>
27*5a8c9aebSJarkko Sakkinen # include <asm/realmode.h>
284d022e35SMiguel Boton #else
29338bac52SFUJITA Tomonori # include <asm/x86_init.h>
304d022e35SMiguel Boton #endif
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 static int reboot_mode;
40660e34ceSMatthew Garrett enum reboot_type reboot_type = BOOT_ACPI;
414d022e35SMiguel Boton int reboot_force;
424d022e35SMiguel Boton 
435955633eSMichael D Labriola /* This variable is used privately to keep track of whether or not
445955633eSMichael D Labriola  * reboot_type is still set to its default value (i.e., reboot= hasn't
455955633eSMichael D Labriola  * been set on the command line).  This is needed so that we can
465955633eSMichael D Labriola  * suppress DMI scanning for reboot quirks.  Without it, it's
475955633eSMichael D Labriola  * impossible to override a faulty reboot quirk without recompiling.
485955633eSMichael D Labriola  */
495955633eSMichael D Labriola static int reboot_default = 1;
505955633eSMichael D Labriola 
514d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
524d022e35SMiguel Boton static int reboot_cpu = -1;
534d022e35SMiguel Boton #endif
544d022e35SMiguel Boton 
55d176720dSEduardo Habkost /* This is set if we need to go through the 'emergency' path.
56d176720dSEduardo Habkost  * When machine_emergency_restart() is called, we may be on
57d176720dSEduardo Habkost  * an inconsistent state and won't be able to do a clean cleanup
58d176720dSEduardo Habkost  */
59d176720dSEduardo Habkost static int reboot_emergency;
60d176720dSEduardo Habkost 
6114d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
6214d7ca5cSH. Peter Anvin bool port_cf9_safe = false;
6314d7ca5cSH. Peter Anvin 
6414d7ca5cSH. Peter Anvin /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
654d022e35SMiguel Boton    warm   Don't set the cold reboot flag
664d022e35SMiguel Boton    cold   Set the cold reboot flag
674d022e35SMiguel Boton    bios   Reboot by jumping through the BIOS (only for X86_32)
684d022e35SMiguel Boton    smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
694d022e35SMiguel Boton    triple Force a triple fault (init)
704d022e35SMiguel Boton    kbd    Use the keyboard controller. cold reset (default)
714d022e35SMiguel Boton    acpi   Use the RESET_REG in the FADT
724d022e35SMiguel Boton    efi    Use efi reset_system runtime service
7314d7ca5cSH. Peter Anvin    pci    Use the so-called "PCI reset register", CF9
744d022e35SMiguel Boton    force  Avoid anything that could hang.
754d022e35SMiguel Boton  */
764d022e35SMiguel Boton static int __init reboot_setup(char *str)
774d022e35SMiguel Boton {
784d022e35SMiguel Boton 	for (;;) {
795955633eSMichael D Labriola 		/* Having anything passed on the command line via
805955633eSMichael D Labriola 		 * reboot= will cause us to disable DMI checking
815955633eSMichael D Labriola 		 * below.
825955633eSMichael D Labriola 		 */
835955633eSMichael D Labriola 		reboot_default = 0;
845955633eSMichael D Labriola 
854d022e35SMiguel Boton 		switch (*str) {
864d022e35SMiguel Boton 		case 'w':
874d022e35SMiguel Boton 			reboot_mode = 0x1234;
884d022e35SMiguel Boton 			break;
894d022e35SMiguel Boton 
904d022e35SMiguel Boton 		case 'c':
914d022e35SMiguel Boton 			reboot_mode = 0;
924d022e35SMiguel Boton 			break;
934d022e35SMiguel Boton 
944d022e35SMiguel Boton #ifdef CONFIG_X86_32
954d022e35SMiguel Boton #ifdef CONFIG_SMP
964d022e35SMiguel Boton 		case 's':
974d022e35SMiguel Boton 			if (isdigit(*(str+1))) {
984d022e35SMiguel Boton 				reboot_cpu = (int) (*(str+1) - '0');
994d022e35SMiguel Boton 				if (isdigit(*(str+2)))
1004d022e35SMiguel Boton 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
1014d022e35SMiguel Boton 			}
1024d022e35SMiguel Boton 				/* we will leave sorting out the final value
1034d022e35SMiguel Boton 				   when we are ready to reboot, since we might not
104f6e9456cSRobert Richter 				   have detected BSP APIC ID or smp_num_cpu */
1054d022e35SMiguel Boton 			break;
1064d022e35SMiguel Boton #endif /* CONFIG_SMP */
1074d022e35SMiguel Boton 
1084d022e35SMiguel Boton 		case 'b':
1094d022e35SMiguel Boton #endif
1104d022e35SMiguel Boton 		case 'a':
1114d022e35SMiguel Boton 		case 'k':
1124d022e35SMiguel Boton 		case 't':
1134d022e35SMiguel Boton 		case 'e':
11414d7ca5cSH. Peter Anvin 		case 'p':
1154d022e35SMiguel Boton 			reboot_type = *str;
1164d022e35SMiguel Boton 			break;
1174d022e35SMiguel Boton 
1184d022e35SMiguel Boton 		case 'f':
1194d022e35SMiguel Boton 			reboot_force = 1;
1204d022e35SMiguel Boton 			break;
1214d022e35SMiguel Boton 		}
1224d022e35SMiguel Boton 
1234d022e35SMiguel Boton 		str = strchr(str, ',');
1244d022e35SMiguel Boton 		if (str)
1254d022e35SMiguel Boton 			str++;
1264d022e35SMiguel Boton 		else
1274d022e35SMiguel Boton 			break;
1284d022e35SMiguel Boton 	}
1294d022e35SMiguel Boton 	return 1;
1304d022e35SMiguel Boton }
1314d022e35SMiguel Boton 
1324d022e35SMiguel Boton __setup("reboot=", reboot_setup);
1334d022e35SMiguel Boton 
1344d022e35SMiguel Boton 
1354d022e35SMiguel Boton #ifdef CONFIG_X86_32
1364d022e35SMiguel Boton /*
1374d022e35SMiguel Boton  * Reboot options and system auto-detection code provided by
1384d022e35SMiguel Boton  * Dell Inc. so their systems "just work". :-)
1394d022e35SMiguel Boton  */
1404d022e35SMiguel Boton 
1414d022e35SMiguel Boton /*
1421ef03890SPeter Chubb  * Some machines require the "reboot=b" or "reboot=k"  commandline options,
1434d022e35SMiguel Boton  * this quirk makes that automatic.
1444d022e35SMiguel Boton  */
1454d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d)
1464d022e35SMiguel Boton {
1474d022e35SMiguel Boton 	if (reboot_type != BOOT_BIOS) {
1484d022e35SMiguel Boton 		reboot_type = BOOT_BIOS;
1494d022e35SMiguel Boton 		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
1504d022e35SMiguel Boton 	}
1514d022e35SMiguel Boton 	return 0;
1524d022e35SMiguel Boton }
1534d022e35SMiguel Boton 
1541ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d)
1551ef03890SPeter Chubb {
1561ef03890SPeter Chubb 	if (reboot_type != BOOT_KBD) {
1571ef03890SPeter Chubb 		reboot_type = BOOT_KBD;
1581ef03890SPeter Chubb 		printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
1591ef03890SPeter Chubb 	}
1601ef03890SPeter Chubb 	return 0;
1611ef03890SPeter Chubb }
1621ef03890SPeter Chubb 
1634d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = {
1644d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell E520's */
1654d022e35SMiguel Boton 		.callback = set_bios_reboot,
1664d022e35SMiguel Boton 		.ident = "Dell E520",
1674d022e35SMiguel Boton 		.matches = {
1684d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1694d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
1704d022e35SMiguel Boton 		},
1714d022e35SMiguel Boton 	},
1724d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 1300's */
1734d022e35SMiguel Boton 		.callback = set_bios_reboot,
1744d022e35SMiguel Boton 		.ident = "Dell PowerEdge 1300",
1754d022e35SMiguel Boton 		.matches = {
1764d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1774d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
1784d022e35SMiguel Boton 		},
1794d022e35SMiguel Boton 	},
1804d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 300's */
1814d022e35SMiguel Boton 		.callback = set_bios_reboot,
1824d022e35SMiguel Boton 		.ident = "Dell PowerEdge 300",
1834d022e35SMiguel Boton 		.matches = {
1844d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1854d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
1864d022e35SMiguel Boton 		},
1874d022e35SMiguel Boton 	},
1884d022e35SMiguel Boton 	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
1894d022e35SMiguel Boton 		.callback = set_bios_reboot,
1904d022e35SMiguel Boton 		.ident = "Dell OptiPlex 745",
1914d022e35SMiguel Boton 		.matches = {
1924d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1934d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
1944d022e35SMiguel Boton 		},
1954d022e35SMiguel Boton 	},
196fc115bf1SColeman Kane 	{       /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
197fc115bf1SColeman Kane 		.callback = set_bios_reboot,
198fc115bf1SColeman Kane 		.ident = "Dell OptiPlex 745",
199fc115bf1SColeman Kane 		.matches = {
200fc115bf1SColeman Kane 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
201fc115bf1SColeman Kane 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
202fc115bf1SColeman Kane 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
203fc115bf1SColeman Kane 		},
204fc115bf1SColeman Kane 	},
205fc1c8925SHeinz-Ado Arnolds 	{       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
206fc1c8925SHeinz-Ado Arnolds 		.callback = set_bios_reboot,
207fc1c8925SHeinz-Ado Arnolds 		.ident = "Dell OptiPlex 745",
208fc1c8925SHeinz-Ado Arnolds 		.matches = {
209fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
210fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
211fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
212fc1c8925SHeinz-Ado Arnolds 		},
213fc1c8925SHeinz-Ado Arnolds 	},
214093bac15SSteve Conklin 	{   /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
215093bac15SSteve Conklin 		.callback = set_bios_reboot,
216093bac15SSteve Conklin 		.ident = "Dell OptiPlex 330",
217093bac15SSteve Conklin 		.matches = {
218093bac15SSteve Conklin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
219093bac15SSteve Conklin 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
220093bac15SSteve Conklin 			DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
221093bac15SSteve Conklin 		},
222093bac15SSteve Conklin 	},
2234a4aca64SJean Delvare 	{   /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
2244a4aca64SJean Delvare 		.callback = set_bios_reboot,
2254a4aca64SJean Delvare 		.ident = "Dell OptiPlex 360",
2264a4aca64SJean Delvare 		.matches = {
2274a4aca64SJean Delvare 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2284a4aca64SJean Delvare 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
2294a4aca64SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
2304a4aca64SJean Delvare 		},
2314a4aca64SJean Delvare 	},
23235ea63d7SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
23335ea63d7SLeann Ogasawara 		.callback = set_bios_reboot,
23435ea63d7SLeann Ogasawara 		.ident = "Dell OptiPlex 760",
23535ea63d7SLeann Ogasawara 		.matches = {
23635ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
23735ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
23835ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
23935ea63d7SLeann Ogasawara 		},
24035ea63d7SLeann Ogasawara 	},
2414d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 2400's */
2424d022e35SMiguel Boton 		.callback = set_bios_reboot,
2434d022e35SMiguel Boton 		.ident = "Dell PowerEdge 2400",
2444d022e35SMiguel Boton 		.matches = {
2454d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2464d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
2474d022e35SMiguel Boton 		},
2484d022e35SMiguel Boton 	},
249fab3b58dSIngo Molnar 	{	/* Handle problems with rebooting on Dell T5400's */
250fab3b58dSIngo Molnar 		.callback = set_bios_reboot,
251fab3b58dSIngo Molnar 		.ident = "Dell Precision T5400",
252fab3b58dSIngo Molnar 		.matches = {
253fab3b58dSIngo Molnar 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
254fab3b58dSIngo Molnar 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
255fab3b58dSIngo Molnar 		},
256fab3b58dSIngo Molnar 	},
257890ffedcSThomas Backlund 	{	/* Handle problems with rebooting on Dell T7400's */
258890ffedcSThomas Backlund 		.callback = set_bios_reboot,
259890ffedcSThomas Backlund 		.ident = "Dell Precision T7400",
260890ffedcSThomas Backlund 		.matches = {
261890ffedcSThomas Backlund 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
262890ffedcSThomas Backlund 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
263890ffedcSThomas Backlund 		},
264890ffedcSThomas Backlund 	},
2654d022e35SMiguel Boton 	{	/* Handle problems with rebooting on HP laptops */
2664d022e35SMiguel Boton 		.callback = set_bios_reboot,
2674d022e35SMiguel Boton 		.ident = "HP Compaq Laptop",
2684d022e35SMiguel Boton 		.matches = {
2694d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2704d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
2714d022e35SMiguel Boton 		},
2724d022e35SMiguel Boton 	},
273dd4124a8SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell XPS710 */
274dd4124a8SLeann Ogasawara 		.callback = set_bios_reboot,
275dd4124a8SLeann Ogasawara 		.ident = "Dell XPS710",
276dd4124a8SLeann Ogasawara 		.matches = {
277dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
278dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
279dd4124a8SLeann Ogasawara 		},
280dd4124a8SLeann Ogasawara 	},
281c5da9a2bSAlan Cox 	{	/* Handle problems with rebooting on Dell DXP061 */
282c5da9a2bSAlan Cox 		.callback = set_bios_reboot,
283c5da9a2bSAlan Cox 		.ident = "Dell DXP061",
284c5da9a2bSAlan Cox 		.matches = {
285c5da9a2bSAlan Cox 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
286c5da9a2bSAlan Cox 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
287c5da9a2bSAlan Cox 		},
288c5da9a2bSAlan Cox 	},
28988dff493SZhang Rui 	{	/* Handle problems with rebooting on Sony VGN-Z540N */
29088dff493SZhang Rui 		.callback = set_bios_reboot,
29188dff493SZhang Rui 		.ident = "Sony VGN-Z540N",
29288dff493SZhang Rui 		.matches = {
29388dff493SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
29488dff493SZhang Rui 			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
29588dff493SZhang Rui 		},
29688dff493SZhang Rui 	},
29777f32dfdSDenis Turischev 	{	/* Handle problems with rebooting on CompuLab SBC-FITPC2 */
29877f32dfdSDenis Turischev 		.callback = set_bios_reboot,
29977f32dfdSDenis Turischev 		.ident = "CompuLab SBC-FITPC2",
30077f32dfdSDenis Turischev 		.matches = {
30177f32dfdSDenis Turischev 			DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
30277f32dfdSDenis Turischev 			DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
30377f32dfdSDenis Turischev 		},
30477f32dfdSDenis Turischev 	},
3054832dddaSLeann Ogasawara 	{       /* Handle problems with rebooting on ASUS P4S800 */
3064832dddaSLeann Ogasawara 		.callback = set_bios_reboot,
3074832dddaSLeann Ogasawara 		.ident = "ASUS P4S800",
3084832dddaSLeann Ogasawara 		.matches = {
3094832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
3104832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
3114832dddaSLeann Ogasawara 		},
3124832dddaSLeann Ogasawara 	},
313b49c78d4SPeter Chubb 	{ /* Handle reboot issue on Acer Aspire one */
3141ef03890SPeter Chubb 		.callback = set_kbd_reboot,
315b49c78d4SPeter Chubb 		.ident = "Acer Aspire One A110",
316b49c78d4SPeter Chubb 		.matches = {
317b49c78d4SPeter Chubb 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
318b49c78d4SPeter Chubb 			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
319b49c78d4SPeter Chubb 		},
320b49c78d4SPeter Chubb 	},
3214d022e35SMiguel Boton 	{ }
3224d022e35SMiguel Boton };
3234d022e35SMiguel Boton 
3244d022e35SMiguel Boton static int __init reboot_init(void)
3254d022e35SMiguel Boton {
3265955633eSMichael D Labriola 	/* Only do the DMI check if reboot_type hasn't been overridden
3275955633eSMichael D Labriola 	 * on the command line
3285955633eSMichael D Labriola 	 */
3295955633eSMichael D Labriola 	if (reboot_default) {
3304d022e35SMiguel Boton 		dmi_check_system(reboot_dmi_table);
3315955633eSMichael D Labriola 	}
3324d022e35SMiguel Boton 	return 0;
3334d022e35SMiguel Boton }
3344d022e35SMiguel Boton core_initcall(reboot_init);
3354d022e35SMiguel Boton 
3363d35ac34SH. Peter Anvin void machine_real_restart(unsigned int type)
3374d022e35SMiguel Boton {
338*5a8c9aebSJarkko Sakkinen 	void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
339*5a8c9aebSJarkko Sakkinen 		real_mode_header.machine_real_restart_asm;
3404d022e35SMiguel Boton 
3414d022e35SMiguel Boton 	local_irq_disable();
3424d022e35SMiguel Boton 
3434d022e35SMiguel Boton 	/* Write zero to CMOS register number 0x0f, which the BIOS POST
3444d022e35SMiguel Boton 	   routine will recognize as telling it to do a proper reboot.  (Well
3454d022e35SMiguel Boton 	   that's what this book in front of me says -- it may only apply to
3464d022e35SMiguel Boton 	   the Phoenix BIOS though, it's not clear).  At the same time,
3474d022e35SMiguel Boton 	   disable NMIs by setting the top bit in the CMOS address register,
3484d022e35SMiguel Boton 	   as we're about to do peculiar things to the CPU.  I'm not sure if
3494d022e35SMiguel Boton 	   `outb_p' is needed instead of just `outb'.  Use it to be on the
3504d022e35SMiguel Boton 	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
3514d022e35SMiguel Boton 	 */
3524d022e35SMiguel Boton 	spin_lock(&rtc_lock);
3534d022e35SMiguel Boton 	CMOS_WRITE(0x00, 0x8f);
3544d022e35SMiguel Boton 	spin_unlock(&rtc_lock);
3554d022e35SMiguel Boton 
3564d022e35SMiguel Boton 	/*
357b40827faSBorislav Petkov 	 * Switch back to the initial page table.
3584d022e35SMiguel Boton 	 */
359b40827faSBorislav Petkov 	load_cr3(initial_page_table);
3604d022e35SMiguel Boton 
3614d022e35SMiguel Boton 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
3624d022e35SMiguel Boton 	   this on booting to tell it to "Bypass memory test (also warm
3634d022e35SMiguel Boton 	   boot)".  This seems like a fairly standard thing that gets set by
3644d022e35SMiguel Boton 	   REBOOT.COM programs, and the previous reset routine did this
3654d022e35SMiguel Boton 	   too. */
3664d022e35SMiguel Boton 	*((unsigned short *)0x472) = reboot_mode;
3674d022e35SMiguel Boton 
3683d35ac34SH. Peter Anvin 	/* Jump to the identity-mapped low memory code */
3693d35ac34SH. Peter Anvin 	restart_lowmem(type);
3704d022e35SMiguel Boton }
3714d022e35SMiguel Boton #ifdef CONFIG_APM_MODULE
3724d022e35SMiguel Boton EXPORT_SYMBOL(machine_real_restart);
3734d022e35SMiguel Boton #endif
3744d022e35SMiguel Boton 
3754d022e35SMiguel Boton #endif /* CONFIG_X86_32 */
3764d022e35SMiguel Boton 
3776c6c51e4SPaul Mackerras /*
378498cdbfbSOzan Çağlayan  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
3796c6c51e4SPaul Mackerras  */
3806c6c51e4SPaul Mackerras static int __init set_pci_reboot(const struct dmi_system_id *d)
3816c6c51e4SPaul Mackerras {
3826c6c51e4SPaul Mackerras 	if (reboot_type != BOOT_CF9) {
3836c6c51e4SPaul Mackerras 		reboot_type = BOOT_CF9;
3846c6c51e4SPaul Mackerras 		printk(KERN_INFO "%s series board detected. "
3856c6c51e4SPaul Mackerras 		       "Selecting PCI-method for reboots.\n", d->ident);
3866c6c51e4SPaul Mackerras 	}
3876c6c51e4SPaul Mackerras 	return 0;
3886c6c51e4SPaul Mackerras }
3896c6c51e4SPaul Mackerras 
3906c6c51e4SPaul Mackerras static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
3913e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBook5 */
3926c6c51e4SPaul Mackerras 		.callback = set_pci_reboot,
3933e03bbeaSShunichi Fuji 		.ident = "Apple MacBook5",
3946c6c51e4SPaul Mackerras 		.matches = {
3956c6c51e4SPaul Mackerras 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
3963e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
3976c6c51e4SPaul Mackerras 		},
3986c6c51e4SPaul Mackerras 	},
3993e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBookPro5 */
400498cdbfbSOzan Çağlayan 		.callback = set_pci_reboot,
4013e03bbeaSShunichi Fuji 		.ident = "Apple MacBookPro5",
402498cdbfbSOzan Çağlayan 		.matches = {
403498cdbfbSOzan Çağlayan 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4043e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
405498cdbfbSOzan Çağlayan 		},
406498cdbfbSOzan Çağlayan 	},
40705154752SGottfried Haider 	{	/* Handle problems with rebooting on Apple Macmini3,1 */
40805154752SGottfried Haider 		.callback = set_pci_reboot,
40905154752SGottfried Haider 		.ident = "Apple Macmini3,1",
41005154752SGottfried Haider 		.matches = {
41105154752SGottfried Haider 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
41205154752SGottfried Haider 			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
41305154752SGottfried Haider 		},
41405154752SGottfried Haider 	},
4150a832320SJustin P. Mattock 	{	/* Handle problems with rebooting on the iMac9,1. */
4160a832320SJustin P. Mattock 		.callback = set_pci_reboot,
4170a832320SJustin P. Mattock 		.ident = "Apple iMac9,1",
4180a832320SJustin P. Mattock 		.matches = {
4190a832320SJustin P. Mattock 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4200a832320SJustin P. Mattock 			DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
4210a832320SJustin P. Mattock 		},
4220a832320SJustin P. Mattock 	},
4233628c3f5SMaxime Ripard 	{	/* Handle problems with rebooting on the Latitude E6320. */
4243628c3f5SMaxime Ripard 		.callback = set_pci_reboot,
4253628c3f5SMaxime Ripard 		.ident = "Dell Latitude E6320",
4263628c3f5SMaxime Ripard 		.matches = {
4273628c3f5SMaxime Ripard 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4283628c3f5SMaxime Ripard 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
4293628c3f5SMaxime Ripard 		},
4303628c3f5SMaxime Ripard 	},
431b7798d28SDaniel J Blueman 	{	/* Handle problems with rebooting on the Latitude E5420. */
432b7798d28SDaniel J Blueman 		.callback = set_pci_reboot,
433b7798d28SDaniel J Blueman 		.ident = "Dell Latitude E5420",
434b7798d28SDaniel J Blueman 		.matches = {
435b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
436b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
437b7798d28SDaniel J Blueman 		},
438b7798d28SDaniel J Blueman 	},
439a536877eSH. Peter Anvin 	{	/* Handle problems with rebooting on the Latitude E6420. */
440a536877eSH. Peter Anvin 		.callback = set_pci_reboot,
441a536877eSH. Peter Anvin 		.ident = "Dell Latitude E6420",
442a536877eSH. Peter Anvin 		.matches = {
443a536877eSH. Peter Anvin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
444a536877eSH. Peter Anvin 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
445a536877eSH. Peter Anvin 		},
446a536877eSH. Peter Anvin 	},
4476be30bb7SRafael J. Wysocki 	{	/* Handle problems with rebooting on the OptiPlex 990. */
4486be30bb7SRafael J. Wysocki 		.callback = set_pci_reboot,
4496be30bb7SRafael J. Wysocki 		.ident = "Dell OptiPlex 990",
4506be30bb7SRafael J. Wysocki 		.matches = {
4516be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4526be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
4536be30bb7SRafael J. Wysocki 		},
4546be30bb7SRafael J. Wysocki 	},
4556c6c51e4SPaul Mackerras 	{ }
4566c6c51e4SPaul Mackerras };
4576c6c51e4SPaul Mackerras 
4586c6c51e4SPaul Mackerras static int __init pci_reboot_init(void)
4596c6c51e4SPaul Mackerras {
4605955633eSMichael D Labriola 	/* Only do the DMI check if reboot_type hasn't been overridden
4615955633eSMichael D Labriola 	 * on the command line
4625955633eSMichael D Labriola 	 */
4635955633eSMichael D Labriola 	if (reboot_default) {
4646c6c51e4SPaul Mackerras 		dmi_check_system(pci_reboot_dmi_table);
4655955633eSMichael D Labriola 	}
4666c6c51e4SPaul Mackerras 	return 0;
4676c6c51e4SPaul Mackerras }
4686c6c51e4SPaul Mackerras core_initcall(pci_reboot_init);
4696c6c51e4SPaul Mackerras 
4704d022e35SMiguel Boton static inline void kb_wait(void)
4714d022e35SMiguel Boton {
4724d022e35SMiguel Boton 	int i;
4734d022e35SMiguel Boton 
474c84d6af8SAlan Cox 	for (i = 0; i < 0x10000; i++) {
475c84d6af8SAlan Cox 		if ((inb(0x64) & 0x02) == 0)
4764d022e35SMiguel Boton 			break;
477c84d6af8SAlan Cox 		udelay(2);
478c84d6af8SAlan Cox 	}
4794d022e35SMiguel Boton }
4804d022e35SMiguel Boton 
4819c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs)
482d176720dSEduardo Habkost {
483d176720dSEduardo Habkost 	cpu_emergency_vmxoff();
484d176720dSEduardo Habkost }
485d176720dSEduardo Habkost 
486d176720dSEduardo Habkost /* Use NMIs as IPIs to tell all CPUs to disable virtualization
487d176720dSEduardo Habkost  */
488d176720dSEduardo Habkost static void emergency_vmx_disable_all(void)
489d176720dSEduardo Habkost {
490d176720dSEduardo Habkost 	/* Just make sure we won't change CPUs while doing this */
491d176720dSEduardo Habkost 	local_irq_disable();
492d176720dSEduardo Habkost 
493d176720dSEduardo Habkost 	/* We need to disable VMX on all CPUs before rebooting, otherwise
494d176720dSEduardo Habkost 	 * we risk hanging up the machine, because the CPU ignore INIT
495d176720dSEduardo Habkost 	 * signals when VMX is enabled.
496d176720dSEduardo Habkost 	 *
497d176720dSEduardo Habkost 	 * We can't take any locks and we may be on an inconsistent
498d176720dSEduardo Habkost 	 * state, so we use NMIs as IPIs to tell the other CPUs to disable
499d176720dSEduardo Habkost 	 * VMX and halt.
500d176720dSEduardo Habkost 	 *
501d176720dSEduardo Habkost 	 * For safety, we will avoid running the nmi_shootdown_cpus()
502d176720dSEduardo Habkost 	 * stuff unnecessarily, but we don't have a way to check
503d176720dSEduardo Habkost 	 * if other CPUs have VMX enabled. So we will call it only if the
504d176720dSEduardo Habkost 	 * CPU we are running on has VMX enabled.
505d176720dSEduardo Habkost 	 *
506d176720dSEduardo Habkost 	 * We will miss cases where VMX is not enabled on all CPUs. This
507d176720dSEduardo Habkost 	 * shouldn't do much harm because KVM always enable VMX on all
508d176720dSEduardo Habkost 	 * CPUs anyway. But we can miss it on the small window where KVM
509d176720dSEduardo Habkost 	 * is still enabling VMX.
510d176720dSEduardo Habkost 	 */
511d176720dSEduardo Habkost 	if (cpu_has_vmx() && cpu_vmx_enabled()) {
512d176720dSEduardo Habkost 		/* Disable VMX on this CPU.
513d176720dSEduardo Habkost 		 */
514d176720dSEduardo Habkost 		cpu_vmxoff();
515d176720dSEduardo Habkost 
516d176720dSEduardo Habkost 		/* Halt and disable VMX on the other CPUs */
517d176720dSEduardo Habkost 		nmi_shootdown_cpus(vmxoff_nmi);
518d176720dSEduardo Habkost 
519d176720dSEduardo Habkost 	}
520d176720dSEduardo Habkost }
521d176720dSEduardo Habkost 
522d176720dSEduardo Habkost 
5237432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void)
5247432d149SIngo Molnar {
5257432d149SIngo Molnar }
5267432d149SIngo Molnar 
527660e34ceSMatthew Garrett /*
528660e34ceSMatthew Garrett  * Windows compatible x86 hardware expects the following on reboot:
529660e34ceSMatthew Garrett  *
530660e34ceSMatthew Garrett  * 1) If the FADT has the ACPI reboot register flag set, try it
531660e34ceSMatthew Garrett  * 2) If still alive, write to the keyboard controller
532660e34ceSMatthew Garrett  * 3) If still alive, write to the ACPI reboot register again
533660e34ceSMatthew Garrett  * 4) If still alive, write to the keyboard controller again
534660e34ceSMatthew Garrett  *
535660e34ceSMatthew Garrett  * If the machine is still alive at this stage, it gives up. We default to
536660e34ceSMatthew Garrett  * following the same pattern, except that if we're still alive after (4) we'll
537660e34ceSMatthew Garrett  * try to force a triple fault and then cycle between hitting the keyboard
538660e34ceSMatthew Garrett  * controller and doing that
539660e34ceSMatthew Garrett  */
540416e2d63SJody Belka static void native_machine_emergency_restart(void)
5414d022e35SMiguel Boton {
5424d022e35SMiguel Boton 	int i;
543660e34ceSMatthew Garrett 	int attempt = 0;
544660e34ceSMatthew Garrett 	int orig_reboot_type = reboot_type;
5454d022e35SMiguel Boton 
546d176720dSEduardo Habkost 	if (reboot_emergency)
547d176720dSEduardo Habkost 		emergency_vmx_disable_all();
548d176720dSEduardo Habkost 
549840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_REBOOT);
550840c2bafSJoseph Cihula 
5514d022e35SMiguel Boton 	/* Tell the BIOS if we want cold or warm reboot */
5524d022e35SMiguel Boton 	*((unsigned short *)__va(0x472)) = reboot_mode;
5534d022e35SMiguel Boton 
5544d022e35SMiguel Boton 	for (;;) {
5554d022e35SMiguel Boton 		/* Could also try the reset bit in the Hammer NB */
5564d022e35SMiguel Boton 		switch (reboot_type) {
5574d022e35SMiguel Boton 		case BOOT_KBD:
5587432d149SIngo Molnar 			mach_reboot_fixups(); /* for board specific fixups */
5597432d149SIngo Molnar 
5604d022e35SMiguel Boton 			for (i = 0; i < 10; i++) {
5614d022e35SMiguel Boton 				kb_wait();
5624d022e35SMiguel Boton 				udelay(50);
5634d022e35SMiguel Boton 				outb(0xfe, 0x64); /* pulse reset low */
5644d022e35SMiguel Boton 				udelay(50);
5654d022e35SMiguel Boton 			}
566660e34ceSMatthew Garrett 			if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
567660e34ceSMatthew Garrett 				attempt = 1;
568660e34ceSMatthew Garrett 				reboot_type = BOOT_ACPI;
569660e34ceSMatthew Garrett 			} else {
570660e34ceSMatthew Garrett 				reboot_type = BOOT_TRIPLE;
571660e34ceSMatthew Garrett 			}
572660e34ceSMatthew Garrett 			break;
5734d022e35SMiguel Boton 
5744d022e35SMiguel Boton 		case BOOT_TRIPLE:
575ebdd561aSJan Beulich 			load_idt(&no_idt);
5764d022e35SMiguel Boton 			__asm__ __volatile__("int3");
5774d022e35SMiguel Boton 
5784d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5794d022e35SMiguel Boton 			break;
5804d022e35SMiguel Boton 
5814d022e35SMiguel Boton #ifdef CONFIG_X86_32
5824d022e35SMiguel Boton 		case BOOT_BIOS:
5833d35ac34SH. Peter Anvin 			machine_real_restart(MRR_BIOS);
5844d022e35SMiguel Boton 
5854d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5864d022e35SMiguel Boton 			break;
5874d022e35SMiguel Boton #endif
5884d022e35SMiguel Boton 
5894d022e35SMiguel Boton 		case BOOT_ACPI:
5904d022e35SMiguel Boton 			acpi_reboot();
5914d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5924d022e35SMiguel Boton 			break;
5934d022e35SMiguel Boton 
5944d022e35SMiguel Boton 		case BOOT_EFI:
5954d022e35SMiguel Boton 			if (efi_enabled)
59614d7ca5cSH. Peter Anvin 				efi.reset_system(reboot_mode ?
59714d7ca5cSH. Peter Anvin 						 EFI_RESET_WARM :
59814d7ca5cSH. Peter Anvin 						 EFI_RESET_COLD,
5994d022e35SMiguel Boton 						 EFI_SUCCESS, 0, NULL);
600b47b9288SH. Peter Anvin 			reboot_type = BOOT_KBD;
60114d7ca5cSH. Peter Anvin 			break;
6024d022e35SMiguel Boton 
60314d7ca5cSH. Peter Anvin 		case BOOT_CF9:
60414d7ca5cSH. Peter Anvin 			port_cf9_safe = true;
60514d7ca5cSH. Peter Anvin 			/* fall through */
60614d7ca5cSH. Peter Anvin 
60714d7ca5cSH. Peter Anvin 		case BOOT_CF9_COND:
60814d7ca5cSH. Peter Anvin 			if (port_cf9_safe) {
60914d7ca5cSH. Peter Anvin 				u8 cf9 = inb(0xcf9) & ~6;
61014d7ca5cSH. Peter Anvin 				outb(cf9|2, 0xcf9); /* Request hard reset */
61114d7ca5cSH. Peter Anvin 				udelay(50);
61214d7ca5cSH. Peter Anvin 				outb(cf9|6, 0xcf9); /* Actually do the reset */
61314d7ca5cSH. Peter Anvin 				udelay(50);
61414d7ca5cSH. Peter Anvin 			}
6154d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6164d022e35SMiguel Boton 			break;
6174d022e35SMiguel Boton 		}
6184d022e35SMiguel Boton 	}
6194d022e35SMiguel Boton }
6204d022e35SMiguel Boton 
6213c62c625SGlauber Costa void native_machine_shutdown(void)
6224d022e35SMiguel Boton {
6234d022e35SMiguel Boton 	/* Stop the cpus and apics */
6244d022e35SMiguel Boton #ifdef CONFIG_SMP
6254d022e35SMiguel Boton 
6264d022e35SMiguel Boton 	/* The boot cpu is always logical cpu 0 */
62765c01184SMike Travis 	int reboot_cpu_id = 0;
6284d022e35SMiguel Boton 
6294d022e35SMiguel Boton #ifdef CONFIG_X86_32
6304d022e35SMiguel Boton 	/* See if there has been given a command line override */
6319628937dSMike Travis 	if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
6320bc3cc03SMike Travis 		cpu_online(reboot_cpu))
6334d022e35SMiguel Boton 		reboot_cpu_id = reboot_cpu;
6344d022e35SMiguel Boton #endif
6354d022e35SMiguel Boton 
6364d022e35SMiguel Boton 	/* Make certain the cpu I'm about to reboot on is online */
6370bc3cc03SMike Travis 	if (!cpu_online(reboot_cpu_id))
6384d022e35SMiguel Boton 		reboot_cpu_id = smp_processor_id();
6394d022e35SMiguel Boton 
6404d022e35SMiguel Boton 	/* Make certain I only run on the appropriate processor */
6419628937dSMike Travis 	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
6424d022e35SMiguel Boton 
6434d022e35SMiguel Boton 	/* O.K Now that I'm on the appropriate processor,
6444d022e35SMiguel Boton 	 * stop all of the others.
6454d022e35SMiguel Boton 	 */
64676fac077SAlok Kataria 	stop_other_cpus();
6474d022e35SMiguel Boton #endif
6484d022e35SMiguel Boton 
6494d022e35SMiguel Boton 	lapic_shutdown();
6504d022e35SMiguel Boton 
6514d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC
6524d022e35SMiguel Boton 	disable_IO_APIC();
6534d022e35SMiguel Boton #endif
6544d022e35SMiguel Boton 
6554d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER
6564d022e35SMiguel Boton 	hpet_disable();
6574d022e35SMiguel Boton #endif
6584d022e35SMiguel Boton 
6594d022e35SMiguel Boton #ifdef CONFIG_X86_64
660338bac52SFUJITA Tomonori 	x86_platform.iommu_shutdown();
6614d022e35SMiguel Boton #endif
6624d022e35SMiguel Boton }
6634d022e35SMiguel Boton 
664d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency)
665d176720dSEduardo Habkost {
666d176720dSEduardo Habkost 	reboot_emergency = emergency;
667d176720dSEduardo Habkost 	machine_ops.emergency_restart();
668d176720dSEduardo Habkost }
669d176720dSEduardo Habkost 
670416e2d63SJody Belka static void native_machine_restart(char *__unused)
6714d022e35SMiguel Boton {
6724d022e35SMiguel Boton 	printk("machine restart\n");
6734d022e35SMiguel Boton 
6744d022e35SMiguel Boton 	if (!reboot_force)
6754d022e35SMiguel Boton 		machine_shutdown();
676d176720dSEduardo Habkost 	__machine_emergency_restart(0);
6774d022e35SMiguel Boton }
6784d022e35SMiguel Boton 
679416e2d63SJody Belka static void native_machine_halt(void)
6804d022e35SMiguel Boton {
681d3ec5caeSIvan Vecera 	/* stop other cpus and apics */
682d3ec5caeSIvan Vecera 	machine_shutdown();
683d3ec5caeSIvan Vecera 
684840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
685840c2bafSJoseph Cihula 
686d3ec5caeSIvan Vecera 	/* stop this cpu */
687d3ec5caeSIvan Vecera 	stop_this_cpu(NULL);
6884d022e35SMiguel Boton }
6894d022e35SMiguel Boton 
690416e2d63SJody Belka static void native_machine_power_off(void)
6914d022e35SMiguel Boton {
6924d022e35SMiguel Boton 	if (pm_power_off) {
6934d022e35SMiguel Boton 		if (!reboot_force)
6944d022e35SMiguel Boton 			machine_shutdown();
6954d022e35SMiguel Boton 		pm_power_off();
6964d022e35SMiguel Boton 	}
697840c2bafSJoseph Cihula 	/* a fallback in case there is no PM info available */
698840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
6994d022e35SMiguel Boton }
7004d022e35SMiguel Boton 
7014d022e35SMiguel Boton struct machine_ops machine_ops = {
702416e2d63SJody Belka 	.power_off = native_machine_power_off,
703416e2d63SJody Belka 	.shutdown = native_machine_shutdown,
704416e2d63SJody Belka 	.emergency_restart = native_machine_emergency_restart,
705416e2d63SJody Belka 	.restart = native_machine_restart,
706ed23dc6fSGlauber Costa 	.halt = native_machine_halt,
707ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
708ed23dc6fSGlauber Costa 	.crash_shutdown = native_machine_crash_shutdown,
709ed23dc6fSGlauber Costa #endif
7104d022e35SMiguel Boton };
711416e2d63SJody Belka 
712416e2d63SJody Belka void machine_power_off(void)
713416e2d63SJody Belka {
714416e2d63SJody Belka 	machine_ops.power_off();
715416e2d63SJody Belka }
716416e2d63SJody Belka 
717416e2d63SJody Belka void machine_shutdown(void)
718416e2d63SJody Belka {
719416e2d63SJody Belka 	machine_ops.shutdown();
720416e2d63SJody Belka }
721416e2d63SJody Belka 
722416e2d63SJody Belka void machine_emergency_restart(void)
723416e2d63SJody Belka {
724d176720dSEduardo Habkost 	__machine_emergency_restart(1);
725416e2d63SJody Belka }
726416e2d63SJody Belka 
727416e2d63SJody Belka void machine_restart(char *cmd)
728416e2d63SJody Belka {
729416e2d63SJody Belka 	machine_ops.restart(cmd);
730416e2d63SJody Belka }
731416e2d63SJody Belka 
732416e2d63SJody Belka void machine_halt(void)
733416e2d63SJody Belka {
734416e2d63SJody Belka 	machine_ops.halt();
735416e2d63SJody Belka }
736416e2d63SJody Belka 
737ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
738ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs)
739ed23dc6fSGlauber Costa {
740ed23dc6fSGlauber Costa 	machine_ops.crash_shutdown(regs);
741ed23dc6fSGlauber Costa }
742ed23dc6fSGlauber Costa #endif
7432ddded21SEduardo Habkost 
7442ddded21SEduardo Habkost 
745bb8dd270SEduardo Habkost #if defined(CONFIG_SMP)
7462ddded21SEduardo Habkost 
7472ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */
7482ddded21SEduardo Habkost static int crashing_cpu;
7492ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback;
7502ddded21SEduardo Habkost 
7512ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi;
7522ddded21SEduardo Habkost 
7539c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
7542ddded21SEduardo Habkost {
7552ddded21SEduardo Habkost 	int cpu;
7562ddded21SEduardo Habkost 
7572ddded21SEduardo Habkost 	cpu = raw_smp_processor_id();
7582ddded21SEduardo Habkost 
7592ddded21SEduardo Habkost 	/* Don't do anything if this handler is invoked on crashing cpu.
7602ddded21SEduardo Habkost 	 * Otherwise, system will completely hang. Crashing cpu can get
7612ddded21SEduardo Habkost 	 * an NMI if system was initially booted with nmi_watchdog parameter.
7622ddded21SEduardo Habkost 	 */
7632ddded21SEduardo Habkost 	if (cpu == crashing_cpu)
7649c48f1c6SDon Zickus 		return NMI_HANDLED;
7652ddded21SEduardo Habkost 	local_irq_disable();
7662ddded21SEduardo Habkost 
7679c48f1c6SDon Zickus 	shootdown_callback(cpu, regs);
7682ddded21SEduardo Habkost 
7692ddded21SEduardo Habkost 	atomic_dec(&waiting_for_crash_ipi);
7702ddded21SEduardo Habkost 	/* Assume hlt works */
7712ddded21SEduardo Habkost 	halt();
7722ddded21SEduardo Habkost 	for (;;)
7732ddded21SEduardo Habkost 		cpu_relax();
7742ddded21SEduardo Habkost 
7759c48f1c6SDon Zickus 	return NMI_HANDLED;
7762ddded21SEduardo Habkost }
7772ddded21SEduardo Habkost 
7782ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void)
7792ddded21SEduardo Habkost {
780dac5f412SIngo Molnar 	apic->send_IPI_allbutself(NMI_VECTOR);
7812ddded21SEduardo Habkost }
7822ddded21SEduardo Habkost 
783bb8dd270SEduardo Habkost /* Halt all other CPUs, calling the specified function on each of them
784bb8dd270SEduardo Habkost  *
785bb8dd270SEduardo Habkost  * This function can be used to halt all other CPUs on crash
786bb8dd270SEduardo Habkost  * or emergency reboot time. The function passed as parameter
787bb8dd270SEduardo Habkost  * will be called inside a NMI handler on all CPUs.
788bb8dd270SEduardo Habkost  */
7892ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
7902ddded21SEduardo Habkost {
7912ddded21SEduardo Habkost 	unsigned long msecs;
792c415b3dcSEduardo Habkost 	local_irq_disable();
7932ddded21SEduardo Habkost 
7942ddded21SEduardo Habkost 	/* Make a note of crashing cpu. Will be used in NMI callback.*/
7952ddded21SEduardo Habkost 	crashing_cpu = safe_smp_processor_id();
7962ddded21SEduardo Habkost 
7972ddded21SEduardo Habkost 	shootdown_callback = callback;
7982ddded21SEduardo Habkost 
7992ddded21SEduardo Habkost 	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
8002ddded21SEduardo Habkost 	/* Would it be better to replace the trap vector here? */
8019c48f1c6SDon Zickus 	if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
8029c48f1c6SDon Zickus 				 NMI_FLAG_FIRST, "crash"))
8032ddded21SEduardo Habkost 		return;		/* return what? */
8042ddded21SEduardo Habkost 	/* Ensure the new callback function is set before sending
8052ddded21SEduardo Habkost 	 * out the NMI
8062ddded21SEduardo Habkost 	 */
8072ddded21SEduardo Habkost 	wmb();
8082ddded21SEduardo Habkost 
8092ddded21SEduardo Habkost 	smp_send_nmi_allbutself();
8102ddded21SEduardo Habkost 
8112ddded21SEduardo Habkost 	msecs = 1000; /* Wait at most a second for the other cpus to stop */
8122ddded21SEduardo Habkost 	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
8132ddded21SEduardo Habkost 		mdelay(1);
8142ddded21SEduardo Habkost 		msecs--;
8152ddded21SEduardo Habkost 	}
8162ddded21SEduardo Habkost 
8172ddded21SEduardo Habkost 	/* Leave the nmi callback set */
8182ddded21SEduardo Habkost }
819bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */
820bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
821bb8dd270SEduardo Habkost {
822bb8dd270SEduardo Habkost 	/* No other CPUs to shoot down */
823bb8dd270SEduardo Habkost }
8242ddded21SEduardo Habkost #endif
825