aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMiguel Boton <mboton.lkml@gmail.com>2008-01-30 07:32:51 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:32:51 -0500
commit4d022e35fd7e07c522c7863fee6f07e53cf3fc14 (patch)
treeaae7e2633bd2808d812df652e00eb3e2ff4745d1 /arch
parent71c339116a216b181fc5e203ef51a033fe5e38cf (diff)
x86: reboot_{32|64}.c unification
reboot_{32|64}.c unification patch. This patch unifies the code from the reboot_32.c and reboot_64.c files. It has been tested in computers with X86_32 and X86_64 kernels and it looks like all reboot modes work fine (EFI restart system hasn't been tested yet). Probably I made some mistakes (like I usually do) so I hope we can identify and fix them soon. Signed-off-by: Miguel Boton <mboton@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/Makefile4
-rw-r--r--arch/x86/kernel/reboot.c (renamed from arch/x86/kernel/reboot_32.c)280
-rw-r--r--arch/x86/kernel/reboot_64.c191
3 files changed, 160 insertions, 315 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0903bbf0ca4d..b40bed4baa77 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -30,8 +30,8 @@ obj-y += step.o
30obj-$(CONFIG_STACKTRACE) += stacktrace.o 30obj-$(CONFIG_STACKTRACE) += stacktrace.o
31obj-y += cpu/ 31obj-y += cpu/
32obj-y += acpi/ 32obj-y += acpi/
33obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o 33obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
34obj-$(CONFIG_X86_64) += reboot_64.o 34obj-$(CONFIG_X86_64) += reboot.o
35obj-$(CONFIG_MCA) += mca_32.o 35obj-$(CONFIG_MCA) += mca_32.o
36obj-$(CONFIG_X86_MSR) += msr.o 36obj-$(CONFIG_X86_MSR) += msr.o
37obj-$(CONFIG_X86_CPUID) += cpuid.o 37obj-$(CONFIG_X86_CPUID) += cpuid.o
diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot.c
index c3376fae639d..5b32f0b4d133 100644
--- a/arch/x86/kernel/reboot_32.c
+++ b/arch/x86/kernel/reboot.c
@@ -1,64 +1,94 @@
1#include <linux/mm.h>
2#include <linux/module.h> 1#include <linux/module.h>
3#include <linux/delay.h>
4#include <linux/init.h> 2#include <linux/init.h>
5#include <linux/interrupt.h>
6#include <linux/mc146818rtc.h>
7#include <linux/efi.h>
8#include <linux/dmi.h>
9#include <linux/ctype.h>
10#include <linux/pm.h>
11#include <linux/reboot.h> 3#include <linux/reboot.h>
12#include <asm/uaccess.h> 4#include <linux/init.h>
5#include <linux/pm.h>
6#include <linux/efi.h>
7#include <acpi/reboot.h>
8#include <asm/io.h>
13#include <asm/apic.h> 9#include <asm/apic.h>
14#include <asm/hpet.h>
15#include <asm/desc.h> 10#include <asm/desc.h>
16#include "mach_reboot.h" 11#include <asm/hpet.h>
17#include <asm/reboot_fixups.h> 12#include <asm/reboot_fixups.h>
18#include <asm/reboot.h> 13#include <asm/reboot.h>
19 14
15#ifdef CONFIG_X86_32
16# include <linux/dmi.h>
17# include <linux/ctype.h>
18# include <linux/mc146818rtc.h>
19# include <asm/pgtable.h>
20#else
21# include <asm/iommu.h>
22#endif
23
20/* 24/*
21 * Power off function, if any 25 * Power off function, if any
22 */ 26 */
23void (*pm_power_off)(void); 27void (*pm_power_off)(void);
24EXPORT_SYMBOL(pm_power_off); 28EXPORT_SYMBOL(pm_power_off);
25 29
30static long no_idt[3];
26static int reboot_mode; 31static int reboot_mode;
27static int reboot_thru_bios; 32enum reboot_type reboot_type = BOOT_KBD;
33int reboot_force;
28 34
29#ifdef CONFIG_SMP 35#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
30static int reboot_cpu = -1; 36static int reboot_cpu = -1;
31#endif 37#endif
38
39/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
40 warm Don't set the cold reboot flag
41 cold Set the cold reboot flag
42 bios Reboot by jumping through the BIOS (only for X86_32)
43 smp Reboot by executing reset on BSP or other CPU (only for X86_32)
44 triple Force a triple fault (init)
45 kbd Use the keyboard controller. cold reset (default)
46 acpi Use the RESET_REG in the FADT
47 efi Use efi reset_system runtime service
48 force Avoid anything that could hang.
49 */
32static int __init reboot_setup(char *str) 50static int __init reboot_setup(char *str)
33{ 51{
34 while(1) { 52 for (;;) {
35 switch (*str) { 53 switch (*str) {
36 case 'w': /* "warm" reboot (no memory testing etc) */ 54 case 'w':
37 reboot_mode = 0x1234; 55 reboot_mode = 0x1234;
38 break; 56 break;
39 case 'c': /* "cold" reboot (with memory testing etc) */ 57
40 reboot_mode = 0x0; 58 case 'c':
41 break; 59 reboot_mode = 0;
42 case 'b': /* "bios" reboot by jumping through the BIOS */
43 reboot_thru_bios = 1;
44 break;
45 case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
46 reboot_thru_bios = 0;
47 break; 60 break;
61
62#ifdef CONFIG_X86_32
48#ifdef CONFIG_SMP 63#ifdef CONFIG_SMP
49 case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ 64 case 's':
50 if (isdigit(*(str+1))) { 65 if (isdigit(*(str+1))) {
51 reboot_cpu = (int) (*(str+1) - '0'); 66 reboot_cpu = (int) (*(str+1) - '0');
52 if (isdigit(*(str+2))) 67 if (isdigit(*(str+2)))
53 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); 68 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
54 } 69 }
55 /* we will leave sorting out the final value 70 /* we will leave sorting out the final value
56 when we are ready to reboot, since we might not 71 when we are ready to reboot, since we might not
57 have set up boot_cpu_id or smp_num_cpu */ 72 have set up boot_cpu_id or smp_num_cpu */
58 break; 73 break;
74#endif /* CONFIG_SMP */
75
76 case 'b':
59#endif 77#endif
78 case 'a':
79 case 'k':
80 case 't':
81 case 'e':
82 reboot_type = *str;
83 break;
84
85 case 'f':
86 reboot_force = 1;
87 break;
60 } 88 }
61 if((str = strchr(str,',')) != NULL) 89
90 str = strchr(str, ',');
91 if (str)
62 str++; 92 str++;
63 else 93 else
64 break; 94 break;
@@ -68,18 +98,21 @@ static int __init reboot_setup(char *str)
68 98
69__setup("reboot=", reboot_setup); 99__setup("reboot=", reboot_setup);
70 100
101
102#ifdef CONFIG_X86_32
71/* 103/*
72 * Reboot options and system auto-detection code provided by 104 * Reboot options and system auto-detection code provided by
73 * Dell Inc. so their systems "just work". :-) 105 * Dell Inc. so their systems "just work". :-)
74 */ 106 */
75 107
76/* 108/*
77 * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. 109 * Some machines require the "reboot=b" commandline option,
110 * this quirk makes that automatic.
78 */ 111 */
79static int __init set_bios_reboot(const struct dmi_system_id *d) 112static int __init set_bios_reboot(const struct dmi_system_id *d)
80{ 113{
81 if (!reboot_thru_bios) { 114 if (reboot_type != BOOT_BIOS) {
82 reboot_thru_bios = 1; 115 reboot_type = BOOT_BIOS;
83 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); 116 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
84 } 117 }
85 return 0; 118 return 0;
@@ -143,7 +176,6 @@ static int __init reboot_init(void)
143 dmi_check_system(reboot_dmi_table); 176 dmi_check_system(reboot_dmi_table);
144 return 0; 177 return 0;
145} 178}
146
147core_initcall(reboot_init); 179core_initcall(reboot_init);
148 180
149/* The following code and data reboots the machine by switching to real 181/* The following code and data reboots the machine by switching to real
@@ -152,7 +184,6 @@ core_initcall(reboot_init);
152 controller to pulse the CPU reset line, which is more thorough, but 184 controller to pulse the CPU reset line, which is more thorough, but
153 doesn't work with at least one type of 486 motherboard. It is easy 185 doesn't work with at least one type of 486 motherboard. It is easy
154 to stop this code working; hence the copious comments. */ 186 to stop this code working; hence the copious comments. */
155
156static unsigned long long 187static unsigned long long
157real_mode_gdt_entries [3] = 188real_mode_gdt_entries [3] =
158{ 189{
@@ -163,9 +194,7 @@ real_mode_gdt_entries [3] =
163 194
164static struct desc_ptr 195static struct desc_ptr
165real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, 196real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
166real_mode_idt = { 0x3ff, 0 }, 197real_mode_idt = { 0x3ff, 0 };
167no_idt = { 0, 0 };
168
169 198
170/* This is 16-bit protected mode code to disable paging and the cache, 199/* This is 16-bit protected mode code to disable paging and the cache,
171 switch to real mode and jump to the BIOS reset code. 200 switch to real mode and jump to the BIOS reset code.
@@ -185,7 +214,6 @@ no_idt = { 0, 0 };
185 214
186 More could be done here to set up the registers as if a CPU reset had 215 More could be done here to set up the registers as if a CPU reset had
187 occurred; hopefully real BIOSs don't assume much. */ 216 occurred; hopefully real BIOSs don't assume much. */
188
189static unsigned char real_mode_switch [] = 217static unsigned char real_mode_switch [] =
190{ 218{
191 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ 219 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */
@@ -223,7 +251,6 @@ void machine_real_restart(unsigned char *code, int length)
223 `outb_p' is needed instead of just `outb'. Use it to be on the 251 `outb_p' is needed instead of just `outb'. Use it to be on the
224 safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 252 safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
225 */ 253 */
226
227 spin_lock(&rtc_lock); 254 spin_lock(&rtc_lock);
228 CMOS_WRITE(0x00, 0x8f); 255 CMOS_WRITE(0x00, 0x8f);
229 spin_unlock(&rtc_lock); 256 spin_unlock(&rtc_lock);
@@ -231,9 +258,8 @@ void machine_real_restart(unsigned char *code, int length)
231 /* Remap the kernel at virtual address zero, as well as offset zero 258 /* Remap the kernel at virtual address zero, as well as offset zero
232 from the kernel segment. This assumes the kernel segment starts at 259 from the kernel segment. This assumes the kernel segment starts at
233 virtual address PAGE_OFFSET. */ 260 virtual address PAGE_OFFSET. */
234 261 memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
235 memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, 262 sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
236 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
237 263
238 /* 264 /*
239 * Use `swapper_pg_dir' as our page directory. 265 * Use `swapper_pg_dir' as our page directory.
@@ -245,7 +271,6 @@ void machine_real_restart(unsigned char *code, int length)
245 boot)". This seems like a fairly standard thing that gets set by 271 boot)". This seems like a fairly standard thing that gets set by
246 REBOOT.COM programs, and the previous reset routine did this 272 REBOOT.COM programs, and the previous reset routine did this
247 too. */ 273 too. */
248
249 *((unsigned short *)0x472) = reboot_mode; 274 *((unsigned short *)0x472) = reboot_mode;
250 275
251 /* For the switch to real mode, copy some code to low memory. It has 276 /* For the switch to real mode, copy some code to low memory. It has
@@ -253,19 +278,16 @@ void machine_real_restart(unsigned char *code, int length)
253 has to have the same physical and virtual address, because it turns 278 has to have the same physical and virtual address, because it turns
254 off paging. Copy it near the end of the first page, out of the way 279 off paging. Copy it near the end of the first page, out of the way
255 of BIOS variables. */ 280 of BIOS variables. */
256 281 memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100),
257 memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
258 real_mode_switch, sizeof (real_mode_switch)); 282 real_mode_switch, sizeof (real_mode_switch));
259 memcpy ((void *) (0x1000 - 100), code, length); 283 memcpy((void *)(0x1000 - 100), code, length);
260 284
261 /* Set up the IDT for real mode. */ 285 /* Set up the IDT for real mode. */
262
263 load_idt(&real_mode_idt); 286 load_idt(&real_mode_idt);
264 287
265 /* Set up a GDT from which we can load segment descriptors for real 288 /* Set up a GDT from which we can load segment descriptors for real
266 mode. The GDT is not used in real mode; it is just needed here to 289 mode. The GDT is not used in real mode; it is just needed here to
267 prepare the descriptors. */ 290 prepare the descriptors. */
268
269 load_gdt(&real_mode_gdt); 291 load_gdt(&real_mode_gdt);
270 292
271 /* Load the data segment registers, and thus the descriptors ready for 293 /* Load the data segment registers, and thus the descriptors ready for
@@ -273,7 +295,6 @@ void machine_real_restart(unsigned char *code, int length)
273 selector value being loaded here. This is so that the segment 295 selector value being loaded here. This is so that the segment
274 registers don't have to be reloaded after switching to real mode: 296 registers don't have to be reloaded after switching to real mode:
275 the values are consistent for real mode operation already. */ 297 the values are consistent for real mode operation already. */
276
277 __asm__ __volatile__ ("movl $0x0010,%%eax\n" 298 __asm__ __volatile__ ("movl $0x0010,%%eax\n"
278 "\tmovl %%eax,%%ds\n" 299 "\tmovl %%eax,%%ds\n"
279 "\tmovl %%eax,%%es\n" 300 "\tmovl %%eax,%%es\n"
@@ -284,130 +305,145 @@ void machine_real_restart(unsigned char *code, int length)
284 /* Jump to the 16-bit code that we copied earlier. It disables paging 305 /* Jump to the 16-bit code that we copied earlier. It disables paging
285 and the cache, switches to real mode, and jumps to the BIOS reset 306 and the cache, switches to real mode, and jumps to the BIOS reset
286 entry point. */ 307 entry point. */
287
288 __asm__ __volatile__ ("ljmp $0x0008,%0" 308 __asm__ __volatile__ ("ljmp $0x0008,%0"
289 : 309 :
290 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); 310 : "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100)));
291} 311}
292#ifdef CONFIG_APM_MODULE 312#ifdef CONFIG_APM_MODULE
293EXPORT_SYMBOL(machine_real_restart); 313EXPORT_SYMBOL(machine_real_restart);
294#endif 314#endif
295 315
296static void native_machine_shutdown(void) 316#endif /* CONFIG_X86_32 */
317
318static inline void kb_wait(void)
319{
320 int i;
321
322 for (i = 0; i < 0x10000; i++)
323 if ((inb_p(0x64) & 0x02) == 0)
324 break;
325}
326
327void machine_emergency_restart(void)
297{ 328{
329 int i;
330
331 /* Tell the BIOS if we want cold or warm reboot */
332 *((unsigned short *)__va(0x472)) = reboot_mode;
333
334 for (;;) {
335 /* Could also try the reset bit in the Hammer NB */
336 switch (reboot_type) {
337 case BOOT_KBD:
338 for (i = 0; i < 10; i++) {
339 kb_wait();
340 udelay(50);
341 outb(0xfe, 0x64); /* pulse reset low */
342 udelay(50);
343 }
344
345 case BOOT_TRIPLE:
346 load_idt((const struct desc_ptr *)&no_idt);
347 __asm__ __volatile__("int3");
348
349 reboot_type = BOOT_KBD;
350 break;
351
352#ifdef CONFIG_X86_32
353 case BOOT_BIOS:
354 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
355
356 reboot_type = BOOT_KBD;
357 break;
358#endif
359
360 case BOOT_ACPI:
361 acpi_reboot();
362 reboot_type = BOOT_KBD;
363 break;
364
365
366 case BOOT_EFI:
367 if (efi_enabled)
368 efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
369 EFI_SUCCESS, 0, NULL);
370
371 reboot_type = BOOT_KBD;
372 break;
373 }
374 }
375}
376
377void machine_shutdown(void)
378{
379 /* Stop the cpus and apics */
298#ifdef CONFIG_SMP 380#ifdef CONFIG_SMP
299 int reboot_cpu_id; 381 int reboot_cpu_id;
300 382
301 /* The boot cpu is always logical cpu 0 */ 383 /* The boot cpu is always logical cpu 0 */
302 reboot_cpu_id = 0; 384 reboot_cpu_id = 0;
303 385
386#ifdef CONFIG_X86_32
304 /* See if there has been given a command line override */ 387 /* See if there has been given a command line override */
305 if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && 388 if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
306 cpu_isset(reboot_cpu, cpu_online_map)) { 389 cpu_isset(reboot_cpu, cpu_online_map))
307 reboot_cpu_id = reboot_cpu; 390 reboot_cpu_id = reboot_cpu;
308 } 391#endif
309 392
310 /* Make certain the cpu I'm rebooting on is online */ 393 /* Make certain the cpu I'm about to reboot on is online */
311 if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { 394 if (!cpu_isset(reboot_cpu_id, cpu_online_map))
312 reboot_cpu_id = smp_processor_id(); 395 reboot_cpu_id = smp_processor_id();
313 }
314 396
315 /* Make certain I only run on the appropriate processor */ 397 /* Make certain I only run on the appropriate processor */
316 set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); 398 set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
317 399
318 /* O.K. Now that I'm on the appropriate processor, stop 400 /* O.K Now that I'm on the appropriate processor,
319 * all of the others, and disable their local APICs. 401 * stop all of the others.
320 */ 402 */
321
322 smp_send_stop(); 403 smp_send_stop();
323#endif /* CONFIG_SMP */ 404#endif
324 405
325 lapic_shutdown(); 406 lapic_shutdown();
326 407
327#ifdef CONFIG_X86_IO_APIC 408#ifdef CONFIG_X86_IO_APIC
328 disable_IO_APIC(); 409 disable_IO_APIC();
329#endif 410#endif
411
330#ifdef CONFIG_HPET_TIMER 412#ifdef CONFIG_HPET_TIMER
331 hpet_disable(); 413 hpet_disable();
332#endif 414#endif
333}
334 415
335void __attribute__((weak)) mach_reboot_fixups(void) 416#ifdef CONFIG_X86_64
336{ 417 pci_iommu_shutdown();
418#endif
337} 419}
338 420
339static void native_machine_emergency_restart(void) 421void machine_restart(char *__unused)
340{ 422{
341 if (!reboot_thru_bios) { 423 printk("machine restart\n");
342 if (efi_enabled) {
343 efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
344 load_idt(&no_idt);
345 __asm__ __volatile__("int3");
346 }
347 /* rebooting needs to touch the page at absolute addr 0 */
348 *((unsigned short *)__va(0x472)) = reboot_mode;
349 for (;;) {
350 mach_reboot_fixups(); /* for board specific fixups */
351 mach_reboot();
352 /* That didn't work - force a triple fault.. */
353 load_idt(&no_idt);
354 __asm__ __volatile__("int3");
355 }
356 }
357 if (efi_enabled)
358 efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
359
360 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
361}
362 424
363static void native_machine_restart(char * __unused) 425 if (!reboot_force)
364{ 426 machine_shutdown();
365 machine_shutdown();
366 machine_emergency_restart(); 427 machine_emergency_restart();
367} 428}
368 429
369static void native_machine_halt(void) 430void machine_halt(void)
370{ 431{
371} 432}
372 433
373static void native_machine_power_off(void) 434void machine_power_off(void)
374{ 435{
375 if (pm_power_off) { 436 if (pm_power_off) {
376 machine_shutdown(); 437 if (!reboot_force)
438 machine_shutdown();
377 pm_power_off(); 439 pm_power_off();
378 } 440 }
379} 441}
380 442
381
382struct machine_ops machine_ops = { 443struct machine_ops machine_ops = {
383 .power_off = native_machine_power_off, 444 .power_off = machine_power_off,
384 .shutdown = native_machine_shutdown, 445 .shutdown = machine_shutdown,
385 .emergency_restart = native_machine_emergency_restart, 446 .emergency_restart = machine_emergency_restart,
386 .restart = native_machine_restart, 447 .restart = machine_restart,
387 .halt = native_machine_halt, 448 .halt = machine_halt
388}; 449};
389
390void machine_power_off(void)
391{
392 machine_ops.power_off();
393}
394
395void machine_shutdown(void)
396{
397 machine_ops.shutdown();
398}
399
400void machine_emergency_restart(void)
401{
402 machine_ops.emergency_restart();
403}
404
405void machine_restart(char *cmd)
406{
407 machine_ops.restart(cmd);
408}
409
410void machine_halt(void)
411{
412 machine_ops.halt();
413}
diff --git a/arch/x86/kernel/reboot_64.c b/arch/x86/kernel/reboot_64.c
deleted file mode 100644
index d6bdf93ffca9..000000000000
--- a/arch/x86/kernel/reboot_64.c
+++ /dev/null
@@ -1,191 +0,0 @@
1/* Various gunk just to reboot the machine. */
2#include <linux/module.h>
3#include <linux/reboot.h>
4#include <linux/init.h>
5#include <linux/smp.h>
6#include <linux/kernel.h>
7#include <linux/ctype.h>
8#include <linux/string.h>
9#include <linux/pm.h>
10#include <linux/kdebug.h>
11#include <linux/sched.h>
12#include <linux/efi.h>
13#include <acpi/reboot.h>
14#include <asm/io.h>
15#include <asm/delay.h>
16#include <asm/desc.h>
17#include <asm/hw_irq.h>
18#include <asm/system.h>
19#include <asm/pgtable.h>
20#include <asm/tlbflush.h>
21#include <asm/apic.h>
22#include <asm/hpet.h>
23#include <asm/gart.h>
24
25/*
26 * Power off function, if any
27 */
28void (*pm_power_off)(void);
29EXPORT_SYMBOL(pm_power_off);
30
31static long no_idt[3];
32enum reboot_type reboot_type = BOOT_KBD;
33static int reboot_mode = 0;
34int reboot_force;
35
36/* reboot=t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
37 warm Don't set the cold reboot flag
38 cold Set the cold reboot flag
39 triple Force a triple fault (init)
40 kbd Use the keyboard controller. cold reset (default)
41 acpi Use the RESET_REG in the FADT
42 efi Use efi reset_system runtime service
43 force Avoid anything that could hang.
44 */
45static int __init reboot_setup(char *str)
46{
47 for (;;) {
48 switch (*str) {
49 case 'w':
50 reboot_mode = 0x1234;
51 break;
52
53 case 'c':
54 reboot_mode = 0;
55 break;
56
57 case 't':
58 case 'a':
59 case 'b':
60 case 'k':
61 case 'e':
62 reboot_type = *str;
63 break;
64 case 'f':
65 reboot_force = 1;
66 break;
67 }
68 if((str = strchr(str,',')) != NULL)
69 str++;
70 else
71 break;
72 }
73 return 1;
74}
75
76__setup("reboot=", reboot_setup);
77
78static inline void kb_wait(void)
79{
80 int i;
81
82 for (i=0; i<0x10000; i++)
83 if ((inb_p(0x64) & 0x02) == 0)
84 break;
85}
86
87void machine_shutdown(void)
88{
89 unsigned long flags;
90
91 /* Stop the cpus and apics */
92#ifdef CONFIG_SMP
93 int reboot_cpu_id;
94
95 /* The boot cpu is always logical cpu 0 */
96 reboot_cpu_id = 0;
97
98 /* Make certain the cpu I'm about to reboot on is online */
99 if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
100 reboot_cpu_id = smp_processor_id();
101 }
102
103 /* Make certain I only run on the appropriate processor */
104 set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
105
106 /* O.K Now that I'm on the appropriate processor,
107 * stop all of the others.
108 */
109 smp_send_stop();
110#endif
111
112 local_irq_save(flags);
113
114#ifndef CONFIG_SMP
115 disable_local_APIC();
116#endif
117
118 disable_IO_APIC();
119
120#ifdef CONFIG_HPET_TIMER
121 hpet_disable();
122#endif
123 local_irq_restore(flags);
124
125 pci_iommu_shutdown();
126}
127
128void machine_emergency_restart(void)
129{
130 int i;
131
132 /* Tell the BIOS if we want cold or warm reboot */
133 *((unsigned short *)__va(0x472)) = reboot_mode;
134
135 for (;;) {
136 /* Could also try the reset bit in the Hammer NB */
137 switch (reboot_type) {
138 case BOOT_KBD:
139 for (i=0; i<10; i++) {
140 kb_wait();
141 udelay(50);
142 outb(0xfe,0x64); /* pulse reset low */
143 udelay(50);
144 }
145
146 case BOOT_TRIPLE:
147 load_idt((const struct desc_ptr *)&no_idt);
148 __asm__ __volatile__("int3");
149
150 reboot_type = BOOT_KBD;
151 break;
152
153 case BOOT_ACPI:
154 acpi_reboot();
155 reboot_type = BOOT_KBD;
156 break;
157
158 case BOOT_EFI:
159 if (efi_enabled)
160 efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
161 EFI_SUCCESS, 0, NULL);
162 reboot_type = BOOT_KBD;
163 break;
164 }
165 }
166}
167
168void machine_restart(char * __unused)
169{
170 printk("machine restart\n");
171
172 if (!reboot_force) {
173 machine_shutdown();
174 }
175 machine_emergency_restart();
176}
177
178void machine_halt(void)
179{
180}
181
182void machine_power_off(void)
183{
184 if (pm_power_off) {
185 if (!reboot_force) {
186 machine_shutdown();
187 }
188 pm_power_off();
189 }
190}
191