Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+34 -9
+3 -1
arch/x86/include/asm/emergency-restart.h
··· 8 8 BOOT_BIOS = 'b', 9 9 #endif 10 10 BOOT_ACPI = 'a', 11 - BOOT_EFI = 'e' 11 + BOOT_EFI = 'e', 12 + BOOT_CF9 = 'p', 13 + BOOT_CF9_COND = 'q', 12 14 }; 13 15 14 16 extern enum reboot_type reboot_type;
+27 -7
arch/x86/kernel/reboot.c
··· 29 29 30 30 static const struct desc_ptr no_idt = {}; 31 31 static int reboot_mode; 32 - enum reboot_type reboot_type = BOOT_KBD; 32 + enum reboot_type reboot_type = BOOT_CF9_COND; 33 33 int reboot_force; 34 34 35 35 #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 36 36 static int reboot_cpu = -1; 37 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 43 warm Don't set the cold reboot flag 41 44 cold Set the cold reboot flag 42 45 bios Reboot by jumping through the BIOS (only for X86_32) ··· 48 45 kbd Use the keyboard controller. cold reset (default) 49 46 acpi Use the RESET_REG in the FADT 50 47 efi Use efi reset_system runtime service 48 + pci Use the so-called "PCI reset register", CF9 51 49 force Avoid anything that could hang. 52 50 */ 53 51 static int __init reboot_setup(char *str) ··· 83 79 case 'k': 84 80 case 't': 85 81 case 'e': 82 + case 'p': 86 83 reboot_type = *str; 87 84 break; 88 85 ··· 384 379 load_idt(&no_idt); 385 380 __asm__ __volatile__("int3"); 386 381 387 - reboot_type = BOOT_KBD; 382 + reboot_type = BOOT_CF9_COND; 388 383 break; 389 384 390 385 #ifdef CONFIG_X86_32 391 386 case BOOT_BIOS: 392 387 machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); 393 388 394 - reboot_type = BOOT_KBD; 389 + reboot_type = BOOT_CF9_COND; 395 390 break; 396 391 #endif 397 392 398 393 case BOOT_ACPI: 399 394 acpi_reboot(); 400 - reboot_type = BOOT_KBD; 395 + reboot_type = BOOT_CF9_COND; 401 396 break; 402 - 403 397 404 398 case BOOT_EFI: 405 399 if (efi_enabled) 406 - efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, 400 + efi.reset_system(reboot_mode ? 401 + EFI_RESET_WARM : 402 + EFI_RESET_COLD, 407 403 EFI_SUCCESS, 0, NULL); 404 + reboot_type = BOOT_CF9_COND; 405 + break; 408 406 407 + case BOOT_CF9: 408 + port_cf9_safe = true; 409 + /* fall through */ 410 + 411 + case BOOT_CF9_COND: 412 + if (port_cf9_safe) { 413 + u8 cf9 = inb(0xcf9) & ~6; 414 + outb(cf9|2, 0xcf9); /* Request hard reset */ 415 + udelay(50); 416 + outb(cf9|6, 0xcf9); /* Actually do the reset */ 417 + udelay(50); 418 + } 409 419 reboot_type = BOOT_KBD; 410 420 break; 411 421 }
+3 -1
arch/x86/pci/direct.c
··· 173 173 174 174 #undef PCI_CONF2_ADDRESS 175 175 176 - static struct pci_raw_ops pci_direct_conf2 = { 176 + struct pci_raw_ops pci_direct_conf2 = { 177 177 .read = pci_conf2_read, 178 178 .write = pci_conf2_write, 179 179 }; ··· 289 289 290 290 if (pci_check_type1()) { 291 291 raw_pci_ops = &pci_direct_conf1; 292 + port_cf9_safe = true; 292 293 return 1; 293 294 } 294 295 release_resource(region); ··· 306 305 307 306 if (pci_check_type2()) { 308 307 raw_pci_ops = &pci_direct_conf2; 308 + port_cf9_safe = true; 309 309 return 2; 310 310 } 311 311
+1
arch/x86/pci/pci.h
··· 96 96 extern struct pci_raw_ops *raw_pci_ext_ops; 97 97 98 98 extern struct pci_raw_ops pci_direct_conf1; 99 + extern bool port_cf9_safe; 99 100 100 101 /* arch_initcall level */ 101 102 extern int pci_direct_probe(void);