diff options
Diffstat (limited to 'arch/i386/kernel/reboot.c')
-rw-r--r-- | arch/i386/kernel/reboot.c | 98 |
1 files changed, 35 insertions, 63 deletions
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 6dc27eb70ee7..c71fef31dc47 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/arch/i386/kernel/reboot.c | 2 | * linux/arch/i386/kernel/reboot.c |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/config.h> | ||
5 | #include <linux/mm.h> | 6 | #include <linux/mm.h> |
6 | #include <linux/module.h> | 7 | #include <linux/module.h> |
7 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
@@ -19,12 +20,12 @@ | |||
19 | * Power off function, if any | 20 | * Power off function, if any |
20 | */ | 21 | */ |
21 | void (*pm_power_off)(void); | 22 | void (*pm_power_off)(void); |
23 | EXPORT_SYMBOL(pm_power_off); | ||
22 | 24 | ||
23 | static int reboot_mode; | 25 | static int reboot_mode; |
24 | static int reboot_thru_bios; | 26 | static int reboot_thru_bios; |
25 | 27 | ||
26 | #ifdef CONFIG_SMP | 28 | #ifdef CONFIG_SMP |
27 | int reboot_smp = 0; | ||
28 | static int reboot_cpu = -1; | 29 | static int reboot_cpu = -1; |
29 | /* shamelessly grabbed from lib/vsprintf.c for readability */ | 30 | /* shamelessly grabbed from lib/vsprintf.c for readability */ |
30 | #define is_digit(c) ((c) >= '0' && (c) <= '9') | 31 | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
@@ -47,7 +48,6 @@ static int __init reboot_setup(char *str) | |||
47 | break; | 48 | break; |
48 | #ifdef CONFIG_SMP | 49 | #ifdef CONFIG_SMP |
49 | case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ | 50 | case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ |
50 | reboot_smp = 1; | ||
51 | if (is_digit(*(str+1))) { | 51 | if (is_digit(*(str+1))) { |
52 | reboot_cpu = (int) (*(str+1) - '0'); | 52 | reboot_cpu = (int) (*(str+1) - '0'); |
53 | if (is_digit(*(str+2))) | 53 | if (is_digit(*(str+2))) |
@@ -86,33 +86,9 @@ static int __init set_bios_reboot(struct dmi_system_id *d) | |||
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
88 | 88 | ||
89 | /* | ||
90 | * Some machines require the "reboot=s" commandline option, this quirk makes that automatic. | ||
91 | */ | ||
92 | static int __init set_smp_reboot(struct dmi_system_id *d) | ||
93 | { | ||
94 | #ifdef CONFIG_SMP | ||
95 | if (!reboot_smp) { | ||
96 | reboot_smp = 1; | ||
97 | printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident); | ||
98 | } | ||
99 | #endif | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic. | ||
105 | */ | ||
106 | static int __init set_smp_bios_reboot(struct dmi_system_id *d) | ||
107 | { | ||
108 | set_smp_reboot(d); | ||
109 | set_bios_reboot(d); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 89 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
114 | { /* Handle problems with rebooting on Dell 1300's */ | 90 | { /* Handle problems with rebooting on Dell 1300's */ |
115 | .callback = set_smp_bios_reboot, | 91 | .callback = set_bios_reboot, |
116 | .ident = "Dell PowerEdge 1300", | 92 | .ident = "Dell PowerEdge 1300", |
117 | .matches = { | 93 | .matches = { |
118 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), | 94 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
@@ -295,42 +271,36 @@ void machine_real_restart(unsigned char *code, int length) | |||
295 | : | 271 | : |
296 | : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); | 272 | : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); |
297 | } | 273 | } |
274 | #ifdef CONFIG_APM_MODULE | ||
275 | EXPORT_SYMBOL(machine_real_restart); | ||
276 | #endif | ||
298 | 277 | ||
299 | void machine_restart(char * __unused) | 278 | void machine_shutdown(void) |
300 | { | 279 | { |
301 | #ifdef CONFIG_SMP | 280 | #ifdef CONFIG_SMP |
302 | int cpuid; | 281 | int reboot_cpu_id; |
303 | 282 | ||
304 | cpuid = GET_APIC_ID(apic_read(APIC_ID)); | 283 | /* The boot cpu is always logical cpu 0 */ |
305 | 284 | reboot_cpu_id = 0; | |
306 | if (reboot_smp) { | 285 | |
307 | 286 | /* See if there has been given a command line override */ | |
308 | /* check to see if reboot_cpu is valid | 287 | if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && |
309 | if its not, default to the BSP */ | 288 | cpu_isset(reboot_cpu, cpu_online_map)) { |
310 | if ((reboot_cpu == -1) || | 289 | reboot_cpu_id = reboot_cpu; |
311 | (reboot_cpu > (NR_CPUS -1)) || | ||
312 | !physid_isset(cpuid, phys_cpu_present_map)) | ||
313 | reboot_cpu = boot_cpu_physical_apicid; | ||
314 | |||
315 | reboot_smp = 0; /* use this as a flag to only go through this once*/ | ||
316 | /* re-run this function on the other CPUs | ||
317 | it will fall though this section since we have | ||
318 | cleared reboot_smp, and do the reboot if it is the | ||
319 | correct CPU, otherwise it halts. */ | ||
320 | if (reboot_cpu != cpuid) | ||
321 | smp_call_function((void *)machine_restart , NULL, 1, 0); | ||
322 | } | 290 | } |
323 | 291 | ||
324 | /* if reboot_cpu is still -1, then we want a tradional reboot, | 292 | /* Make certain the cpu I'm rebooting on is online */ |
325 | and if we are not running on the reboot_cpu,, halt */ | 293 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { |
326 | if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) { | 294 | reboot_cpu_id = smp_processor_id(); |
327 | for (;;) | ||
328 | __asm__ __volatile__ ("hlt"); | ||
329 | } | 295 | } |
330 | /* | 296 | |
331 | * Stop all CPUs and turn off local APICs and the IO-APIC, so | 297 | /* Make certain I only run on the appropriate processor */ |
332 | * other OSs see a clean IRQ state. | 298 | set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); |
299 | |||
300 | /* O.K. Now that I'm on the appropriate processor, stop | ||
301 | * all of the others, and disable their local APICs. | ||
333 | */ | 302 | */ |
303 | |||
334 | smp_send_stop(); | 304 | smp_send_stop(); |
335 | #endif /* CONFIG_SMP */ | 305 | #endif /* CONFIG_SMP */ |
336 | 306 | ||
@@ -339,7 +309,10 @@ void machine_restart(char * __unused) | |||
339 | #ifdef CONFIG_X86_IO_APIC | 309 | #ifdef CONFIG_X86_IO_APIC |
340 | disable_IO_APIC(); | 310 | disable_IO_APIC(); |
341 | #endif | 311 | #endif |
312 | } | ||
342 | 313 | ||
314 | void machine_emergency_restart(void) | ||
315 | { | ||
343 | if (!reboot_thru_bios) { | 316 | if (!reboot_thru_bios) { |
344 | if (efi_enabled) { | 317 | if (efi_enabled) { |
345 | efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); | 318 | efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); |
@@ -362,23 +335,22 @@ void machine_restart(char * __unused) | |||
362 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); | 335 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); |
363 | } | 336 | } |
364 | 337 | ||
365 | EXPORT_SYMBOL(machine_restart); | 338 | void machine_restart(char * __unused) |
339 | { | ||
340 | machine_shutdown(); | ||
341 | machine_emergency_restart(); | ||
342 | } | ||
366 | 343 | ||
367 | void machine_halt(void) | 344 | void machine_halt(void) |
368 | { | 345 | { |
369 | } | 346 | } |
370 | 347 | ||
371 | EXPORT_SYMBOL(machine_halt); | ||
372 | |||
373 | void machine_power_off(void) | 348 | void machine_power_off(void) |
374 | { | 349 | { |
375 | lapic_shutdown(); | 350 | machine_shutdown(); |
376 | 351 | ||
377 | if (efi_enabled) | ||
378 | efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); | ||
379 | if (pm_power_off) | 352 | if (pm_power_off) |
380 | pm_power_off(); | 353 | pm_power_off(); |
381 | } | 354 | } |
382 | 355 | ||
383 | EXPORT_SYMBOL(machine_power_off); | ||
384 | 356 | ||