diff options
author | H. Peter Anvin <hpa@zytor.com> | 2008-11-11 19:19:48 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2008-11-11 19:19:48 -0500 |
commit | 14d7ca5c575853664d8fe4f225a77b8df1b7de7d (patch) | |
tree | 0d16169c5fde30712109c3a316652d0525646f4f /arch/x86/kernel/reboot.c | |
parent | d3ec5cae0921611ceae06464ef6291012dd9849f (diff) |
x86: attempt reboot via port CF9 if we have standard PCI ports
Impact: Changes reboot behavior.
If port CF9 seems to be safe to touch, attempt it before trying the
keyboard controller. Port CF9 is not available on all chipsets (a
significant but decreasing number of modern chipsets don't implement
it), but port CF9 itself should in general be safe to poke (no ill
effects if unimplemented) on any system which has PCI Configuration
Method #1 or #2, as it falls inside the PCI configuration port range
in both cases. No chipset without PCI is known to have port CF9,
either, although an explicit "pci=bios" would mean we miss this and
therefore don't use port CF9. An explicit "reboot=pci" can be used to
force the use of port CF9.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r-- | arch/x86/kernel/reboot.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 34f8d37ae3c5..ddc93891cdcd 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -29,14 +29,17 @@ EXPORT_SYMBOL(pm_power_off); | |||
29 | 29 | ||
30 | static const struct desc_ptr no_idt = {}; | 30 | static const struct desc_ptr no_idt = {}; |
31 | static int reboot_mode; | 31 | static int reboot_mode; |
32 | enum reboot_type reboot_type = BOOT_KBD; | 32 | enum reboot_type reboot_type = BOOT_CF9_COND; |
33 | int reboot_force; | 33 | int reboot_force; |
34 | 34 | ||
35 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) | 35 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) |
36 | static int reboot_cpu = -1; | 36 | static int reboot_cpu = -1; |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | 39 | /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ |
40 | bool port_cf9_safe = false; | ||
41 | |||
42 | /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] | ||
40 | warm Don't set the cold reboot flag | 43 | warm Don't set the cold reboot flag |
41 | cold Set the cold reboot flag | 44 | cold Set the cold reboot flag |
42 | bios Reboot by jumping through the BIOS (only for X86_32) | 45 | bios Reboot by jumping through the BIOS (only for X86_32) |
@@ -45,6 +48,7 @@ static int reboot_cpu = -1; | |||
45 | kbd Use the keyboard controller. cold reset (default) | 48 | kbd Use the keyboard controller. cold reset (default) |
46 | acpi Use the RESET_REG in the FADT | 49 | acpi Use the RESET_REG in the FADT |
47 | efi Use efi reset_system runtime service | 50 | efi Use efi reset_system runtime service |
51 | pci Use the so-called "PCI reset register", CF9 | ||
48 | force Avoid anything that could hang. | 52 | force Avoid anything that could hang. |
49 | */ | 53 | */ |
50 | static int __init reboot_setup(char *str) | 54 | static int __init reboot_setup(char *str) |
@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str) | |||
79 | case 'k': | 83 | case 'k': |
80 | case 't': | 84 | case 't': |
81 | case 'e': | 85 | case 'e': |
86 | case 'p': | ||
82 | reboot_type = *str; | 87 | reboot_type = *str; |
83 | break; | 88 | break; |
84 | 89 | ||
@@ -379,28 +384,43 @@ static void native_machine_emergency_restart(void) | |||
379 | load_idt(&no_idt); | 384 | load_idt(&no_idt); |
380 | __asm__ __volatile__("int3"); | 385 | __asm__ __volatile__("int3"); |
381 | 386 | ||
382 | reboot_type = BOOT_KBD; | 387 | reboot_type = BOOT_CF9_COND; |
383 | break; | 388 | break; |
384 | 389 | ||
385 | #ifdef CONFIG_X86_32 | 390 | #ifdef CONFIG_X86_32 |
386 | case BOOT_BIOS: | 391 | case BOOT_BIOS: |
387 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); | 392 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); |
388 | 393 | ||
389 | reboot_type = BOOT_KBD; | 394 | reboot_type = BOOT_CF9_COND; |
390 | break; | 395 | break; |
391 | #endif | 396 | #endif |
392 | 397 | ||
393 | case BOOT_ACPI: | 398 | case BOOT_ACPI: |
394 | acpi_reboot(); | 399 | acpi_reboot(); |
395 | reboot_type = BOOT_KBD; | 400 | reboot_type = BOOT_CF9_COND; |
396 | break; | 401 | break; |
397 | 402 | ||
398 | |||
399 | case BOOT_EFI: | 403 | case BOOT_EFI: |
400 | if (efi_enabled) | 404 | if (efi_enabled) |
401 | efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, | 405 | efi.reset_system(reboot_mode ? |
406 | EFI_RESET_WARM : | ||
407 | EFI_RESET_COLD, | ||
402 | EFI_SUCCESS, 0, NULL); | 408 | EFI_SUCCESS, 0, NULL); |
409 | reboot_type = BOOT_CF9_COND; | ||
410 | break; | ||
411 | |||
412 | case BOOT_CF9: | ||
413 | port_cf9_safe = true; | ||
414 | /* fall through */ | ||
403 | 415 | ||
416 | case BOOT_CF9_COND: | ||
417 | if (port_cf9_safe) { | ||
418 | u8 cf9 = inb(0xcf9) & ~6; | ||
419 | outb(cf9|2, 0xcf9); /* Request hard reset */ | ||
420 | udelay(50); | ||
421 | outb(cf9|6, 0xcf9); /* Actually do the reset */ | ||
422 | udelay(50); | ||
423 | } | ||
404 | reboot_type = BOOT_KBD; | 424 | reboot_type = BOOT_KBD; |
405 | break; | 425 | break; |
406 | } | 426 | } |