14d022e35SMiguel Boton #include <linux/module.h> 24d022e35SMiguel Boton #include <linux/reboot.h> 34d022e35SMiguel Boton #include <linux/init.h> 44d022e35SMiguel Boton #include <linux/pm.h> 54d022e35SMiguel Boton #include <linux/efi.h> 64d022e35SMiguel Boton #include <acpi/reboot.h> 74d022e35SMiguel Boton #include <asm/io.h> 84d022e35SMiguel Boton #include <asm/apic.h> 94d022e35SMiguel Boton #include <asm/desc.h> 104d022e35SMiguel Boton #include <asm/hpet.h> 1168db065cSJeremy Fitzhardinge #include <asm/pgtable.h> 124412620fSDmitri Vorobiev #include <asm/proto.h> 134d022e35SMiguel Boton #include <asm/reboot_fixups.h> 144d022e35SMiguel Boton #include <asm/reboot.h> 154d022e35SMiguel Boton 164d022e35SMiguel Boton #ifdef CONFIG_X86_32 174d022e35SMiguel Boton # include <linux/dmi.h> 184d022e35SMiguel Boton # include <linux/ctype.h> 194d022e35SMiguel Boton # include <linux/mc146818rtc.h> 204d022e35SMiguel Boton #else 214d022e35SMiguel Boton # include <asm/iommu.h> 224d022e35SMiguel Boton #endif 234d022e35SMiguel Boton 244d022e35SMiguel Boton /* 254d022e35SMiguel Boton * Power off function, if any 264d022e35SMiguel Boton */ 274d022e35SMiguel Boton void (*pm_power_off)(void); 284d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off); 294d022e35SMiguel Boton 30ebdd561aSJan Beulich static const struct desc_ptr no_idt = {}; 314d022e35SMiguel Boton static int reboot_mode; 32*14d7ca5cSH. Peter Anvin enum reboot_type reboot_type = BOOT_CF9_COND; 334d022e35SMiguel Boton int reboot_force; 344d022e35SMiguel Boton 354d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 364d022e35SMiguel Boton static int reboot_cpu = -1; 374d022e35SMiguel Boton #endif 384d022e35SMiguel Boton 39*14d7ca5cSH. Peter Anvin /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ 40*14d7ca5cSH. Peter Anvin bool port_cf9_safe = false; 41*14d7ca5cSH. Peter Anvin 42*14d7ca5cSH. Peter Anvin /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] 434d022e35SMiguel Boton warm Don't set the cold reboot flag 444d022e35SMiguel Boton cold Set the cold reboot flag 454d022e35SMiguel Boton bios Reboot by jumping through the BIOS (only for X86_32) 464d022e35SMiguel Boton smp Reboot by executing reset on BSP or other CPU (only for X86_32) 474d022e35SMiguel Boton triple Force a triple fault (init) 484d022e35SMiguel Boton kbd Use the keyboard controller. cold reset (default) 494d022e35SMiguel Boton acpi Use the RESET_REG in the FADT 504d022e35SMiguel Boton efi Use efi reset_system runtime service 51*14d7ca5cSH. Peter Anvin pci Use the so-called "PCI reset register", CF9 524d022e35SMiguel Boton force Avoid anything that could hang. 534d022e35SMiguel Boton */ 544d022e35SMiguel Boton static int __init reboot_setup(char *str) 554d022e35SMiguel Boton { 564d022e35SMiguel Boton for (;;) { 574d022e35SMiguel Boton switch (*str) { 584d022e35SMiguel Boton case 'w': 594d022e35SMiguel Boton reboot_mode = 0x1234; 604d022e35SMiguel Boton break; 614d022e35SMiguel Boton 624d022e35SMiguel Boton case 'c': 634d022e35SMiguel Boton reboot_mode = 0; 644d022e35SMiguel Boton break; 654d022e35SMiguel Boton 664d022e35SMiguel Boton #ifdef CONFIG_X86_32 674d022e35SMiguel Boton #ifdef CONFIG_SMP 684d022e35SMiguel Boton case 's': 694d022e35SMiguel Boton if (isdigit(*(str+1))) { 704d022e35SMiguel Boton reboot_cpu = (int) (*(str+1) - '0'); 714d022e35SMiguel Boton if (isdigit(*(str+2))) 724d022e35SMiguel Boton reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); 734d022e35SMiguel Boton } 744d022e35SMiguel Boton /* we will leave sorting out the final value 754d022e35SMiguel Boton when we are ready to reboot, since we might not 764d022e35SMiguel Boton have set up boot_cpu_id or smp_num_cpu */ 774d022e35SMiguel Boton break; 784d022e35SMiguel Boton #endif /* CONFIG_SMP */ 794d022e35SMiguel Boton 804d022e35SMiguel Boton case 'b': 814d022e35SMiguel Boton #endif 824d022e35SMiguel Boton case 'a': 834d022e35SMiguel Boton case 'k': 844d022e35SMiguel Boton case 't': 854d022e35SMiguel Boton case 'e': 86*14d7ca5cSH. Peter Anvin case 'p': 874d022e35SMiguel Boton reboot_type = *str; 884d022e35SMiguel Boton break; 894d022e35SMiguel Boton 904d022e35SMiguel Boton case 'f': 914d022e35SMiguel Boton reboot_force = 1; 924d022e35SMiguel Boton break; 934d022e35SMiguel Boton } 944d022e35SMiguel Boton 954d022e35SMiguel Boton str = strchr(str, ','); 964d022e35SMiguel Boton if (str) 974d022e35SMiguel Boton str++; 984d022e35SMiguel Boton else 994d022e35SMiguel Boton break; 1004d022e35SMiguel Boton } 1014d022e35SMiguel Boton return 1; 1024d022e35SMiguel Boton } 1034d022e35SMiguel Boton 1044d022e35SMiguel Boton __setup("reboot=", reboot_setup); 1054d022e35SMiguel Boton 1064d022e35SMiguel Boton 1074d022e35SMiguel Boton #ifdef CONFIG_X86_32 1084d022e35SMiguel Boton /* 1094d022e35SMiguel Boton * Reboot options and system auto-detection code provided by 1104d022e35SMiguel Boton * Dell Inc. so their systems "just work". :-) 1114d022e35SMiguel Boton */ 1124d022e35SMiguel Boton 1134d022e35SMiguel Boton /* 1144d022e35SMiguel Boton * Some machines require the "reboot=b" commandline option, 1154d022e35SMiguel Boton * this quirk makes that automatic. 1164d022e35SMiguel Boton */ 1174d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d) 1184d022e35SMiguel Boton { 1194d022e35SMiguel Boton if (reboot_type != BOOT_BIOS) { 1204d022e35SMiguel Boton reboot_type = BOOT_BIOS; 1214d022e35SMiguel Boton printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); 1224d022e35SMiguel Boton } 1234d022e35SMiguel Boton return 0; 1244d022e35SMiguel Boton } 1254d022e35SMiguel Boton 1264d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = { 1274d022e35SMiguel Boton { /* Handle problems with rebooting on Dell E520's */ 1284d022e35SMiguel Boton .callback = set_bios_reboot, 1294d022e35SMiguel Boton .ident = "Dell E520", 1304d022e35SMiguel Boton .matches = { 1314d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1324d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), 1334d022e35SMiguel Boton }, 1344d022e35SMiguel Boton }, 1354d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 1300's */ 1364d022e35SMiguel Boton .callback = set_bios_reboot, 1374d022e35SMiguel Boton .ident = "Dell PowerEdge 1300", 1384d022e35SMiguel Boton .matches = { 1394d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 1404d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), 1414d022e35SMiguel Boton }, 1424d022e35SMiguel Boton }, 1434d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 300's */ 1444d022e35SMiguel Boton .callback = set_bios_reboot, 1454d022e35SMiguel Boton .ident = "Dell PowerEdge 300", 1464d022e35SMiguel Boton .matches = { 1474d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 1484d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), 1494d022e35SMiguel Boton }, 1504d022e35SMiguel Boton }, 1514d022e35SMiguel Boton { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/ 1524d022e35SMiguel Boton .callback = set_bios_reboot, 1534d022e35SMiguel Boton .ident = "Dell OptiPlex 745", 1544d022e35SMiguel Boton .matches = { 1554d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1564d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 1574d022e35SMiguel Boton }, 1584d022e35SMiguel Boton }, 159fc115bf1SColeman Kane { /* Handle problems with rebooting on Dell Optiplex 745's DFF*/ 160fc115bf1SColeman Kane .callback = set_bios_reboot, 161fc115bf1SColeman Kane .ident = "Dell OptiPlex 745", 162fc115bf1SColeman Kane .matches = { 163fc115bf1SColeman Kane DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 164fc115bf1SColeman Kane DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 165fc115bf1SColeman Kane DMI_MATCH(DMI_BOARD_NAME, "0MM599"), 166fc115bf1SColeman Kane }, 167fc115bf1SColeman Kane }, 168fc1c8925SHeinz-Ado Arnolds { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ 169fc1c8925SHeinz-Ado Arnolds .callback = set_bios_reboot, 170fc1c8925SHeinz-Ado Arnolds .ident = "Dell OptiPlex 745", 171fc1c8925SHeinz-Ado Arnolds .matches = { 172fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 173fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), 174fc1c8925SHeinz-Ado Arnolds DMI_MATCH(DMI_BOARD_NAME, "0KW626"), 175fc1c8925SHeinz-Ado Arnolds }, 176fc1c8925SHeinz-Ado Arnolds }, 1774d022e35SMiguel Boton { /* Handle problems with rebooting on Dell 2400's */ 1784d022e35SMiguel Boton .callback = set_bios_reboot, 1794d022e35SMiguel Boton .ident = "Dell PowerEdge 2400", 1804d022e35SMiguel Boton .matches = { 1814d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 1824d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), 1834d022e35SMiguel Boton }, 1844d022e35SMiguel Boton }, 185fab3b58dSIngo Molnar { /* Handle problems with rebooting on Dell T5400's */ 186fab3b58dSIngo Molnar .callback = set_bios_reboot, 187fab3b58dSIngo Molnar .ident = "Dell Precision T5400", 188fab3b58dSIngo Molnar .matches = { 189fab3b58dSIngo Molnar DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 190fab3b58dSIngo Molnar DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), 191fab3b58dSIngo Molnar }, 192fab3b58dSIngo Molnar }, 1934d022e35SMiguel Boton { /* Handle problems with rebooting on HP laptops */ 1944d022e35SMiguel Boton .callback = set_bios_reboot, 1954d022e35SMiguel Boton .ident = "HP Compaq Laptop", 1964d022e35SMiguel Boton .matches = { 1974d022e35SMiguel Boton DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 1984d022e35SMiguel Boton DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), 1994d022e35SMiguel Boton }, 2004d022e35SMiguel Boton }, 2014d022e35SMiguel Boton { } 2024d022e35SMiguel Boton }; 2034d022e35SMiguel Boton 2044d022e35SMiguel Boton static int __init reboot_init(void) 2054d022e35SMiguel Boton { 2064d022e35SMiguel Boton dmi_check_system(reboot_dmi_table); 2074d022e35SMiguel Boton return 0; 2084d022e35SMiguel Boton } 2094d022e35SMiguel Boton core_initcall(reboot_init); 2104d022e35SMiguel Boton 2114d022e35SMiguel Boton /* The following code and data reboots the machine by switching to real 2124d022e35SMiguel Boton mode and jumping to the BIOS reset entry point, as if the CPU has 2134d022e35SMiguel Boton really been reset. The previous version asked the keyboard 2144d022e35SMiguel Boton controller to pulse the CPU reset line, which is more thorough, but 2154d022e35SMiguel Boton doesn't work with at least one type of 486 motherboard. It is easy 2164d022e35SMiguel Boton to stop this code working; hence the copious comments. */ 217ebdd561aSJan Beulich static const unsigned long long 2184d022e35SMiguel Boton real_mode_gdt_entries [3] = 2194d022e35SMiguel Boton { 2204d022e35SMiguel Boton 0x0000000000000000ULL, /* Null descriptor */ 221ebdd561aSJan Beulich 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ 222ebdd561aSJan Beulich 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ 2234d022e35SMiguel Boton }; 2244d022e35SMiguel Boton 225ebdd561aSJan Beulich static const struct desc_ptr 2264d022e35SMiguel Boton real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, 2274d022e35SMiguel Boton real_mode_idt = { 0x3ff, 0 }; 2284d022e35SMiguel Boton 2294d022e35SMiguel Boton /* This is 16-bit protected mode code to disable paging and the cache, 2304d022e35SMiguel Boton switch to real mode and jump to the BIOS reset code. 2314d022e35SMiguel Boton 2324d022e35SMiguel Boton The instruction that switches to real mode by writing to CR0 must be 2334d022e35SMiguel Boton followed immediately by a far jump instruction, which set CS to a 2344d022e35SMiguel Boton valid value for real mode, and flushes the prefetch queue to avoid 2354d022e35SMiguel Boton running instructions that have already been decoded in protected 2364d022e35SMiguel Boton mode. 2374d022e35SMiguel Boton 2384d022e35SMiguel Boton Clears all the flags except ET, especially PG (paging), PE 2394d022e35SMiguel Boton (protected-mode enable) and TS (task switch for coprocessor state 2404d022e35SMiguel Boton save). Flushes the TLB after paging has been disabled. Sets CD and 2414d022e35SMiguel Boton NW, to disable the cache on a 486, and invalidates the cache. This 2424d022e35SMiguel Boton is more like the state of a 486 after reset. I don't know if 2434d022e35SMiguel Boton something else should be done for other chips. 2444d022e35SMiguel Boton 2454d022e35SMiguel Boton More could be done here to set up the registers as if a CPU reset had 2464d022e35SMiguel Boton occurred; hopefully real BIOSs don't assume much. */ 247ebdd561aSJan Beulich static const unsigned char real_mode_switch [] = 2484d022e35SMiguel Boton { 2494d022e35SMiguel Boton 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ 2504d022e35SMiguel Boton 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ 2514d022e35SMiguel Boton 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ 2524d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ 2534d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ 2544d022e35SMiguel Boton 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ 2554d022e35SMiguel Boton 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ 2564d022e35SMiguel Boton 0x74, 0x02, /* jz f */ 2574d022e35SMiguel Boton 0x0f, 0x09, /* wbinvd */ 2584d022e35SMiguel Boton 0x24, 0x10, /* f: andb $0x10,al */ 2594d022e35SMiguel Boton 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ 2604d022e35SMiguel Boton }; 261ebdd561aSJan Beulich static const unsigned char jump_to_bios [] = 2624d022e35SMiguel Boton { 2634d022e35SMiguel Boton 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ 2644d022e35SMiguel Boton }; 2654d022e35SMiguel Boton 2664d022e35SMiguel Boton /* 2674d022e35SMiguel Boton * Switch to real mode and then execute the code 2684d022e35SMiguel Boton * specified by the code and length parameters. 2694d022e35SMiguel Boton * We assume that length will aways be less that 100! 2704d022e35SMiguel Boton */ 271ebdd561aSJan Beulich void machine_real_restart(const unsigned char *code, int length) 2724d022e35SMiguel Boton { 2734d022e35SMiguel Boton local_irq_disable(); 2744d022e35SMiguel Boton 2754d022e35SMiguel Boton /* Write zero to CMOS register number 0x0f, which the BIOS POST 2764d022e35SMiguel Boton routine will recognize as telling it to do a proper reboot. (Well 2774d022e35SMiguel Boton that's what this book in front of me says -- it may only apply to 2784d022e35SMiguel Boton the Phoenix BIOS though, it's not clear). At the same time, 2794d022e35SMiguel Boton disable NMIs by setting the top bit in the CMOS address register, 2804d022e35SMiguel Boton as we're about to do peculiar things to the CPU. I'm not sure if 2814d022e35SMiguel Boton `outb_p' is needed instead of just `outb'. Use it to be on the 2824d022e35SMiguel Boton safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) 2834d022e35SMiguel Boton */ 2844d022e35SMiguel Boton spin_lock(&rtc_lock); 2854d022e35SMiguel Boton CMOS_WRITE(0x00, 0x8f); 2864d022e35SMiguel Boton spin_unlock(&rtc_lock); 2874d022e35SMiguel Boton 2884d022e35SMiguel Boton /* Remap the kernel at virtual address zero, as well as offset zero 2894d022e35SMiguel Boton from the kernel segment. This assumes the kernel segment starts at 2904d022e35SMiguel Boton virtual address PAGE_OFFSET. */ 29168db065cSJeremy Fitzhardinge memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, 2924d022e35SMiguel Boton sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); 2934d022e35SMiguel Boton 2944d022e35SMiguel Boton /* 2954d022e35SMiguel Boton * Use `swapper_pg_dir' as our page directory. 2964d022e35SMiguel Boton */ 2974d022e35SMiguel Boton load_cr3(swapper_pg_dir); 2984d022e35SMiguel Boton 2994d022e35SMiguel Boton /* Write 0x1234 to absolute memory location 0x472. The BIOS reads 3004d022e35SMiguel Boton this on booting to tell it to "Bypass memory test (also warm 3014d022e35SMiguel Boton boot)". This seems like a fairly standard thing that gets set by 3024d022e35SMiguel Boton REBOOT.COM programs, and the previous reset routine did this 3034d022e35SMiguel Boton too. */ 3044d022e35SMiguel Boton *((unsigned short *)0x472) = reboot_mode; 3054d022e35SMiguel Boton 3064d022e35SMiguel Boton /* For the switch to real mode, copy some code to low memory. It has 3074d022e35SMiguel Boton to be in the first 64k because it is running in 16-bit mode, and it 3084d022e35SMiguel Boton has to have the same physical and virtual address, because it turns 3094d022e35SMiguel Boton off paging. Copy it near the end of the first page, out of the way 3104d022e35SMiguel Boton of BIOS variables. */ 3114d022e35SMiguel Boton memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100), 3124d022e35SMiguel Boton real_mode_switch, sizeof (real_mode_switch)); 3134d022e35SMiguel Boton memcpy((void *)(0x1000 - 100), code, length); 3144d022e35SMiguel Boton 3154d022e35SMiguel Boton /* Set up the IDT for real mode. */ 3164d022e35SMiguel Boton load_idt(&real_mode_idt); 3174d022e35SMiguel Boton 3184d022e35SMiguel Boton /* Set up a GDT from which we can load segment descriptors for real 3194d022e35SMiguel Boton mode. The GDT is not used in real mode; it is just needed here to 3204d022e35SMiguel Boton prepare the descriptors. */ 3214d022e35SMiguel Boton load_gdt(&real_mode_gdt); 3224d022e35SMiguel Boton 3234d022e35SMiguel Boton /* Load the data segment registers, and thus the descriptors ready for 3244d022e35SMiguel Boton real mode. The base address of each segment is 0x100, 16 times the 3254d022e35SMiguel Boton selector value being loaded here. This is so that the segment 3264d022e35SMiguel Boton registers don't have to be reloaded after switching to real mode: 3274d022e35SMiguel Boton the values are consistent for real mode operation already. */ 3284d022e35SMiguel Boton __asm__ __volatile__ ("movl $0x0010,%%eax\n" 3294d022e35SMiguel Boton "\tmovl %%eax,%%ds\n" 3304d022e35SMiguel Boton "\tmovl %%eax,%%es\n" 3314d022e35SMiguel Boton "\tmovl %%eax,%%fs\n" 3324d022e35SMiguel Boton "\tmovl %%eax,%%gs\n" 3334d022e35SMiguel Boton "\tmovl %%eax,%%ss" : : : "eax"); 3344d022e35SMiguel Boton 3354d022e35SMiguel Boton /* Jump to the 16-bit code that we copied earlier. It disables paging 3364d022e35SMiguel Boton and the cache, switches to real mode, and jumps to the BIOS reset 3374d022e35SMiguel Boton entry point. */ 3384d022e35SMiguel Boton __asm__ __volatile__ ("ljmp $0x0008,%0" 3394d022e35SMiguel Boton : 3404d022e35SMiguel Boton : "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100))); 3414d022e35SMiguel Boton } 3424d022e35SMiguel Boton #ifdef CONFIG_APM_MODULE 3434d022e35SMiguel Boton EXPORT_SYMBOL(machine_real_restart); 3444d022e35SMiguel Boton #endif 3454d022e35SMiguel Boton 3464d022e35SMiguel Boton #endif /* CONFIG_X86_32 */ 3474d022e35SMiguel Boton 3484d022e35SMiguel Boton static inline void kb_wait(void) 3494d022e35SMiguel Boton { 3504d022e35SMiguel Boton int i; 3514d022e35SMiguel Boton 352c84d6af8SAlan Cox for (i = 0; i < 0x10000; i++) { 353c84d6af8SAlan Cox if ((inb(0x64) & 0x02) == 0) 3544d022e35SMiguel Boton break; 355c84d6af8SAlan Cox udelay(2); 356c84d6af8SAlan Cox } 3574d022e35SMiguel Boton } 3584d022e35SMiguel Boton 3597432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void) 3607432d149SIngo Molnar { 3617432d149SIngo Molnar } 3627432d149SIngo Molnar 363416e2d63SJody Belka static void native_machine_emergency_restart(void) 3644d022e35SMiguel Boton { 3654d022e35SMiguel Boton int i; 3664d022e35SMiguel Boton 3674d022e35SMiguel Boton /* Tell the BIOS if we want cold or warm reboot */ 3684d022e35SMiguel Boton *((unsigned short *)__va(0x472)) = reboot_mode; 3694d022e35SMiguel Boton 3704d022e35SMiguel Boton for (;;) { 3714d022e35SMiguel Boton /* Could also try the reset bit in the Hammer NB */ 3724d022e35SMiguel Boton switch (reboot_type) { 3734d022e35SMiguel Boton case BOOT_KBD: 3747432d149SIngo Molnar mach_reboot_fixups(); /* for board specific fixups */ 3757432d149SIngo Molnar 3764d022e35SMiguel Boton for (i = 0; i < 10; i++) { 3774d022e35SMiguel Boton kb_wait(); 3784d022e35SMiguel Boton udelay(50); 3794d022e35SMiguel Boton outb(0xfe, 0x64); /* pulse reset low */ 3804d022e35SMiguel Boton udelay(50); 3814d022e35SMiguel Boton } 3824d022e35SMiguel Boton 3834d022e35SMiguel Boton case BOOT_TRIPLE: 384ebdd561aSJan Beulich load_idt(&no_idt); 3854d022e35SMiguel Boton __asm__ __volatile__("int3"); 3864d022e35SMiguel Boton 387*14d7ca5cSH. Peter Anvin reboot_type = BOOT_CF9_COND; 3884d022e35SMiguel Boton break; 3894d022e35SMiguel Boton 3904d022e35SMiguel Boton #ifdef CONFIG_X86_32 3914d022e35SMiguel Boton case BOOT_BIOS: 3924d022e35SMiguel Boton machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); 3934d022e35SMiguel Boton 394*14d7ca5cSH. Peter Anvin reboot_type = BOOT_CF9_COND; 3954d022e35SMiguel Boton break; 3964d022e35SMiguel Boton #endif 3974d022e35SMiguel Boton 3984d022e35SMiguel Boton case BOOT_ACPI: 3994d022e35SMiguel Boton acpi_reboot(); 400*14d7ca5cSH. Peter Anvin reboot_type = BOOT_CF9_COND; 4014d022e35SMiguel Boton break; 4024d022e35SMiguel Boton 4034d022e35SMiguel Boton case BOOT_EFI: 4044d022e35SMiguel Boton if (efi_enabled) 405*14d7ca5cSH. Peter Anvin efi.reset_system(reboot_mode ? 406*14d7ca5cSH. Peter Anvin EFI_RESET_WARM : 407*14d7ca5cSH. Peter Anvin EFI_RESET_COLD, 4084d022e35SMiguel Boton EFI_SUCCESS, 0, NULL); 409*14d7ca5cSH. Peter Anvin reboot_type = BOOT_CF9_COND; 410*14d7ca5cSH. Peter Anvin break; 4114d022e35SMiguel Boton 412*14d7ca5cSH. Peter Anvin case BOOT_CF9: 413*14d7ca5cSH. Peter Anvin port_cf9_safe = true; 414*14d7ca5cSH. Peter Anvin /* fall through */ 415*14d7ca5cSH. Peter Anvin 416*14d7ca5cSH. Peter Anvin case BOOT_CF9_COND: 417*14d7ca5cSH. Peter Anvin if (port_cf9_safe) { 418*14d7ca5cSH. Peter Anvin u8 cf9 = inb(0xcf9) & ~6; 419*14d7ca5cSH. Peter Anvin outb(cf9|2, 0xcf9); /* Request hard reset */ 420*14d7ca5cSH. Peter Anvin udelay(50); 421*14d7ca5cSH. Peter Anvin outb(cf9|6, 0xcf9); /* Actually do the reset */ 422*14d7ca5cSH. Peter Anvin udelay(50); 423*14d7ca5cSH. Peter Anvin } 4244d022e35SMiguel Boton reboot_type = BOOT_KBD; 4254d022e35SMiguel Boton break; 4264d022e35SMiguel Boton } 4274d022e35SMiguel Boton } 4284d022e35SMiguel Boton } 4294d022e35SMiguel Boton 4303c62c625SGlauber Costa void native_machine_shutdown(void) 4314d022e35SMiguel Boton { 4324d022e35SMiguel Boton /* Stop the cpus and apics */ 4334d022e35SMiguel Boton #ifdef CONFIG_SMP 4344d022e35SMiguel Boton 4354d022e35SMiguel Boton /* The boot cpu is always logical cpu 0 */ 43665c01184SMike Travis int reboot_cpu_id = 0; 4374d022e35SMiguel Boton 4384d022e35SMiguel Boton #ifdef CONFIG_X86_32 4394d022e35SMiguel Boton /* See if there has been given a command line override */ 4404d022e35SMiguel Boton if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && 4410bc3cc03SMike Travis cpu_online(reboot_cpu)) 4424d022e35SMiguel Boton reboot_cpu_id = reboot_cpu; 4434d022e35SMiguel Boton #endif 4444d022e35SMiguel Boton 4454d022e35SMiguel Boton /* Make certain the cpu I'm about to reboot on is online */ 4460bc3cc03SMike Travis if (!cpu_online(reboot_cpu_id)) 4474d022e35SMiguel Boton reboot_cpu_id = smp_processor_id(); 4484d022e35SMiguel Boton 4494d022e35SMiguel Boton /* Make certain I only run on the appropriate processor */ 4500bc3cc03SMike Travis set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_cpu_id)); 4514d022e35SMiguel Boton 4524d022e35SMiguel Boton /* O.K Now that I'm on the appropriate processor, 4534d022e35SMiguel Boton * stop all of the others. 4544d022e35SMiguel Boton */ 4554d022e35SMiguel Boton smp_send_stop(); 4564d022e35SMiguel Boton #endif 4574d022e35SMiguel Boton 4584d022e35SMiguel Boton lapic_shutdown(); 4594d022e35SMiguel Boton 4604d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC 4614d022e35SMiguel Boton disable_IO_APIC(); 4624d022e35SMiguel Boton #endif 4634d022e35SMiguel Boton 4644d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER 4654d022e35SMiguel Boton hpet_disable(); 4664d022e35SMiguel Boton #endif 4674d022e35SMiguel Boton 4684d022e35SMiguel Boton #ifdef CONFIG_X86_64 4694d022e35SMiguel Boton pci_iommu_shutdown(); 4704d022e35SMiguel Boton #endif 4714d022e35SMiguel Boton } 4724d022e35SMiguel Boton 473416e2d63SJody Belka static void native_machine_restart(char *__unused) 4744d022e35SMiguel Boton { 4754d022e35SMiguel Boton printk("machine restart\n"); 4764d022e35SMiguel Boton 4774d022e35SMiguel Boton if (!reboot_force) 4784d022e35SMiguel Boton machine_shutdown(); 4794d022e35SMiguel Boton machine_emergency_restart(); 4804d022e35SMiguel Boton } 4814d022e35SMiguel Boton 482416e2d63SJody Belka static void native_machine_halt(void) 4834d022e35SMiguel Boton { 484d3ec5caeSIvan Vecera /* stop other cpus and apics */ 485d3ec5caeSIvan Vecera machine_shutdown(); 486d3ec5caeSIvan Vecera 487d3ec5caeSIvan Vecera /* stop this cpu */ 488d3ec5caeSIvan Vecera stop_this_cpu(NULL); 4894d022e35SMiguel Boton } 4904d022e35SMiguel Boton 491416e2d63SJody Belka static void native_machine_power_off(void) 4924d022e35SMiguel Boton { 4934d022e35SMiguel Boton if (pm_power_off) { 4944d022e35SMiguel Boton if (!reboot_force) 4954d022e35SMiguel Boton machine_shutdown(); 4964d022e35SMiguel Boton pm_power_off(); 4974d022e35SMiguel Boton } 4984d022e35SMiguel Boton } 4994d022e35SMiguel Boton 5004d022e35SMiguel Boton struct machine_ops machine_ops = { 501416e2d63SJody Belka .power_off = native_machine_power_off, 502416e2d63SJody Belka .shutdown = native_machine_shutdown, 503416e2d63SJody Belka .emergency_restart = native_machine_emergency_restart, 504416e2d63SJody Belka .restart = native_machine_restart, 505ed23dc6fSGlauber Costa .halt = native_machine_halt, 506ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 507ed23dc6fSGlauber Costa .crash_shutdown = native_machine_crash_shutdown, 508ed23dc6fSGlauber Costa #endif 5094d022e35SMiguel Boton }; 510416e2d63SJody Belka 511416e2d63SJody Belka void machine_power_off(void) 512416e2d63SJody Belka { 513416e2d63SJody Belka machine_ops.power_off(); 514416e2d63SJody Belka } 515416e2d63SJody Belka 516416e2d63SJody Belka void machine_shutdown(void) 517416e2d63SJody Belka { 518416e2d63SJody Belka machine_ops.shutdown(); 519416e2d63SJody Belka } 520416e2d63SJody Belka 521416e2d63SJody Belka void machine_emergency_restart(void) 522416e2d63SJody Belka { 523416e2d63SJody Belka machine_ops.emergency_restart(); 524416e2d63SJody Belka } 525416e2d63SJody Belka 526416e2d63SJody Belka void machine_restart(char *cmd) 527416e2d63SJody Belka { 528416e2d63SJody Belka machine_ops.restart(cmd); 529416e2d63SJody Belka } 530416e2d63SJody Belka 531416e2d63SJody Belka void machine_halt(void) 532416e2d63SJody Belka { 533416e2d63SJody Belka machine_ops.halt(); 534416e2d63SJody Belka } 535416e2d63SJody Belka 536ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC 537ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs) 538ed23dc6fSGlauber Costa { 539ed23dc6fSGlauber Costa machine_ops.crash_shutdown(regs); 540ed23dc6fSGlauber Costa } 541ed23dc6fSGlauber Costa #endif 542