diff options
Diffstat (limited to 'arch/x86/kernel/reboot_64.c')
-rw-r--r-- | arch/x86/kernel/reboot_64.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/arch/x86/kernel/reboot_64.c b/arch/x86/kernel/reboot_64.c new file mode 100644 index 000000000000..368db2b9c5ac --- /dev/null +++ b/arch/x86/kernel/reboot_64.c | |||
@@ -0,0 +1,171 @@ | |||
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 <asm/io.h> | ||
13 | #include <asm/delay.h> | ||
14 | #include <asm/hw_irq.h> | ||
15 | #include <asm/system.h> | ||
16 | #include <asm/pgtable.h> | ||
17 | #include <asm/tlbflush.h> | ||
18 | #include <asm/apic.h> | ||
19 | #include <asm/iommu.h> | ||
20 | |||
21 | /* | ||
22 | * Power off function, if any | ||
23 | */ | ||
24 | void (*pm_power_off)(void); | ||
25 | EXPORT_SYMBOL(pm_power_off); | ||
26 | |||
27 | static long no_idt[3]; | ||
28 | static enum { | ||
29 | BOOT_TRIPLE = 't', | ||
30 | BOOT_KBD = 'k' | ||
31 | } reboot_type = BOOT_KBD; | ||
32 | static int reboot_mode = 0; | ||
33 | int reboot_force; | ||
34 | |||
35 | /* reboot=t[riple] | k[bd] [, [w]arm | [c]old] | ||
36 | warm Don't set the cold reboot flag | ||
37 | cold Set the cold reboot flag | ||
38 | triple Force a triple fault (init) | ||
39 | kbd Use the keyboard controller. cold reset (default) | ||
40 | force Avoid anything that could hang. | ||
41 | */ | ||
42 | static int __init reboot_setup(char *str) | ||
43 | { | ||
44 | for (;;) { | ||
45 | switch (*str) { | ||
46 | case 'w': | ||
47 | reboot_mode = 0x1234; | ||
48 | break; | ||
49 | |||
50 | case 'c': | ||
51 | reboot_mode = 0; | ||
52 | break; | ||
53 | |||
54 | case 't': | ||
55 | case 'b': | ||
56 | case 'k': | ||
57 | reboot_type = *str; | ||
58 | break; | ||
59 | case 'f': | ||
60 | reboot_force = 1; | ||
61 | break; | ||
62 | } | ||
63 | if((str = strchr(str,',')) != NULL) | ||
64 | str++; | ||
65 | else | ||
66 | break; | ||
67 | } | ||
68 | return 1; | ||
69 | } | ||
70 | |||
71 | __setup("reboot=", reboot_setup); | ||
72 | |||
73 | static inline void kb_wait(void) | ||
74 | { | ||
75 | int i; | ||
76 | |||
77 | for (i=0; i<0x10000; i++) | ||
78 | if ((inb_p(0x64) & 0x02) == 0) | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | void machine_shutdown(void) | ||
83 | { | ||
84 | unsigned long flags; | ||
85 | |||
86 | /* Stop the cpus and apics */ | ||
87 | #ifdef CONFIG_SMP | ||
88 | int reboot_cpu_id; | ||
89 | |||
90 | /* The boot cpu is always logical cpu 0 */ | ||
91 | reboot_cpu_id = 0; | ||
92 | |||
93 | /* Make certain the cpu I'm about to reboot on is online */ | ||
94 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { | ||
95 | reboot_cpu_id = smp_processor_id(); | ||
96 | } | ||
97 | |||
98 | /* Make certain I only run on the appropriate processor */ | ||
99 | set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); | ||
100 | |||
101 | /* O.K Now that I'm on the appropriate processor, | ||
102 | * stop all of the others. | ||
103 | */ | ||
104 | smp_send_stop(); | ||
105 | #endif | ||
106 | |||
107 | local_irq_save(flags); | ||
108 | |||
109 | #ifndef CONFIG_SMP | ||
110 | disable_local_APIC(); | ||
111 | #endif | ||
112 | |||
113 | disable_IO_APIC(); | ||
114 | |||
115 | local_irq_restore(flags); | ||
116 | |||
117 | pci_iommu_shutdown(); | ||
118 | } | ||
119 | |||
120 | void machine_emergency_restart(void) | ||
121 | { | ||
122 | int i; | ||
123 | |||
124 | /* Tell the BIOS if we want cold or warm reboot */ | ||
125 | *((unsigned short *)__va(0x472)) = reboot_mode; | ||
126 | |||
127 | for (;;) { | ||
128 | /* Could also try the reset bit in the Hammer NB */ | ||
129 | switch (reboot_type) { | ||
130 | case BOOT_KBD: | ||
131 | for (i=0; i<10; i++) { | ||
132 | kb_wait(); | ||
133 | udelay(50); | ||
134 | outb(0xfe,0x64); /* pulse reset low */ | ||
135 | udelay(50); | ||
136 | } | ||
137 | |||
138 | case BOOT_TRIPLE: | ||
139 | __asm__ __volatile__("lidt (%0)": :"r" (&no_idt)); | ||
140 | __asm__ __volatile__("int3"); | ||
141 | |||
142 | reboot_type = BOOT_KBD; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | void machine_restart(char * __unused) | ||
149 | { | ||
150 | printk("machine restart\n"); | ||
151 | |||
152 | if (!reboot_force) { | ||
153 | machine_shutdown(); | ||
154 | } | ||
155 | machine_emergency_restart(); | ||
156 | } | ||
157 | |||
158 | void machine_halt(void) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | void machine_power_off(void) | ||
163 | { | ||
164 | if (pm_power_off) { | ||
165 | if (!reboot_force) { | ||
166 | machine_shutdown(); | ||
167 | } | ||
168 | pm_power_off(); | ||
169 | } | ||
170 | } | ||
171 | |||