1 2 #include <linux/pci.h> 3 #include <linux/acpi.h> 4 #include <acpi/reboot.h> 5 6 void acpi_reboot(void) 7 { 8 struct acpi_generic_address *rr; 9 struct pci_bus *bus0; 10 u8 reset_value; 11 unsigned int devfn; 12 13 if (acpi_disabled) 14 return; 15 16 rr = &acpi_gbl_FADT.reset_register; 17 18 /* 19 * Is the ACPI reset register supported? 20 * 21 * According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates 22 * whether the ACPI reset mechanism is supported. 23 * 24 * However, some boxes have this bit clear, yet a valid 25 * ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only 26 * mechanism that works for them after S3. 27 * 28 * This suggests that other operating systems may not be checking 29 * the RESET_REG_SUP bit, and are using other means to decide 30 * whether to use the ACPI reboot mechanism or not. 31 * 32 * So when acpi reboot is requested, 33 * only the reset_register is checked. If the following 34 * conditions are met, it indicates that the reset register is supported. 35 * a. reset_register is not zero 36 * b. the access width is eight 37 * c. the bit_offset is zero 38 */ 39 if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0) 40 return; 41 42 reset_value = acpi_gbl_FADT.reset_value; 43 44 /* The reset register can only exist in I/O, Memory or PCI config space 45 * on a device on bus 0. */ 46 switch (rr->space_id) { 47 case ACPI_ADR_SPACE_PCI_CONFIG: 48 /* The reset register can only live on bus 0. */ 49 bus0 = pci_find_bus(0, 0); 50 if (!bus0) 51 return; 52 /* Form PCI device/function pair. */ 53 devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, 54 (rr->address >> 16) & 0xffff); 55 printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); 56 /* Write the value that resets us. */ 57 pci_bus_write_config_byte(bus0, devfn, 58 (rr->address & 0xffff), reset_value); 59 break; 60 61 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 62 case ACPI_ADR_SPACE_SYSTEM_IO: 63 printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); 64 acpi_hw_low_level_write(8, reset_value, rr); 65 break; 66 } 67 /* Wait ten seconds */ 68 acpi_os_stall(10000000); 69 } 70