Skip to content

Commit 5be44a6

Browse files
author
Ingo Molnar
committed
x86: Remove the PCI reboot method from the default chain
Steve reported a reboot hang and bisected it back to this commit: a4f1987 x86, reboot: Add EFI and CF9 reboot methods into the default list He heroically tested all reboot methods and found the following: reboot=t # triple fault ok reboot=k # keyboard ctrl FAIL reboot=b # BIOS ok reboot=a # ACPI FAIL reboot=e # EFI FAIL [system has no EFI] reboot=p # PCI 0xcf9 FAIL And I think it's pretty obvious that we should only try PCI 0xcf9 as a last resort - if at all. The other observation is that (on this box) we should never try the PCI reboot method, but close with either the 'triple fault' or the 'BIOS' (terminal!) reboot methods. Thirdly, CF9_COND is a total misnomer - it should be something like CF9_SAFE or CF9_CAREFUL, and 'CF9' should be 'CF9_FORCE' ... So this patch fixes the worst problems: - it orders the actual reboot logic to follow the reboot ordering pattern - it was in a pretty random order before for no good reason. - it fixes the CF9 misnomers and uses BOOT_CF9_FORCE and BOOT_CF9_SAFE flags to make the code more obvious. - it tries the BIOS reboot method before the PCI reboot method. (Since 'BIOS' is a terminal reboot method resulting in a hang if it does not work, this is essentially equivalent to removing the PCI reboot method from the default reboot chain.) - just for the miraculous possibility of terminal (resulting in hang) reboot methods of triple fault or BIOS returning without having done their job, there's an ordering between them as well. Reported-and-bisected-and-tested-by: Steven Rostedt <[email protected]> Cc: Li Aubrey <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Matthew Garrett <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent e6bcd1a commit 5be44a6

File tree

2 files changed

+44
-42
lines changed

2 files changed

+44
-42
lines changed

arch/x86/kernel/reboot.c

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ EXPORT_SYMBOL(machine_real_restart);
114114
*/
115115
static int __init set_pci_reboot(const struct dmi_system_id *d)
116116
{
117-
if (reboot_type != BOOT_CF9) {
118-
reboot_type = BOOT_CF9;
117+
if (reboot_type != BOOT_CF9_FORCE) {
118+
reboot_type = BOOT_CF9_FORCE;
119119
pr_info("%s series board detected. Selecting %s-method for reboots.\n",
120120
d->ident, "PCI");
121121
}
@@ -458,20 +458,23 @@ void __attribute__((weak)) mach_reboot_fixups(void)
458458
}
459459

460460
/*
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:
462463
*
463464
* 1) If the FADT has the ACPI reboot register flag set, try it
464465
* 2) If still alive, write to the keyboard controller
465466
* 3) If still alive, write to the ACPI reboot register again
466467
* 4) If still alive, write to the keyboard controller again
467468
* 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-
* 7) If still alive, inform BIOS to do a proper reboot
469+
* 6) If no EFI runtime service, call the BIOS to do a reboot
470470
*
471-
* If the machine is still alive at this stage, it gives up. We default to
472-
* following the same pattern, except that if we're still alive after (7) we'll
473-
* try to force a triple fault and then cycle between hitting the keyboard
474-
* controller and doing that
471+
* We default to following the same pattern. We also have
472+
* two other reboot methods: 'triple fault' and 'PCI', which
473+
* can be triggered via the reboot= kernel boot option or
474+
* via quirks.
475+
*
476+
* This means that this function can never return, it can misbehave
477+
* by not rebooting properly and hanging.
475478
*/
476479
static void native_machine_emergency_restart(void)
477480
{
@@ -492,6 +495,11 @@ static void native_machine_emergency_restart(void)
492495
for (;;) {
493496
/* Could also try the reset bit in the Hammer NB */
494497
switch (reboot_type) {
498+
case BOOT_ACPI:
499+
acpi_reboot();
500+
reboot_type = BOOT_KBD;
501+
break;
502+
495503
case BOOT_KBD:
496504
mach_reboot_fixups(); /* For board specific fixups */
497505

@@ -509,51 +517,45 @@ static void native_machine_emergency_restart(void)
509517
}
510518
break;
511519

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-
532520
case BOOT_EFI:
533521
if (efi_enabled(EFI_RUNTIME_SERVICES))
534522
efi.reset_system(reboot_mode == REBOOT_WARM ?
535523
EFI_RESET_WARM :
536524
EFI_RESET_COLD,
537525
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;
539534
break;
540535

541-
case BOOT_CF9:
536+
case BOOT_CF9_FORCE:
542537
port_cf9_safe = true;
543538
/* Fall through */
544539

545-
case BOOT_CF9_COND:
540+
case BOOT_CF9_SAFE:
546541
if (port_cf9_safe) {
547-
u8 reboot_code = reboot_mode == REBOOT_WARM ?
548-
0x06 : 0x0E;
542+
u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E;
549543
u8 cf9 = inb(0xcf9) & ~reboot_code;
550544
outb(cf9|2, 0xcf9); /* Request hard reset */
551545
udelay(50);
552546
/* Actually do the reset */
553547
outb(cf9|reboot_code, 0xcf9);
554548
udelay(50);
555549
}
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;
557559
break;
558560
}
559561
}

include/linux/reboot.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ enum reboot_mode {
2020
extern enum reboot_mode reboot_mode;
2121

2222
enum reboot_type {
23-
BOOT_TRIPLE = 't',
24-
BOOT_KBD = 'k',
25-
BOOT_BIOS = 'b',
26-
BOOT_ACPI = 'a',
27-
BOOT_EFI = 'e',
28-
BOOT_CF9 = 'p',
29-
BOOT_CF9_COND = 'q',
23+
BOOT_TRIPLE = 't',
24+
BOOT_KBD = 'k',
25+
BOOT_BIOS = 'b',
26+
BOOT_ACPI = 'a',
27+
BOOT_EFI = 'e',
28+
BOOT_CF9_FORCE = 'p',
29+
BOOT_CF9_SAFE = 'q',
3030
};
3131
extern enum reboot_type reboot_type;
3232

0 commit comments

Comments
 (0)