diff options
| -rw-r--r-- | arch/i386/kernel/reboot.c | 82 |
1 files changed, 26 insertions, 56 deletions
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index db912209a8d3..b3e584849961 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c | |||
| @@ -26,7 +26,6 @@ static int reboot_mode; | |||
| 26 | static int reboot_thru_bios; | 26 | static int reboot_thru_bios; |
| 27 | 27 | ||
| 28 | #ifdef CONFIG_SMP | 28 | #ifdef CONFIG_SMP |
| 29 | int reboot_smp = 0; | ||
| 30 | static int reboot_cpu = -1; | 29 | static int reboot_cpu = -1; |
| 31 | /* shamelessly grabbed from lib/vsprintf.c for readability */ | 30 | /* shamelessly grabbed from lib/vsprintf.c for readability */ |
| 32 | #define is_digit(c) ((c) >= '0' && (c) <= '9') | 31 | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
| @@ -49,7 +48,6 @@ static int __init reboot_setup(char *str) | |||
| 49 | break; | 48 | break; |
| 50 | #ifdef CONFIG_SMP | 49 | #ifdef CONFIG_SMP |
| 51 | 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*/ |
| 52 | reboot_smp = 1; | ||
| 53 | if (is_digit(*(str+1))) { | 51 | if (is_digit(*(str+1))) { |
| 54 | reboot_cpu = (int) (*(str+1) - '0'); | 52 | reboot_cpu = (int) (*(str+1) - '0'); |
| 55 | if (is_digit(*(str+2))) | 53 | if (is_digit(*(str+2))) |
| @@ -88,33 +86,9 @@ static int __init set_bios_reboot(struct dmi_system_id *d) | |||
| 88 | return 0; | 86 | return 0; |
| 89 | } | 87 | } |
| 90 | 88 | ||
| 91 | /* | ||
| 92 | * Some machines require the "reboot=s" commandline option, this quirk makes that automatic. | ||
| 93 | */ | ||
| 94 | static int __init set_smp_reboot(struct dmi_system_id *d) | ||
| 95 | { | ||
| 96 | #ifdef CONFIG_SMP | ||
| 97 | if (!reboot_smp) { | ||
| 98 | reboot_smp = 1; | ||
| 99 | printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident); | ||
| 100 | } | ||
| 101 | #endif | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic. | ||
| 107 | */ | ||
| 108 | static int __init set_smp_bios_reboot(struct dmi_system_id *d) | ||
| 109 | { | ||
| 110 | set_smp_reboot(d); | ||
| 111 | set_bios_reboot(d); | ||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 89 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
| 116 | { /* Handle problems with rebooting on Dell 1300's */ | 90 | { /* Handle problems with rebooting on Dell 1300's */ |
| 117 | .callback = set_smp_bios_reboot, | 91 | .callback = set_bios_reboot, |
| 118 | .ident = "Dell PowerEdge 1300", | 92 | .ident = "Dell PowerEdge 1300", |
| 119 | .matches = { | 93 | .matches = { |
| 120 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), | 94 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
| @@ -301,41 +275,32 @@ void machine_real_restart(unsigned char *code, int length) | |||
| 301 | EXPORT_SYMBOL(machine_real_restart); | 275 | EXPORT_SYMBOL(machine_real_restart); |
| 302 | #endif | 276 | #endif |
| 303 | 277 | ||
| 304 | void machine_restart(char * __unused) | 278 | void machine_shutdown(void) |
| 305 | { | 279 | { |
| 306 | #ifdef CONFIG_SMP | 280 | #ifdef CONFIG_SMP |
| 307 | int cpuid; | 281 | int reboot_cpu_id; |
| 308 | 282 | ||
| 309 | cpuid = GET_APIC_ID(apic_read(APIC_ID)); | 283 | /* The boot cpu is always logical cpu 0 */ |
| 310 | 284 | reboot_cpu_id = 0; | |
| 311 | if (reboot_smp) { | 285 | |
| 312 | 286 | /* See if there has been given a command line override */ | |
| 313 | /* check to see if reboot_cpu is valid | 287 | if ((reboot_cpu_id != -1) && (reboot_cpu < NR_CPUS) && |
| 314 | if its not, default to the BSP */ | 288 | cpu_isset(reboot_cpu, cpu_online_map)) { |
| 315 | if ((reboot_cpu == -1) || | 289 | reboot_cpu_id = reboot_cpu; |
| 316 | (reboot_cpu > (NR_CPUS -1)) || | ||
| 317 | !physid_isset(cpuid, phys_cpu_present_map)) | ||
| 318 | reboot_cpu = boot_cpu_physical_apicid; | ||
| 319 | |||
| 320 | reboot_smp = 0; /* use this as a flag to only go through this once*/ | ||
| 321 | /* re-run this function on the other CPUs | ||
| 322 | it will fall though this section since we have | ||
| 323 | cleared reboot_smp, and do the reboot if it is the | ||
| 324 | correct CPU, otherwise it halts. */ | ||
| 325 | if (reboot_cpu != cpuid) | ||
| 326 | smp_call_function((void *)machine_restart , NULL, 1, 0); | ||
| 327 | } | 290 | } |
| 328 | 291 | ||
| 329 | /* if reboot_cpu is still -1, then we want a tradional reboot, | 292 | /* Make certain the cpu I'm rebooting on is online */ |
| 330 | and if we are not running on the reboot_cpu,, halt */ | 293 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { |
| 331 | if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) { | 294 | reboot_cpu_id = smp_processor_id(); |
| 332 | for (;;) | ||
| 333 | __asm__ __volatile__ ("hlt"); | ||
| 334 | } | 295 | } |
| 335 | /* | 296 | |
| 336 | * Stop all CPUs and turn off local APICs and the IO-APIC, so | 297 | /* Make certain I only run on the appropriate processor */ |
| 337 | * 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. | ||
| 338 | */ | 302 | */ |
| 303 | |||
| 339 | smp_send_stop(); | 304 | smp_send_stop(); |
| 340 | #endif /* CONFIG_SMP */ | 305 | #endif /* CONFIG_SMP */ |
| 341 | 306 | ||
| @@ -344,6 +309,11 @@ void machine_restart(char * __unused) | |||
| 344 | #ifdef CONFIG_X86_IO_APIC | 309 | #ifdef CONFIG_X86_IO_APIC |
| 345 | disable_IO_APIC(); | 310 | disable_IO_APIC(); |
| 346 | #endif | 311 | #endif |
| 312 | } | ||
| 313 | |||
| 314 | void machine_restart(char * __unused) | ||
| 315 | { | ||
| 316 | machine_shutdown(); | ||
| 347 | 317 | ||
| 348 | if (!reboot_thru_bios) { | 318 | if (!reboot_thru_bios) { |
| 349 | if (efi_enabled) { | 319 | if (efi_enabled) { |
