14d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
24d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin#include <linux/pci.h>
34d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin#include <linux/acpi.h>
44d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin#include <acpi/reboot.h>
54d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
64d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbinvoid acpi_reboot(void)
74d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin{
84d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	struct acpi_generic_address *rr;
94d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	struct pci_bus *bus0;
104d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	u8 reset_value;
114d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	unsigned int devfn;
124d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
134d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	if (acpi_disabled)
144d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		return;
154d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
164d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	rr = &acpi_gbl_FADT.reset_register;
174d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
1895cf3e12e7f659e536215b37c67d46f3e2ce95ccMatthew Garrett	/* ACPI reset register was only introduced with v2 of the FADT */
1995cf3e12e7f659e536215b37c67d46f3e2ce95ccMatthew Garrett
2095cf3e12e7f659e536215b37c67d46f3e2ce95ccMatthew Garrett	if (acpi_gbl_FADT.header.revision < 2)
2195cf3e12e7f659e536215b37c67d46f3e2ce95ccMatthew Garrett		return;
2295cf3e12e7f659e536215b37c67d46f3e2ce95ccMatthew Garrett
236734fe57a07b2dd23ef1ef2ac1f790747e53eefcMatthew Garrett	/* Is the reset register supported? The spec says we should be
246734fe57a07b2dd23ef1ef2ac1f790747e53eefcMatthew Garrett	 * checking the bit width and bit offset, but Windows ignores
256734fe57a07b2dd23ef1ef2ac1f790747e53eefcMatthew Garrett	 * these fields */
266734fe57a07b2dd23ef1ef2ac1f790747e53eefcMatthew Garrett	if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER))
274d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		return;
284d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
294d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	reset_value = acpi_gbl_FADT.reset_value;
304d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
314d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	/* The reset register can only exist in I/O, Memory or PCI config space
324d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	 * on a device on bus 0. */
334d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	switch (rr->space_id) {
344d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	case ACPI_ADR_SPACE_PCI_CONFIG:
354d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		/* The reset register can only live on bus 0. */
364d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		bus0 = pci_find_bus(0, 0);
374d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		if (!bus0)
384d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin			return;
394d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		/* Form PCI device/function pair. */
404d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
414d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin				  (rr->address >> 16) & 0xffff);
424d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.");
434d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		/* Write the value that resets us. */
444d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		pci_bus_write_config_byte(bus0, devfn,
454d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin				(rr->address & 0xffff), reset_value);
464d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		break;
474d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin
484d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
494d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	case ACPI_ADR_SPACE_SYSTEM_IO:
504d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
512ee62612485f888b731804ca1b3b18ed8e842b51Lin Ming		acpi_reset();
524d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin		break;
534d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin	}
544d3870431d17346c4fdd80e087b7d76f1b5941d5Aaron Durbin}
55