diff options
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r-- | arch/x86/kernel/reboot.c | 82 |
1 files changed, 47 insertions, 35 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 654b46574b91..52b1157c53eb 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 | } |
@@ -191,6 +191,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
191 | }, | 191 | }, |
192 | }, | 192 | }, |
193 | 193 | ||
194 | /* Certec */ | ||
195 | { /* Handle problems with rebooting on Certec BPC600 */ | ||
196 | .callback = set_pci_reboot, | ||
197 | .ident = "Certec BPC600", | ||
198 | .matches = { | ||
199 | DMI_MATCH(DMI_SYS_VENDOR, "Certec"), | ||
200 | DMI_MATCH(DMI_PRODUCT_NAME, "BPC600"), | ||
201 | }, | ||
202 | }, | ||
203 | |||
194 | /* Dell */ | 204 | /* Dell */ |
195 | { /* Handle problems with rebooting on Dell DXP061 */ | 205 | { /* Handle problems with rebooting on Dell DXP061 */ |
196 | .callback = set_bios_reboot, | 206 | .callback = set_bios_reboot, |
@@ -458,20 +468,23 @@ void __attribute__((weak)) mach_reboot_fixups(void) | |||
458 | } | 468 | } |
459 | 469 | ||
460 | /* | 470 | /* |
461 | * Windows compatible x86 hardware expects the following on reboot: | 471 | * To the best of our knowledge Windows compatible x86 hardware expects |
472 | * the following on reboot: | ||
462 | * | 473 | * |
463 | * 1) If the FADT has the ACPI reboot register flag set, try it | 474 | * 1) If the FADT has the ACPI reboot register flag set, try it |
464 | * 2) If still alive, write to the keyboard controller | 475 | * 2) If still alive, write to the keyboard controller |
465 | * 3) If still alive, write to the ACPI reboot register again | 476 | * 3) If still alive, write to the ACPI reboot register again |
466 | * 4) If still alive, write to the keyboard controller again | 477 | * 4) If still alive, write to the keyboard controller again |
467 | * 5) If still alive, call the EFI runtime service to reboot | 478 | * 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 | 479 | * 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 | 480 | * |
481 | * We default to following the same pattern. We also have | ||
482 | * two other reboot methods: 'triple fault' and 'PCI', which | ||
483 | * can be triggered via the reboot= kernel boot option or | ||
484 | * via quirks. | ||
470 | * | 485 | * |
471 | * If the machine is still alive at this stage, it gives up. We default to | 486 | * This means that this function can never return, it can misbehave |
472 | * following the same pattern, except that if we're still alive after (7) we'll | 487 | * by not rebooting properly and hanging. |
473 | * try to force a triple fault and then cycle between hitting the keyboard | ||
474 | * controller and doing that | ||
475 | */ | 488 | */ |
476 | static void native_machine_emergency_restart(void) | 489 | static void native_machine_emergency_restart(void) |
477 | { | 490 | { |
@@ -492,6 +505,11 @@ static void native_machine_emergency_restart(void) | |||
492 | for (;;) { | 505 | for (;;) { |
493 | /* Could also try the reset bit in the Hammer NB */ | 506 | /* Could also try the reset bit in the Hammer NB */ |
494 | switch (reboot_type) { | 507 | switch (reboot_type) { |
508 | case BOOT_ACPI: | ||
509 | acpi_reboot(); | ||
510 | reboot_type = BOOT_KBD; | ||
511 | break; | ||
512 | |||
495 | case BOOT_KBD: | 513 | case BOOT_KBD: |
496 | mach_reboot_fixups(); /* For board specific fixups */ | 514 | mach_reboot_fixups(); /* For board specific fixups */ |
497 | 515 | ||
@@ -509,43 +527,29 @@ static void native_machine_emergency_restart(void) | |||
509 | } | 527 | } |
510 | break; | 528 | break; |
511 | 529 | ||
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: | 530 | case BOOT_EFI: |
533 | if (efi_enabled(EFI_RUNTIME_SERVICES)) | 531 | if (efi_enabled(EFI_RUNTIME_SERVICES)) |
534 | efi.reset_system(reboot_mode == REBOOT_WARM ? | 532 | efi.reset_system(reboot_mode == REBOOT_WARM ? |
535 | EFI_RESET_WARM : | 533 | EFI_RESET_WARM : |
536 | EFI_RESET_COLD, | 534 | EFI_RESET_COLD, |
537 | EFI_SUCCESS, 0, NULL); | 535 | EFI_SUCCESS, 0, NULL); |
538 | reboot_type = BOOT_CF9_COND; | 536 | reboot_type = BOOT_BIOS; |
537 | break; | ||
538 | |||
539 | case BOOT_BIOS: | ||
540 | machine_real_restart(MRR_BIOS); | ||
541 | |||
542 | /* We're probably dead after this, but... */ | ||
543 | reboot_type = BOOT_CF9_SAFE; | ||
539 | break; | 544 | break; |
540 | 545 | ||
541 | case BOOT_CF9: | 546 | case BOOT_CF9_FORCE: |
542 | port_cf9_safe = true; | 547 | port_cf9_safe = true; |
543 | /* Fall through */ | 548 | /* Fall through */ |
544 | 549 | ||
545 | case BOOT_CF9_COND: | 550 | case BOOT_CF9_SAFE: |
546 | if (port_cf9_safe) { | 551 | if (port_cf9_safe) { |
547 | u8 reboot_code = reboot_mode == REBOOT_WARM ? | 552 | u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; |
548 | 0x06 : 0x0E; | ||
549 | u8 cf9 = inb(0xcf9) & ~reboot_code; | 553 | u8 cf9 = inb(0xcf9) & ~reboot_code; |
550 | outb(cf9|2, 0xcf9); /* Request hard reset */ | 554 | outb(cf9|2, 0xcf9); /* Request hard reset */ |
551 | udelay(50); | 555 | udelay(50); |
@@ -553,7 +557,15 @@ static void native_machine_emergency_restart(void) | |||
553 | outb(cf9|reboot_code, 0xcf9); | 557 | outb(cf9|reboot_code, 0xcf9); |
554 | udelay(50); | 558 | udelay(50); |
555 | } | 559 | } |
556 | reboot_type = BOOT_BIOS; | 560 | reboot_type = BOOT_TRIPLE; |
561 | break; | ||
562 | |||
563 | case BOOT_TRIPLE: | ||
564 | load_idt(&no_idt); | ||
565 | __asm__ __volatile__("int3"); | ||
566 | |||
567 | /* We're probably dead after this, but... */ | ||
568 | reboot_type = BOOT_KBD; | ||
557 | break; | 569 | break; |
558 | } | 570 | } |
559 | } | 571 | } |