1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/pci.h> 4 #include <linux/acpi.h> 5 #include <acpi/reboot.h> 6 7 void acpi_reboot(void) 8 { 9 struct acpi_generic_address *rr; 10 struct pci_bus *bus0; 11 u8 reset_value; 12 unsigned int devfn; 13 14 if (acpi_disabled) 15 return; 16 17 rr = &acpi_gbl_FADT.reset_register; 18 19 /* ACPI reset register was only introduced with v2 of the FADT */ 20 21 if (acpi_gbl_FADT.header.revision < 2) 22 return; 23 24 /* Is the reset register supported? The spec says we should be 25 * checking the bit width and bit offset, but Windows ignores 26 * these fields */ 27 if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) 28 return; 29 30 reset_value = acpi_gbl_FADT.reset_value; 31 32 /* The reset register can only exist in I/O, Memory or PCI config space 33 * on a device on bus 0. */ 34 switch (rr->space_id) { 35 case ACPI_ADR_SPACE_PCI_CONFIG: 36 /* The reset register can only live on bus 0. */ 37 bus0 = pci_find_bus(0, 0); 38 if (!bus0) 39 return; 40 /* Form PCI device/function pair. */ 41 devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, 42 (rr->address >> 16) & 0xffff); 43 printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); 44 /* Write the value that resets us. */ 45 pci_bus_write_config_byte(bus0, devfn, 46 (rr->address & 0xffff), reset_value); 47 break; 48 49 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 50 case ACPI_ADR_SPACE_SYSTEM_IO: 51 printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); 52 acpi_reset(); 53 break; 54 } 55 } 56