blob: 77215c23fba1250dc9b45085e36d99d7356358b7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/module.h>
Adrian Bunkcd6ed522006-12-06 20:40:06 -08002#include <linux/reboot.h>
Miguel Boton4d022e32008-01-30 13:32:51 +01003#include <linux/init.h>
4#include <linux/pm.h>
5#include <linux/efi.h>
Paul Mackerras6c6c51e2009-08-03 22:47:32 +10006#include <linux/dmi.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +04007#include <linux/sched.h>
Shane Wang69575d32009-09-01 18:25:07 -07008#include <linux/tboot.h>
Jean Delvareca4445642011-03-25 15:20:14 +01009#include <linux/delay.h>
Miguel Boton4d022e32008-01-30 13:32:51 +010010#include <acpi/reboot.h>
11#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/apic.h>
Zachary Amsden4d37e7e2005-09-03 15:56:38 -070013#include <asm/desc.h>
Miguel Boton4d022e32008-01-30 13:32:51 +010014#include <asm/hpet.h>
Jeremy Fitzhardinge68db0652008-03-17 16:37:13 -070015#include <asm/pgtable.h>
Dmitri Vorobiev44126202008-04-28 03:15:59 +040016#include <asm/proto.h>
Jeremy Fitzhardinge973efae2007-05-02 19:27:06 +020017#include <asm/reboot_fixups.h>
Jeremy Fitzhardinge07f33312007-05-02 19:27:11 +020018#include <asm/reboot.h>
Jaswinder Singh Rajput82487712008-12-27 18:32:28 +053019#include <asm/pci_x86.h>
Eduardo Habkostd1767202008-11-17 19:03:24 -020020#include <asm/virtext.h>
Jaswinder Singh Rajput96b89dc2009-01-07 21:35:48 +053021#include <asm/cpu.h>
Don Zickusc410b832011-01-06 16:18:50 -050022#include <asm/nmi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Miguel Boton4d022e32008-01-30 13:32:51 +010024#ifdef CONFIG_X86_32
Miguel Boton4d022e32008-01-30 13:32:51 +010025# include <linux/ctype.h>
26# include <linux/mc146818rtc.h>
Miguel Boton4d022e32008-01-30 13:32:51 +010027#else
FUJITA Tomonori338bac52009-10-27 16:34:44 +090028# include <asm/x86_init.h>
Miguel Boton4d022e32008-01-30 13:32:51 +010029#endif
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031/*
32 * Power off function, if any
33 */
34void (*pm_power_off)(void);
Alexey Dobriyan129f6942005-06-23 00:08:33 -070035EXPORT_SYMBOL(pm_power_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Jan Beulichebdd5612008-05-12 15:43:38 +020037static const struct desc_ptr no_idt = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static int reboot_mode;
Matthew Garrett660e34c2011-04-04 13:55:05 -040039enum reboot_type reboot_type = BOOT_ACPI;
Miguel Boton4d022e32008-01-30 13:32:51 +010040int reboot_force;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Michael D Labriola144d1022012-02-01 10:06:34 -050042/*
43 * This variable is used privately to keep track of whether or not
Michael D Labriola59556332012-01-29 14:17:22 -050044 * reboot_type is still set to its default value (i.e., reboot= hasn't
45 * been set on the command line). This is needed so that we can
46 * suppress DMI scanning for reboot quirks. Without it, it's
47 * impossible to override a faulty reboot quirk without recompiling.
48 */
49static int reboot_default = 1;
50
Miguel Boton4d022e32008-01-30 13:32:51 +010051#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052static int reboot_cpu = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#endif
Miguel Boton4d022e32008-01-30 13:32:51 +010054
Michael D Labriola144d1022012-02-01 10:06:34 -050055/*
56 * This is set if we need to go through the 'emergency' path.
Eduardo Habkostd1767202008-11-17 19:03:24 -020057 * When machine_emergency_restart() is called, we may be on
58 * an inconsistent state and won't be able to do a clean cleanup
59 */
60static int reboot_emergency;
61
H. Peter Anvin14d7ca52008-11-11 16:19:48 -080062/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
63bool port_cf9_safe = false;
64
Michael D Labriola144d1022012-02-01 10:06:34 -050065/*
66 * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
67 * warm Don't set the cold reboot flag
68 * cold Set the cold reboot flag
69 * bios Reboot by jumping through the BIOS (only for X86_32)
70 * smp Reboot by executing reset on BSP or other CPU (only for X86_32)
71 * triple Force a triple fault (init)
72 * kbd Use the keyboard controller. cold reset (default)
73 * acpi Use the RESET_REG in the FADT
74 * efi Use efi reset_system runtime service
75 * pci Use the so-called "PCI reset register", CF9
76 * force Avoid anything that could hang.
Miguel Boton4d022e32008-01-30 13:32:51 +010077 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static int __init reboot_setup(char *str)
79{
Miguel Boton4d022e32008-01-30 13:32:51 +010080 for (;;) {
Michael D Labriola144d1022012-02-01 10:06:34 -050081 /*
82 * Having anything passed on the command line via
Michael D Labriola59556332012-01-29 14:17:22 -050083 * reboot= will cause us to disable DMI checking
84 * below.
85 */
86 reboot_default = 0;
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 switch (*str) {
Miguel Boton4d022e32008-01-30 13:32:51 +010089 case 'w':
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 reboot_mode = 0x1234;
91 break;
Miguel Boton4d022e32008-01-30 13:32:51 +010092
93 case 'c':
94 reboot_mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 break;
Miguel Boton4d022e32008-01-30 13:32:51 +010096
97#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#ifdef CONFIG_SMP
Miguel Boton4d022e32008-01-30 13:32:51 +010099 case 's':
Tobias Klauser6f673d82005-09-13 01:25:48 -0700100 if (isdigit(*(str+1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 reboot_cpu = (int) (*(str+1) - '0');
Tobias Klauser6f673d82005-09-13 01:25:48 -0700102 if (isdigit(*(str+2)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
104 }
Michael D Labriola144d1022012-02-01 10:06:34 -0500105 /*
106 * We will leave sorting out the final value
107 * when we are ready to reboot, since we might not
108 * have detected BSP APIC ID or smp_num_cpu
109 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 break;
Miguel Boton4d022e32008-01-30 13:32:51 +0100111#endif /* CONFIG_SMP */
112
113 case 'b':
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#endif
Miguel Boton4d022e32008-01-30 13:32:51 +0100115 case 'a':
116 case 'k':
117 case 't':
118 case 'e':
H. Peter Anvin14d7ca52008-11-11 16:19:48 -0800119 case 'p':
Miguel Boton4d022e32008-01-30 13:32:51 +0100120 reboot_type = *str;
121 break;
122
123 case 'f':
124 reboot_force = 1;
125 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 }
Miguel Boton4d022e32008-01-30 13:32:51 +0100127
128 str = strchr(str, ',');
129 if (str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 str++;
131 else
132 break;
133 }
134 return 1;
135}
136
137__setup("reboot=", reboot_setup);
138
Miguel Boton4d022e32008-01-30 13:32:51 +0100139
140#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141/*
142 * Reboot options and system auto-detection code provided by
143 * Dell Inc. so their systems "just work". :-)
144 */
145
146/*
Peter Chubb1ef03892011-12-05 16:53:53 +0300147 * Some machines require the "reboot=b" or "reboot=k" commandline options,
Miguel Boton4d022e32008-01-30 13:32:51 +0100148 * this quirk makes that automatic.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 */
Jeff Garzik18552562007-10-03 15:15:40 -0400150static int __init set_bios_reboot(const struct dmi_system_id *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Miguel Boton4d022e32008-01-30 13:32:51 +0100152 if (reboot_type != BOOT_BIOS) {
153 reboot_type = BOOT_BIOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
155 }
156 return 0;
157}
158
Michael D Labriola57b16592012-02-01 10:05:00 -0500159extern const unsigned char machine_real_restart_asm[];
160extern const u64 machine_real_restart_gdt[3];
161
162void machine_real_restart(unsigned int type)
163{
164 void *restart_va;
165 unsigned long restart_pa;
166 void (*restart_lowmem)(unsigned int);
167 u64 *lowmem_gdt;
168
169 local_irq_disable();
170
Michael D Labriola144d1022012-02-01 10:06:34 -0500171 /*
172 * Write zero to CMOS register number 0x0f, which the BIOS POST
173 * routine will recognize as telling it to do a proper reboot. (Well
174 * that's what this book in front of me says -- it may only apply to
175 * the Phoenix BIOS though, it's not clear). At the same time,
176 * disable NMIs by setting the top bit in the CMOS address register,
177 * as we're about to do peculiar things to the CPU. I'm not sure if
178 * `outb_p' is needed instead of just `outb'. Use it to be on the
179 * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
Michael D Labriola57b16592012-02-01 10:05:00 -0500180 */
181 spin_lock(&rtc_lock);
182 CMOS_WRITE(0x00, 0x8f);
183 spin_unlock(&rtc_lock);
184
185 /*
186 * Switch back to the initial page table.
187 */
188 load_cr3(initial_page_table);
189
Michael D Labriola144d1022012-02-01 10:06:34 -0500190 /*
191 * Write 0x1234 to absolute memory location 0x472. The BIOS reads
192 * this on booting to tell it to "Bypass memory test (also warm
193 * boot)". This seems like a fairly standard thing that gets set by
194 * REBOOT.COM programs, and the previous reset routine did this
195 * too. */
Michael D Labriola57b16592012-02-01 10:05:00 -0500196 *((unsigned short *)0x472) = reboot_mode;
197
198 /* Patch the GDT in the low memory trampoline */
199 lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
200
201 restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
202 restart_pa = virt_to_phys(restart_va);
203 restart_lowmem = (void (*)(unsigned int))restart_pa;
204
205 /* GDT[0]: GDT self-pointer */
206 lowmem_gdt[0] =
207 (u64)(sizeof(machine_real_restart_gdt) - 1) +
208 ((u64)virt_to_phys(lowmem_gdt) << 16);
209 /* GDT[1]: 64K real mode code segment */
210 lowmem_gdt[1] =
211 GDT_ENTRY(0x009b, restart_pa, 0xffff);
212
213 /* Jump to the identity-mapped low memory code */
214 restart_lowmem(type);
215}
216#ifdef CONFIG_APM_MODULE
217EXPORT_SYMBOL(machine_real_restart);
218#endif
219
220#endif /* CONFIG_X86_32 */
221
222/*
223 * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
224 */
225static int __init set_pci_reboot(const struct dmi_system_id *d)
226{
227 if (reboot_type != BOOT_CF9) {
228 reboot_type = BOOT_CF9;
229 printk(KERN_INFO "%s series board detected. "
230 "Selecting PCI-method for reboots.\n", d->ident);
231 }
232 return 0;
233}
234
Peter Chubb1ef03892011-12-05 16:53:53 +0300235static int __init set_kbd_reboot(const struct dmi_system_id *d)
236{
237 if (reboot_type != BOOT_KBD) {
238 reboot_type = BOOT_KBD;
239 printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
240 }
241 return 0;
242}
243
Michael D Labriola144d1022012-02-01 10:06:34 -0500244/*
245 * This is a single dmi_table handling all reboot quirks. Note that
Michael D Labriola57b16592012-02-01 10:05:00 -0500246 * REBOOT_BIOS is only available for 32bit
247 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248static struct dmi_system_id __initdata reboot_dmi_table[] = {
Michael D Labriola57b16592012-02-01 10:05:00 -0500249#ifdef CONFIG_X86_32
Tim Gardnerb9e82af2007-06-01 00:46:40 -0700250 { /* Handle problems with rebooting on Dell E520's */
251 .callback = set_bios_reboot,
252 .ident = "Dell E520",
253 .matches = {
254 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
255 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
256 },
257 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 { /* Handle problems with rebooting on Dell 1300's */
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700259 .callback = set_bios_reboot,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 .ident = "Dell PowerEdge 1300",
261 .matches = {
262 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
263 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
264 },
265 },
266 { /* Handle problems with rebooting on Dell 300's */
267 .callback = set_bios_reboot,
268 .ident = "Dell PowerEdge 300",
269 .matches = {
270 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
271 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
272 },
273 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500274 { /* Handle problems with rebooting on Dell Optiplex 745's SFF */
James Jarvisdf2edcf2007-07-21 17:11:11 +0200275 .callback = set_bios_reboot,
276 .ident = "Dell OptiPlex 745",
277 .matches = {
278 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
279 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
James Jarvisdf2edcf2007-07-21 17:11:11 +0200280 },
281 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500282 { /* Handle problems with rebooting on Dell Optiplex 745's DFF */
Coleman Kanefc115bf2008-03-04 15:05:41 -0800283 .callback = set_bios_reboot,
284 .ident = "Dell OptiPlex 745",
285 .matches = {
286 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
287 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
288 DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
289 },
290 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500291 { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
Heinz-Ado Arnoldsfc1c89252008-03-12 16:27:56 +0100292 .callback = set_bios_reboot,
293 .ident = "Dell OptiPlex 745",
294 .matches = {
295 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
296 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
297 DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
298 },
299 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500300 { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
Steve Conklin093bac12008-11-14 00:55:51 -0600301 .callback = set_bios_reboot,
302 .ident = "Dell OptiPlex 330",
303 .matches = {
304 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
305 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
306 DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
307 },
308 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500309 { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
Jean Delvare4a4aca62009-06-05 12:02:38 +0200310 .callback = set_bios_reboot,
311 .ident = "Dell OptiPlex 360",
312 .matches = {
313 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
314 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
315 DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
316 },
317 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500318 { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
Leann Ogasawara35ea63d2010-01-27 15:29:18 -0800319 .callback = set_bios_reboot,
320 .ident = "Dell OptiPlex 760",
321 .matches = {
322 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
323 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
324 DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
325 },
326 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 { /* Handle problems with rebooting on Dell 2400's */
328 .callback = set_bios_reboot,
329 .ident = "Dell PowerEdge 2400",
330 .matches = {
331 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
332 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
333 },
334 },
Ingo Molnarfab3b582008-07-17 13:50:15 +0200335 { /* Handle problems with rebooting on Dell T5400's */
336 .callback = set_bios_reboot,
337 .ident = "Dell Precision T5400",
338 .matches = {
339 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
340 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
341 },
342 },
Thomas Backlund890ffed2010-06-19 16:32:25 +0300343 { /* Handle problems with rebooting on Dell T7400's */
344 .callback = set_bios_reboot,
345 .ident = "Dell Precision T7400",
346 .matches = {
347 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
348 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
349 },
350 },
Ben Collins766c3f92006-01-06 00:12:20 -0800351 { /* Handle problems with rebooting on HP laptops */
Thierry Vignaudd91b14c2005-11-29 19:34:35 -0800352 .callback = set_bios_reboot,
Ben Collins766c3f92006-01-06 00:12:20 -0800353 .ident = "HP Compaq Laptop",
Thierry Vignaudd91b14c2005-11-29 19:34:35 -0800354 .matches = {
355 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
Ben Collins766c3f92006-01-06 00:12:20 -0800356 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
Thierry Vignaudd91b14c2005-11-29 19:34:35 -0800357 },
358 },
Leann Ogasawaradd4124a2009-03-04 11:53:00 -0800359 { /* Handle problems with rebooting on Dell XPS710 */
360 .callback = set_bios_reboot,
361 .ident = "Dell XPS710",
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
364 DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
365 },
366 },
Alan Coxc5da9a22009-03-26 20:45:28 +0000367 { /* Handle problems with rebooting on Dell DXP061 */
368 .callback = set_bios_reboot,
369 .ident = "Dell DXP061",
370 .matches = {
371 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
372 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
373 },
374 },
Zhang Rui88dff492009-05-22 11:35:50 +0800375 { /* Handle problems with rebooting on Sony VGN-Z540N */
376 .callback = set_bios_reboot,
377 .ident = "Sony VGN-Z540N",
378 .matches = {
379 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
380 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
381 },
382 },
Denis Turischev77f32df2009-07-20 18:48:17 +0300383 { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */
384 .callback = set_bios_reboot,
385 .ident = "CompuLab SBC-FITPC2",
386 .matches = {
387 DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
388 DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
389 },
390 },
Michael D Labriola144d1022012-02-01 10:06:34 -0500391 { /* Handle problems with rebooting on ASUS P4S800 */
Leann Ogasawara4832ddd2009-12-04 15:42:22 -0800392 .callback = set_bios_reboot,
393 .ident = "ASUS P4S800",
394 .matches = {
395 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
396 DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
397 },
398 },
Michael D Labriola57b16592012-02-01 10:05:00 -0500399#endif /* CONFIG_X86_32 */
400
Michael D Labriola144d1022012-02-01 10:06:34 -0500401 { /* Handle reboot issue on Acer Aspire one */
Peter Chubb1ef03892011-12-05 16:53:53 +0300402 .callback = set_kbd_reboot,
Peter Chubbb49c78d2011-07-06 10:56:30 +1000403 .ident = "Acer Aspire One A110",
404 .matches = {
405 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
406 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
407 },
408 },
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900409 { /* Handle problems with rebooting on Apple MacBook5 */
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000410 .callback = set_pci_reboot,
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900411 .ident = "Apple MacBook5",
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000412 .matches = {
413 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900414 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000415 },
416 },
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900417 { /* Handle problems with rebooting on Apple MacBookPro5 */
Ozan Çağlayan498cdbf2009-08-04 19:39:31 +0300418 .callback = set_pci_reboot,
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900419 .ident = "Apple MacBookPro5",
Ozan Çağlayan498cdbf2009-08-04 19:39:31 +0300420 .matches = {
421 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
Shunichi Fuji3e03bbe2009-08-11 03:34:40 +0900422 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
Ozan Çağlayan498cdbf2009-08-04 19:39:31 +0300423 },
424 },
Gottfried Haider05154752009-11-02 11:51:11 +0100425 { /* Handle problems with rebooting on Apple Macmini3,1 */
426 .callback = set_pci_reboot,
427 .ident = "Apple Macmini3,1",
428 .matches = {
429 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
430 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
431 },
432 },
Justin P. Mattock0a832322010-02-16 15:17:29 -0800433 { /* Handle problems with rebooting on the iMac9,1. */
434 .callback = set_pci_reboot,
435 .ident = "Apple iMac9,1",
436 .matches = {
437 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
438 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
439 },
440 },
Maxime Ripard3628c3f2011-06-28 15:57:31 +0200441 { /* Handle problems with rebooting on the Latitude E6320. */
442 .callback = set_pci_reboot,
443 .ident = "Dell Latitude E6320",
444 .matches = {
445 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
446 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
447 },
448 },
Daniel J Bluemanb7798d22011-05-13 09:04:59 +0800449 { /* Handle problems with rebooting on the Latitude E5420. */
450 .callback = set_pci_reboot,
451 .ident = "Dell Latitude E5420",
452 .matches = {
453 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
454 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
455 },
456 },
H. Peter Anvina5368772011-07-21 11:22:21 -0700457 { /* Handle problems with rebooting on the Latitude E6420. */
458 .callback = set_pci_reboot,
459 .ident = "Dell Latitude E6420",
460 .matches = {
461 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
462 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
463 },
464 },
Rafael J. Wysocki6be30bb2011-11-16 00:19:51 +0100465 { /* Handle problems with rebooting on the OptiPlex 990. */
466 .callback = set_pci_reboot,
467 .ident = "Dell OptiPlex 990",
468 .matches = {
469 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
470 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
471 },
472 },
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000473 { }
474};
475
Michael D Labriola57b16592012-02-01 10:05:00 -0500476static int __init reboot_init(void)
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000477{
Michael D Labriola144d1022012-02-01 10:06:34 -0500478 /*
479 * Only do the DMI check if reboot_type hasn't been overridden
Michael D Labriola59556332012-01-29 14:17:22 -0500480 * on the command line
481 */
Michael D Labriola144d1022012-02-01 10:06:34 -0500482 if (reboot_default)
Michael D Labriola57b16592012-02-01 10:05:00 -0500483 dmi_check_system(reboot_dmi_table);
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000484 return 0;
485}
Michael D Labriola57b16592012-02-01 10:05:00 -0500486core_initcall(reboot_init);
Paul Mackerras6c6c51e2009-08-03 22:47:32 +1000487
Miguel Boton4d022e32008-01-30 13:32:51 +0100488static inline void kb_wait(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Miguel Boton4d022e32008-01-30 13:32:51 +0100490 int i;
491
Alan Coxc84d6af82008-01-30 13:33:25 +0100492 for (i = 0; i < 0x10000; i++) {
493 if ((inb(0x64) & 0x02) == 0)
Miguel Boton4d022e32008-01-30 13:32:51 +0100494 break;
Alan Coxc84d6af82008-01-30 13:33:25 +0100495 udelay(2);
496 }
Miguel Boton4d022e32008-01-30 13:32:51 +0100497}
498
Don Zickus9c48f1c2011-09-30 15:06:21 -0400499static void vmxoff_nmi(int cpu, struct pt_regs *regs)
Eduardo Habkostd1767202008-11-17 19:03:24 -0200500{
501 cpu_emergency_vmxoff();
502}
503
Michael D Labriola144d1022012-02-01 10:06:34 -0500504/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
Eduardo Habkostd1767202008-11-17 19:03:24 -0200505static void emergency_vmx_disable_all(void)
506{
507 /* Just make sure we won't change CPUs while doing this */
508 local_irq_disable();
509
Michael D Labriola144d1022012-02-01 10:06:34 -0500510 /*
511 * We need to disable VMX on all CPUs before rebooting, otherwise
Eduardo Habkostd1767202008-11-17 19:03:24 -0200512 * we risk hanging up the machine, because the CPU ignore INIT
513 * signals when VMX is enabled.
514 *
515 * We can't take any locks and we may be on an inconsistent
516 * state, so we use NMIs as IPIs to tell the other CPUs to disable
517 * VMX and halt.
518 *
519 * For safety, we will avoid running the nmi_shootdown_cpus()
520 * stuff unnecessarily, but we don't have a way to check
521 * if other CPUs have VMX enabled. So we will call it only if the
522 * CPU we are running on has VMX enabled.
523 *
524 * We will miss cases where VMX is not enabled on all CPUs. This
525 * shouldn't do much harm because KVM always enable VMX on all
526 * CPUs anyway. But we can miss it on the small window where KVM
527 * is still enabling VMX.
528 */
529 if (cpu_has_vmx() && cpu_vmx_enabled()) {
Michael D Labriola144d1022012-02-01 10:06:34 -0500530 /* Disable VMX on this CPU. */
Eduardo Habkostd1767202008-11-17 19:03:24 -0200531 cpu_vmxoff();
532
533 /* Halt and disable VMX on the other CPUs */
534 nmi_shootdown_cpus(vmxoff_nmi);
535
536 }
537}
538
539
Ingo Molnar7432d142008-03-06 18:29:43 +0100540void __attribute__((weak)) mach_reboot_fixups(void)
541{
542}
543
Matthew Garrett660e34c2011-04-04 13:55:05 -0400544/*
545 * Windows compatible x86 hardware expects the following on reboot:
546 *
547 * 1) If the FADT has the ACPI reboot register flag set, try it
548 * 2) If still alive, write to the keyboard controller
549 * 3) If still alive, write to the ACPI reboot register again
550 * 4) If still alive, write to the keyboard controller again
551 *
552 * If the machine is still alive at this stage, it gives up. We default to
553 * following the same pattern, except that if we're still alive after (4) we'll
554 * try to force a triple fault and then cycle between hitting the keyboard
555 * controller and doing that
556 */
Jody Belka416e2d62008-02-12 23:37:48 +0000557static void native_machine_emergency_restart(void)
Miguel Boton4d022e32008-01-30 13:32:51 +0100558{
559 int i;
Matthew Garrett660e34c2011-04-04 13:55:05 -0400560 int attempt = 0;
561 int orig_reboot_type = reboot_type;
Miguel Boton4d022e32008-01-30 13:32:51 +0100562
Eduardo Habkostd1767202008-11-17 19:03:24 -0200563 if (reboot_emergency)
564 emergency_vmx_disable_all();
565
Joseph Cihula840c2ba2009-06-30 19:31:02 -0700566 tboot_shutdown(TB_SHUTDOWN_REBOOT);
567
Miguel Boton4d022e32008-01-30 13:32:51 +0100568 /* Tell the BIOS if we want cold or warm reboot */
569 *((unsigned short *)__va(0x472)) = reboot_mode;
570
571 for (;;) {
572 /* Could also try the reset bit in the Hammer NB */
573 switch (reboot_type) {
574 case BOOT_KBD:
Michael D Labriola144d1022012-02-01 10:06:34 -0500575 mach_reboot_fixups(); /* For board specific fixups */
Ingo Molnar7432d142008-03-06 18:29:43 +0100576
Miguel Boton4d022e32008-01-30 13:32:51 +0100577 for (i = 0; i < 10; i++) {
578 kb_wait();
579 udelay(50);
Michael D Labriola144d1022012-02-01 10:06:34 -0500580 outb(0xfe, 0x64); /* Pulse reset low */
Miguel Boton4d022e32008-01-30 13:32:51 +0100581 udelay(50);
582 }
Matthew Garrett660e34c2011-04-04 13:55:05 -0400583 if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
584 attempt = 1;
585 reboot_type = BOOT_ACPI;
586 } else {
587 reboot_type = BOOT_TRIPLE;
588 }
589 break;
Miguel Boton4d022e32008-01-30 13:32:51 +0100590
591 case BOOT_TRIPLE:
Jan Beulichebdd5612008-05-12 15:43:38 +0200592 load_idt(&no_idt);
Miguel Boton4d022e32008-01-30 13:32:51 +0100593 __asm__ __volatile__("int3");
594
595 reboot_type = BOOT_KBD;
596 break;
597
598#ifdef CONFIG_X86_32
599 case BOOT_BIOS:
H. Peter Anvin3d35ac32011-02-14 18:36:03 -0800600 machine_real_restart(MRR_BIOS);
Miguel Boton4d022e32008-01-30 13:32:51 +0100601
602 reboot_type = BOOT_KBD;
603 break;
604#endif
605
606 case BOOT_ACPI:
607 acpi_reboot();
608 reboot_type = BOOT_KBD;
609 break;
610
Miguel Boton4d022e32008-01-30 13:32:51 +0100611 case BOOT_EFI:
612 if (efi_enabled)
H. Peter Anvin14d7ca52008-11-11 16:19:48 -0800613 efi.reset_system(reboot_mode ?
614 EFI_RESET_WARM :
615 EFI_RESET_COLD,
Miguel Boton4d022e32008-01-30 13:32:51 +0100616 EFI_SUCCESS, 0, NULL);
H. Peter Anvinb47b9282008-11-24 00:50:09 -0800617 reboot_type = BOOT_KBD;
H. Peter Anvin14d7ca52008-11-11 16:19:48 -0800618 break;
Miguel Boton4d022e32008-01-30 13:32:51 +0100619
H. Peter Anvin14d7ca52008-11-11 16:19:48 -0800620 case BOOT_CF9:
621 port_cf9_safe = true;
Michael D Labriola144d1022012-02-01 10:06:34 -0500622 /* Fall through */
H. Peter Anvin14d7ca52008-11-11 16:19:48 -0800623
624 case BOOT_CF9_COND:
625 if (port_cf9_safe) {
626 u8 cf9 = inb(0xcf9) & ~6;
627 outb(cf9|2, 0xcf9); /* Request hard reset */
628 udelay(50);
629 outb(cf9|6, 0xcf9); /* Actually do the reset */
630 udelay(50);
631 }
Miguel Boton4d022e32008-01-30 13:32:51 +0100632 reboot_type = BOOT_KBD;
633 break;
634 }
635 }
636}
637
Glauber Costa3c62c622008-03-17 16:08:39 -0300638void native_machine_shutdown(void)
Miguel Boton4d022e32008-01-30 13:32:51 +0100639{
640 /* Stop the cpus and apics */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700643 /* The boot cpu is always logical cpu 0 */
Mike Travis65c01182008-07-15 14:14:30 -0700644 int reboot_cpu_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Miguel Boton4d022e32008-01-30 13:32:51 +0100646#ifdef CONFIG_X86_32
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700647 /* See if there has been given a command line override */
Mike Travis96289372008-12-31 18:08:46 -0800648 if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
Mike Travis0bc3cc02008-07-24 18:21:31 -0700649 cpu_online(reboot_cpu))
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700650 reboot_cpu_id = reboot_cpu;
Miguel Boton4d022e32008-01-30 13:32:51 +0100651#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Miguel Boton4d022e32008-01-30 13:32:51 +0100653 /* Make certain the cpu I'm about to reboot on is online */
Mike Travis0bc3cc02008-07-24 18:21:31 -0700654 if (!cpu_online(reboot_cpu_id))
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700655 reboot_cpu_id = smp_processor_id();
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700656
657 /* Make certain I only run on the appropriate processor */
Mike Travis96289372008-12-31 18:08:46 -0800658 set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700659
Michael D Labriola144d1022012-02-01 10:06:34 -0500660 /*
661 * O.K Now that I'm on the appropriate processor,
Miguel Boton4d022e32008-01-30 13:32:51 +0100662 * stop all of the others.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 */
Alok Kataria76fac072010-10-11 14:37:08 -0700664 stop_other_cpus();
Miguel Boton4d022e32008-01-30 13:32:51 +0100665#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 lapic_shutdown();
668
669#ifdef CONFIG_X86_IO_APIC
670 disable_IO_APIC();
671#endif
Miguel Boton4d022e32008-01-30 13:32:51 +0100672
OGAWA Hirofumic86c7fb2007-12-03 17:17:10 +0100673#ifdef CONFIG_HPET_TIMER
674 hpet_disable();
675#endif
Miguel Boton4d022e32008-01-30 13:32:51 +0100676
677#ifdef CONFIG_X86_64
FUJITA Tomonori338bac52009-10-27 16:34:44 +0900678 x86_platform.iommu_shutdown();
Miguel Boton4d022e32008-01-30 13:32:51 +0100679#endif
Eric W. Biedermandd2a1302005-06-25 14:57:55 -0700680}
681
Eduardo Habkostd1767202008-11-17 19:03:24 -0200682static void __machine_emergency_restart(int emergency)
683{
684 reboot_emergency = emergency;
685 machine_ops.emergency_restart();
686}
687
Jody Belka416e2d62008-02-12 23:37:48 +0000688static void native_machine_restart(char *__unused)
Jeremy Fitzhardinge973efae2007-05-02 19:27:06 +0200689{
Miguel Boton4d022e32008-01-30 13:32:51 +0100690 printk("machine restart\n");
Jeremy Fitzhardinge973efae2007-05-02 19:27:06 +0200691
Miguel Boton4d022e32008-01-30 13:32:51 +0100692 if (!reboot_force)
Eric W. Biederman6e3fbee2006-01-11 22:43:12 +0100693 machine_shutdown();
Eduardo Habkostd1767202008-11-17 19:03:24 -0200694 __machine_emergency_restart(0);
Jeremy Fitzhardinge07f33312007-05-02 19:27:11 +0200695}
696
Jody Belka416e2d62008-02-12 23:37:48 +0000697static void native_machine_halt(void)
Jeremy Fitzhardinge07f33312007-05-02 19:27:11 +0200698{
Michael D Labriola144d1022012-02-01 10:06:34 -0500699 /* Stop other cpus and apics */
Ivan Vecerad3ec5ca2008-11-11 14:33:44 +0100700 machine_shutdown();
701
Joseph Cihula840c2ba2009-06-30 19:31:02 -0700702 tboot_shutdown(TB_SHUTDOWN_HALT);
703
Ivan Vecerad3ec5ca2008-11-11 14:33:44 +0100704 stop_this_cpu(NULL);
Jeremy Fitzhardinge07f33312007-05-02 19:27:11 +0200705}
Miguel Boton4d022e32008-01-30 13:32:51 +0100706
Jody Belka416e2d62008-02-12 23:37:48 +0000707static void native_machine_power_off(void)
Miguel Boton4d022e32008-01-30 13:32:51 +0100708{
709 if (pm_power_off) {
710 if (!reboot_force)
711 machine_shutdown();
712 pm_power_off();
713 }
Michael D Labriola144d1022012-02-01 10:06:34 -0500714 /* A fallback in case there is no PM info available */
Joseph Cihula840c2ba2009-06-30 19:31:02 -0700715 tboot_shutdown(TB_SHUTDOWN_HALT);
Miguel Boton4d022e32008-01-30 13:32:51 +0100716}
717
718struct machine_ops machine_ops = {
Jody Belka416e2d62008-02-12 23:37:48 +0000719 .power_off = native_machine_power_off,
720 .shutdown = native_machine_shutdown,
721 .emergency_restart = native_machine_emergency_restart,
722 .restart = native_machine_restart,
Glauber Costaed23dc62008-03-17 16:08:38 -0300723 .halt = native_machine_halt,
724#ifdef CONFIG_KEXEC
725 .crash_shutdown = native_machine_crash_shutdown,
726#endif
Miguel Boton4d022e32008-01-30 13:32:51 +0100727};
Jody Belka416e2d62008-02-12 23:37:48 +0000728
729void machine_power_off(void)
730{
731 machine_ops.power_off();
732}
733
734void machine_shutdown(void)
735{
736 machine_ops.shutdown();
737}
738
739void machine_emergency_restart(void)
740{
Eduardo Habkostd1767202008-11-17 19:03:24 -0200741 __machine_emergency_restart(1);
Jody Belka416e2d62008-02-12 23:37:48 +0000742}
743
744void machine_restart(char *cmd)
745{
746 machine_ops.restart(cmd);
747}
748
749void machine_halt(void)
750{
751 machine_ops.halt();
752}
753
Glauber Costaed23dc62008-03-17 16:08:38 -0300754#ifdef CONFIG_KEXEC
755void machine_crash_shutdown(struct pt_regs *regs)
756{
757 machine_ops.crash_shutdown(regs);
758}
759#endif
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200760
761
Eduardo Habkostbb8dd272008-11-12 11:34:43 -0200762#if defined(CONFIG_SMP)
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200763
764/* This keeps a track of which one is crashing cpu. */
765static int crashing_cpu;
766static nmi_shootdown_cb shootdown_callback;
767
768static atomic_t waiting_for_crash_ipi;
769
Don Zickus9c48f1c2011-09-30 15:06:21 -0400770static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200771{
772 int cpu;
773
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200774 cpu = raw_smp_processor_id();
775
Michael D Labriola144d1022012-02-01 10:06:34 -0500776 /*
777 * Don't do anything if this handler is invoked on crashing cpu.
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200778 * Otherwise, system will completely hang. Crashing cpu can get
779 * an NMI if system was initially booted with nmi_watchdog parameter.
780 */
781 if (cpu == crashing_cpu)
Don Zickus9c48f1c2011-09-30 15:06:21 -0400782 return NMI_HANDLED;
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200783 local_irq_disable();
784
Don Zickus9c48f1c2011-09-30 15:06:21 -0400785 shootdown_callback(cpu, regs);
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200786
787 atomic_dec(&waiting_for_crash_ipi);
788 /* Assume hlt works */
789 halt();
790 for (;;)
791 cpu_relax();
792
Don Zickus9c48f1c2011-09-30 15:06:21 -0400793 return NMI_HANDLED;
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200794}
795
796static void smp_send_nmi_allbutself(void)
797{
Ingo Molnardac5f412009-01-28 15:42:24 +0100798 apic->send_IPI_allbutself(NMI_VECTOR);
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200799}
800
Michael D Labriola144d1022012-02-01 10:06:34 -0500801/*
802 * Halt all other CPUs, calling the specified function on each of them
Eduardo Habkostbb8dd272008-11-12 11:34:43 -0200803 *
804 * This function can be used to halt all other CPUs on crash
805 * or emergency reboot time. The function passed as parameter
806 * will be called inside a NMI handler on all CPUs.
807 */
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200808void nmi_shootdown_cpus(nmi_shootdown_cb callback)
809{
810 unsigned long msecs;
Eduardo Habkostc415b3d2008-11-12 11:34:44 -0200811 local_irq_disable();
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200812
Michael D Labriola144d1022012-02-01 10:06:34 -0500813 /* Make a note of crashing cpu. Will be used in NMI callback. */
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200814 crashing_cpu = safe_smp_processor_id();
815
816 shootdown_callback = callback;
817
818 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
819 /* Would it be better to replace the trap vector here? */
Don Zickus9c48f1c2011-09-30 15:06:21 -0400820 if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
821 NMI_FLAG_FIRST, "crash"))
Michael D Labriola144d1022012-02-01 10:06:34 -0500822 return; /* Return what? */
823 /*
824 * Ensure the new callback function is set before sending
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200825 * out the NMI
826 */
827 wmb();
828
829 smp_send_nmi_allbutself();
830
831 msecs = 1000; /* Wait at most a second for the other cpus to stop */
832 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
833 mdelay(1);
834 msecs--;
835 }
836
837 /* Leave the nmi callback set */
838}
Eduardo Habkostbb8dd272008-11-12 11:34:43 -0200839#else /* !CONFIG_SMP */
840void nmi_shootdown_cpus(nmi_shootdown_cb callback)
841{
842 /* No other CPUs to shoot down */
843}
Eduardo Habkost2ddded22008-11-12 11:34:42 -0200844#endif