diff options
| -rw-r--r-- | arch/x86/kernel/reboot.c | 72 | ||||
| -rw-r--r-- | include/linux/reboot.h | 14 |
2 files changed, 44 insertions, 42 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 654b46574b91..3399d3a99730 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
| @@ -114,8 +114,8 @@ EXPORT_SYMBOL(machine_real_restart); | |||
| 114 | */ | 114 | */ |
| 115 | static int __init set_pci_reboot(const struct dmi_system_id *d) | 115 | static int __init set_pci_reboot(const struct dmi_system_id *d) |
| 116 | { | 116 | { |
| 117 | if (reboot_type != BOOT_CF9) { | 117 | if (reboot_type != BOOT_CF9_FORCE) { |
| 118 | reboot_type = BOOT_CF9; | 118 | reboot_type = BOOT_CF9_FORCE; |
| 119 | pr_info("%s series board detected. Selecting %s-method for reboots.\n", | 119 | pr_info("%s series board detected. Selecting %s-method for reboots.\n", |
| 120 | d->ident, "PCI"); | 120 | d->ident, "PCI"); |
| 121 | } | 121 | } |
| @@ -458,20 +458,23 @@ void __attribute__((weak)) mach_reboot_fixups(void) | |||
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | /* | 460 | /* |
| 461 | * Windows compatible x86 hardware expects the following on reboot: | 461 | * To the best of our knowledge Windows compatible x86 hardware expects |
| 462 | * the following on reboot: | ||
| 462 | * | 463 | * |
| 463 | * 1) If the FADT has the ACPI reboot register flag set, try it | 464 | * 1) If the FADT has the ACPI reboot register flag set, try it |
| 464 | * 2) If still alive, write to the keyboard controller | 465 | * 2) If still alive, write to the keyboard controller |
| 465 | * 3) If still alive, write to the ACPI reboot register again | 466 | * 3) If still alive, write to the ACPI reboot register again |
| 466 | * 4) If still alive, write to the keyboard controller again | 467 | * 4) If still alive, write to the keyboard controller again |
| 467 | * 5) If still alive, call the EFI runtime service to reboot | 468 | * 5) If still alive, call the EFI runtime service to reboot |
| 468 | * 6) If still alive, write to the PCI IO port 0xCF9 to reboot | 469 | * 6) If no EFI runtime service, call the BIOS to do a reboot |
| 469 | * 7) If still alive, inform BIOS to do a proper reboot | ||
| 470 | * | 470 | * |
| 471 | * If the machine is still alive at this stage, it gives up. We default to | 471 | * We default to following the same pattern. We also have |
| 472 | * following the same pattern, except that if we're still alive after (7) we'll | 472 | * two other reboot methods: 'triple fault' and 'PCI', which |
| 473 | * try to force a triple fault and then cycle between hitting the keyboard | 473 | * can be triggered via the reboot= kernel boot option or |
| 474 | * controller and doing that | 474 | * via quirks. |
| 475 | * | ||
| 476 | * This means that this function can never return, it can misbehave | ||
| 477 | * by not rebooting properly and hanging. | ||
| 475 | */ | 478 | */ |
| 476 | static void native_machine_emergency_restart(void) | 479 | static void native_machine_emergency_restart(void) |
| 477 | { | 480 | { |
| @@ -492,6 +495,11 @@ static void native_machine_emergency_restart(void) | |||
| 492 | for (;;) { | 495 | for (;;) { |
| 493 | /* Could also try the reset bit in the Hammer NB */ | 496 | /* Could also try the reset bit in the Hammer NB */ |
| 494 | switch (reboot_type) { | 497 | switch (reboot_type) { |
| 498 | case BOOT_ACPI: | ||
| 499 | acpi_reboot(); | ||
| 500 | reboot_type = BOOT_KBD; | ||
| 501 | break; | ||
| 502 | |||
| 495 | case BOOT_KBD: | 503 | case BOOT_KBD: |
| 496 | mach_reboot_fixups(); /* For board specific fixups */ | 504 | mach_reboot_fixups(); /* For board specific fixups */ |
| 497 | 505 | ||
| @@ -509,43 +517,29 @@ static void native_machine_emergency_restart(void) | |||
| 509 | } | 517 | } |
| 510 | break; | 518 | break; |
| 511 | 519 | ||
| 512 | case BOOT_TRIPLE: | ||
| 513 | load_idt(&no_idt); | ||
| 514 | __asm__ __volatile__("int3"); | ||
| 515 | |||
| 516 | /* We're probably dead after this, but... */ | ||
| 517 | reboot_type = BOOT_KBD; | ||
| 518 | break; | ||
| 519 | |||
| 520 | case BOOT_BIOS: | ||
| 521 | machine_real_restart(MRR_BIOS); | ||
| 522 | |||
| 523 | /* We're probably dead after this, but... */ | ||
| 524 | reboot_type = BOOT_TRIPLE; | ||
| 525 | break; | ||
| 526 | |||
| 527 | case BOOT_ACPI: | ||
| 528 | acpi_reboot(); | ||
| 529 | reboot_type = BOOT_KBD; | ||
| 530 | break; | ||
| 531 | |||
| 532 | case BOOT_EFI: | 520 | case BOOT_EFI: |
| 533 | if (efi_enabled(EFI_RUNTIME_SERVICES)) | 521 | if (efi_enabled(EFI_RUNTIME_SERVICES)) |
| 534 | efi.reset_system(reboot_mode == REBOOT_WARM ? | 522 | efi.reset_system(reboot_mode == REBOOT_WARM ? |
| 535 | EFI_RESET_WARM : | 523 | EFI_RESET_WARM : |
| 536 | EFI_RESET_COLD, | 524 | EFI_RESET_COLD, |
| 537 | EFI_SUCCESS, 0, NULL); | 525 | EFI_SUCCESS, 0, NULL); |
| 538 | reboot_type = BOOT_CF9_COND; | 526 | reboot_type = BOOT_BIOS; |
| 527 | break; | ||
| 528 | |||
| 529 | case BOOT_BIOS: | ||
| 530 | machine_real_restart(MRR_BIOS); | ||
| 531 | |||
| 532 | /* We're probably dead after this, but... */ | ||
| 533 | reboot_type = BOOT_CF9_SAFE; | ||
| 539 | break; | 534 | break; |
| 540 | 535 | ||
| 541 | case BOOT_CF9: | 536 | case BOOT_CF9_FORCE: |
| 542 | port_cf9_safe = true; | 537 | port_cf9_safe = true; |
| 543 | /* Fall through */ | 538 | /* Fall through */ |
| 544 | 539 | ||
| 545 | case BOOT_CF9_COND: | 540 | case BOOT_CF9_SAFE: |
| 546 | if (port_cf9_safe) { | 541 | if (port_cf9_safe) { |
| 547 | u8 reboot_code = reboot_mode == REBOOT_WARM ? | 542 | u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; |
| 548 | 0x06 : 0x0E; | ||
| 549 | u8 cf9 = inb(0xcf9) & ~reboot_code; | 543 | u8 cf9 = inb(0xcf9) & ~reboot_code; |
| 550 | outb(cf9|2, 0xcf9); /* Request hard reset */ | 544 | outb(cf9|2, 0xcf9); /* Request hard reset */ |
| 551 | udelay(50); | 545 | udelay(50); |
| @@ -553,7 +547,15 @@ static void native_machine_emergency_restart(void) | |||
| 553 | outb(cf9|reboot_code, 0xcf9); | 547 | outb(cf9|reboot_code, 0xcf9); |
| 554 | udelay(50); | 548 | udelay(50); |
| 555 | } | 549 | } |
| 556 | reboot_type = BOOT_BIOS; | 550 | reboot_type = BOOT_TRIPLE; |
| 551 | break; | ||
| 552 | |||
| 553 | case BOOT_TRIPLE: | ||
| 554 | load_idt(&no_idt); | ||
| 555 | __asm__ __volatile__("int3"); | ||
| 556 | |||
| 557 | /* We're probably dead after this, but... */ | ||
| 558 | reboot_type = BOOT_KBD; | ||
| 557 | break; | 559 | break; |
| 558 | } | 560 | } |
| 559 | } | 561 | } |
diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 9e7db9e73cc1..48bf152761c7 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h | |||
| @@ -20,13 +20,13 @@ enum reboot_mode { | |||
| 20 | extern enum reboot_mode reboot_mode; | 20 | extern enum reboot_mode reboot_mode; |
| 21 | 21 | ||
| 22 | enum reboot_type { | 22 | enum reboot_type { |
| 23 | BOOT_TRIPLE = 't', | 23 | BOOT_TRIPLE = 't', |
| 24 | BOOT_KBD = 'k', | 24 | BOOT_KBD = 'k', |
| 25 | BOOT_BIOS = 'b', | 25 | BOOT_BIOS = 'b', |
| 26 | BOOT_ACPI = 'a', | 26 | BOOT_ACPI = 'a', |
| 27 | BOOT_EFI = 'e', | 27 | BOOT_EFI = 'e', |
| 28 | BOOT_CF9 = 'p', | 28 | BOOT_CF9_FORCE = 'p', |
| 29 | BOOT_CF9_COND = 'q', | 29 | BOOT_CF9_SAFE = 'q', |
| 30 | }; | 30 | }; |
| 31 | extern enum reboot_type reboot_type; | 31 | extern enum reboot_type reboot_type; |
| 32 | 32 | ||
