xref: /linux/arch/x86/kernel/reboot.c (revision edf2b1394611fef7806d4af72179dc3ac101f275)
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 = {};
39*edf2b139SRobin Holt static enum reboot_mode reboot_mode;
40660e34ceSMatthew Garrett enum reboot_type reboot_type = BOOT_ACPI;
414d022e35SMiguel Boton int reboot_force;
424d022e35SMiguel Boton 
43144d102bSMichael D Labriola /*
44144d102bSMichael D Labriola  * This variable is used privately to keep track of whether or not
455955633eSMichael D Labriola  * reboot_type is still set to its default value (i.e., reboot= hasn't
465955633eSMichael D Labriola  * been set on the command line).  This is needed so that we can
475955633eSMichael D Labriola  * suppress DMI scanning for reboot quirks.  Without it, it's
485955633eSMichael D Labriola  * impossible to override a faulty reboot quirk without recompiling.
495955633eSMichael D Labriola  */
505955633eSMichael D Labriola static int reboot_default = 1;
515955633eSMichael D Labriola 
5265051397SH. Peter Anvin #ifdef CONFIG_SMP
534d022e35SMiguel Boton static int reboot_cpu = -1;
544d022e35SMiguel Boton #endif
554d022e35SMiguel Boton 
56144d102bSMichael D Labriola /*
57144d102bSMichael D Labriola  * This is set if we need to go through the 'emergency' path.
58d176720dSEduardo Habkost  * When machine_emergency_restart() is called, we may be on
59d176720dSEduardo Habkost  * an inconsistent state and won't be able to do a clean cleanup
60d176720dSEduardo Habkost  */
61d176720dSEduardo Habkost static int reboot_emergency;
62d176720dSEduardo Habkost 
6314d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
6414d7ca5cSH. Peter Anvin bool port_cf9_safe = false;
6514d7ca5cSH. Peter Anvin 
66144d102bSMichael D Labriola /*
67144d102bSMichael D Labriola  * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
68144d102bSMichael D Labriola  * warm   Don't set the cold reboot flag
69144d102bSMichael D Labriola  * cold   Set the cold reboot flag
7065051397SH. Peter Anvin  * bios   Reboot by jumping through the BIOS
7165051397SH. Peter Anvin  * smp    Reboot by executing reset on BSP or other CPU
72144d102bSMichael D Labriola  * triple Force a triple fault (init)
73144d102bSMichael D Labriola  * kbd    Use the keyboard controller. cold reset (default)
74144d102bSMichael D Labriola  * acpi   Use the RESET_REG in the FADT
75144d102bSMichael D Labriola  * efi    Use efi reset_system runtime service
76144d102bSMichael D Labriola  * pci    Use the so-called "PCI reset register", CF9
77144d102bSMichael D Labriola  * force  Avoid anything that could hang.
784d022e35SMiguel Boton  */
794d022e35SMiguel Boton static int __init reboot_setup(char *str)
804d022e35SMiguel Boton {
814d022e35SMiguel Boton 	for (;;) {
82144d102bSMichael D Labriola 		/*
83144d102bSMichael D Labriola 		 * Having anything passed on the command line via
845955633eSMichael D Labriola 		 * reboot= will cause us to disable DMI checking
855955633eSMichael D Labriola 		 * below.
865955633eSMichael D Labriola 		 */
875955633eSMichael D Labriola 		reboot_default = 0;
885955633eSMichael D Labriola 
894d022e35SMiguel Boton 		switch (*str) {
904d022e35SMiguel Boton 		case 'w':
91*edf2b139SRobin Holt 			reboot_mode = REBOOT_WARM;
924d022e35SMiguel Boton 			break;
934d022e35SMiguel Boton 
944d022e35SMiguel Boton 		case 'c':
95*edf2b139SRobin Holt 			reboot_mode = REBOOT_COLD;
964d022e35SMiguel Boton 			break;
974d022e35SMiguel Boton 
984d022e35SMiguel Boton #ifdef CONFIG_SMP
994d022e35SMiguel Boton 		case 's':
1004d022e35SMiguel Boton 			if (isdigit(*(str+1))) {
1014d022e35SMiguel Boton 				reboot_cpu = (int) (*(str+1) - '0');
1024d022e35SMiguel Boton 				if (isdigit(*(str+2)))
1034d022e35SMiguel Boton 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
1044d022e35SMiguel Boton 			}
105144d102bSMichael D Labriola 			/*
106144d102bSMichael D Labriola 			 * We will leave sorting out the final value
107144d102bSMichael D Labriola 			 * when we are ready to reboot, since we might not
108144d102bSMichael D Labriola 			 * have detected BSP APIC ID or smp_num_cpu
109144d102bSMichael D Labriola 			 */
1104d022e35SMiguel Boton 			break;
1114d022e35SMiguel Boton #endif /* CONFIG_SMP */
1124d022e35SMiguel Boton 
1134d022e35SMiguel Boton 		case 'b':
1144d022e35SMiguel Boton 		case 'a':
1154d022e35SMiguel Boton 		case 'k':
1164d022e35SMiguel Boton 		case 't':
1174d022e35SMiguel Boton 		case 'e':
11814d7ca5cSH. Peter Anvin 		case 'p':
1194d022e35SMiguel Boton 			reboot_type = *str;
1204d022e35SMiguel Boton 			break;
1214d022e35SMiguel Boton 
1224d022e35SMiguel Boton 		case 'f':
1234d022e35SMiguel Boton 			reboot_force = 1;
1244d022e35SMiguel Boton 			break;
1254d022e35SMiguel Boton 		}
1264d022e35SMiguel Boton 
1274d022e35SMiguel Boton 		str = strchr(str, ',');
1284d022e35SMiguel Boton 		if (str)
1294d022e35SMiguel Boton 			str++;
1304d022e35SMiguel Boton 		else
1314d022e35SMiguel Boton 			break;
1324d022e35SMiguel Boton 	}
1334d022e35SMiguel Boton 	return 1;
1344d022e35SMiguel Boton }
1354d022e35SMiguel Boton 
1364d022e35SMiguel Boton __setup("reboot=", reboot_setup);
1374d022e35SMiguel Boton 
1384d022e35SMiguel Boton 
1394d022e35SMiguel Boton /*
1404d022e35SMiguel Boton  * Reboot options and system auto-detection code provided by
1414d022e35SMiguel Boton  * Dell Inc. so their systems "just work". :-)
1424d022e35SMiguel Boton  */
1434d022e35SMiguel Boton 
1444d022e35SMiguel Boton /*
1451ef03890SPeter Chubb  * Some machines require the "reboot=b" or "reboot=k"  commandline options,
1464d022e35SMiguel Boton  * this quirk makes that automatic.
1474d022e35SMiguel Boton  */
1484d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d)
1494d022e35SMiguel Boton {
1504d022e35SMiguel Boton 	if (reboot_type != BOOT_BIOS) {
1514d022e35SMiguel Boton 		reboot_type = BOOT_BIOS;
152c767a54bSJoe Perches 		pr_info("%s series board detected. Selecting %s-method for reboots.\n",
153c767a54bSJoe Perches 			"BIOS", d->ident);
1544d022e35SMiguel Boton 	}
1554d022e35SMiguel Boton 	return 0;
1564d022e35SMiguel Boton }
1574d022e35SMiguel Boton 
15865051397SH. Peter Anvin void __noreturn machine_real_restart(unsigned int type)
15957b16594SMichael D Labriola {
16057b16594SMichael D Labriola 	local_irq_disable();
16157b16594SMichael D Labriola 
162144d102bSMichael D Labriola 	/*
163144d102bSMichael D Labriola 	 * Write zero to CMOS register number 0x0f, which the BIOS POST
164144d102bSMichael D Labriola 	 * routine will recognize as telling it to do a proper reboot.  (Well
165144d102bSMichael D Labriola 	 * that's what this book in front of me says -- it may only apply to
166144d102bSMichael D Labriola 	 * the Phoenix BIOS though, it's not clear).  At the same time,
167144d102bSMichael D Labriola 	 * disable NMIs by setting the top bit in the CMOS address register,
168144d102bSMichael D Labriola 	 * as we're about to do peculiar things to the CPU.  I'm not sure if
169144d102bSMichael D Labriola 	 * `outb_p' is needed instead of just `outb'.  Use it to be on the
170144d102bSMichael D Labriola 	 * safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
17157b16594SMichael D Labriola 	 */
17257b16594SMichael D Labriola 	spin_lock(&rtc_lock);
17357b16594SMichael D Labriola 	CMOS_WRITE(0x00, 0x8f);
17457b16594SMichael D Labriola 	spin_unlock(&rtc_lock);
17557b16594SMichael D Labriola 
17657b16594SMichael D Labriola 	/*
17757b16594SMichael D Labriola 	 * Switch back to the initial page table.
17857b16594SMichael D Labriola 	 */
17965051397SH. Peter Anvin #ifdef CONFIG_X86_32
18057b16594SMichael D Labriola 	load_cr3(initial_page_table);
18165051397SH. Peter Anvin #else
18265051397SH. Peter Anvin 	write_cr3(real_mode_header->trampoline_pgd);
18365051397SH. Peter Anvin #endif
18457b16594SMichael D Labriola 
18557b16594SMichael D Labriola 	/* Jump to the identity-mapped low memory code */
18665051397SH. Peter Anvin #ifdef CONFIG_X86_32
18765051397SH. Peter Anvin 	asm volatile("jmpl *%0" : :
18865051397SH. Peter Anvin 		     "rm" (real_mode_header->machine_real_restart_asm),
18965051397SH. Peter Anvin 		     "a" (type));
19065051397SH. Peter Anvin #else
19165051397SH. Peter Anvin 	asm volatile("ljmpl *%0" : :
19265051397SH. Peter Anvin 		     "m" (real_mode_header->machine_real_restart_asm),
19365051397SH. Peter Anvin 		     "D" (type));
19465051397SH. Peter Anvin #endif
19565051397SH. Peter Anvin 	unreachable();
19657b16594SMichael D Labriola }
19757b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE
19857b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart);
19957b16594SMichael D Labriola #endif
20057b16594SMichael D Labriola 
20157b16594SMichael D Labriola /*
20257b16594SMichael D Labriola  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
20357b16594SMichael D Labriola  */
20457b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d)
20557b16594SMichael D Labriola {
20657b16594SMichael D Labriola 	if (reboot_type != BOOT_CF9) {
20757b16594SMichael D Labriola 		reboot_type = BOOT_CF9;
208c767a54bSJoe Perches 		pr_info("%s series board detected. Selecting %s-method for reboots.\n",
209c767a54bSJoe Perches 			"PCI", d->ident);
21057b16594SMichael D Labriola 	}
21157b16594SMichael D Labriola 	return 0;
21257b16594SMichael D Labriola }
21357b16594SMichael D Labriola 
2141ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d)
2151ef03890SPeter Chubb {
2161ef03890SPeter Chubb 	if (reboot_type != BOOT_KBD) {
2171ef03890SPeter Chubb 		reboot_type = BOOT_KBD;
218c767a54bSJoe Perches 		pr_info("%s series board detected. Selecting %s-method for reboot.\n",
219c767a54bSJoe Perches 			"KBD", d->ident);
2201ef03890SPeter Chubb 	}
2211ef03890SPeter Chubb 	return 0;
2221ef03890SPeter Chubb }
2231ef03890SPeter Chubb 
224144d102bSMichael D Labriola /*
22565051397SH. Peter Anvin  * This is a single dmi_table handling all reboot quirks.
22657b16594SMichael D Labriola  */
2274d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = {
2284d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell E520's */
2294d022e35SMiguel Boton 		.callback = set_bios_reboot,
2304d022e35SMiguel Boton 		.ident = "Dell E520",
2314d022e35SMiguel Boton 		.matches = {
2324d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2334d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
2344d022e35SMiguel Boton 		},
2354d022e35SMiguel Boton 	},
2364d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 1300's */
2374d022e35SMiguel Boton 		.callback = set_bios_reboot,
2384d022e35SMiguel Boton 		.ident = "Dell PowerEdge 1300",
2394d022e35SMiguel Boton 		.matches = {
2404d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2414d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
2424d022e35SMiguel Boton 		},
2434d022e35SMiguel Boton 	},
2444d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 300's */
2454d022e35SMiguel Boton 		.callback = set_bios_reboot,
2464d022e35SMiguel Boton 		.ident = "Dell PowerEdge 300",
2474d022e35SMiguel Boton 		.matches = {
2484d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2494d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
2504d022e35SMiguel Boton 		},
2514d022e35SMiguel Boton 	},
2524d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell Optiplex 745's SFF */
2534d022e35SMiguel Boton 		.callback = set_bios_reboot,
2544d022e35SMiguel Boton 		.ident = "Dell OptiPlex 745",
2554d022e35SMiguel Boton 		.matches = {
2564d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2574d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
2584d022e35SMiguel Boton 		},
2594d022e35SMiguel Boton 	},
260fc115bf1SColeman Kane 	{	/* Handle problems with rebooting on Dell Optiplex 745's DFF */
261fc115bf1SColeman Kane 		.callback = set_bios_reboot,
262fc115bf1SColeman Kane 		.ident = "Dell OptiPlex 745",
263fc115bf1SColeman Kane 		.matches = {
264fc115bf1SColeman Kane 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
265fc115bf1SColeman Kane 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
266fc115bf1SColeman Kane 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
267fc115bf1SColeman Kane 		},
268fc115bf1SColeman Kane 	},
269fc1c8925SHeinz-Ado Arnolds 	{	/* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
270fc1c8925SHeinz-Ado Arnolds 		.callback = set_bios_reboot,
271fc1c8925SHeinz-Ado Arnolds 		.ident = "Dell OptiPlex 745",
272fc1c8925SHeinz-Ado Arnolds 		.matches = {
273fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
274fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
275fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
276fc1c8925SHeinz-Ado Arnolds 		},
277fc1c8925SHeinz-Ado Arnolds 	},
278093bac15SSteve Conklin 	{	/* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
279093bac15SSteve Conklin 		.callback = set_bios_reboot,
280093bac15SSteve Conklin 		.ident = "Dell OptiPlex 330",
281093bac15SSteve Conklin 		.matches = {
282093bac15SSteve Conklin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
283093bac15SSteve Conklin 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
284093bac15SSteve Conklin 			DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
285093bac15SSteve Conklin 		},
286093bac15SSteve Conklin 	},
2874a4aca64SJean Delvare 	{	/* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
2884a4aca64SJean Delvare 		.callback = set_bios_reboot,
2894a4aca64SJean Delvare 		.ident = "Dell OptiPlex 360",
2904a4aca64SJean Delvare 		.matches = {
2914a4aca64SJean Delvare 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2924a4aca64SJean Delvare 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
2934a4aca64SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
2944a4aca64SJean Delvare 		},
2954a4aca64SJean Delvare 	},
29635ea63d7SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
29735ea63d7SLeann Ogasawara 		.callback = set_bios_reboot,
29835ea63d7SLeann Ogasawara 		.ident = "Dell OptiPlex 760",
29935ea63d7SLeann Ogasawara 		.matches = {
30035ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
30135ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
30235ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
30335ea63d7SLeann Ogasawara 		},
30435ea63d7SLeann Ogasawara 	},
3054d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 2400's */
3064d022e35SMiguel Boton 		.callback = set_bios_reboot,
3074d022e35SMiguel Boton 		.ident = "Dell PowerEdge 2400",
3084d022e35SMiguel Boton 		.matches = {
3094d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
3104d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
3114d022e35SMiguel Boton 		},
3124d022e35SMiguel Boton 	},
313fab3b58dSIngo Molnar 	{	/* Handle problems with rebooting on Dell T5400's */
314fab3b58dSIngo Molnar 		.callback = set_bios_reboot,
315fab3b58dSIngo Molnar 		.ident = "Dell Precision T5400",
316fab3b58dSIngo Molnar 		.matches = {
317fab3b58dSIngo Molnar 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
318fab3b58dSIngo Molnar 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
319fab3b58dSIngo Molnar 		},
320fab3b58dSIngo Molnar 	},
321890ffedcSThomas Backlund 	{	/* Handle problems with rebooting on Dell T7400's */
322890ffedcSThomas Backlund 		.callback = set_bios_reboot,
323890ffedcSThomas Backlund 		.ident = "Dell Precision T7400",
324890ffedcSThomas Backlund 		.matches = {
325890ffedcSThomas Backlund 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
326890ffedcSThomas Backlund 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
327890ffedcSThomas Backlund 		},
328890ffedcSThomas Backlund 	},
3294d022e35SMiguel Boton 	{	/* Handle problems with rebooting on HP laptops */
3304d022e35SMiguel Boton 		.callback = set_bios_reboot,
3314d022e35SMiguel Boton 		.ident = "HP Compaq Laptop",
3324d022e35SMiguel Boton 		.matches = {
3334d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
3344d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
3354d022e35SMiguel Boton 		},
3364d022e35SMiguel Boton 	},
337dd4124a8SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell XPS710 */
338dd4124a8SLeann Ogasawara 		.callback = set_bios_reboot,
339dd4124a8SLeann Ogasawara 		.ident = "Dell XPS710",
340dd4124a8SLeann Ogasawara 		.matches = {
341dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
342dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
343dd4124a8SLeann Ogasawara 		},
344dd4124a8SLeann Ogasawara 	},
345c5da9a2bSAlan Cox 	{	/* Handle problems with rebooting on Dell DXP061 */
346c5da9a2bSAlan Cox 		.callback = set_bios_reboot,
347c5da9a2bSAlan Cox 		.ident = "Dell DXP061",
348c5da9a2bSAlan Cox 		.matches = {
349c5da9a2bSAlan Cox 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
350c5da9a2bSAlan Cox 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
351c5da9a2bSAlan Cox 		},
352c5da9a2bSAlan Cox 	},
35388dff493SZhang Rui 	{	/* Handle problems with rebooting on Sony VGN-Z540N */
35488dff493SZhang Rui 		.callback = set_bios_reboot,
35588dff493SZhang Rui 		.ident = "Sony VGN-Z540N",
35688dff493SZhang Rui 		.matches = {
35788dff493SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
35888dff493SZhang Rui 			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
35988dff493SZhang Rui 		},
36088dff493SZhang Rui 	},
3614832dddaSLeann Ogasawara 	{	/* Handle problems with rebooting on ASUS P4S800 */
3624832dddaSLeann Ogasawara 		.callback = set_bios_reboot,
3634832dddaSLeann Ogasawara 		.ident = "ASUS P4S800",
3644832dddaSLeann Ogasawara 		.matches = {
3654832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
3664832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
3674832dddaSLeann Ogasawara 		},
3684832dddaSLeann Ogasawara 	},
36957b16594SMichael D Labriola 
370b49c78d4SPeter Chubb 	{	/* Handle reboot issue on Acer Aspire one */
3711ef03890SPeter Chubb 		.callback = set_kbd_reboot,
372b49c78d4SPeter Chubb 		.ident = "Acer Aspire One A110",
373b49c78d4SPeter Chubb 		.matches = {
374b49c78d4SPeter Chubb 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
375b49c78d4SPeter Chubb 			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
376b49c78d4SPeter Chubb 		},
377b49c78d4SPeter Chubb 	},
3783e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBook5 */
3796c6c51e4SPaul Mackerras 		.callback = set_pci_reboot,
3803e03bbeaSShunichi Fuji 		.ident = "Apple MacBook5",
3816c6c51e4SPaul Mackerras 		.matches = {
3826c6c51e4SPaul Mackerras 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
3833e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
3846c6c51e4SPaul Mackerras 		},
3856c6c51e4SPaul Mackerras 	},
3863e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBookPro5 */
387498cdbfbSOzan Çağlayan 		.callback = set_pci_reboot,
3883e03bbeaSShunichi Fuji 		.ident = "Apple MacBookPro5",
389498cdbfbSOzan Çağlayan 		.matches = {
390498cdbfbSOzan Çağlayan 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
3913e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
392498cdbfbSOzan Çağlayan 		},
393498cdbfbSOzan Çağlayan 	},
39405154752SGottfried Haider 	{	/* Handle problems with rebooting on Apple Macmini3,1 */
39505154752SGottfried Haider 		.callback = set_pci_reboot,
39605154752SGottfried Haider 		.ident = "Apple Macmini3,1",
39705154752SGottfried Haider 		.matches = {
39805154752SGottfried Haider 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
39905154752SGottfried Haider 			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
40005154752SGottfried Haider 		},
40105154752SGottfried Haider 	},
4020a832320SJustin P. Mattock 	{	/* Handle problems with rebooting on the iMac9,1. */
4030a832320SJustin P. Mattock 		.callback = set_pci_reboot,
4040a832320SJustin P. Mattock 		.ident = "Apple iMac9,1",
4050a832320SJustin P. Mattock 		.matches = {
4060a832320SJustin P. Mattock 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4070a832320SJustin P. Mattock 			DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
4080a832320SJustin P. Mattock 		},
4090a832320SJustin P. Mattock 	},
4103628c3f5SMaxime Ripard 	{	/* Handle problems with rebooting on the Latitude E6320. */
4113628c3f5SMaxime Ripard 		.callback = set_pci_reboot,
4123628c3f5SMaxime Ripard 		.ident = "Dell Latitude E6320",
4133628c3f5SMaxime Ripard 		.matches = {
4143628c3f5SMaxime Ripard 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4153628c3f5SMaxime Ripard 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
4163628c3f5SMaxime Ripard 		},
4173628c3f5SMaxime Ripard 	},
418b7798d28SDaniel J Blueman 	{	/* Handle problems with rebooting on the Latitude E5420. */
419b7798d28SDaniel J Blueman 		.callback = set_pci_reboot,
420b7798d28SDaniel J Blueman 		.ident = "Dell Latitude E5420",
421b7798d28SDaniel J Blueman 		.matches = {
422b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
423b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
424b7798d28SDaniel J Blueman 		},
425b7798d28SDaniel J Blueman 	},
426a536877eSH. Peter Anvin 	{	/* Handle problems with rebooting on the Latitude E6420. */
427a536877eSH. Peter Anvin 		.callback = set_pci_reboot,
428a536877eSH. Peter Anvin 		.ident = "Dell Latitude E6420",
429a536877eSH. Peter Anvin 		.matches = {
430a536877eSH. Peter Anvin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
431a536877eSH. Peter Anvin 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
432a536877eSH. Peter Anvin 		},
433a536877eSH. Peter Anvin 	},
4346be30bb7SRafael J. Wysocki 	{	/* Handle problems with rebooting on the OptiPlex 990. */
4356be30bb7SRafael J. Wysocki 		.callback = set_pci_reboot,
4366be30bb7SRafael J. Wysocki 		.ident = "Dell OptiPlex 990",
4376be30bb7SRafael J. Wysocki 		.matches = {
4386be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4396be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
4406be30bb7SRafael J. Wysocki 		},
4416be30bb7SRafael J. Wysocki 	},
44276eb9a30SZhang Rui 	{	/* Handle problems with rebooting on the Precision M6600. */
44376eb9a30SZhang Rui 		.callback = set_pci_reboot,
44476eb9a30SZhang Rui 		.ident = "Dell OptiPlex 990",
44576eb9a30SZhang Rui 		.matches = {
44676eb9a30SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
44776eb9a30SZhang Rui 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
44876eb9a30SZhang Rui 		},
44976eb9a30SZhang Rui 	},
4506c6c51e4SPaul Mackerras 	{ }
4516c6c51e4SPaul Mackerras };
4526c6c51e4SPaul Mackerras 
45357b16594SMichael D Labriola static int __init reboot_init(void)
4546c6c51e4SPaul Mackerras {
455144d102bSMichael D Labriola 	/*
456144d102bSMichael D Labriola 	 * Only do the DMI check if reboot_type hasn't been overridden
4575955633eSMichael D Labriola 	 * on the command line
4585955633eSMichael D Labriola 	 */
459144d102bSMichael D Labriola 	if (reboot_default)
46057b16594SMichael D Labriola 		dmi_check_system(reboot_dmi_table);
4616c6c51e4SPaul Mackerras 	return 0;
4626c6c51e4SPaul Mackerras }
46357b16594SMichael D Labriola core_initcall(reboot_init);
4646c6c51e4SPaul Mackerras 
4654d022e35SMiguel Boton static inline void kb_wait(void)
4664d022e35SMiguel Boton {
4674d022e35SMiguel Boton 	int i;
4684d022e35SMiguel Boton 
469c84d6af8SAlan Cox 	for (i = 0; i < 0x10000; i++) {
470c84d6af8SAlan Cox 		if ((inb(0x64) & 0x02) == 0)
4714d022e35SMiguel Boton 			break;
472c84d6af8SAlan Cox 		udelay(2);
473c84d6af8SAlan Cox 	}
4744d022e35SMiguel Boton }
4754d022e35SMiguel Boton 
4769c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs)
477d176720dSEduardo Habkost {
478d176720dSEduardo Habkost 	cpu_emergency_vmxoff();
479d176720dSEduardo Habkost }
480d176720dSEduardo Habkost 
481144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */
482d176720dSEduardo Habkost static void emergency_vmx_disable_all(void)
483d176720dSEduardo Habkost {
484d176720dSEduardo Habkost 	/* Just make sure we won't change CPUs while doing this */
485d176720dSEduardo Habkost 	local_irq_disable();
486d176720dSEduardo Habkost 
487144d102bSMichael D Labriola 	/*
488144d102bSMichael D Labriola 	 * We need to disable VMX on all CPUs before rebooting, otherwise
489d176720dSEduardo Habkost 	 * we risk hanging up the machine, because the CPU ignore INIT
490d176720dSEduardo Habkost 	 * signals when VMX is enabled.
491d176720dSEduardo Habkost 	 *
492d176720dSEduardo Habkost 	 * We can't take any locks and we may be on an inconsistent
493d176720dSEduardo Habkost 	 * state, so we use NMIs as IPIs to tell the other CPUs to disable
494d176720dSEduardo Habkost 	 * VMX and halt.
495d176720dSEduardo Habkost 	 *
496d176720dSEduardo Habkost 	 * For safety, we will avoid running the nmi_shootdown_cpus()
497d176720dSEduardo Habkost 	 * stuff unnecessarily, but we don't have a way to check
498d176720dSEduardo Habkost 	 * if other CPUs have VMX enabled. So we will call it only if the
499d176720dSEduardo Habkost 	 * CPU we are running on has VMX enabled.
500d176720dSEduardo Habkost 	 *
501d176720dSEduardo Habkost 	 * We will miss cases where VMX is not enabled on all CPUs. This
502d176720dSEduardo Habkost 	 * shouldn't do much harm because KVM always enable VMX on all
503d176720dSEduardo Habkost 	 * CPUs anyway. But we can miss it on the small window where KVM
504d176720dSEduardo Habkost 	 * is still enabling VMX.
505d176720dSEduardo Habkost 	 */
506d176720dSEduardo Habkost 	if (cpu_has_vmx() && cpu_vmx_enabled()) {
507144d102bSMichael D Labriola 		/* Disable VMX on this CPU. */
508d176720dSEduardo Habkost 		cpu_vmxoff();
509d176720dSEduardo Habkost 
510d176720dSEduardo Habkost 		/* Halt and disable VMX on the other CPUs */
511d176720dSEduardo Habkost 		nmi_shootdown_cpus(vmxoff_nmi);
512d176720dSEduardo Habkost 
513d176720dSEduardo Habkost 	}
514d176720dSEduardo Habkost }
515d176720dSEduardo Habkost 
516d176720dSEduardo Habkost 
5177432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void)
5187432d149SIngo Molnar {
5197432d149SIngo Molnar }
5207432d149SIngo Molnar 
521660e34ceSMatthew Garrett /*
522660e34ceSMatthew Garrett  * Windows compatible x86 hardware expects the following on reboot:
523660e34ceSMatthew Garrett  *
524660e34ceSMatthew Garrett  * 1) If the FADT has the ACPI reboot register flag set, try it
525660e34ceSMatthew Garrett  * 2) If still alive, write to the keyboard controller
526660e34ceSMatthew Garrett  * 3) If still alive, write to the ACPI reboot register again
527660e34ceSMatthew Garrett  * 4) If still alive, write to the keyboard controller again
528660e34ceSMatthew Garrett  *
529660e34ceSMatthew Garrett  * If the machine is still alive at this stage, it gives up. We default to
530660e34ceSMatthew Garrett  * following the same pattern, except that if we're still alive after (4) we'll
531660e34ceSMatthew Garrett  * try to force a triple fault and then cycle between hitting the keyboard
532660e34ceSMatthew Garrett  * controller and doing that
533660e34ceSMatthew Garrett  */
534416e2d63SJody Belka static void native_machine_emergency_restart(void)
5354d022e35SMiguel Boton {
5364d022e35SMiguel Boton 	int i;
537660e34ceSMatthew Garrett 	int attempt = 0;
538660e34ceSMatthew Garrett 	int orig_reboot_type = reboot_type;
539*edf2b139SRobin Holt 	unsigned short mode;
5404d022e35SMiguel Boton 
541d176720dSEduardo Habkost 	if (reboot_emergency)
542d176720dSEduardo Habkost 		emergency_vmx_disable_all();
543d176720dSEduardo Habkost 
544840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_REBOOT);
545840c2bafSJoseph Cihula 
5464d022e35SMiguel Boton 	/* Tell the BIOS if we want cold or warm reboot */
547*edf2b139SRobin Holt 	mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0;
548*edf2b139SRobin Holt 	*((unsigned short *)__va(0x472)) = mode;
5494d022e35SMiguel Boton 
5504d022e35SMiguel Boton 	for (;;) {
5514d022e35SMiguel Boton 		/* Could also try the reset bit in the Hammer NB */
5524d022e35SMiguel Boton 		switch (reboot_type) {
5534d022e35SMiguel Boton 		case BOOT_KBD:
554144d102bSMichael D Labriola 			mach_reboot_fixups(); /* For board specific fixups */
5557432d149SIngo Molnar 
5564d022e35SMiguel Boton 			for (i = 0; i < 10; i++) {
5574d022e35SMiguel Boton 				kb_wait();
5584d022e35SMiguel Boton 				udelay(50);
559144d102bSMichael D Labriola 				outb(0xfe, 0x64); /* Pulse reset low */
5604d022e35SMiguel Boton 				udelay(50);
5614d022e35SMiguel Boton 			}
562660e34ceSMatthew Garrett 			if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
563660e34ceSMatthew Garrett 				attempt = 1;
564660e34ceSMatthew Garrett 				reboot_type = BOOT_ACPI;
565660e34ceSMatthew Garrett 			} else {
566660e34ceSMatthew Garrett 				reboot_type = BOOT_TRIPLE;
567660e34ceSMatthew Garrett 			}
568660e34ceSMatthew Garrett 			break;
5694d022e35SMiguel Boton 
5704d022e35SMiguel Boton 		case BOOT_TRIPLE:
571ebdd561aSJan Beulich 			load_idt(&no_idt);
5724d022e35SMiguel Boton 			__asm__ __volatile__("int3");
5734d022e35SMiguel Boton 
5744d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5754d022e35SMiguel Boton 			break;
5764d022e35SMiguel Boton 
5774d022e35SMiguel Boton 		case BOOT_BIOS:
5783d35ac34SH. Peter Anvin 			machine_real_restart(MRR_BIOS);
5794d022e35SMiguel Boton 
5804d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5814d022e35SMiguel Boton 			break;
5824d022e35SMiguel Boton 
5834d022e35SMiguel Boton 		case BOOT_ACPI:
5844d022e35SMiguel Boton 			acpi_reboot();
5854d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5864d022e35SMiguel Boton 			break;
5874d022e35SMiguel Boton 
5884d022e35SMiguel Boton 		case BOOT_EFI:
58983e68189SMatt Fleming 			if (efi_enabled(EFI_RUNTIME_SERVICES))
590*edf2b139SRobin Holt 				efi.reset_system(reboot_mode == REBOOT_WARM ?
59114d7ca5cSH. Peter Anvin 						 EFI_RESET_WARM :
59214d7ca5cSH. Peter Anvin 						 EFI_RESET_COLD,
5934d022e35SMiguel Boton 						 EFI_SUCCESS, 0, NULL);
594b47b9288SH. Peter Anvin 			reboot_type = BOOT_KBD;
59514d7ca5cSH. Peter Anvin 			break;
5964d022e35SMiguel Boton 
59714d7ca5cSH. Peter Anvin 		case BOOT_CF9:
59814d7ca5cSH. Peter Anvin 			port_cf9_safe = true;
599144d102bSMichael D Labriola 			/* Fall through */
60014d7ca5cSH. Peter Anvin 
60114d7ca5cSH. Peter Anvin 		case BOOT_CF9_COND:
60214d7ca5cSH. Peter Anvin 			if (port_cf9_safe) {
60314d7ca5cSH. Peter Anvin 				u8 cf9 = inb(0xcf9) & ~6;
60414d7ca5cSH. Peter Anvin 				outb(cf9|2, 0xcf9); /* Request hard reset */
60514d7ca5cSH. Peter Anvin 				udelay(50);
60614d7ca5cSH. Peter Anvin 				outb(cf9|6, 0xcf9); /* Actually do the reset */
60714d7ca5cSH. Peter Anvin 				udelay(50);
60814d7ca5cSH. Peter Anvin 			}
6094d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6104d022e35SMiguel Boton 			break;
6114d022e35SMiguel Boton 		}
6124d022e35SMiguel Boton 	}
6134d022e35SMiguel Boton }
6144d022e35SMiguel Boton 
6153c62c625SGlauber Costa void native_machine_shutdown(void)
6164d022e35SMiguel Boton {
6174d022e35SMiguel Boton 	/* Stop the cpus and apics */
6184d022e35SMiguel Boton #ifdef CONFIG_SMP
6194d022e35SMiguel Boton 
6204d022e35SMiguel Boton 	/* The boot cpu is always logical cpu 0 */
62165c01184SMike Travis 	int reboot_cpu_id = 0;
6224d022e35SMiguel Boton 
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 
6284d022e35SMiguel Boton 	/* Make certain the cpu I'm about to reboot on is online */
6290bc3cc03SMike Travis 	if (!cpu_online(reboot_cpu_id))
6304d022e35SMiguel Boton 		reboot_cpu_id = smp_processor_id();
6314d022e35SMiguel Boton 
6324d022e35SMiguel Boton 	/* Make certain I only run on the appropriate processor */
6339628937dSMike Travis 	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
6344d022e35SMiguel Boton 
635144d102bSMichael D Labriola 	/*
63655c844a4SFeng Tang 	 * O.K Now that I'm on the appropriate processor, stop all of the
63755c844a4SFeng Tang 	 * others. Also disable the local irq to not receive the per-cpu
63855c844a4SFeng Tang 	 * timer interrupt which may trigger scheduler's load balance.
6394d022e35SMiguel Boton 	 */
64055c844a4SFeng Tang 	local_irq_disable();
64176fac077SAlok Kataria 	stop_other_cpus();
6424d022e35SMiguel Boton #endif
6434d022e35SMiguel Boton 
6444d022e35SMiguel Boton 	lapic_shutdown();
6454d022e35SMiguel Boton 
6464d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC
6474d022e35SMiguel Boton 	disable_IO_APIC();
6484d022e35SMiguel Boton #endif
6494d022e35SMiguel Boton 
6504d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER
6514d022e35SMiguel Boton 	hpet_disable();
6524d022e35SMiguel Boton #endif
6534d022e35SMiguel Boton 
6544d022e35SMiguel Boton #ifdef CONFIG_X86_64
655338bac52SFUJITA Tomonori 	x86_platform.iommu_shutdown();
6564d022e35SMiguel Boton #endif
6574d022e35SMiguel Boton }
6584d022e35SMiguel Boton 
659d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency)
660d176720dSEduardo Habkost {
661d176720dSEduardo Habkost 	reboot_emergency = emergency;
662d176720dSEduardo Habkost 	machine_ops.emergency_restart();
663d176720dSEduardo Habkost }
664d176720dSEduardo Habkost 
665416e2d63SJody Belka static void native_machine_restart(char *__unused)
6664d022e35SMiguel Boton {
667c767a54bSJoe Perches 	pr_notice("machine restart\n");
6684d022e35SMiguel Boton 
6694d022e35SMiguel Boton 	if (!reboot_force)
6704d022e35SMiguel Boton 		machine_shutdown();
671d176720dSEduardo Habkost 	__machine_emergency_restart(0);
6724d022e35SMiguel Boton }
6734d022e35SMiguel Boton 
674416e2d63SJody Belka static void native_machine_halt(void)
6754d022e35SMiguel Boton {
676144d102bSMichael D Labriola 	/* Stop other cpus and apics */
677d3ec5caeSIvan Vecera 	machine_shutdown();
678d3ec5caeSIvan Vecera 
679840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
680840c2bafSJoseph Cihula 
681d3ec5caeSIvan Vecera 	stop_this_cpu(NULL);
6824d022e35SMiguel Boton }
6834d022e35SMiguel Boton 
684416e2d63SJody Belka static void native_machine_power_off(void)
6854d022e35SMiguel Boton {
6864d022e35SMiguel Boton 	if (pm_power_off) {
6874d022e35SMiguel Boton 		if (!reboot_force)
6884d022e35SMiguel Boton 			machine_shutdown();
6894d022e35SMiguel Boton 		pm_power_off();
6904d022e35SMiguel Boton 	}
691144d102bSMichael D Labriola 	/* A fallback in case there is no PM info available */
692840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
6934d022e35SMiguel Boton }
6944d022e35SMiguel Boton 
6954d022e35SMiguel Boton struct machine_ops machine_ops = {
696416e2d63SJody Belka 	.power_off = native_machine_power_off,
697416e2d63SJody Belka 	.shutdown = native_machine_shutdown,
698416e2d63SJody Belka 	.emergency_restart = native_machine_emergency_restart,
699416e2d63SJody Belka 	.restart = native_machine_restart,
700ed23dc6fSGlauber Costa 	.halt = native_machine_halt,
701ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
702ed23dc6fSGlauber Costa 	.crash_shutdown = native_machine_crash_shutdown,
703ed23dc6fSGlauber Costa #endif
7044d022e35SMiguel Boton };
705416e2d63SJody Belka 
706416e2d63SJody Belka void machine_power_off(void)
707416e2d63SJody Belka {
708416e2d63SJody Belka 	machine_ops.power_off();
709416e2d63SJody Belka }
710416e2d63SJody Belka 
711416e2d63SJody Belka void machine_shutdown(void)
712416e2d63SJody Belka {
713416e2d63SJody Belka 	machine_ops.shutdown();
714416e2d63SJody Belka }
715416e2d63SJody Belka 
716416e2d63SJody Belka void machine_emergency_restart(void)
717416e2d63SJody Belka {
718d176720dSEduardo Habkost 	__machine_emergency_restart(1);
719416e2d63SJody Belka }
720416e2d63SJody Belka 
721416e2d63SJody Belka void machine_restart(char *cmd)
722416e2d63SJody Belka {
723416e2d63SJody Belka 	machine_ops.restart(cmd);
724416e2d63SJody Belka }
725416e2d63SJody Belka 
726416e2d63SJody Belka void machine_halt(void)
727416e2d63SJody Belka {
728416e2d63SJody Belka 	machine_ops.halt();
729416e2d63SJody Belka }
730416e2d63SJody Belka 
731ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
732ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs)
733ed23dc6fSGlauber Costa {
734ed23dc6fSGlauber Costa 	machine_ops.crash_shutdown(regs);
735ed23dc6fSGlauber Costa }
736ed23dc6fSGlauber Costa #endif
7372ddded21SEduardo Habkost 
7382ddded21SEduardo Habkost 
739bb8dd270SEduardo Habkost #if defined(CONFIG_SMP)
7402ddded21SEduardo Habkost 
7412ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */
7422ddded21SEduardo Habkost static int crashing_cpu;
7432ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback;
7442ddded21SEduardo Habkost 
7452ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi;
7462ddded21SEduardo Habkost 
7479c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
7482ddded21SEduardo Habkost {
7492ddded21SEduardo Habkost 	int cpu;
7502ddded21SEduardo Habkost 
7512ddded21SEduardo Habkost 	cpu = raw_smp_processor_id();
7522ddded21SEduardo Habkost 
753144d102bSMichael D Labriola 	/*
754144d102bSMichael D Labriola 	 * Don't do anything if this handler is invoked on crashing cpu.
7552ddded21SEduardo Habkost 	 * Otherwise, system will completely hang. Crashing cpu can get
7562ddded21SEduardo Habkost 	 * an NMI if system was initially booted with nmi_watchdog parameter.
7572ddded21SEduardo Habkost 	 */
7582ddded21SEduardo Habkost 	if (cpu == crashing_cpu)
7599c48f1c6SDon Zickus 		return NMI_HANDLED;
7602ddded21SEduardo Habkost 	local_irq_disable();
7612ddded21SEduardo Habkost 
7629c48f1c6SDon Zickus 	shootdown_callback(cpu, regs);
7632ddded21SEduardo Habkost 
7642ddded21SEduardo Habkost 	atomic_dec(&waiting_for_crash_ipi);
7652ddded21SEduardo Habkost 	/* Assume hlt works */
7662ddded21SEduardo Habkost 	halt();
7672ddded21SEduardo Habkost 	for (;;)
7682ddded21SEduardo Habkost 		cpu_relax();
7692ddded21SEduardo Habkost 
7709c48f1c6SDon Zickus 	return NMI_HANDLED;
7712ddded21SEduardo Habkost }
7722ddded21SEduardo Habkost 
7732ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void)
7742ddded21SEduardo Habkost {
775dac5f412SIngo Molnar 	apic->send_IPI_allbutself(NMI_VECTOR);
7762ddded21SEduardo Habkost }
7772ddded21SEduardo Habkost 
778144d102bSMichael D Labriola /*
779144d102bSMichael D Labriola  * Halt all other CPUs, calling the specified function on each of them
780bb8dd270SEduardo Habkost  *
781bb8dd270SEduardo Habkost  * This function can be used to halt all other CPUs on crash
782bb8dd270SEduardo Habkost  * or emergency reboot time. The function passed as parameter
783bb8dd270SEduardo Habkost  * will be called inside a NMI handler on all CPUs.
784bb8dd270SEduardo Habkost  */
7852ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
7862ddded21SEduardo Habkost {
7872ddded21SEduardo Habkost 	unsigned long msecs;
788c415b3dcSEduardo Habkost 	local_irq_disable();
7892ddded21SEduardo Habkost 
7902ddded21SEduardo Habkost 	/* Make a note of crashing cpu. Will be used in NMI callback. */
7912ddded21SEduardo Habkost 	crashing_cpu = safe_smp_processor_id();
7922ddded21SEduardo Habkost 
7932ddded21SEduardo Habkost 	shootdown_callback = callback;
7942ddded21SEduardo Habkost 
7952ddded21SEduardo Habkost 	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
7962ddded21SEduardo Habkost 	/* Would it be better to replace the trap vector here? */
7979c48f1c6SDon Zickus 	if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
7989c48f1c6SDon Zickus 				 NMI_FLAG_FIRST, "crash"))
799144d102bSMichael D Labriola 		return;		/* Return what? */
800144d102bSMichael D Labriola 	/*
801144d102bSMichael D Labriola 	 * Ensure the new callback function is set before sending
8022ddded21SEduardo Habkost 	 * out the NMI
8032ddded21SEduardo Habkost 	 */
8042ddded21SEduardo Habkost 	wmb();
8052ddded21SEduardo Habkost 
8062ddded21SEduardo Habkost 	smp_send_nmi_allbutself();
8072ddded21SEduardo Habkost 
8082ddded21SEduardo Habkost 	msecs = 1000; /* Wait at most a second for the other cpus to stop */
8092ddded21SEduardo Habkost 	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
8102ddded21SEduardo Habkost 		mdelay(1);
8112ddded21SEduardo Habkost 		msecs--;
8122ddded21SEduardo Habkost 	}
8132ddded21SEduardo Habkost 
8142ddded21SEduardo Habkost 	/* Leave the nmi callback set */
8152ddded21SEduardo Habkost }
816bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */
817bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
818bb8dd270SEduardo Habkost {
819bb8dd270SEduardo Habkost 	/* No other CPUs to shoot down */
820bb8dd270SEduardo Habkost }
8212ddded21SEduardo Habkost #endif
822