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