xref: /linux/arch/x86/kernel/reboot.c (revision c410b8307702c1e1f35be3fd868ad18e4ba0410f)
14d022e35SMiguel Boton #include <linux/module.h>
24d022e35SMiguel Boton #include <linux/reboot.h>
34d022e35SMiguel Boton #include <linux/init.h>
44d022e35SMiguel Boton #include <linux/pm.h>
54d022e35SMiguel Boton #include <linux/efi.h>
66c6c51e4SPaul Mackerras #include <linux/dmi.h>
7d43c36dcSAlexey Dobriyan #include <linux/sched.h>
869575d38SShane Wang #include <linux/tboot.h>
94d022e35SMiguel Boton #include <acpi/reboot.h>
104d022e35SMiguel Boton #include <asm/io.h>
114d022e35SMiguel Boton #include <asm/apic.h>
124d022e35SMiguel Boton #include <asm/desc.h>
134d022e35SMiguel Boton #include <asm/hpet.h>
1468db065cSJeremy Fitzhardinge #include <asm/pgtable.h>
154412620fSDmitri Vorobiev #include <asm/proto.h>
164d022e35SMiguel Boton #include <asm/reboot_fixups.h>
174d022e35SMiguel Boton #include <asm/reboot.h>
1882487711SJaswinder Singh Rajput #include <asm/pci_x86.h>
19d176720dSEduardo Habkost #include <asm/virtext.h>
2096b89dc6SJaswinder Singh Rajput #include <asm/cpu.h>
21*c410b830SDon Zickus #include <asm/nmi.h>
224d022e35SMiguel Boton 
234d022e35SMiguel Boton #ifdef CONFIG_X86_32
244d022e35SMiguel Boton # include <linux/ctype.h>
254d022e35SMiguel Boton # include <linux/mc146818rtc.h>
264d022e35SMiguel Boton #else
27338bac52SFUJITA Tomonori # include <asm/x86_init.h>
284d022e35SMiguel Boton #endif
294d022e35SMiguel Boton 
304d022e35SMiguel Boton /*
314d022e35SMiguel Boton  * Power off function, if any
324d022e35SMiguel Boton  */
334d022e35SMiguel Boton void (*pm_power_off)(void);
344d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off);
354d022e35SMiguel Boton 
36ebdd561aSJan Beulich static const struct desc_ptr no_idt = {};
374d022e35SMiguel Boton static int reboot_mode;
388d00450dSEduardo Habkost enum reboot_type reboot_type = BOOT_KBD;
394d022e35SMiguel Boton int reboot_force;
404d022e35SMiguel Boton 
414d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
424d022e35SMiguel Boton static int reboot_cpu = -1;
434d022e35SMiguel Boton #endif
444d022e35SMiguel Boton 
45d176720dSEduardo Habkost /* This is set if we need to go through the 'emergency' path.
46d176720dSEduardo Habkost  * When machine_emergency_restart() is called, we may be on
47d176720dSEduardo Habkost  * an inconsistent state and won't be able to do a clean cleanup
48d176720dSEduardo Habkost  */
49d176720dSEduardo Habkost static int reboot_emergency;
50d176720dSEduardo Habkost 
5114d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
5214d7ca5cSH. Peter Anvin bool port_cf9_safe = false;
5314d7ca5cSH. Peter Anvin 
5414d7ca5cSH. Peter Anvin /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
554d022e35SMiguel Boton    warm   Don't set the cold reboot flag
564d022e35SMiguel Boton    cold   Set the cold reboot flag
574d022e35SMiguel Boton    bios   Reboot by jumping through the BIOS (only for X86_32)
584d022e35SMiguel Boton    smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
594d022e35SMiguel Boton    triple Force a triple fault (init)
604d022e35SMiguel Boton    kbd    Use the keyboard controller. cold reset (default)
614d022e35SMiguel Boton    acpi   Use the RESET_REG in the FADT
624d022e35SMiguel Boton    efi    Use efi reset_system runtime service
6314d7ca5cSH. Peter Anvin    pci    Use the so-called "PCI reset register", CF9
644d022e35SMiguel Boton    force  Avoid anything that could hang.
654d022e35SMiguel Boton  */
664d022e35SMiguel Boton static int __init reboot_setup(char *str)
674d022e35SMiguel Boton {
684d022e35SMiguel Boton 	for (;;) {
694d022e35SMiguel Boton 		switch (*str) {
704d022e35SMiguel Boton 		case 'w':
714d022e35SMiguel Boton 			reboot_mode = 0x1234;
724d022e35SMiguel Boton 			break;
734d022e35SMiguel Boton 
744d022e35SMiguel Boton 		case 'c':
754d022e35SMiguel Boton 			reboot_mode = 0;
764d022e35SMiguel Boton 			break;
774d022e35SMiguel Boton 
784d022e35SMiguel Boton #ifdef CONFIG_X86_32
794d022e35SMiguel Boton #ifdef CONFIG_SMP
804d022e35SMiguel Boton 		case 's':
814d022e35SMiguel Boton 			if (isdigit(*(str+1))) {
824d022e35SMiguel Boton 				reboot_cpu = (int) (*(str+1) - '0');
834d022e35SMiguel Boton 				if (isdigit(*(str+2)))
844d022e35SMiguel Boton 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
854d022e35SMiguel Boton 			}
864d022e35SMiguel Boton 				/* we will leave sorting out the final value
874d022e35SMiguel Boton 				   when we are ready to reboot, since we might not
88f6e9456cSRobert Richter 				   have detected BSP APIC ID or smp_num_cpu */
894d022e35SMiguel Boton 			break;
904d022e35SMiguel Boton #endif /* CONFIG_SMP */
914d022e35SMiguel Boton 
924d022e35SMiguel Boton 		case 'b':
934d022e35SMiguel Boton #endif
944d022e35SMiguel Boton 		case 'a':
954d022e35SMiguel Boton 		case 'k':
964d022e35SMiguel Boton 		case 't':
974d022e35SMiguel Boton 		case 'e':
9814d7ca5cSH. Peter Anvin 		case 'p':
994d022e35SMiguel Boton 			reboot_type = *str;
1004d022e35SMiguel Boton 			break;
1014d022e35SMiguel Boton 
1024d022e35SMiguel Boton 		case 'f':
1034d022e35SMiguel Boton 			reboot_force = 1;
1044d022e35SMiguel Boton 			break;
1054d022e35SMiguel Boton 		}
1064d022e35SMiguel Boton 
1074d022e35SMiguel Boton 		str = strchr(str, ',');
1084d022e35SMiguel Boton 		if (str)
1094d022e35SMiguel Boton 			str++;
1104d022e35SMiguel Boton 		else
1114d022e35SMiguel Boton 			break;
1124d022e35SMiguel Boton 	}
1134d022e35SMiguel Boton 	return 1;
1144d022e35SMiguel Boton }
1154d022e35SMiguel Boton 
1164d022e35SMiguel Boton __setup("reboot=", reboot_setup);
1174d022e35SMiguel Boton 
1184d022e35SMiguel Boton 
1194d022e35SMiguel Boton #ifdef CONFIG_X86_32
1204d022e35SMiguel Boton /*
1214d022e35SMiguel Boton  * Reboot options and system auto-detection code provided by
1224d022e35SMiguel Boton  * Dell Inc. so their systems "just work". :-)
1234d022e35SMiguel Boton  */
1244d022e35SMiguel Boton 
1254d022e35SMiguel Boton /*
1264d022e35SMiguel Boton  * Some machines require the "reboot=b"  commandline option,
1274d022e35SMiguel Boton  * this quirk makes that automatic.
1284d022e35SMiguel Boton  */
1294d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d)
1304d022e35SMiguel Boton {
1314d022e35SMiguel Boton 	if (reboot_type != BOOT_BIOS) {
1324d022e35SMiguel Boton 		reboot_type = BOOT_BIOS;
1334d022e35SMiguel Boton 		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
1344d022e35SMiguel Boton 	}
1354d022e35SMiguel Boton 	return 0;
1364d022e35SMiguel Boton }
1374d022e35SMiguel Boton 
1384d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = {
1394d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell E520's */
1404d022e35SMiguel Boton 		.callback = set_bios_reboot,
1414d022e35SMiguel Boton 		.ident = "Dell E520",
1424d022e35SMiguel Boton 		.matches = {
1434d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1444d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
1454d022e35SMiguel Boton 		},
1464d022e35SMiguel Boton 	},
1474d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 1300's */
1484d022e35SMiguel Boton 		.callback = set_bios_reboot,
1494d022e35SMiguel Boton 		.ident = "Dell PowerEdge 1300",
1504d022e35SMiguel Boton 		.matches = {
1514d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1524d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
1534d022e35SMiguel Boton 		},
1544d022e35SMiguel Boton 	},
1554d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 300's */
1564d022e35SMiguel Boton 		.callback = set_bios_reboot,
1574d022e35SMiguel Boton 		.ident = "Dell PowerEdge 300",
1584d022e35SMiguel Boton 		.matches = {
1594d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1604d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
1614d022e35SMiguel Boton 		},
1624d022e35SMiguel Boton 	},
1634d022e35SMiguel Boton 	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
1644d022e35SMiguel Boton 		.callback = set_bios_reboot,
1654d022e35SMiguel Boton 		.ident = "Dell OptiPlex 745",
1664d022e35SMiguel Boton 		.matches = {
1674d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1684d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
1694d022e35SMiguel Boton 		},
1704d022e35SMiguel Boton 	},
171fc115bf1SColeman Kane 	{       /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
172fc115bf1SColeman Kane 		.callback = set_bios_reboot,
173fc115bf1SColeman Kane 		.ident = "Dell OptiPlex 745",
174fc115bf1SColeman Kane 		.matches = {
175fc115bf1SColeman Kane 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
176fc115bf1SColeman Kane 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
177fc115bf1SColeman Kane 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
178fc115bf1SColeman Kane 		},
179fc115bf1SColeman Kane 	},
180fc1c8925SHeinz-Ado Arnolds 	{       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
181fc1c8925SHeinz-Ado Arnolds 		.callback = set_bios_reboot,
182fc1c8925SHeinz-Ado Arnolds 		.ident = "Dell OptiPlex 745",
183fc1c8925SHeinz-Ado Arnolds 		.matches = {
184fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
185fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
186fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
187fc1c8925SHeinz-Ado Arnolds 		},
188fc1c8925SHeinz-Ado Arnolds 	},
189093bac15SSteve Conklin 	{   /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
190093bac15SSteve Conklin 		.callback = set_bios_reboot,
191093bac15SSteve Conklin 		.ident = "Dell OptiPlex 330",
192093bac15SSteve Conklin 		.matches = {
193093bac15SSteve Conklin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
194093bac15SSteve Conklin 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
195093bac15SSteve Conklin 			DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
196093bac15SSteve Conklin 		},
197093bac15SSteve Conklin 	},
1984a4aca64SJean Delvare 	{   /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
1994a4aca64SJean Delvare 		.callback = set_bios_reboot,
2004a4aca64SJean Delvare 		.ident = "Dell OptiPlex 360",
2014a4aca64SJean Delvare 		.matches = {
2024a4aca64SJean Delvare 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2034a4aca64SJean Delvare 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
2044a4aca64SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
2054a4aca64SJean Delvare 		},
2064a4aca64SJean Delvare 	},
20735ea63d7SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
20835ea63d7SLeann Ogasawara 		.callback = set_bios_reboot,
20935ea63d7SLeann Ogasawara 		.ident = "Dell OptiPlex 760",
21035ea63d7SLeann Ogasawara 		.matches = {
21135ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
21235ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
21335ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
21435ea63d7SLeann Ogasawara 		},
21535ea63d7SLeann Ogasawara 	},
2164d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 2400's */
2174d022e35SMiguel Boton 		.callback = set_bios_reboot,
2184d022e35SMiguel Boton 		.ident = "Dell PowerEdge 2400",
2194d022e35SMiguel Boton 		.matches = {
2204d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2214d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
2224d022e35SMiguel Boton 		},
2234d022e35SMiguel Boton 	},
224fab3b58dSIngo Molnar 	{	/* Handle problems with rebooting on Dell T5400's */
225fab3b58dSIngo Molnar 		.callback = set_bios_reboot,
226fab3b58dSIngo Molnar 		.ident = "Dell Precision T5400",
227fab3b58dSIngo Molnar 		.matches = {
228fab3b58dSIngo Molnar 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
229fab3b58dSIngo Molnar 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
230fab3b58dSIngo Molnar 		},
231fab3b58dSIngo Molnar 	},
232890ffedcSThomas Backlund 	{	/* Handle problems with rebooting on Dell T7400's */
233890ffedcSThomas Backlund 		.callback = set_bios_reboot,
234890ffedcSThomas Backlund 		.ident = "Dell Precision T7400",
235890ffedcSThomas Backlund 		.matches = {
236890ffedcSThomas Backlund 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
237890ffedcSThomas Backlund 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
238890ffedcSThomas Backlund 		},
239890ffedcSThomas Backlund 	},
2404d022e35SMiguel Boton 	{	/* Handle problems with rebooting on HP laptops */
2414d022e35SMiguel Boton 		.callback = set_bios_reboot,
2424d022e35SMiguel Boton 		.ident = "HP Compaq Laptop",
2434d022e35SMiguel Boton 		.matches = {
2444d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2454d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
2464d022e35SMiguel Boton 		},
2474d022e35SMiguel Boton 	},
248dd4124a8SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell XPS710 */
249dd4124a8SLeann Ogasawara 		.callback = set_bios_reboot,
250dd4124a8SLeann Ogasawara 		.ident = "Dell XPS710",
251dd4124a8SLeann Ogasawara 		.matches = {
252dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
253dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
254dd4124a8SLeann Ogasawara 		},
255dd4124a8SLeann Ogasawara 	},
256c5da9a2bSAlan Cox 	{	/* Handle problems with rebooting on Dell DXP061 */
257c5da9a2bSAlan Cox 		.callback = set_bios_reboot,
258c5da9a2bSAlan Cox 		.ident = "Dell DXP061",
259c5da9a2bSAlan Cox 		.matches = {
260c5da9a2bSAlan Cox 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
261c5da9a2bSAlan Cox 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
262c5da9a2bSAlan Cox 		},
263c5da9a2bSAlan Cox 	},
26488dff493SZhang Rui 	{	/* Handle problems with rebooting on Sony VGN-Z540N */
26588dff493SZhang Rui 		.callback = set_bios_reboot,
26688dff493SZhang Rui 		.ident = "Sony VGN-Z540N",
26788dff493SZhang Rui 		.matches = {
26888dff493SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
26988dff493SZhang Rui 			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
27088dff493SZhang Rui 		},
27188dff493SZhang Rui 	},
27277f32dfdSDenis Turischev 	{	/* Handle problems with rebooting on CompuLab SBC-FITPC2 */
27377f32dfdSDenis Turischev 		.callback = set_bios_reboot,
27477f32dfdSDenis Turischev 		.ident = "CompuLab SBC-FITPC2",
27577f32dfdSDenis Turischev 		.matches = {
27677f32dfdSDenis Turischev 			DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
27777f32dfdSDenis Turischev 			DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
27877f32dfdSDenis Turischev 		},
27977f32dfdSDenis Turischev 	},
2804832dddaSLeann Ogasawara 	{       /* Handle problems with rebooting on ASUS P4S800 */
2814832dddaSLeann Ogasawara 		.callback = set_bios_reboot,
2824832dddaSLeann Ogasawara 		.ident = "ASUS P4S800",
2834832dddaSLeann Ogasawara 		.matches = {
2844832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
2854832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
2864832dddaSLeann Ogasawara 		},
2874832dddaSLeann Ogasawara 	},
2884d022e35SMiguel Boton 	{ }
2894d022e35SMiguel Boton };
2904d022e35SMiguel Boton 
2914d022e35SMiguel Boton static int __init reboot_init(void)
2924d022e35SMiguel Boton {
2934d022e35SMiguel Boton 	dmi_check_system(reboot_dmi_table);
2944d022e35SMiguel Boton 	return 0;
2954d022e35SMiguel Boton }
2964d022e35SMiguel Boton core_initcall(reboot_init);
2974d022e35SMiguel Boton 
2984d022e35SMiguel Boton /* The following code and data reboots the machine by switching to real
2994d022e35SMiguel Boton    mode and jumping to the BIOS reset entry point, as if the CPU has
3004d022e35SMiguel Boton    really been reset.  The previous version asked the keyboard
3014d022e35SMiguel Boton    controller to pulse the CPU reset line, which is more thorough, but
3024d022e35SMiguel Boton    doesn't work with at least one type of 486 motherboard.  It is easy
3034d022e35SMiguel Boton    to stop this code working; hence the copious comments. */
304ebdd561aSJan Beulich static const unsigned long long
3054d022e35SMiguel Boton real_mode_gdt_entries [3] =
3064d022e35SMiguel Boton {
3074d022e35SMiguel Boton 	0x0000000000000000ULL,	/* Null descriptor */
308ebdd561aSJan Beulich 	0x00009b000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
309ebdd561aSJan Beulich 	0x000093000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
3104d022e35SMiguel Boton };
3114d022e35SMiguel Boton 
312ebdd561aSJan Beulich static const struct desc_ptr
3134d022e35SMiguel Boton real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
3144d022e35SMiguel Boton real_mode_idt = { 0x3ff, 0 };
3154d022e35SMiguel Boton 
3164d022e35SMiguel Boton /* This is 16-bit protected mode code to disable paging and the cache,
3174d022e35SMiguel Boton    switch to real mode and jump to the BIOS reset code.
3184d022e35SMiguel Boton 
3194d022e35SMiguel Boton    The instruction that switches to real mode by writing to CR0 must be
3204d022e35SMiguel Boton    followed immediately by a far jump instruction, which set CS to a
3214d022e35SMiguel Boton    valid value for real mode, and flushes the prefetch queue to avoid
3224d022e35SMiguel Boton    running instructions that have already been decoded in protected
3234d022e35SMiguel Boton    mode.
3244d022e35SMiguel Boton 
3254d022e35SMiguel Boton    Clears all the flags except ET, especially PG (paging), PE
3264d022e35SMiguel Boton    (protected-mode enable) and TS (task switch for coprocessor state
3274d022e35SMiguel Boton    save).  Flushes the TLB after paging has been disabled.  Sets CD and
3284d022e35SMiguel Boton    NW, to disable the cache on a 486, and invalidates the cache.  This
3294d022e35SMiguel Boton    is more like the state of a 486 after reset.  I don't know if
3304d022e35SMiguel Boton    something else should be done for other chips.
3314d022e35SMiguel Boton 
3324d022e35SMiguel Boton    More could be done here to set up the registers as if a CPU reset had
3334d022e35SMiguel Boton    occurred; hopefully real BIOSs don't assume much. */
334ebdd561aSJan Beulich static const unsigned char real_mode_switch [] =
3354d022e35SMiguel Boton {
3364d022e35SMiguel Boton 	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
3374d022e35SMiguel Boton 	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
3384d022e35SMiguel Boton 	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
3394d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
3404d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
3414d022e35SMiguel Boton 	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
3424d022e35SMiguel Boton 	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
3434d022e35SMiguel Boton 	0x74, 0x02,				/*    jz    f                */
3444d022e35SMiguel Boton 	0x0f, 0x09,				/*    wbinvd                 */
3454d022e35SMiguel Boton 	0x24, 0x10,				/* f: andb  $0x10,al         */
3464d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
3474d022e35SMiguel Boton };
348ebdd561aSJan Beulich static const unsigned char jump_to_bios [] =
3494d022e35SMiguel Boton {
3504d022e35SMiguel Boton 	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
3514d022e35SMiguel Boton };
3524d022e35SMiguel Boton 
3534d022e35SMiguel Boton /*
3544d022e35SMiguel Boton  * Switch to real mode and then execute the code
3554d022e35SMiguel Boton  * specified by the code and length parameters.
3564d022e35SMiguel Boton  * We assume that length will aways be less that 100!
3574d022e35SMiguel Boton  */
358ebdd561aSJan Beulich void machine_real_restart(const unsigned char *code, int length)
3594d022e35SMiguel Boton {
3604d022e35SMiguel Boton 	local_irq_disable();
3614d022e35SMiguel Boton 
3624d022e35SMiguel Boton 	/* Write zero to CMOS register number 0x0f, which the BIOS POST
3634d022e35SMiguel Boton 	   routine will recognize as telling it to do a proper reboot.  (Well
3644d022e35SMiguel Boton 	   that's what this book in front of me says -- it may only apply to
3654d022e35SMiguel Boton 	   the Phoenix BIOS though, it's not clear).  At the same time,
3664d022e35SMiguel Boton 	   disable NMIs by setting the top bit in the CMOS address register,
3674d022e35SMiguel Boton 	   as we're about to do peculiar things to the CPU.  I'm not sure if
3684d022e35SMiguel Boton 	   `outb_p' is needed instead of just `outb'.  Use it to be on the
3694d022e35SMiguel Boton 	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
3704d022e35SMiguel Boton 	 */
3714d022e35SMiguel Boton 	spin_lock(&rtc_lock);
3724d022e35SMiguel Boton 	CMOS_WRITE(0x00, 0x8f);
3734d022e35SMiguel Boton 	spin_unlock(&rtc_lock);
3744d022e35SMiguel Boton 
3754d022e35SMiguel Boton 	/*
376b40827faSBorislav Petkov 	 * Switch back to the initial page table.
3774d022e35SMiguel Boton 	 */
378b40827faSBorislav Petkov 	load_cr3(initial_page_table);
3794d022e35SMiguel Boton 
3804d022e35SMiguel Boton 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
3814d022e35SMiguel Boton 	   this on booting to tell it to "Bypass memory test (also warm
3824d022e35SMiguel Boton 	   boot)".  This seems like a fairly standard thing that gets set by
3834d022e35SMiguel Boton 	   REBOOT.COM programs, and the previous reset routine did this
3844d022e35SMiguel Boton 	   too. */
3854d022e35SMiguel Boton 	*((unsigned short *)0x472) = reboot_mode;
3864d022e35SMiguel Boton 
3874d022e35SMiguel Boton 	/* For the switch to real mode, copy some code to low memory.  It has
3884d022e35SMiguel Boton 	   to be in the first 64k because it is running in 16-bit mode, and it
3894d022e35SMiguel Boton 	   has to have the same physical and virtual address, because it turns
3904d022e35SMiguel Boton 	   off paging.  Copy it near the end of the first page, out of the way
3914d022e35SMiguel Boton 	   of BIOS variables. */
3924d022e35SMiguel Boton 	memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100),
3934d022e35SMiguel Boton 		real_mode_switch, sizeof (real_mode_switch));
3944d022e35SMiguel Boton 	memcpy((void *)(0x1000 - 100), code, length);
3954d022e35SMiguel Boton 
3964d022e35SMiguel Boton 	/* Set up the IDT for real mode. */
3974d022e35SMiguel Boton 	load_idt(&real_mode_idt);
3984d022e35SMiguel Boton 
3994d022e35SMiguel Boton 	/* Set up a GDT from which we can load segment descriptors for real
4004d022e35SMiguel Boton 	   mode.  The GDT is not used in real mode; it is just needed here to
4014d022e35SMiguel Boton 	   prepare the descriptors. */
4024d022e35SMiguel Boton 	load_gdt(&real_mode_gdt);
4034d022e35SMiguel Boton 
4044d022e35SMiguel Boton 	/* Load the data segment registers, and thus the descriptors ready for
4054d022e35SMiguel Boton 	   real mode.  The base address of each segment is 0x100, 16 times the
4064d022e35SMiguel Boton 	   selector value being loaded here.  This is so that the segment
4074d022e35SMiguel Boton 	   registers don't have to be reloaded after switching to real mode:
4084d022e35SMiguel Boton 	   the values are consistent for real mode operation already. */
4094d022e35SMiguel Boton 	__asm__ __volatile__ ("movl $0x0010,%%eax\n"
4104d022e35SMiguel Boton 				"\tmovl %%eax,%%ds\n"
4114d022e35SMiguel Boton 				"\tmovl %%eax,%%es\n"
4124d022e35SMiguel Boton 				"\tmovl %%eax,%%fs\n"
4134d022e35SMiguel Boton 				"\tmovl %%eax,%%gs\n"
4144d022e35SMiguel Boton 				"\tmovl %%eax,%%ss" : : : "eax");
4154d022e35SMiguel Boton 
4164d022e35SMiguel Boton 	/* Jump to the 16-bit code that we copied earlier.  It disables paging
4174d022e35SMiguel Boton 	   and the cache, switches to real mode, and jumps to the BIOS reset
4184d022e35SMiguel Boton 	   entry point. */
4194d022e35SMiguel Boton 	__asm__ __volatile__ ("ljmp $0x0008,%0"
4204d022e35SMiguel Boton 				:
4214d022e35SMiguel Boton 				: "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100)));
4224d022e35SMiguel Boton }
4234d022e35SMiguel Boton #ifdef CONFIG_APM_MODULE
4244d022e35SMiguel Boton EXPORT_SYMBOL(machine_real_restart);
4254d022e35SMiguel Boton #endif
4264d022e35SMiguel Boton 
4274d022e35SMiguel Boton #endif /* CONFIG_X86_32 */
4284d022e35SMiguel Boton 
4296c6c51e4SPaul Mackerras /*
430498cdbfbSOzan Çağlayan  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
4316c6c51e4SPaul Mackerras  */
4326c6c51e4SPaul Mackerras static int __init set_pci_reboot(const struct dmi_system_id *d)
4336c6c51e4SPaul Mackerras {
4346c6c51e4SPaul Mackerras 	if (reboot_type != BOOT_CF9) {
4356c6c51e4SPaul Mackerras 		reboot_type = BOOT_CF9;
4366c6c51e4SPaul Mackerras 		printk(KERN_INFO "%s series board detected. "
4376c6c51e4SPaul Mackerras 		       "Selecting PCI-method for reboots.\n", d->ident);
4386c6c51e4SPaul Mackerras 	}
4396c6c51e4SPaul Mackerras 	return 0;
4406c6c51e4SPaul Mackerras }
4416c6c51e4SPaul Mackerras 
4426c6c51e4SPaul Mackerras static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
4433e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBook5 */
4446c6c51e4SPaul Mackerras 		.callback = set_pci_reboot,
4453e03bbeaSShunichi Fuji 		.ident = "Apple MacBook5",
4466c6c51e4SPaul Mackerras 		.matches = {
4476c6c51e4SPaul Mackerras 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4483e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
4496c6c51e4SPaul Mackerras 		},
4506c6c51e4SPaul Mackerras 	},
4513e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBookPro5 */
452498cdbfbSOzan Çağlayan 		.callback = set_pci_reboot,
4533e03bbeaSShunichi Fuji 		.ident = "Apple MacBookPro5",
454498cdbfbSOzan Çağlayan 		.matches = {
455498cdbfbSOzan Çağlayan 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4563e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
457498cdbfbSOzan Çağlayan 		},
458498cdbfbSOzan Çağlayan 	},
45905154752SGottfried Haider 	{	/* Handle problems with rebooting on Apple Macmini3,1 */
46005154752SGottfried Haider 		.callback = set_pci_reboot,
46105154752SGottfried Haider 		.ident = "Apple Macmini3,1",
46205154752SGottfried Haider 		.matches = {
46305154752SGottfried Haider 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
46405154752SGottfried Haider 			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
46505154752SGottfried Haider 		},
46605154752SGottfried Haider 	},
4670a832320SJustin P. Mattock 	{	/* Handle problems with rebooting on the iMac9,1. */
4680a832320SJustin P. Mattock 		.callback = set_pci_reboot,
4690a832320SJustin P. Mattock 		.ident = "Apple iMac9,1",
4700a832320SJustin P. Mattock 		.matches = {
4710a832320SJustin P. Mattock 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4720a832320SJustin P. Mattock 			DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
4730a832320SJustin P. Mattock 		},
4740a832320SJustin P. Mattock 	},
4756c6c51e4SPaul Mackerras 	{ }
4766c6c51e4SPaul Mackerras };
4776c6c51e4SPaul Mackerras 
4786c6c51e4SPaul Mackerras static int __init pci_reboot_init(void)
4796c6c51e4SPaul Mackerras {
4806c6c51e4SPaul Mackerras 	dmi_check_system(pci_reboot_dmi_table);
4816c6c51e4SPaul Mackerras 	return 0;
4826c6c51e4SPaul Mackerras }
4836c6c51e4SPaul Mackerras core_initcall(pci_reboot_init);
4846c6c51e4SPaul Mackerras 
4854d022e35SMiguel Boton static inline void kb_wait(void)
4864d022e35SMiguel Boton {
4874d022e35SMiguel Boton 	int i;
4884d022e35SMiguel Boton 
489c84d6af8SAlan Cox 	for (i = 0; i < 0x10000; i++) {
490c84d6af8SAlan Cox 		if ((inb(0x64) & 0x02) == 0)
4914d022e35SMiguel Boton 			break;
492c84d6af8SAlan Cox 		udelay(2);
493c84d6af8SAlan Cox 	}
4944d022e35SMiguel Boton }
4954d022e35SMiguel Boton 
496d176720dSEduardo Habkost static void vmxoff_nmi(int cpu, struct die_args *args)
497d176720dSEduardo Habkost {
498d176720dSEduardo Habkost 	cpu_emergency_vmxoff();
499d176720dSEduardo Habkost }
500d176720dSEduardo Habkost 
501d176720dSEduardo Habkost /* Use NMIs as IPIs to tell all CPUs to disable virtualization
502d176720dSEduardo Habkost  */
503d176720dSEduardo Habkost static void emergency_vmx_disable_all(void)
504d176720dSEduardo Habkost {
505d176720dSEduardo Habkost 	/* Just make sure we won't change CPUs while doing this */
506d176720dSEduardo Habkost 	local_irq_disable();
507d176720dSEduardo Habkost 
508d176720dSEduardo Habkost 	/* We need to disable VMX on all CPUs before rebooting, otherwise
509d176720dSEduardo Habkost 	 * we risk hanging up the machine, because the CPU ignore INIT
510d176720dSEduardo Habkost 	 * signals when VMX is enabled.
511d176720dSEduardo Habkost 	 *
512d176720dSEduardo Habkost 	 * We can't take any locks and we may be on an inconsistent
513d176720dSEduardo Habkost 	 * state, so we use NMIs as IPIs to tell the other CPUs to disable
514d176720dSEduardo Habkost 	 * VMX and halt.
515d176720dSEduardo Habkost 	 *
516d176720dSEduardo Habkost 	 * For safety, we will avoid running the nmi_shootdown_cpus()
517d176720dSEduardo Habkost 	 * stuff unnecessarily, but we don't have a way to check
518d176720dSEduardo Habkost 	 * if other CPUs have VMX enabled. So we will call it only if the
519d176720dSEduardo Habkost 	 * CPU we are running on has VMX enabled.
520d176720dSEduardo Habkost 	 *
521d176720dSEduardo Habkost 	 * We will miss cases where VMX is not enabled on all CPUs. This
522d176720dSEduardo Habkost 	 * shouldn't do much harm because KVM always enable VMX on all
523d176720dSEduardo Habkost 	 * CPUs anyway. But we can miss it on the small window where KVM
524d176720dSEduardo Habkost 	 * is still enabling VMX.
525d176720dSEduardo Habkost 	 */
526d176720dSEduardo Habkost 	if (cpu_has_vmx() && cpu_vmx_enabled()) {
527d176720dSEduardo Habkost 		/* Disable VMX on this CPU.
528d176720dSEduardo Habkost 		 */
529d176720dSEduardo Habkost 		cpu_vmxoff();
530d176720dSEduardo Habkost 
531d176720dSEduardo Habkost 		/* Halt and disable VMX on the other CPUs */
532d176720dSEduardo Habkost 		nmi_shootdown_cpus(vmxoff_nmi);
533d176720dSEduardo Habkost 
534d176720dSEduardo Habkost 	}
535d176720dSEduardo Habkost }
536d176720dSEduardo Habkost 
537d176720dSEduardo Habkost 
5387432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void)
5397432d149SIngo Molnar {
5407432d149SIngo Molnar }
5417432d149SIngo Molnar 
542416e2d63SJody Belka static void native_machine_emergency_restart(void)
5434d022e35SMiguel Boton {
5444d022e35SMiguel Boton 	int i;
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 			}
5664d022e35SMiguel Boton 
5674d022e35SMiguel Boton 		case BOOT_TRIPLE:
568ebdd561aSJan Beulich 			load_idt(&no_idt);
5694d022e35SMiguel Boton 			__asm__ __volatile__("int3");
5704d022e35SMiguel Boton 
5714d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5724d022e35SMiguel Boton 			break;
5734d022e35SMiguel Boton 
5744d022e35SMiguel Boton #ifdef CONFIG_X86_32
5754d022e35SMiguel Boton 		case BOOT_BIOS:
5764d022e35SMiguel Boton 			machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
5774d022e35SMiguel Boton 
5784d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5794d022e35SMiguel Boton 			break;
5804d022e35SMiguel Boton #endif
5814d022e35SMiguel Boton 
5824d022e35SMiguel Boton 		case BOOT_ACPI:
5834d022e35SMiguel Boton 			acpi_reboot();
5844d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5854d022e35SMiguel Boton 			break;
5864d022e35SMiguel Boton 
5874d022e35SMiguel Boton 		case BOOT_EFI:
5884d022e35SMiguel Boton 			if (efi_enabled)
58914d7ca5cSH. Peter Anvin 				efi.reset_system(reboot_mode ?
59014d7ca5cSH. Peter Anvin 						 EFI_RESET_WARM :
59114d7ca5cSH. Peter Anvin 						 EFI_RESET_COLD,
5924d022e35SMiguel Boton 						 EFI_SUCCESS, 0, NULL);
593b47b9288SH. Peter Anvin 			reboot_type = BOOT_KBD;
59414d7ca5cSH. Peter Anvin 			break;
5954d022e35SMiguel Boton 
59614d7ca5cSH. Peter Anvin 		case BOOT_CF9:
59714d7ca5cSH. Peter Anvin 			port_cf9_safe = true;
59814d7ca5cSH. Peter Anvin 			/* fall through */
59914d7ca5cSH. Peter Anvin 
60014d7ca5cSH. Peter Anvin 		case BOOT_CF9_COND:
60114d7ca5cSH. Peter Anvin 			if (port_cf9_safe) {
60214d7ca5cSH. Peter Anvin 				u8 cf9 = inb(0xcf9) & ~6;
60314d7ca5cSH. Peter Anvin 				outb(cf9|2, 0xcf9); /* Request hard reset */
60414d7ca5cSH. Peter Anvin 				udelay(50);
60514d7ca5cSH. Peter Anvin 				outb(cf9|6, 0xcf9); /* Actually do the reset */
60614d7ca5cSH. Peter Anvin 				udelay(50);
60714d7ca5cSH. Peter Anvin 			}
6084d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6094d022e35SMiguel Boton 			break;
6104d022e35SMiguel Boton 		}
6114d022e35SMiguel Boton 	}
6124d022e35SMiguel Boton }
6134d022e35SMiguel Boton 
6143c62c625SGlauber Costa void native_machine_shutdown(void)
6154d022e35SMiguel Boton {
6164d022e35SMiguel Boton 	/* Stop the cpus and apics */
6174d022e35SMiguel Boton #ifdef CONFIG_SMP
6184d022e35SMiguel Boton 
6194d022e35SMiguel Boton 	/* The boot cpu is always logical cpu 0 */
62065c01184SMike Travis 	int reboot_cpu_id = 0;
6214d022e35SMiguel Boton 
6224d022e35SMiguel Boton #ifdef CONFIG_X86_32
6234d022e35SMiguel Boton 	/* See if there has been given a command line override */
6249628937dSMike Travis 	if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
6250bc3cc03SMike Travis 		cpu_online(reboot_cpu))
6264d022e35SMiguel Boton 		reboot_cpu_id = reboot_cpu;
6274d022e35SMiguel Boton #endif
6284d022e35SMiguel Boton 
6294d022e35SMiguel Boton 	/* Make certain the cpu I'm about to reboot on is online */
6300bc3cc03SMike Travis 	if (!cpu_online(reboot_cpu_id))
6314d022e35SMiguel Boton 		reboot_cpu_id = smp_processor_id();
6324d022e35SMiguel Boton 
6334d022e35SMiguel Boton 	/* Make certain I only run on the appropriate processor */
6349628937dSMike Travis 	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
6354d022e35SMiguel Boton 
6364d022e35SMiguel Boton 	/* O.K Now that I'm on the appropriate processor,
6374d022e35SMiguel Boton 	 * stop all of the others.
6384d022e35SMiguel Boton 	 */
63976fac077SAlok Kataria 	stop_other_cpus();
6404d022e35SMiguel Boton #endif
6414d022e35SMiguel Boton 
6424d022e35SMiguel Boton 	lapic_shutdown();
6434d022e35SMiguel Boton 
6444d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC
6454d022e35SMiguel Boton 	disable_IO_APIC();
6464d022e35SMiguel Boton #endif
6474d022e35SMiguel Boton 
6484d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER
6494d022e35SMiguel Boton 	hpet_disable();
6504d022e35SMiguel Boton #endif
6514d022e35SMiguel Boton 
6524d022e35SMiguel Boton #ifdef CONFIG_X86_64
653338bac52SFUJITA Tomonori 	x86_platform.iommu_shutdown();
6544d022e35SMiguel Boton #endif
6554d022e35SMiguel Boton }
6564d022e35SMiguel Boton 
657d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency)
658d176720dSEduardo Habkost {
659d176720dSEduardo Habkost 	reboot_emergency = emergency;
660d176720dSEduardo Habkost 	machine_ops.emergency_restart();
661d176720dSEduardo Habkost }
662d176720dSEduardo Habkost 
663416e2d63SJody Belka static void native_machine_restart(char *__unused)
6644d022e35SMiguel Boton {
6654d022e35SMiguel Boton 	printk("machine restart\n");
6664d022e35SMiguel Boton 
6674d022e35SMiguel Boton 	if (!reboot_force)
6684d022e35SMiguel Boton 		machine_shutdown();
669d176720dSEduardo Habkost 	__machine_emergency_restart(0);
6704d022e35SMiguel Boton }
6714d022e35SMiguel Boton 
672416e2d63SJody Belka static void native_machine_halt(void)
6734d022e35SMiguel Boton {
674d3ec5caeSIvan Vecera 	/* stop other cpus and apics */
675d3ec5caeSIvan Vecera 	machine_shutdown();
676d3ec5caeSIvan Vecera 
677840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
678840c2bafSJoseph Cihula 
679d3ec5caeSIvan Vecera 	/* stop this cpu */
680d3ec5caeSIvan Vecera 	stop_this_cpu(NULL);
6814d022e35SMiguel Boton }
6824d022e35SMiguel Boton 
683416e2d63SJody Belka static void native_machine_power_off(void)
6844d022e35SMiguel Boton {
6854d022e35SMiguel Boton 	if (pm_power_off) {
6864d022e35SMiguel Boton 		if (!reboot_force)
6874d022e35SMiguel Boton 			machine_shutdown();
6884d022e35SMiguel Boton 		pm_power_off();
6894d022e35SMiguel Boton 	}
690840c2bafSJoseph Cihula 	/* a fallback in case there is no PM info available */
691840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
6924d022e35SMiguel Boton }
6934d022e35SMiguel Boton 
6944d022e35SMiguel Boton struct machine_ops machine_ops = {
695416e2d63SJody Belka 	.power_off = native_machine_power_off,
696416e2d63SJody Belka 	.shutdown = native_machine_shutdown,
697416e2d63SJody Belka 	.emergency_restart = native_machine_emergency_restart,
698416e2d63SJody Belka 	.restart = native_machine_restart,
699ed23dc6fSGlauber Costa 	.halt = native_machine_halt,
700ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
701ed23dc6fSGlauber Costa 	.crash_shutdown = native_machine_crash_shutdown,
702ed23dc6fSGlauber Costa #endif
7034d022e35SMiguel Boton };
704416e2d63SJody Belka 
705416e2d63SJody Belka void machine_power_off(void)
706416e2d63SJody Belka {
707416e2d63SJody Belka 	machine_ops.power_off();
708416e2d63SJody Belka }
709416e2d63SJody Belka 
710416e2d63SJody Belka void machine_shutdown(void)
711416e2d63SJody Belka {
712416e2d63SJody Belka 	machine_ops.shutdown();
713416e2d63SJody Belka }
714416e2d63SJody Belka 
715416e2d63SJody Belka void machine_emergency_restart(void)
716416e2d63SJody Belka {
717d176720dSEduardo Habkost 	__machine_emergency_restart(1);
718416e2d63SJody Belka }
719416e2d63SJody Belka 
720416e2d63SJody Belka void machine_restart(char *cmd)
721416e2d63SJody Belka {
722416e2d63SJody Belka 	machine_ops.restart(cmd);
723416e2d63SJody Belka }
724416e2d63SJody Belka 
725416e2d63SJody Belka void machine_halt(void)
726416e2d63SJody Belka {
727416e2d63SJody Belka 	machine_ops.halt();
728416e2d63SJody Belka }
729416e2d63SJody Belka 
730ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
731ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs)
732ed23dc6fSGlauber Costa {
733ed23dc6fSGlauber Costa 	machine_ops.crash_shutdown(regs);
734ed23dc6fSGlauber Costa }
735ed23dc6fSGlauber Costa #endif
7362ddded21SEduardo Habkost 
7372ddded21SEduardo Habkost 
738bb8dd270SEduardo Habkost #if defined(CONFIG_SMP)
7392ddded21SEduardo Habkost 
7402ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */
7412ddded21SEduardo Habkost static int crashing_cpu;
7422ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback;
7432ddded21SEduardo Habkost 
7442ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi;
7452ddded21SEduardo Habkost 
7462ddded21SEduardo Habkost static int crash_nmi_callback(struct notifier_block *self,
7472ddded21SEduardo Habkost 			unsigned long val, void *data)
7482ddded21SEduardo Habkost {
7492ddded21SEduardo Habkost 	int cpu;
7502ddded21SEduardo Habkost 
751*c410b830SDon Zickus 	if (val != DIE_NMI)
7522ddded21SEduardo Habkost 		return NOTIFY_OK;
7532ddded21SEduardo Habkost 
7542ddded21SEduardo Habkost 	cpu = raw_smp_processor_id();
7552ddded21SEduardo Habkost 
7562ddded21SEduardo Habkost 	/* Don't do anything if this handler is invoked on crashing cpu.
7572ddded21SEduardo Habkost 	 * Otherwise, system will completely hang. Crashing cpu can get
7582ddded21SEduardo Habkost 	 * an NMI if system was initially booted with nmi_watchdog parameter.
7592ddded21SEduardo Habkost 	 */
7602ddded21SEduardo Habkost 	if (cpu == crashing_cpu)
7612ddded21SEduardo Habkost 		return NOTIFY_STOP;
7622ddded21SEduardo Habkost 	local_irq_disable();
7632ddded21SEduardo Habkost 
7642ddded21SEduardo Habkost 	shootdown_callback(cpu, (struct die_args *)data);
7652ddded21SEduardo Habkost 
7662ddded21SEduardo Habkost 	atomic_dec(&waiting_for_crash_ipi);
7672ddded21SEduardo Habkost 	/* Assume hlt works */
7682ddded21SEduardo Habkost 	halt();
7692ddded21SEduardo Habkost 	for (;;)
7702ddded21SEduardo Habkost 		cpu_relax();
7712ddded21SEduardo Habkost 
7722ddded21SEduardo Habkost 	return 1;
7732ddded21SEduardo Habkost }
7742ddded21SEduardo Habkost 
7752ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void)
7762ddded21SEduardo Habkost {
777dac5f412SIngo Molnar 	apic->send_IPI_allbutself(NMI_VECTOR);
7782ddded21SEduardo Habkost }
7792ddded21SEduardo Habkost 
7802ddded21SEduardo Habkost static struct notifier_block crash_nmi_nb = {
7812ddded21SEduardo Habkost 	.notifier_call = crash_nmi_callback,
782166d7514SDon Zickus 	/* we want to be the first one called */
783166d7514SDon Zickus 	.priority = NMI_LOCAL_HIGH_PRIOR+1,
7842ddded21SEduardo Habkost };
7852ddded21SEduardo Habkost 
786bb8dd270SEduardo Habkost /* Halt all other CPUs, calling the specified function on each of them
787bb8dd270SEduardo Habkost  *
788bb8dd270SEduardo Habkost  * This function can be used to halt all other CPUs on crash
789bb8dd270SEduardo Habkost  * or emergency reboot time. The function passed as parameter
790bb8dd270SEduardo Habkost  * will be called inside a NMI handler on all CPUs.
791bb8dd270SEduardo Habkost  */
7922ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
7932ddded21SEduardo Habkost {
7942ddded21SEduardo Habkost 	unsigned long msecs;
795c415b3dcSEduardo Habkost 	local_irq_disable();
7962ddded21SEduardo Habkost 
7972ddded21SEduardo Habkost 	/* Make a note of crashing cpu. Will be used in NMI callback.*/
7982ddded21SEduardo Habkost 	crashing_cpu = safe_smp_processor_id();
7992ddded21SEduardo Habkost 
8002ddded21SEduardo Habkost 	shootdown_callback = callback;
8012ddded21SEduardo Habkost 
8022ddded21SEduardo Habkost 	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
8032ddded21SEduardo Habkost 	/* Would it be better to replace the trap vector here? */
8042ddded21SEduardo Habkost 	if (register_die_notifier(&crash_nmi_nb))
8052ddded21SEduardo Habkost 		return;		/* return what? */
8062ddded21SEduardo Habkost 	/* Ensure the new callback function is set before sending
8072ddded21SEduardo Habkost 	 * out the NMI
8082ddded21SEduardo Habkost 	 */
8092ddded21SEduardo Habkost 	wmb();
8102ddded21SEduardo Habkost 
8112ddded21SEduardo Habkost 	smp_send_nmi_allbutself();
8122ddded21SEduardo Habkost 
8132ddded21SEduardo Habkost 	msecs = 1000; /* Wait at most a second for the other cpus to stop */
8142ddded21SEduardo Habkost 	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
8152ddded21SEduardo Habkost 		mdelay(1);
8162ddded21SEduardo Habkost 		msecs--;
8172ddded21SEduardo Habkost 	}
8182ddded21SEduardo Habkost 
8192ddded21SEduardo Habkost 	/* Leave the nmi callback set */
8202ddded21SEduardo Habkost }
821bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */
822bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
823bb8dd270SEduardo Habkost {
824bb8dd270SEduardo Habkost 	/* No other CPUs to shoot down */
825bb8dd270SEduardo Habkost }
8262ddded21SEduardo Habkost #endif
827