reboot.c (2055B)
1// SPDX-License-Identifier: GPL-2.0 2 3#define pr_fmt(fmt) "ACPI: " fmt 4 5#include <linux/pci.h> 6#include <linux/acpi.h> 7#include <acpi/reboot.h> 8#include <linux/delay.h> 9 10#ifdef CONFIG_PCI 11static void acpi_pci_reboot(struct acpi_generic_address *rr, u8 reset_value) 12{ 13 unsigned int devfn; 14 struct pci_bus *bus0; 15 16 /* The reset register can only live on bus 0. */ 17 bus0 = pci_find_bus(0, 0); 18 if (!bus0) 19 return; 20 /* Form PCI device/function pair. */ 21 devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, 22 (rr->address >> 16) & 0xffff); 23 pr_debug("Resetting with ACPI PCI RESET_REG.\n"); 24 /* Write the value that resets us. */ 25 pci_bus_write_config_byte(bus0, devfn, 26 (rr->address & 0xffff), reset_value); 27} 28#else 29static inline void acpi_pci_reboot(struct acpi_generic_address *rr, 30 u8 reset_value) 31{ 32 pr_warn_once("PCI configuration space access is not supported\n"); 33} 34#endif 35 36void acpi_reboot(void) 37{ 38 struct acpi_generic_address *rr; 39 u8 reset_value; 40 41 if (acpi_disabled) 42 return; 43 44 rr = &acpi_gbl_FADT.reset_register; 45 46 /* ACPI reset register was only introduced with v2 of the FADT */ 47 48 if (acpi_gbl_FADT.header.revision < 2) 49 return; 50 51 /* Is the reset register supported? The spec says we should be 52 * checking the bit width and bit offset, but Windows ignores 53 * these fields */ 54 if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) 55 return; 56 57 reset_value = acpi_gbl_FADT.reset_value; 58 59 /* The reset register can only exist in I/O, Memory or PCI config space 60 * on a device on bus 0. */ 61 switch (rr->space_id) { 62 case ACPI_ADR_SPACE_PCI_CONFIG: 63 acpi_pci_reboot(rr, reset_value); 64 break; 65 66 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 67 case ACPI_ADR_SPACE_SYSTEM_IO: 68 pr_debug("ACPI MEMORY or I/O RESET_REG.\n"); 69 acpi_reset(); 70 break; 71 } 72 73 /* 74 * Some platforms do not shut down immediately after writing to the 75 * ACPI reset register, and this results in racing with the 76 * subsequent reboot mechanism. 77 * 78 * The 15ms delay has been found to be long enough for the system 79 * to reboot on the affected platforms. 80 */ 81 mdelay(15); 82}