diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 14:31:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 14:31:22 -0400 |
commit | 2335a8366f63a5191b5a2b3c5a05d90fe814654c (patch) | |
tree | 20b2da7333a5003a22466895338e7734aa40f784 | |
parent | 44bc40e1489622234169786b0ad5a1f4a01e1090 (diff) | |
parent | 3aac27aba79b7c52e709ef6de0f7d8139caedc01 (diff) |
Merge branch 'x86-reboot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 reboot changes from Ingo Molnar:
"The biggest change is a gentler method of rebooting/stopping via IRQs
first and then via NMIs. There are several cleanups in the tree as
well."
* 'x86-reboot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/reboot: Update nonmi_ipi parameter
x86/reboot: Use NMI to assist in shutting down if IRQ fails
Revert "x86, reboot: Use NMI instead of REBOOT_VECTOR to stop cpus"
x86/reboot: Clean up coding style
x86/reboot: Reduce to a single DMI table for reboot quirks
-rw-r--r-- | arch/x86/kernel/reboot.c | 277 | ||||
-rw-r--r-- | arch/x86/kernel/smp.c | 100 |
2 files changed, 185 insertions, 192 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d840e69a853c..77215c23fba1 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -39,7 +39,8 @@ static int reboot_mode; | |||
39 | enum reboot_type reboot_type = BOOT_ACPI; | 39 | enum reboot_type reboot_type = BOOT_ACPI; |
40 | int reboot_force; | 40 | int reboot_force; |
41 | 41 | ||
42 | /* This variable is used privately to keep track of whether or not | 42 | /* |
43 | * This variable is used privately to keep track of whether or not | ||
43 | * reboot_type is still set to its default value (i.e., reboot= hasn't | 44 | * reboot_type is still set to its default value (i.e., reboot= hasn't |
44 | * been set on the command line). This is needed so that we can | 45 | * been set on the command line). This is needed so that we can |
45 | * suppress DMI scanning for reboot quirks. Without it, it's | 46 | * suppress DMI scanning for reboot quirks. Without it, it's |
@@ -51,7 +52,8 @@ static int reboot_default = 1; | |||
51 | static int reboot_cpu = -1; | 52 | static int reboot_cpu = -1; |
52 | #endif | 53 | #endif |
53 | 54 | ||
54 | /* This is set if we need to go through the 'emergency' path. | 55 | /* |
56 | * This is set if we need to go through the 'emergency' path. | ||
55 | * When machine_emergency_restart() is called, we may be on | 57 | * When machine_emergency_restart() is called, we may be on |
56 | * an inconsistent state and won't be able to do a clean cleanup | 58 | * an inconsistent state and won't be able to do a clean cleanup |
57 | */ | 59 | */ |
@@ -60,22 +62,24 @@ static int reboot_emergency; | |||
60 | /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ | 62 | /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ |
61 | bool port_cf9_safe = false; | 63 | bool port_cf9_safe = false; |
62 | 64 | ||
63 | /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] | 65 | /* |
64 | warm Don't set the cold reboot flag | 66 | * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] |
65 | cold Set the cold reboot flag | 67 | * warm Don't set the cold reboot flag |
66 | bios Reboot by jumping through the BIOS (only for X86_32) | 68 | * cold Set the cold reboot flag |
67 | smp Reboot by executing reset on BSP or other CPU (only for X86_32) | 69 | * bios Reboot by jumping through the BIOS (only for X86_32) |
68 | triple Force a triple fault (init) | 70 | * smp Reboot by executing reset on BSP or other CPU (only for X86_32) |
69 | kbd Use the keyboard controller. cold reset (default) | 71 | * triple Force a triple fault (init) |
70 | acpi Use the RESET_REG in the FADT | 72 | * kbd Use the keyboard controller. cold reset (default) |
71 | efi Use efi reset_system runtime service | 73 | * acpi Use the RESET_REG in the FADT |
72 | pci Use the so-called "PCI reset register", CF9 | 74 | * efi Use efi reset_system runtime service |
73 | force Avoid anything that could hang. | 75 | * pci Use the so-called "PCI reset register", CF9 |
76 | * force Avoid anything that could hang. | ||
74 | */ | 77 | */ |
75 | static int __init reboot_setup(char *str) | 78 | static int __init reboot_setup(char *str) |
76 | { | 79 | { |
77 | for (;;) { | 80 | for (;;) { |
78 | /* Having anything passed on the command line via | 81 | /* |
82 | * Having anything passed on the command line via | ||
79 | * reboot= will cause us to disable DMI checking | 83 | * reboot= will cause us to disable DMI checking |
80 | * below. | 84 | * below. |
81 | */ | 85 | */ |
@@ -98,9 +102,11 @@ static int __init reboot_setup(char *str) | |||
98 | if (isdigit(*(str+2))) | 102 | if (isdigit(*(str+2))) |
99 | reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); | 103 | reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); |
100 | } | 104 | } |
101 | /* we will leave sorting out the final value | 105 | /* |
102 | when we are ready to reboot, since we might not | 106 | * We will leave sorting out the final value |
103 | have detected BSP APIC ID or smp_num_cpu */ | 107 | * when we are ready to reboot, since we might not |
108 | * have detected BSP APIC ID or smp_num_cpu | ||
109 | */ | ||
104 | break; | 110 | break; |
105 | #endif /* CONFIG_SMP */ | 111 | #endif /* CONFIG_SMP */ |
106 | 112 | ||
@@ -150,6 +156,82 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) | |||
150 | return 0; | 156 | return 0; |
151 | } | 157 | } |
152 | 158 | ||
159 | extern const unsigned char machine_real_restart_asm[]; | ||
160 | extern const u64 machine_real_restart_gdt[3]; | ||
161 | |||
162 | void 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 | |||
171 | /* | ||
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.) | ||
180 | */ | ||
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 | |||
190 | /* | ||
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. */ | ||
196 | *((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 | ||
217 | EXPORT_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 | */ | ||
225 | static 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 | |||
153 | static int __init set_kbd_reboot(const struct dmi_system_id *d) | 235 | static int __init set_kbd_reboot(const struct dmi_system_id *d) |
154 | { | 236 | { |
155 | if (reboot_type != BOOT_KBD) { | 237 | if (reboot_type != BOOT_KBD) { |
@@ -159,7 +241,12 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d) | |||
159 | return 0; | 241 | return 0; |
160 | } | 242 | } |
161 | 243 | ||
244 | /* | ||
245 | * This is a single dmi_table handling all reboot quirks. Note that | ||
246 | * REBOOT_BIOS is only available for 32bit | ||
247 | */ | ||
162 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 248 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
249 | #ifdef CONFIG_X86_32 | ||
163 | { /* Handle problems with rebooting on Dell E520's */ | 250 | { /* Handle problems with rebooting on Dell E520's */ |
164 | .callback = set_bios_reboot, | 251 | .callback = set_bios_reboot, |
165 | .ident = "Dell E520", | 252 | .ident = "Dell E520", |
@@ -184,7 +271,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
184 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), | 271 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), |
185 | }, | 272 | }, |
186 | }, | 273 | }, |
187 | { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/ | 274 | { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ |
188 | .callback = set_bios_reboot, | 275 | .callback = set_bios_reboot, |
189 | .ident = "Dell OptiPlex 745", | 276 | .ident = "Dell OptiPlex 745", |
190 | .matches = { | 277 | .matches = { |
@@ -192,7 +279,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
192 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), | 279 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
193 | }, | 280 | }, |
194 | }, | 281 | }, |
195 | { /* Handle problems with rebooting on Dell Optiplex 745's DFF*/ | 282 | { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ |
196 | .callback = set_bios_reboot, | 283 | .callback = set_bios_reboot, |
197 | .ident = "Dell OptiPlex 745", | 284 | .ident = "Dell OptiPlex 745", |
198 | .matches = { | 285 | .matches = { |
@@ -201,7 +288,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
201 | DMI_MATCH(DMI_BOARD_NAME, "0MM599"), | 288 | DMI_MATCH(DMI_BOARD_NAME, "0MM599"), |
202 | }, | 289 | }, |
203 | }, | 290 | }, |
204 | { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ | 291 | { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ |
205 | .callback = set_bios_reboot, | 292 | .callback = set_bios_reboot, |
206 | .ident = "Dell OptiPlex 745", | 293 | .ident = "Dell OptiPlex 745", |
207 | .matches = { | 294 | .matches = { |
@@ -210,7 +297,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
210 | DMI_MATCH(DMI_BOARD_NAME, "0KW626"), | 297 | DMI_MATCH(DMI_BOARD_NAME, "0KW626"), |
211 | }, | 298 | }, |
212 | }, | 299 | }, |
213 | { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ | 300 | { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ |
214 | .callback = set_bios_reboot, | 301 | .callback = set_bios_reboot, |
215 | .ident = "Dell OptiPlex 330", | 302 | .ident = "Dell OptiPlex 330", |
216 | .matches = { | 303 | .matches = { |
@@ -219,7 +306,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
219 | DMI_MATCH(DMI_BOARD_NAME, "0KP561"), | 306 | DMI_MATCH(DMI_BOARD_NAME, "0KP561"), |
220 | }, | 307 | }, |
221 | }, | 308 | }, |
222 | { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ | 309 | { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ |
223 | .callback = set_bios_reboot, | 310 | .callback = set_bios_reboot, |
224 | .ident = "Dell OptiPlex 360", | 311 | .ident = "Dell OptiPlex 360", |
225 | .matches = { | 312 | .matches = { |
@@ -228,7 +315,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
228 | DMI_MATCH(DMI_BOARD_NAME, "0T656F"), | 315 | DMI_MATCH(DMI_BOARD_NAME, "0T656F"), |
229 | }, | 316 | }, |
230 | }, | 317 | }, |
231 | { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/ | 318 | { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ |
232 | .callback = set_bios_reboot, | 319 | .callback = set_bios_reboot, |
233 | .ident = "Dell OptiPlex 760", | 320 | .ident = "Dell OptiPlex 760", |
234 | .matches = { | 321 | .matches = { |
@@ -301,7 +388,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
301 | DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), | 388 | DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), |
302 | }, | 389 | }, |
303 | }, | 390 | }, |
304 | { /* Handle problems with rebooting on ASUS P4S800 */ | 391 | { /* Handle problems with rebooting on ASUS P4S800 */ |
305 | .callback = set_bios_reboot, | 392 | .callback = set_bios_reboot, |
306 | .ident = "ASUS P4S800", | 393 | .ident = "ASUS P4S800", |
307 | .matches = { | 394 | .matches = { |
@@ -309,7 +396,9 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
309 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), | 396 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
310 | }, | 397 | }, |
311 | }, | 398 | }, |
312 | { /* Handle reboot issue on Acer Aspire one */ | 399 | #endif /* CONFIG_X86_32 */ |
400 | |||
401 | { /* Handle reboot issue on Acer Aspire one */ | ||
313 | .callback = set_kbd_reboot, | 402 | .callback = set_kbd_reboot, |
314 | .ident = "Acer Aspire One A110", | 403 | .ident = "Acer Aspire One A110", |
315 | .matches = { | 404 | .matches = { |
@@ -317,96 +406,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
317 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), | 406 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), |
318 | }, | 407 | }, |
319 | }, | 408 | }, |
320 | { } | ||
321 | }; | ||
322 | |||
323 | static int __init reboot_init(void) | ||
324 | { | ||
325 | /* Only do the DMI check if reboot_type hasn't been overridden | ||
326 | * on the command line | ||
327 | */ | ||
328 | if (reboot_default) { | ||
329 | dmi_check_system(reboot_dmi_table); | ||
330 | } | ||
331 | return 0; | ||
332 | } | ||
333 | core_initcall(reboot_init); | ||
334 | |||
335 | extern const unsigned char machine_real_restart_asm[]; | ||
336 | extern const u64 machine_real_restart_gdt[3]; | ||
337 | |||
338 | void machine_real_restart(unsigned int type) | ||
339 | { | ||
340 | void *restart_va; | ||
341 | unsigned long restart_pa; | ||
342 | void (*restart_lowmem)(unsigned int); | ||
343 | u64 *lowmem_gdt; | ||
344 | |||
345 | local_irq_disable(); | ||
346 | |||
347 | /* Write zero to CMOS register number 0x0f, which the BIOS POST | ||
348 | routine will recognize as telling it to do a proper reboot. (Well | ||
349 | that's what this book in front of me says -- it may only apply to | ||
350 | the Phoenix BIOS though, it's not clear). At the same time, | ||
351 | disable NMIs by setting the top bit in the CMOS address register, | ||
352 | as we're about to do peculiar things to the CPU. I'm not sure if | ||
353 | `outb_p' is needed instead of just `outb'. Use it to be on the | ||
354 | safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) | ||
355 | */ | ||
356 | spin_lock(&rtc_lock); | ||
357 | CMOS_WRITE(0x00, 0x8f); | ||
358 | spin_unlock(&rtc_lock); | ||
359 | |||
360 | /* | ||
361 | * Switch back to the initial page table. | ||
362 | */ | ||
363 | load_cr3(initial_page_table); | ||
364 | |||
365 | /* Write 0x1234 to absolute memory location 0x472. The BIOS reads | ||
366 | this on booting to tell it to "Bypass memory test (also warm | ||
367 | boot)". This seems like a fairly standard thing that gets set by | ||
368 | REBOOT.COM programs, and the previous reset routine did this | ||
369 | too. */ | ||
370 | *((unsigned short *)0x472) = reboot_mode; | ||
371 | |||
372 | /* Patch the GDT in the low memory trampoline */ | ||
373 | lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); | ||
374 | |||
375 | restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); | ||
376 | restart_pa = virt_to_phys(restart_va); | ||
377 | restart_lowmem = (void (*)(unsigned int))restart_pa; | ||
378 | |||
379 | /* GDT[0]: GDT self-pointer */ | ||
380 | lowmem_gdt[0] = | ||
381 | (u64)(sizeof(machine_real_restart_gdt) - 1) + | ||
382 | ((u64)virt_to_phys(lowmem_gdt) << 16); | ||
383 | /* GDT[1]: 64K real mode code segment */ | ||
384 | lowmem_gdt[1] = | ||
385 | GDT_ENTRY(0x009b, restart_pa, 0xffff); | ||
386 | |||
387 | /* Jump to the identity-mapped low memory code */ | ||
388 | restart_lowmem(type); | ||
389 | } | ||
390 | #ifdef CONFIG_APM_MODULE | ||
391 | EXPORT_SYMBOL(machine_real_restart); | ||
392 | #endif | ||
393 | |||
394 | #endif /* CONFIG_X86_32 */ | ||
395 | |||
396 | /* | ||
397 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | ||
398 | */ | ||
399 | static int __init set_pci_reboot(const struct dmi_system_id *d) | ||
400 | { | ||
401 | if (reboot_type != BOOT_CF9) { | ||
402 | reboot_type = BOOT_CF9; | ||
403 | printk(KERN_INFO "%s series board detected. " | ||
404 | "Selecting PCI-method for reboots.\n", d->ident); | ||
405 | } | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { | ||
410 | { /* Handle problems with rebooting on Apple MacBook5 */ | 409 | { /* Handle problems with rebooting on Apple MacBook5 */ |
411 | .callback = set_pci_reboot, | 410 | .callback = set_pci_reboot, |
412 | .ident = "Apple MacBook5", | 411 | .ident = "Apple MacBook5", |
@@ -474,17 +473,17 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { | |||
474 | { } | 473 | { } |
475 | }; | 474 | }; |
476 | 475 | ||
477 | static int __init pci_reboot_init(void) | 476 | static int __init reboot_init(void) |
478 | { | 477 | { |
479 | /* Only do the DMI check if reboot_type hasn't been overridden | 478 | /* |
479 | * Only do the DMI check if reboot_type hasn't been overridden | ||
480 | * on the command line | 480 | * on the command line |
481 | */ | 481 | */ |
482 | if (reboot_default) { | 482 | if (reboot_default) |
483 | dmi_check_system(pci_reboot_dmi_table); | 483 | dmi_check_system(reboot_dmi_table); |
484 | } | ||
485 | return 0; | 484 | return 0; |
486 | } | 485 | } |
487 | core_initcall(pci_reboot_init); | 486 | core_initcall(reboot_init); |
488 | 487 | ||
489 | static inline void kb_wait(void) | 488 | static inline void kb_wait(void) |
490 | { | 489 | { |
@@ -502,14 +501,14 @@ static void vmxoff_nmi(int cpu, struct pt_regs *regs) | |||
502 | cpu_emergency_vmxoff(); | 501 | cpu_emergency_vmxoff(); |
503 | } | 502 | } |
504 | 503 | ||
505 | /* Use NMIs as IPIs to tell all CPUs to disable virtualization | 504 | /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ |
506 | */ | ||
507 | static void emergency_vmx_disable_all(void) | 505 | static void emergency_vmx_disable_all(void) |
508 | { | 506 | { |
509 | /* Just make sure we won't change CPUs while doing this */ | 507 | /* Just make sure we won't change CPUs while doing this */ |
510 | local_irq_disable(); | 508 | local_irq_disable(); |
511 | 509 | ||
512 | /* We need to disable VMX on all CPUs before rebooting, otherwise | 510 | /* |
511 | * We need to disable VMX on all CPUs before rebooting, otherwise | ||
513 | * we risk hanging up the machine, because the CPU ignore INIT | 512 | * we risk hanging up the machine, because the CPU ignore INIT |
514 | * signals when VMX is enabled. | 513 | * signals when VMX is enabled. |
515 | * | 514 | * |
@@ -528,8 +527,7 @@ static void emergency_vmx_disable_all(void) | |||
528 | * is still enabling VMX. | 527 | * is still enabling VMX. |
529 | */ | 528 | */ |
530 | if (cpu_has_vmx() && cpu_vmx_enabled()) { | 529 | if (cpu_has_vmx() && cpu_vmx_enabled()) { |
531 | /* Disable VMX on this CPU. | 530 | /* Disable VMX on this CPU. */ |
532 | */ | ||
533 | cpu_vmxoff(); | 531 | cpu_vmxoff(); |
534 | 532 | ||
535 | /* Halt and disable VMX on the other CPUs */ | 533 | /* Halt and disable VMX on the other CPUs */ |
@@ -574,12 +572,12 @@ static void native_machine_emergency_restart(void) | |||
574 | /* Could also try the reset bit in the Hammer NB */ | 572 | /* Could also try the reset bit in the Hammer NB */ |
575 | switch (reboot_type) { | 573 | switch (reboot_type) { |
576 | case BOOT_KBD: | 574 | case BOOT_KBD: |
577 | mach_reboot_fixups(); /* for board specific fixups */ | 575 | mach_reboot_fixups(); /* For board specific fixups */ |
578 | 576 | ||
579 | for (i = 0; i < 10; i++) { | 577 | for (i = 0; i < 10; i++) { |
580 | kb_wait(); | 578 | kb_wait(); |
581 | udelay(50); | 579 | udelay(50); |
582 | outb(0xfe, 0x64); /* pulse reset low */ | 580 | outb(0xfe, 0x64); /* Pulse reset low */ |
583 | udelay(50); | 581 | udelay(50); |
584 | } | 582 | } |
585 | if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { | 583 | if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { |
@@ -621,7 +619,7 @@ static void native_machine_emergency_restart(void) | |||
621 | 619 | ||
622 | case BOOT_CF9: | 620 | case BOOT_CF9: |
623 | port_cf9_safe = true; | 621 | port_cf9_safe = true; |
624 | /* fall through */ | 622 | /* Fall through */ |
625 | 623 | ||
626 | case BOOT_CF9_COND: | 624 | case BOOT_CF9_COND: |
627 | if (port_cf9_safe) { | 625 | if (port_cf9_safe) { |
@@ -659,7 +657,8 @@ void native_machine_shutdown(void) | |||
659 | /* Make certain I only run on the appropriate processor */ | 657 | /* Make certain I only run on the appropriate processor */ |
660 | set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); | 658 | set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); |
661 | 659 | ||
662 | /* O.K Now that I'm on the appropriate processor, | 660 | /* |
661 | * O.K Now that I'm on the appropriate processor, | ||
663 | * stop all of the others. | 662 | * stop all of the others. |
664 | */ | 663 | */ |
665 | stop_other_cpus(); | 664 | stop_other_cpus(); |
@@ -697,12 +696,11 @@ static void native_machine_restart(char *__unused) | |||
697 | 696 | ||
698 | static void native_machine_halt(void) | 697 | static void native_machine_halt(void) |
699 | { | 698 | { |
700 | /* stop other cpus and apics */ | 699 | /* Stop other cpus and apics */ |
701 | machine_shutdown(); | 700 | machine_shutdown(); |
702 | 701 | ||
703 | tboot_shutdown(TB_SHUTDOWN_HALT); | 702 | tboot_shutdown(TB_SHUTDOWN_HALT); |
704 | 703 | ||
705 | /* stop this cpu */ | ||
706 | stop_this_cpu(NULL); | 704 | stop_this_cpu(NULL); |
707 | } | 705 | } |
708 | 706 | ||
@@ -713,7 +711,7 @@ static void native_machine_power_off(void) | |||
713 | machine_shutdown(); | 711 | machine_shutdown(); |
714 | pm_power_off(); | 712 | pm_power_off(); |
715 | } | 713 | } |
716 | /* a fallback in case there is no PM info available */ | 714 | /* A fallback in case there is no PM info available */ |
717 | tboot_shutdown(TB_SHUTDOWN_HALT); | 715 | tboot_shutdown(TB_SHUTDOWN_HALT); |
718 | } | 716 | } |
719 | 717 | ||
@@ -775,7 +773,8 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) | |||
775 | 773 | ||
776 | cpu = raw_smp_processor_id(); | 774 | cpu = raw_smp_processor_id(); |
777 | 775 | ||
778 | /* Don't do anything if this handler is invoked on crashing cpu. | 776 | /* |
777 | * Don't do anything if this handler is invoked on crashing cpu. | ||
779 | * Otherwise, system will completely hang. Crashing cpu can get | 778 | * Otherwise, system will completely hang. Crashing cpu can get |
780 | * an NMI if system was initially booted with nmi_watchdog parameter. | 779 | * an NMI if system was initially booted with nmi_watchdog parameter. |
781 | */ | 780 | */ |
@@ -799,7 +798,8 @@ static void smp_send_nmi_allbutself(void) | |||
799 | apic->send_IPI_allbutself(NMI_VECTOR); | 798 | apic->send_IPI_allbutself(NMI_VECTOR); |
800 | } | 799 | } |
801 | 800 | ||
802 | /* Halt all other CPUs, calling the specified function on each of them | 801 | /* |
802 | * Halt all other CPUs, calling the specified function on each of them | ||
803 | * | 803 | * |
804 | * This function can be used to halt all other CPUs on crash | 804 | * This function can be used to halt all other CPUs on crash |
805 | * or emergency reboot time. The function passed as parameter | 805 | * or emergency reboot time. The function passed as parameter |
@@ -810,7 +810,7 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) | |||
810 | unsigned long msecs; | 810 | unsigned long msecs; |
811 | local_irq_disable(); | 811 | local_irq_disable(); |
812 | 812 | ||
813 | /* Make a note of crashing cpu. Will be used in NMI callback.*/ | 813 | /* Make a note of crashing cpu. Will be used in NMI callback. */ |
814 | crashing_cpu = safe_smp_processor_id(); | 814 | crashing_cpu = safe_smp_processor_id(); |
815 | 815 | ||
816 | shootdown_callback = callback; | 816 | shootdown_callback = callback; |
@@ -819,8 +819,9 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) | |||
819 | /* Would it be better to replace the trap vector here? */ | 819 | /* Would it be better to replace the trap vector here? */ |
820 | if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, | 820 | if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, |
821 | NMI_FLAG_FIRST, "crash")) | 821 | NMI_FLAG_FIRST, "crash")) |
822 | return; /* return what? */ | 822 | return; /* Return what? */ |
823 | /* Ensure the new callback function is set before sending | 823 | /* |
824 | * Ensure the new callback function is set before sending | ||
824 | * out the NMI | 825 | * out the NMI |
825 | */ | 826 | */ |
826 | wmb(); | 827 | wmb(); |
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 66c74f481cab..48d2b7ded422 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c | |||
@@ -109,6 +109,9 @@ | |||
109 | * about nothing of note with C stepping upwards. | 109 | * about nothing of note with C stepping upwards. |
110 | */ | 110 | */ |
111 | 111 | ||
112 | static atomic_t stopping_cpu = ATOMIC_INIT(-1); | ||
113 | static bool smp_no_nmi_ipi = false; | ||
114 | |||
112 | /* | 115 | /* |
113 | * this function sends a 'reschedule' IPI to another CPU. | 116 | * this function sends a 'reschedule' IPI to another CPU. |
114 | * it goes straight through and wastes no time serializing | 117 | * it goes straight through and wastes no time serializing |
@@ -149,8 +152,6 @@ void native_send_call_func_ipi(const struct cpumask *mask) | |||
149 | free_cpumask_var(allbutself); | 152 | free_cpumask_var(allbutself); |
150 | } | 153 | } |
151 | 154 | ||
152 | static atomic_t stopping_cpu = ATOMIC_INIT(-1); | ||
153 | |||
154 | static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) | 155 | static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) |
155 | { | 156 | { |
156 | /* We are registered on stopping cpu too, avoid spurious NMI */ | 157 | /* We are registered on stopping cpu too, avoid spurious NMI */ |
@@ -162,7 +163,19 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) | |||
162 | return NMI_HANDLED; | 163 | return NMI_HANDLED; |
163 | } | 164 | } |
164 | 165 | ||
165 | static void native_nmi_stop_other_cpus(int wait) | 166 | /* |
167 | * this function calls the 'stop' function on all other CPUs in the system. | ||
168 | */ | ||
169 | |||
170 | asmlinkage void smp_reboot_interrupt(void) | ||
171 | { | ||
172 | ack_APIC_irq(); | ||
173 | irq_enter(); | ||
174 | stop_this_cpu(NULL); | ||
175 | irq_exit(); | ||
176 | } | ||
177 | |||
178 | static void native_stop_other_cpus(int wait) | ||
166 | { | 179 | { |
167 | unsigned long flags; | 180 | unsigned long flags; |
168 | unsigned long timeout; | 181 | unsigned long timeout; |
@@ -174,20 +187,25 @@ static void native_nmi_stop_other_cpus(int wait) | |||
174 | * Use an own vector here because smp_call_function | 187 | * Use an own vector here because smp_call_function |
175 | * does lots of things not suitable in a panic situation. | 188 | * does lots of things not suitable in a panic situation. |
176 | */ | 189 | */ |
190 | |||
191 | /* | ||
192 | * We start by using the REBOOT_VECTOR irq. | ||
193 | * The irq is treated as a sync point to allow critical | ||
194 | * regions of code on other cpus to release their spin locks | ||
195 | * and re-enable irqs. Jumping straight to an NMI might | ||
196 | * accidentally cause deadlocks with further shutdown/panic | ||
197 | * code. By syncing, we give the cpus up to one second to | ||
198 | * finish their work before we force them off with the NMI. | ||
199 | */ | ||
177 | if (num_online_cpus() > 1) { | 200 | if (num_online_cpus() > 1) { |
178 | /* did someone beat us here? */ | 201 | /* did someone beat us here? */ |
179 | if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1) | 202 | if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1) |
180 | return; | 203 | return; |
181 | 204 | ||
182 | if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, | 205 | /* sync above data before sending IRQ */ |
183 | NMI_FLAG_FIRST, "smp_stop")) | ||
184 | /* Note: we ignore failures here */ | ||
185 | return; | ||
186 | |||
187 | /* sync above data before sending NMI */ | ||
188 | wmb(); | 206 | wmb(); |
189 | 207 | ||
190 | apic->send_IPI_allbutself(NMI_VECTOR); | 208 | apic->send_IPI_allbutself(REBOOT_VECTOR); |
191 | 209 | ||
192 | /* | 210 | /* |
193 | * Don't wait longer than a second if the caller | 211 | * Don't wait longer than a second if the caller |
@@ -197,63 +215,37 @@ static void native_nmi_stop_other_cpus(int wait) | |||
197 | while (num_online_cpus() > 1 && (wait || timeout--)) | 215 | while (num_online_cpus() > 1 && (wait || timeout--)) |
198 | udelay(1); | 216 | udelay(1); |
199 | } | 217 | } |
218 | |||
219 | /* if the REBOOT_VECTOR didn't work, try with the NMI */ | ||
220 | if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) { | ||
221 | if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, | ||
222 | NMI_FLAG_FIRST, "smp_stop")) | ||
223 | /* Note: we ignore failures here */ | ||
224 | /* Hope the REBOOT_IRQ is good enough */ | ||
225 | goto finish; | ||
200 | 226 | ||
201 | local_irq_save(flags); | 227 | /* sync above data before sending IRQ */ |
202 | disable_local_APIC(); | 228 | wmb(); |
203 | local_irq_restore(flags); | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * this function calls the 'stop' function on all other CPUs in the system. | ||
208 | */ | ||
209 | |||
210 | asmlinkage void smp_reboot_interrupt(void) | ||
211 | { | ||
212 | ack_APIC_irq(); | ||
213 | irq_enter(); | ||
214 | stop_this_cpu(NULL); | ||
215 | irq_exit(); | ||
216 | } | ||
217 | |||
218 | static void native_irq_stop_other_cpus(int wait) | ||
219 | { | ||
220 | unsigned long flags; | ||
221 | unsigned long timeout; | ||
222 | 229 | ||
223 | if (reboot_force) | 230 | pr_emerg("Shutting down cpus with NMI\n"); |
224 | return; | ||
225 | 231 | ||
226 | /* | 232 | apic->send_IPI_allbutself(NMI_VECTOR); |
227 | * Use an own vector here because smp_call_function | ||
228 | * does lots of things not suitable in a panic situation. | ||
229 | * On most systems we could also use an NMI here, | ||
230 | * but there are a few systems around where NMI | ||
231 | * is problematic so stay with an non NMI for now | ||
232 | * (this implies we cannot stop CPUs spinning with irq off | ||
233 | * currently) | ||
234 | */ | ||
235 | if (num_online_cpus() > 1) { | ||
236 | apic->send_IPI_allbutself(REBOOT_VECTOR); | ||
237 | 233 | ||
238 | /* | 234 | /* |
239 | * Don't wait longer than a second if the caller | 235 | * Don't wait longer than a 10 ms if the caller |
240 | * didn't ask us to wait. | 236 | * didn't ask us to wait. |
241 | */ | 237 | */ |
242 | timeout = USEC_PER_SEC; | 238 | timeout = USEC_PER_MSEC * 10; |
243 | while (num_online_cpus() > 1 && (wait || timeout--)) | 239 | while (num_online_cpus() > 1 && (wait || timeout--)) |
244 | udelay(1); | 240 | udelay(1); |
245 | } | 241 | } |
246 | 242 | ||
243 | finish: | ||
247 | local_irq_save(flags); | 244 | local_irq_save(flags); |
248 | disable_local_APIC(); | 245 | disable_local_APIC(); |
249 | local_irq_restore(flags); | 246 | local_irq_restore(flags); |
250 | } | 247 | } |
251 | 248 | ||
252 | static void native_smp_disable_nmi_ipi(void) | ||
253 | { | ||
254 | smp_ops.stop_other_cpus = native_irq_stop_other_cpus; | ||
255 | } | ||
256 | |||
257 | /* | 249 | /* |
258 | * Reschedule call back. | 250 | * Reschedule call back. |
259 | */ | 251 | */ |
@@ -287,8 +279,8 @@ void smp_call_function_single_interrupt(struct pt_regs *regs) | |||
287 | 279 | ||
288 | static int __init nonmi_ipi_setup(char *str) | 280 | static int __init nonmi_ipi_setup(char *str) |
289 | { | 281 | { |
290 | native_smp_disable_nmi_ipi(); | 282 | smp_no_nmi_ipi = true; |
291 | return 1; | 283 | return 1; |
292 | } | 284 | } |
293 | 285 | ||
294 | __setup("nonmi_ipi", nonmi_ipi_setup); | 286 | __setup("nonmi_ipi", nonmi_ipi_setup); |
@@ -298,7 +290,7 @@ struct smp_ops smp_ops = { | |||
298 | .smp_prepare_cpus = native_smp_prepare_cpus, | 290 | .smp_prepare_cpus = native_smp_prepare_cpus, |
299 | .smp_cpus_done = native_smp_cpus_done, | 291 | .smp_cpus_done = native_smp_cpus_done, |
300 | 292 | ||
301 | .stop_other_cpus = native_nmi_stop_other_cpus, | 293 | .stop_other_cpus = native_stop_other_cpus, |
302 | .smp_send_reschedule = native_smp_send_reschedule, | 294 | .smp_send_reschedule = native_smp_send_reschedule, |
303 | 295 | ||
304 | .cpu_up = native_cpu_up, | 296 | .cpu_up = native_cpu_up, |