xref: /linux/arch/x86/kernel/reboot.c (revision 144d102b926f887d3d9f909b69a5c4f504ae0d40)
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>
274d022e35SMiguel Boton #else
28338bac52SFUJITA Tomonori # include <asm/x86_init.h>
294d022e35SMiguel Boton #endif
304d022e35SMiguel Boton 
314d022e35SMiguel Boton /*
324d022e35SMiguel Boton  * Power off function, if any
334d022e35SMiguel Boton  */
344d022e35SMiguel Boton void (*pm_power_off)(void);
354d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off);
364d022e35SMiguel Boton 
37ebdd561aSJan Beulich static const struct desc_ptr no_idt = {};
384d022e35SMiguel Boton static int reboot_mode;
39660e34ceSMatthew Garrett enum reboot_type reboot_type = BOOT_ACPI;
404d022e35SMiguel Boton int reboot_force;
414d022e35SMiguel Boton 
42*144d102bSMichael D Labriola /*
43*144d102bSMichael 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 
55*144d102bSMichael D Labriola /*
56*144d102bSMichael D Labriola  * This is set if we need to go through the 'emergency' path.
57d176720dSEduardo Habkost  * When machine_emergency_restart() is called, we may be on
58d176720dSEduardo Habkost  * an inconsistent state and won't be able to do a clean cleanup
59d176720dSEduardo Habkost  */
60d176720dSEduardo Habkost static int reboot_emergency;
61d176720dSEduardo Habkost 
6214d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
6314d7ca5cSH. Peter Anvin bool port_cf9_safe = false;
6414d7ca5cSH. Peter Anvin 
65*144d102bSMichael D Labriola /*
66*144d102bSMichael D Labriola  * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
67*144d102bSMichael D Labriola  * warm   Don't set the cold reboot flag
68*144d102bSMichael D Labriola  * cold   Set the cold reboot flag
69*144d102bSMichael D Labriola  * bios   Reboot by jumping through the BIOS (only for X86_32)
70*144d102bSMichael D Labriola  * smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
71*144d102bSMichael D Labriola  * triple Force a triple fault (init)
72*144d102bSMichael D Labriola  * kbd    Use the keyboard controller. cold reset (default)
73*144d102bSMichael D Labriola  * acpi   Use the RESET_REG in the FADT
74*144d102bSMichael D Labriola  * efi    Use efi reset_system runtime service
75*144d102bSMichael D Labriola  * pci    Use the so-called "PCI reset register", CF9
76*144d102bSMichael D Labriola  * force  Avoid anything that could hang.
774d022e35SMiguel Boton  */
784d022e35SMiguel Boton static int __init reboot_setup(char *str)
794d022e35SMiguel Boton {
804d022e35SMiguel Boton 	for (;;) {
81*144d102bSMichael D Labriola 		/*
82*144d102bSMichael D Labriola 		 * Having anything passed on the command line via
835955633eSMichael D Labriola 		 * reboot= will cause us to disable DMI checking
845955633eSMichael D Labriola 		 * below.
855955633eSMichael D Labriola 		 */
865955633eSMichael D Labriola 		reboot_default = 0;
875955633eSMichael D Labriola 
884d022e35SMiguel Boton 		switch (*str) {
894d022e35SMiguel Boton 		case 'w':
904d022e35SMiguel Boton 			reboot_mode = 0x1234;
914d022e35SMiguel Boton 			break;
924d022e35SMiguel Boton 
934d022e35SMiguel Boton 		case 'c':
944d022e35SMiguel Boton 			reboot_mode = 0;
954d022e35SMiguel Boton 			break;
964d022e35SMiguel Boton 
974d022e35SMiguel Boton #ifdef CONFIG_X86_32
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 			}
105*144d102bSMichael D Labriola 			/*
106*144d102bSMichael D Labriola 			 * We will leave sorting out the final value
107*144d102bSMichael D Labriola 			 * when we are ready to reboot, since we might not
108*144d102bSMichael D Labriola 			 * have detected BSP APIC ID or smp_num_cpu
109*144d102bSMichael D Labriola 			 */
1104d022e35SMiguel Boton 			break;
1114d022e35SMiguel Boton #endif /* CONFIG_SMP */
1124d022e35SMiguel Boton 
1134d022e35SMiguel Boton 		case 'b':
1144d022e35SMiguel Boton #endif
1154d022e35SMiguel Boton 		case 'a':
1164d022e35SMiguel Boton 		case 'k':
1174d022e35SMiguel Boton 		case 't':
1184d022e35SMiguel Boton 		case 'e':
11914d7ca5cSH. Peter Anvin 		case 'p':
1204d022e35SMiguel Boton 			reboot_type = *str;
1214d022e35SMiguel Boton 			break;
1224d022e35SMiguel Boton 
1234d022e35SMiguel Boton 		case 'f':
1244d022e35SMiguel Boton 			reboot_force = 1;
1254d022e35SMiguel Boton 			break;
1264d022e35SMiguel Boton 		}
1274d022e35SMiguel Boton 
1284d022e35SMiguel Boton 		str = strchr(str, ',');
1294d022e35SMiguel Boton 		if (str)
1304d022e35SMiguel Boton 			str++;
1314d022e35SMiguel Boton 		else
1324d022e35SMiguel Boton 			break;
1334d022e35SMiguel Boton 	}
1344d022e35SMiguel Boton 	return 1;
1354d022e35SMiguel Boton }
1364d022e35SMiguel Boton 
1374d022e35SMiguel Boton __setup("reboot=", reboot_setup);
1384d022e35SMiguel Boton 
1394d022e35SMiguel Boton 
1404d022e35SMiguel Boton #ifdef CONFIG_X86_32
1414d022e35SMiguel Boton /*
1424d022e35SMiguel Boton  * Reboot options and system auto-detection code provided by
1434d022e35SMiguel Boton  * Dell Inc. so their systems "just work". :-)
1444d022e35SMiguel Boton  */
1454d022e35SMiguel Boton 
1464d022e35SMiguel Boton /*
1471ef03890SPeter Chubb  * Some machines require the "reboot=b" or "reboot=k"  commandline options,
1484d022e35SMiguel Boton  * this quirk makes that automatic.
1494d022e35SMiguel Boton  */
1504d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d)
1514d022e35SMiguel Boton {
1524d022e35SMiguel Boton 	if (reboot_type != BOOT_BIOS) {
1534d022e35SMiguel Boton 		reboot_type = BOOT_BIOS;
1544d022e35SMiguel Boton 		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
1554d022e35SMiguel Boton 	}
1564d022e35SMiguel Boton 	return 0;
1574d022e35SMiguel Boton }
1584d022e35SMiguel Boton 
15957b16594SMichael D Labriola extern const unsigned char machine_real_restart_asm[];
16057b16594SMichael D Labriola extern const u64 machine_real_restart_gdt[3];
16157b16594SMichael D Labriola 
16257b16594SMichael D Labriola void machine_real_restart(unsigned int type)
16357b16594SMichael D Labriola {
16457b16594SMichael D Labriola 	void *restart_va;
16557b16594SMichael D Labriola 	unsigned long restart_pa;
16657b16594SMichael D Labriola 	void (*restart_lowmem)(unsigned int);
16757b16594SMichael D Labriola 	u64 *lowmem_gdt;
16857b16594SMichael D Labriola 
16957b16594SMichael D Labriola 	local_irq_disable();
17057b16594SMichael D Labriola 
171*144d102bSMichael D Labriola 	/*
172*144d102bSMichael D Labriola 	 * Write zero to CMOS register number 0x0f, which the BIOS POST
173*144d102bSMichael D Labriola 	 * routine will recognize as telling it to do a proper reboot.  (Well
174*144d102bSMichael D Labriola 	 * that's what this book in front of me says -- it may only apply to
175*144d102bSMichael D Labriola 	 * the Phoenix BIOS though, it's not clear).  At the same time,
176*144d102bSMichael D Labriola 	 * disable NMIs by setting the top bit in the CMOS address register,
177*144d102bSMichael D Labriola 	 * as we're about to do peculiar things to the CPU.  I'm not sure if
178*144d102bSMichael D Labriola 	 * `outb_p' is needed instead of just `outb'.  Use it to be on the
179*144d102bSMichael D Labriola 	 * safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
18057b16594SMichael D Labriola 	 */
18157b16594SMichael D Labriola 	spin_lock(&rtc_lock);
18257b16594SMichael D Labriola 	CMOS_WRITE(0x00, 0x8f);
18357b16594SMichael D Labriola 	spin_unlock(&rtc_lock);
18457b16594SMichael D Labriola 
18557b16594SMichael D Labriola 	/*
18657b16594SMichael D Labriola 	 * Switch back to the initial page table.
18757b16594SMichael D Labriola 	 */
18857b16594SMichael D Labriola 	load_cr3(initial_page_table);
18957b16594SMichael D Labriola 
190*144d102bSMichael D Labriola 	/*
191*144d102bSMichael D Labriola 	 * Write 0x1234 to absolute memory location 0x472.  The BIOS reads
192*144d102bSMichael D Labriola 	 * this on booting to tell it to "Bypass memory test (also warm
193*144d102bSMichael D Labriola 	 * boot)".  This seems like a fairly standard thing that gets set by
194*144d102bSMichael D Labriola 	 * REBOOT.COM programs, and the previous reset routine did this
195*144d102bSMichael D Labriola 	 * too. */
19657b16594SMichael D Labriola 	*((unsigned short *)0x472) = reboot_mode;
19757b16594SMichael D Labriola 
19857b16594SMichael D Labriola 	/* Patch the GDT in the low memory trampoline */
19957b16594SMichael D Labriola 	lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
20057b16594SMichael D Labriola 
20157b16594SMichael D Labriola 	restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
20257b16594SMichael D Labriola 	restart_pa = virt_to_phys(restart_va);
20357b16594SMichael D Labriola 	restart_lowmem = (void (*)(unsigned int))restart_pa;
20457b16594SMichael D Labriola 
20557b16594SMichael D Labriola 	/* GDT[0]: GDT self-pointer */
20657b16594SMichael D Labriola 	lowmem_gdt[0] =
20757b16594SMichael D Labriola 		(u64)(sizeof(machine_real_restart_gdt) - 1) +
20857b16594SMichael D Labriola 		((u64)virt_to_phys(lowmem_gdt) << 16);
20957b16594SMichael D Labriola 	/* GDT[1]: 64K real mode code segment */
21057b16594SMichael D Labriola 	lowmem_gdt[1] =
21157b16594SMichael D Labriola 		GDT_ENTRY(0x009b, restart_pa, 0xffff);
21257b16594SMichael D Labriola 
21357b16594SMichael D Labriola 	/* Jump to the identity-mapped low memory code */
21457b16594SMichael D Labriola 	restart_lowmem(type);
21557b16594SMichael D Labriola }
21657b16594SMichael D Labriola #ifdef CONFIG_APM_MODULE
21757b16594SMichael D Labriola EXPORT_SYMBOL(machine_real_restart);
21857b16594SMichael D Labriola #endif
21957b16594SMichael D Labriola 
22057b16594SMichael D Labriola #endif /* CONFIG_X86_32 */
22157b16594SMichael D Labriola 
22257b16594SMichael D Labriola /*
22357b16594SMichael D Labriola  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
22457b16594SMichael D Labriola  */
22557b16594SMichael D Labriola static int __init set_pci_reboot(const struct dmi_system_id *d)
22657b16594SMichael D Labriola {
22757b16594SMichael D Labriola 	if (reboot_type != BOOT_CF9) {
22857b16594SMichael D Labriola 		reboot_type = BOOT_CF9;
22957b16594SMichael D Labriola 		printk(KERN_INFO "%s series board detected. "
23057b16594SMichael D Labriola 		       "Selecting PCI-method for reboots.\n", d->ident);
23157b16594SMichael D Labriola 	}
23257b16594SMichael D Labriola 	return 0;
23357b16594SMichael D Labriola }
23457b16594SMichael D Labriola 
2351ef03890SPeter Chubb static int __init set_kbd_reboot(const struct dmi_system_id *d)
2361ef03890SPeter Chubb {
2371ef03890SPeter Chubb 	if (reboot_type != BOOT_KBD) {
2381ef03890SPeter Chubb 		reboot_type = BOOT_KBD;
2391ef03890SPeter Chubb 		printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
2401ef03890SPeter Chubb 	}
2411ef03890SPeter Chubb 	return 0;
2421ef03890SPeter Chubb }
2431ef03890SPeter Chubb 
244*144d102bSMichael D Labriola /*
245*144d102bSMichael D Labriola  * This is a single dmi_table handling all reboot quirks.  Note that
24657b16594SMichael D Labriola  * REBOOT_BIOS is only available for 32bit
24757b16594SMichael D Labriola  */
2484d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = {
24957b16594SMichael D Labriola #ifdef CONFIG_X86_32
2504d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell E520's */
2514d022e35SMiguel Boton 		.callback = set_bios_reboot,
2524d022e35SMiguel Boton 		.ident = "Dell E520",
2534d022e35SMiguel Boton 		.matches = {
2544d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2554d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
2564d022e35SMiguel Boton 		},
2574d022e35SMiguel Boton 	},
2584d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 1300's */
2594d022e35SMiguel Boton 		.callback = set_bios_reboot,
2604d022e35SMiguel Boton 		.ident = "Dell PowerEdge 1300",
2614d022e35SMiguel Boton 		.matches = {
2624d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2634d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
2644d022e35SMiguel Boton 		},
2654d022e35SMiguel Boton 	},
2664d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 300's */
2674d022e35SMiguel Boton 		.callback = set_bios_reboot,
2684d022e35SMiguel Boton 		.ident = "Dell PowerEdge 300",
2694d022e35SMiguel Boton 		.matches = {
2704d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
2714d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
2724d022e35SMiguel Boton 		},
2734d022e35SMiguel Boton 	},
2744d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell Optiplex 745's SFF */
2754d022e35SMiguel Boton 		.callback = set_bios_reboot,
2764d022e35SMiguel Boton 		.ident = "Dell OptiPlex 745",
2774d022e35SMiguel Boton 		.matches = {
2784d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2794d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
2804d022e35SMiguel Boton 		},
2814d022e35SMiguel Boton 	},
282fc115bf1SColeman Kane 	{	/* Handle problems with rebooting on Dell Optiplex 745's DFF */
283fc115bf1SColeman Kane 		.callback = set_bios_reboot,
284fc115bf1SColeman Kane 		.ident = "Dell OptiPlex 745",
285fc115bf1SColeman Kane 		.matches = {
286fc115bf1SColeman Kane 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
287fc115bf1SColeman Kane 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
288fc115bf1SColeman Kane 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
289fc115bf1SColeman Kane 		},
290fc115bf1SColeman Kane 	},
291fc1c8925SHeinz-Ado Arnolds 	{	/* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
292fc1c8925SHeinz-Ado Arnolds 		.callback = set_bios_reboot,
293fc1c8925SHeinz-Ado Arnolds 		.ident = "Dell OptiPlex 745",
294fc1c8925SHeinz-Ado Arnolds 		.matches = {
295fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
296fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
297fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
298fc1c8925SHeinz-Ado Arnolds 		},
299fc1c8925SHeinz-Ado Arnolds 	},
300093bac15SSteve Conklin 	{	/* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
301093bac15SSteve Conklin 		.callback = set_bios_reboot,
302093bac15SSteve Conklin 		.ident = "Dell OptiPlex 330",
303093bac15SSteve Conklin 		.matches = {
304093bac15SSteve Conklin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
305093bac15SSteve Conklin 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
306093bac15SSteve Conklin 			DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
307093bac15SSteve Conklin 		},
308093bac15SSteve Conklin 	},
3094a4aca64SJean Delvare 	{	/* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
3104a4aca64SJean Delvare 		.callback = set_bios_reboot,
3114a4aca64SJean Delvare 		.ident = "Dell OptiPlex 360",
3124a4aca64SJean Delvare 		.matches = {
3134a4aca64SJean Delvare 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
3144a4aca64SJean Delvare 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
3154a4aca64SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
3164a4aca64SJean Delvare 		},
3174a4aca64SJean Delvare 	},
31835ea63d7SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
31935ea63d7SLeann Ogasawara 		.callback = set_bios_reboot,
32035ea63d7SLeann Ogasawara 		.ident = "Dell OptiPlex 760",
32135ea63d7SLeann Ogasawara 		.matches = {
32235ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
32335ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
32435ea63d7SLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
32535ea63d7SLeann Ogasawara 		},
32635ea63d7SLeann Ogasawara 	},
3274d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 2400's */
3284d022e35SMiguel Boton 		.callback = set_bios_reboot,
3294d022e35SMiguel Boton 		.ident = "Dell PowerEdge 2400",
3304d022e35SMiguel Boton 		.matches = {
3314d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
3324d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
3334d022e35SMiguel Boton 		},
3344d022e35SMiguel Boton 	},
335fab3b58dSIngo Molnar 	{	/* Handle problems with rebooting on Dell T5400's */
336fab3b58dSIngo Molnar 		.callback = set_bios_reboot,
337fab3b58dSIngo Molnar 		.ident = "Dell Precision T5400",
338fab3b58dSIngo Molnar 		.matches = {
339fab3b58dSIngo Molnar 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
340fab3b58dSIngo Molnar 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
341fab3b58dSIngo Molnar 		},
342fab3b58dSIngo Molnar 	},
343890ffedcSThomas Backlund 	{	/* Handle problems with rebooting on Dell T7400's */
344890ffedcSThomas Backlund 		.callback = set_bios_reboot,
345890ffedcSThomas Backlund 		.ident = "Dell Precision T7400",
346890ffedcSThomas Backlund 		.matches = {
347890ffedcSThomas Backlund 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
348890ffedcSThomas Backlund 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
349890ffedcSThomas Backlund 		},
350890ffedcSThomas Backlund 	},
3514d022e35SMiguel Boton 	{	/* Handle problems with rebooting on HP laptops */
3524d022e35SMiguel Boton 		.callback = set_bios_reboot,
3534d022e35SMiguel Boton 		.ident = "HP Compaq Laptop",
3544d022e35SMiguel Boton 		.matches = {
3554d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
3564d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
3574d022e35SMiguel Boton 		},
3584d022e35SMiguel Boton 	},
359dd4124a8SLeann Ogasawara 	{	/* Handle problems with rebooting on Dell XPS710 */
360dd4124a8SLeann Ogasawara 		.callback = set_bios_reboot,
361dd4124a8SLeann Ogasawara 		.ident = "Dell XPS710",
362dd4124a8SLeann Ogasawara 		.matches = {
363dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
364dd4124a8SLeann Ogasawara 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
365dd4124a8SLeann Ogasawara 		},
366dd4124a8SLeann Ogasawara 	},
367c5da9a2bSAlan Cox 	{	/* Handle problems with rebooting on Dell DXP061 */
368c5da9a2bSAlan Cox 		.callback = set_bios_reboot,
369c5da9a2bSAlan Cox 		.ident = "Dell DXP061",
370c5da9a2bSAlan Cox 		.matches = {
371c5da9a2bSAlan Cox 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
372c5da9a2bSAlan Cox 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
373c5da9a2bSAlan Cox 		},
374c5da9a2bSAlan Cox 	},
37588dff493SZhang Rui 	{	/* Handle problems with rebooting on Sony VGN-Z540N */
37688dff493SZhang Rui 		.callback = set_bios_reboot,
37788dff493SZhang Rui 		.ident = "Sony VGN-Z540N",
37888dff493SZhang Rui 		.matches = {
37988dff493SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
38088dff493SZhang Rui 			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
38188dff493SZhang Rui 		},
38288dff493SZhang Rui 	},
38377f32dfdSDenis Turischev 	{	/* Handle problems with rebooting on CompuLab SBC-FITPC2 */
38477f32dfdSDenis Turischev 		.callback = set_bios_reboot,
38577f32dfdSDenis Turischev 		.ident = "CompuLab SBC-FITPC2",
38677f32dfdSDenis Turischev 		.matches = {
38777f32dfdSDenis Turischev 			DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
38877f32dfdSDenis Turischev 			DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
38977f32dfdSDenis Turischev 		},
39077f32dfdSDenis Turischev 	},
3914832dddaSLeann Ogasawara 	{	/* Handle problems with rebooting on ASUS P4S800 */
3924832dddaSLeann Ogasawara 		.callback = set_bios_reboot,
3934832dddaSLeann Ogasawara 		.ident = "ASUS P4S800",
3944832dddaSLeann Ogasawara 		.matches = {
3954832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
3964832dddaSLeann Ogasawara 			DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
3974832dddaSLeann Ogasawara 		},
3984832dddaSLeann Ogasawara 	},
39957b16594SMichael D Labriola #endif /* CONFIG_X86_32 */
40057b16594SMichael D Labriola 
401b49c78d4SPeter Chubb 	{	/* Handle reboot issue on Acer Aspire one */
4021ef03890SPeter Chubb 		.callback = set_kbd_reboot,
403b49c78d4SPeter Chubb 		.ident = "Acer Aspire One A110",
404b49c78d4SPeter Chubb 		.matches = {
405b49c78d4SPeter Chubb 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
406b49c78d4SPeter Chubb 			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
407b49c78d4SPeter Chubb 		},
408b49c78d4SPeter Chubb 	},
4093e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBook5 */
4106c6c51e4SPaul Mackerras 		.callback = set_pci_reboot,
4113e03bbeaSShunichi Fuji 		.ident = "Apple MacBook5",
4126c6c51e4SPaul Mackerras 		.matches = {
4136c6c51e4SPaul Mackerras 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4143e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
4156c6c51e4SPaul Mackerras 		},
4166c6c51e4SPaul Mackerras 	},
4173e03bbeaSShunichi Fuji 	{	/* Handle problems with rebooting on Apple MacBookPro5 */
418498cdbfbSOzan Çağlayan 		.callback = set_pci_reboot,
4193e03bbeaSShunichi Fuji 		.ident = "Apple MacBookPro5",
420498cdbfbSOzan Çağlayan 		.matches = {
421498cdbfbSOzan Çağlayan 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4223e03bbeaSShunichi Fuji 			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
423498cdbfbSOzan Çağlayan 		},
424498cdbfbSOzan Çağlayan 	},
42505154752SGottfried Haider 	{	/* Handle problems with rebooting on Apple Macmini3,1 */
42605154752SGottfried Haider 		.callback = set_pci_reboot,
42705154752SGottfried Haider 		.ident = "Apple Macmini3,1",
42805154752SGottfried Haider 		.matches = {
42905154752SGottfried Haider 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
43005154752SGottfried Haider 			DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
43105154752SGottfried Haider 		},
43205154752SGottfried Haider 	},
4330a832320SJustin P. Mattock 	{	/* Handle problems with rebooting on the iMac9,1. */
4340a832320SJustin P. Mattock 		.callback = set_pci_reboot,
4350a832320SJustin P. Mattock 		.ident = "Apple iMac9,1",
4360a832320SJustin P. Mattock 		.matches = {
4370a832320SJustin P. Mattock 			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
4380a832320SJustin P. Mattock 			DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
4390a832320SJustin P. Mattock 		},
4400a832320SJustin P. Mattock 	},
4413628c3f5SMaxime Ripard 	{	/* Handle problems with rebooting on the Latitude E6320. */
4423628c3f5SMaxime Ripard 		.callback = set_pci_reboot,
4433628c3f5SMaxime Ripard 		.ident = "Dell Latitude E6320",
4443628c3f5SMaxime Ripard 		.matches = {
4453628c3f5SMaxime Ripard 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4463628c3f5SMaxime Ripard 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
4473628c3f5SMaxime Ripard 		},
4483628c3f5SMaxime Ripard 	},
449b7798d28SDaniel J Blueman 	{	/* Handle problems with rebooting on the Latitude E5420. */
450b7798d28SDaniel J Blueman 		.callback = set_pci_reboot,
451b7798d28SDaniel J Blueman 		.ident = "Dell Latitude E5420",
452b7798d28SDaniel J Blueman 		.matches = {
453b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
454b7798d28SDaniel J Blueman 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
455b7798d28SDaniel J Blueman 		},
456b7798d28SDaniel J Blueman 	},
457a536877eSH. Peter Anvin 	{	/* Handle problems with rebooting on the Latitude E6420. */
458a536877eSH. Peter Anvin 		.callback = set_pci_reboot,
459a536877eSH. Peter Anvin 		.ident = "Dell Latitude E6420",
460a536877eSH. Peter Anvin 		.matches = {
461a536877eSH. Peter Anvin 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
462a536877eSH. Peter Anvin 			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
463a536877eSH. Peter Anvin 		},
464a536877eSH. Peter Anvin 	},
4656be30bb7SRafael J. Wysocki 	{	/* Handle problems with rebooting on the OptiPlex 990. */
4666be30bb7SRafael J. Wysocki 		.callback = set_pci_reboot,
4676be30bb7SRafael J. Wysocki 		.ident = "Dell OptiPlex 990",
4686be30bb7SRafael J. Wysocki 		.matches = {
4696be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
4706be30bb7SRafael J. Wysocki 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
4716be30bb7SRafael J. Wysocki 		},
4726be30bb7SRafael J. Wysocki 	},
4736c6c51e4SPaul Mackerras 	{ }
4746c6c51e4SPaul Mackerras };
4756c6c51e4SPaul Mackerras 
47657b16594SMichael D Labriola static int __init reboot_init(void)
4776c6c51e4SPaul Mackerras {
478*144d102bSMichael D Labriola 	/*
479*144d102bSMichael D Labriola 	 * Only do the DMI check if reboot_type hasn't been overridden
4805955633eSMichael D Labriola 	 * on the command line
4815955633eSMichael D Labriola 	 */
482*144d102bSMichael D Labriola 	if (reboot_default)
48357b16594SMichael D Labriola 		dmi_check_system(reboot_dmi_table);
4846c6c51e4SPaul Mackerras 	return 0;
4856c6c51e4SPaul Mackerras }
48657b16594SMichael D Labriola core_initcall(reboot_init);
4876c6c51e4SPaul Mackerras 
4884d022e35SMiguel Boton static inline void kb_wait(void)
4894d022e35SMiguel Boton {
4904d022e35SMiguel Boton 	int i;
4914d022e35SMiguel Boton 
492c84d6af8SAlan Cox 	for (i = 0; i < 0x10000; i++) {
493c84d6af8SAlan Cox 		if ((inb(0x64) & 0x02) == 0)
4944d022e35SMiguel Boton 			break;
495c84d6af8SAlan Cox 		udelay(2);
496c84d6af8SAlan Cox 	}
4974d022e35SMiguel Boton }
4984d022e35SMiguel Boton 
4999c48f1c6SDon Zickus static void vmxoff_nmi(int cpu, struct pt_regs *regs)
500d176720dSEduardo Habkost {
501d176720dSEduardo Habkost 	cpu_emergency_vmxoff();
502d176720dSEduardo Habkost }
503d176720dSEduardo Habkost 
504*144d102bSMichael D Labriola /* Use NMIs as IPIs to tell all CPUs to disable virtualization */
505d176720dSEduardo Habkost static void emergency_vmx_disable_all(void)
506d176720dSEduardo Habkost {
507d176720dSEduardo Habkost 	/* Just make sure we won't change CPUs while doing this */
508d176720dSEduardo Habkost 	local_irq_disable();
509d176720dSEduardo Habkost 
510*144d102bSMichael D Labriola 	/*
511*144d102bSMichael D Labriola 	 * We need to disable VMX on all CPUs before rebooting, otherwise
512d176720dSEduardo Habkost 	 * we risk hanging up the machine, because the CPU ignore INIT
513d176720dSEduardo Habkost 	 * signals when VMX is enabled.
514d176720dSEduardo Habkost 	 *
515d176720dSEduardo Habkost 	 * We can't take any locks and we may be on an inconsistent
516d176720dSEduardo Habkost 	 * state, so we use NMIs as IPIs to tell the other CPUs to disable
517d176720dSEduardo Habkost 	 * VMX and halt.
518d176720dSEduardo Habkost 	 *
519d176720dSEduardo Habkost 	 * For safety, we will avoid running the nmi_shootdown_cpus()
520d176720dSEduardo Habkost 	 * stuff unnecessarily, but we don't have a way to check
521d176720dSEduardo Habkost 	 * if other CPUs have VMX enabled. So we will call it only if the
522d176720dSEduardo Habkost 	 * CPU we are running on has VMX enabled.
523d176720dSEduardo Habkost 	 *
524d176720dSEduardo Habkost 	 * We will miss cases where VMX is not enabled on all CPUs. This
525d176720dSEduardo Habkost 	 * shouldn't do much harm because KVM always enable VMX on all
526d176720dSEduardo Habkost 	 * CPUs anyway. But we can miss it on the small window where KVM
527d176720dSEduardo Habkost 	 * is still enabling VMX.
528d176720dSEduardo Habkost 	 */
529d176720dSEduardo Habkost 	if (cpu_has_vmx() && cpu_vmx_enabled()) {
530*144d102bSMichael D Labriola 		/* Disable VMX on this CPU. */
531d176720dSEduardo Habkost 		cpu_vmxoff();
532d176720dSEduardo Habkost 
533d176720dSEduardo Habkost 		/* Halt and disable VMX on the other CPUs */
534d176720dSEduardo Habkost 		nmi_shootdown_cpus(vmxoff_nmi);
535d176720dSEduardo Habkost 
536d176720dSEduardo Habkost 	}
537d176720dSEduardo Habkost }
538d176720dSEduardo Habkost 
539d176720dSEduardo Habkost 
5407432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void)
5417432d149SIngo Molnar {
5427432d149SIngo Molnar }
5437432d149SIngo Molnar 
544660e34ceSMatthew Garrett /*
545660e34ceSMatthew Garrett  * Windows compatible x86 hardware expects the following on reboot:
546660e34ceSMatthew Garrett  *
547660e34ceSMatthew Garrett  * 1) If the FADT has the ACPI reboot register flag set, try it
548660e34ceSMatthew Garrett  * 2) If still alive, write to the keyboard controller
549660e34ceSMatthew Garrett  * 3) If still alive, write to the ACPI reboot register again
550660e34ceSMatthew Garrett  * 4) If still alive, write to the keyboard controller again
551660e34ceSMatthew Garrett  *
552660e34ceSMatthew Garrett  * If the machine is still alive at this stage, it gives up. We default to
553660e34ceSMatthew Garrett  * following the same pattern, except that if we're still alive after (4) we'll
554660e34ceSMatthew Garrett  * try to force a triple fault and then cycle between hitting the keyboard
555660e34ceSMatthew Garrett  * controller and doing that
556660e34ceSMatthew Garrett  */
557416e2d63SJody Belka static void native_machine_emergency_restart(void)
5584d022e35SMiguel Boton {
5594d022e35SMiguel Boton 	int i;
560660e34ceSMatthew Garrett 	int attempt = 0;
561660e34ceSMatthew Garrett 	int orig_reboot_type = reboot_type;
5624d022e35SMiguel Boton 
563d176720dSEduardo Habkost 	if (reboot_emergency)
564d176720dSEduardo Habkost 		emergency_vmx_disable_all();
565d176720dSEduardo Habkost 
566840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_REBOOT);
567840c2bafSJoseph Cihula 
5684d022e35SMiguel Boton 	/* Tell the BIOS if we want cold or warm reboot */
5694d022e35SMiguel Boton 	*((unsigned short *)__va(0x472)) = reboot_mode;
5704d022e35SMiguel Boton 
5714d022e35SMiguel Boton 	for (;;) {
5724d022e35SMiguel Boton 		/* Could also try the reset bit in the Hammer NB */
5734d022e35SMiguel Boton 		switch (reboot_type) {
5744d022e35SMiguel Boton 		case BOOT_KBD:
575*144d102bSMichael D Labriola 			mach_reboot_fixups(); /* For board specific fixups */
5767432d149SIngo Molnar 
5774d022e35SMiguel Boton 			for (i = 0; i < 10; i++) {
5784d022e35SMiguel Boton 				kb_wait();
5794d022e35SMiguel Boton 				udelay(50);
580*144d102bSMichael D Labriola 				outb(0xfe, 0x64); /* Pulse reset low */
5814d022e35SMiguel Boton 				udelay(50);
5824d022e35SMiguel Boton 			}
583660e34ceSMatthew Garrett 			if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
584660e34ceSMatthew Garrett 				attempt = 1;
585660e34ceSMatthew Garrett 				reboot_type = BOOT_ACPI;
586660e34ceSMatthew Garrett 			} else {
587660e34ceSMatthew Garrett 				reboot_type = BOOT_TRIPLE;
588660e34ceSMatthew Garrett 			}
589660e34ceSMatthew Garrett 			break;
5904d022e35SMiguel Boton 
5914d022e35SMiguel Boton 		case BOOT_TRIPLE:
592ebdd561aSJan Beulich 			load_idt(&no_idt);
5934d022e35SMiguel Boton 			__asm__ __volatile__("int3");
5944d022e35SMiguel Boton 
5954d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
5964d022e35SMiguel Boton 			break;
5974d022e35SMiguel Boton 
5984d022e35SMiguel Boton #ifdef CONFIG_X86_32
5994d022e35SMiguel Boton 		case BOOT_BIOS:
6003d35ac34SH. Peter Anvin 			machine_real_restart(MRR_BIOS);
6014d022e35SMiguel Boton 
6024d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6034d022e35SMiguel Boton 			break;
6044d022e35SMiguel Boton #endif
6054d022e35SMiguel Boton 
6064d022e35SMiguel Boton 		case BOOT_ACPI:
6074d022e35SMiguel Boton 			acpi_reboot();
6084d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6094d022e35SMiguel Boton 			break;
6104d022e35SMiguel Boton 
6114d022e35SMiguel Boton 		case BOOT_EFI:
6124d022e35SMiguel Boton 			if (efi_enabled)
61314d7ca5cSH. Peter Anvin 				efi.reset_system(reboot_mode ?
61414d7ca5cSH. Peter Anvin 						 EFI_RESET_WARM :
61514d7ca5cSH. Peter Anvin 						 EFI_RESET_COLD,
6164d022e35SMiguel Boton 						 EFI_SUCCESS, 0, NULL);
617b47b9288SH. Peter Anvin 			reboot_type = BOOT_KBD;
61814d7ca5cSH. Peter Anvin 			break;
6194d022e35SMiguel Boton 
62014d7ca5cSH. Peter Anvin 		case BOOT_CF9:
62114d7ca5cSH. Peter Anvin 			port_cf9_safe = true;
622*144d102bSMichael D Labriola 			/* Fall through */
62314d7ca5cSH. Peter Anvin 
62414d7ca5cSH. Peter Anvin 		case BOOT_CF9_COND:
62514d7ca5cSH. Peter Anvin 			if (port_cf9_safe) {
62614d7ca5cSH. Peter Anvin 				u8 cf9 = inb(0xcf9) & ~6;
62714d7ca5cSH. Peter Anvin 				outb(cf9|2, 0xcf9); /* Request hard reset */
62814d7ca5cSH. Peter Anvin 				udelay(50);
62914d7ca5cSH. Peter Anvin 				outb(cf9|6, 0xcf9); /* Actually do the reset */
63014d7ca5cSH. Peter Anvin 				udelay(50);
63114d7ca5cSH. Peter Anvin 			}
6324d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
6334d022e35SMiguel Boton 			break;
6344d022e35SMiguel Boton 		}
6354d022e35SMiguel Boton 	}
6364d022e35SMiguel Boton }
6374d022e35SMiguel Boton 
6383c62c625SGlauber Costa void native_machine_shutdown(void)
6394d022e35SMiguel Boton {
6404d022e35SMiguel Boton 	/* Stop the cpus and apics */
6414d022e35SMiguel Boton #ifdef CONFIG_SMP
6424d022e35SMiguel Boton 
6434d022e35SMiguel Boton 	/* The boot cpu is always logical cpu 0 */
64465c01184SMike Travis 	int reboot_cpu_id = 0;
6454d022e35SMiguel Boton 
6464d022e35SMiguel Boton #ifdef CONFIG_X86_32
6474d022e35SMiguel Boton 	/* See if there has been given a command line override */
6489628937dSMike Travis 	if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
6490bc3cc03SMike Travis 		cpu_online(reboot_cpu))
6504d022e35SMiguel Boton 		reboot_cpu_id = reboot_cpu;
6514d022e35SMiguel Boton #endif
6524d022e35SMiguel Boton 
6534d022e35SMiguel Boton 	/* Make certain the cpu I'm about to reboot on is online */
6540bc3cc03SMike Travis 	if (!cpu_online(reboot_cpu_id))
6554d022e35SMiguel Boton 		reboot_cpu_id = smp_processor_id();
6564d022e35SMiguel Boton 
6574d022e35SMiguel Boton 	/* Make certain I only run on the appropriate processor */
6589628937dSMike Travis 	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
6594d022e35SMiguel Boton 
660*144d102bSMichael D Labriola 	/*
661*144d102bSMichael D Labriola 	 * O.K Now that I'm on the appropriate processor,
6624d022e35SMiguel Boton 	 * stop all of the others.
6634d022e35SMiguel Boton 	 */
66476fac077SAlok Kataria 	stop_other_cpus();
6654d022e35SMiguel Boton #endif
6664d022e35SMiguel Boton 
6674d022e35SMiguel Boton 	lapic_shutdown();
6684d022e35SMiguel Boton 
6694d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC
6704d022e35SMiguel Boton 	disable_IO_APIC();
6714d022e35SMiguel Boton #endif
6724d022e35SMiguel Boton 
6734d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER
6744d022e35SMiguel Boton 	hpet_disable();
6754d022e35SMiguel Boton #endif
6764d022e35SMiguel Boton 
6774d022e35SMiguel Boton #ifdef CONFIG_X86_64
678338bac52SFUJITA Tomonori 	x86_platform.iommu_shutdown();
6794d022e35SMiguel Boton #endif
6804d022e35SMiguel Boton }
6814d022e35SMiguel Boton 
682d176720dSEduardo Habkost static void __machine_emergency_restart(int emergency)
683d176720dSEduardo Habkost {
684d176720dSEduardo Habkost 	reboot_emergency = emergency;
685d176720dSEduardo Habkost 	machine_ops.emergency_restart();
686d176720dSEduardo Habkost }
687d176720dSEduardo Habkost 
688416e2d63SJody Belka static void native_machine_restart(char *__unused)
6894d022e35SMiguel Boton {
6904d022e35SMiguel Boton 	printk("machine restart\n");
6914d022e35SMiguel Boton 
6924d022e35SMiguel Boton 	if (!reboot_force)
6934d022e35SMiguel Boton 		machine_shutdown();
694d176720dSEduardo Habkost 	__machine_emergency_restart(0);
6954d022e35SMiguel Boton }
6964d022e35SMiguel Boton 
697416e2d63SJody Belka static void native_machine_halt(void)
6984d022e35SMiguel Boton {
699*144d102bSMichael D Labriola 	/* Stop other cpus and apics */
700d3ec5caeSIvan Vecera 	machine_shutdown();
701d3ec5caeSIvan Vecera 
702840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
703840c2bafSJoseph Cihula 
704d3ec5caeSIvan Vecera 	stop_this_cpu(NULL);
7054d022e35SMiguel Boton }
7064d022e35SMiguel Boton 
707416e2d63SJody Belka static void native_machine_power_off(void)
7084d022e35SMiguel Boton {
7094d022e35SMiguel Boton 	if (pm_power_off) {
7104d022e35SMiguel Boton 		if (!reboot_force)
7114d022e35SMiguel Boton 			machine_shutdown();
7124d022e35SMiguel Boton 		pm_power_off();
7134d022e35SMiguel Boton 	}
714*144d102bSMichael D Labriola 	/* A fallback in case there is no PM info available */
715840c2bafSJoseph Cihula 	tboot_shutdown(TB_SHUTDOWN_HALT);
7164d022e35SMiguel Boton }
7174d022e35SMiguel Boton 
7184d022e35SMiguel Boton struct machine_ops machine_ops = {
719416e2d63SJody Belka 	.power_off = native_machine_power_off,
720416e2d63SJody Belka 	.shutdown = native_machine_shutdown,
721416e2d63SJody Belka 	.emergency_restart = native_machine_emergency_restart,
722416e2d63SJody Belka 	.restart = native_machine_restart,
723ed23dc6fSGlauber Costa 	.halt = native_machine_halt,
724ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
725ed23dc6fSGlauber Costa 	.crash_shutdown = native_machine_crash_shutdown,
726ed23dc6fSGlauber Costa #endif
7274d022e35SMiguel Boton };
728416e2d63SJody Belka 
729416e2d63SJody Belka void machine_power_off(void)
730416e2d63SJody Belka {
731416e2d63SJody Belka 	machine_ops.power_off();
732416e2d63SJody Belka }
733416e2d63SJody Belka 
734416e2d63SJody Belka void machine_shutdown(void)
735416e2d63SJody Belka {
736416e2d63SJody Belka 	machine_ops.shutdown();
737416e2d63SJody Belka }
738416e2d63SJody Belka 
739416e2d63SJody Belka void machine_emergency_restart(void)
740416e2d63SJody Belka {
741d176720dSEduardo Habkost 	__machine_emergency_restart(1);
742416e2d63SJody Belka }
743416e2d63SJody Belka 
744416e2d63SJody Belka void machine_restart(char *cmd)
745416e2d63SJody Belka {
746416e2d63SJody Belka 	machine_ops.restart(cmd);
747416e2d63SJody Belka }
748416e2d63SJody Belka 
749416e2d63SJody Belka void machine_halt(void)
750416e2d63SJody Belka {
751416e2d63SJody Belka 	machine_ops.halt();
752416e2d63SJody Belka }
753416e2d63SJody Belka 
754ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
755ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs)
756ed23dc6fSGlauber Costa {
757ed23dc6fSGlauber Costa 	machine_ops.crash_shutdown(regs);
758ed23dc6fSGlauber Costa }
759ed23dc6fSGlauber Costa #endif
7602ddded21SEduardo Habkost 
7612ddded21SEduardo Habkost 
762bb8dd270SEduardo Habkost #if defined(CONFIG_SMP)
7632ddded21SEduardo Habkost 
7642ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */
7652ddded21SEduardo Habkost static int crashing_cpu;
7662ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback;
7672ddded21SEduardo Habkost 
7682ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi;
7692ddded21SEduardo Habkost 
7709c48f1c6SDon Zickus static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
7712ddded21SEduardo Habkost {
7722ddded21SEduardo Habkost 	int cpu;
7732ddded21SEduardo Habkost 
7742ddded21SEduardo Habkost 	cpu = raw_smp_processor_id();
7752ddded21SEduardo Habkost 
776*144d102bSMichael D Labriola 	/*
777*144d102bSMichael D Labriola 	 * Don't do anything if this handler is invoked on crashing cpu.
7782ddded21SEduardo Habkost 	 * Otherwise, system will completely hang. Crashing cpu can get
7792ddded21SEduardo Habkost 	 * an NMI if system was initially booted with nmi_watchdog parameter.
7802ddded21SEduardo Habkost 	 */
7812ddded21SEduardo Habkost 	if (cpu == crashing_cpu)
7829c48f1c6SDon Zickus 		return NMI_HANDLED;
7832ddded21SEduardo Habkost 	local_irq_disable();
7842ddded21SEduardo Habkost 
7859c48f1c6SDon Zickus 	shootdown_callback(cpu, regs);
7862ddded21SEduardo Habkost 
7872ddded21SEduardo Habkost 	atomic_dec(&waiting_for_crash_ipi);
7882ddded21SEduardo Habkost 	/* Assume hlt works */
7892ddded21SEduardo Habkost 	halt();
7902ddded21SEduardo Habkost 	for (;;)
7912ddded21SEduardo Habkost 		cpu_relax();
7922ddded21SEduardo Habkost 
7939c48f1c6SDon Zickus 	return NMI_HANDLED;
7942ddded21SEduardo Habkost }
7952ddded21SEduardo Habkost 
7962ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void)
7972ddded21SEduardo Habkost {
798dac5f412SIngo Molnar 	apic->send_IPI_allbutself(NMI_VECTOR);
7992ddded21SEduardo Habkost }
8002ddded21SEduardo Habkost 
801*144d102bSMichael D Labriola /*
802*144d102bSMichael D Labriola  * Halt all other CPUs, calling the specified function on each of them
803bb8dd270SEduardo Habkost  *
804bb8dd270SEduardo Habkost  * This function can be used to halt all other CPUs on crash
805bb8dd270SEduardo Habkost  * or emergency reboot time. The function passed as parameter
806bb8dd270SEduardo Habkost  * will be called inside a NMI handler on all CPUs.
807bb8dd270SEduardo Habkost  */
8082ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
8092ddded21SEduardo Habkost {
8102ddded21SEduardo Habkost 	unsigned long msecs;
811c415b3dcSEduardo Habkost 	local_irq_disable();
8122ddded21SEduardo Habkost 
8132ddded21SEduardo Habkost 	/* Make a note of crashing cpu. Will be used in NMI callback. */
8142ddded21SEduardo Habkost 	crashing_cpu = safe_smp_processor_id();
8152ddded21SEduardo Habkost 
8162ddded21SEduardo Habkost 	shootdown_callback = callback;
8172ddded21SEduardo Habkost 
8182ddded21SEduardo Habkost 	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
8192ddded21SEduardo Habkost 	/* Would it be better to replace the trap vector here? */
8209c48f1c6SDon Zickus 	if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
8219c48f1c6SDon Zickus 				 NMI_FLAG_FIRST, "crash"))
822*144d102bSMichael D Labriola 		return;		/* Return what? */
823*144d102bSMichael D Labriola 	/*
824*144d102bSMichael D Labriola 	 * Ensure the new callback function is set before sending
8252ddded21SEduardo Habkost 	 * out the NMI
8262ddded21SEduardo Habkost 	 */
8272ddded21SEduardo Habkost 	wmb();
8282ddded21SEduardo Habkost 
8292ddded21SEduardo Habkost 	smp_send_nmi_allbutself();
8302ddded21SEduardo Habkost 
8312ddded21SEduardo Habkost 	msecs = 1000; /* Wait at most a second for the other cpus to stop */
8322ddded21SEduardo Habkost 	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
8332ddded21SEduardo Habkost 		mdelay(1);
8342ddded21SEduardo Habkost 		msecs--;
8352ddded21SEduardo Habkost 	}
8362ddded21SEduardo Habkost 
8372ddded21SEduardo Habkost 	/* Leave the nmi callback set */
8382ddded21SEduardo Habkost }
839bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */
840bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
841bb8dd270SEduardo Habkost {
842bb8dd270SEduardo Habkost 	/* No other CPUs to shoot down */
843bb8dd270SEduardo Habkost }
8442ddded21SEduardo Habkost #endif
845