ecfbbc7b46
Changed the acpi_hw_low_level_read and acpi_hw_low_level_write functions to the public acpi_read and acpi_write to allow direct access to ACPI registers. Removed the "width" parameter since the width can be obtained from the input GAS structure. Updated the FADT initialization to setup the GAS structures with the proper widths. Some widths are still hardcoded because many FADTs have incorrect register lengths. Signed-off-by: Bob Moore <robert.moore@intel.com Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
51 lines
1.2 KiB
C
51 lines
1.2 KiB
C
|
|
#include <linux/pci.h>
|
|
#include <linux/acpi.h>
|
|
#include <acpi/reboot.h>
|
|
|
|
void acpi_reboot(void)
|
|
{
|
|
struct acpi_generic_address *rr;
|
|
struct pci_bus *bus0;
|
|
u8 reset_value;
|
|
unsigned int devfn;
|
|
|
|
if (acpi_disabled)
|
|
return;
|
|
|
|
rr = &acpi_gbl_FADT.reset_register;
|
|
|
|
/* Is the reset register supported? */
|
|
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
|
|
rr->bit_width != 8 || rr->bit_offset != 0)
|
|
return;
|
|
|
|
reset_value = acpi_gbl_FADT.reset_value;
|
|
|
|
/* The reset register can only exist in I/O, Memory or PCI config space
|
|
* on a device on bus 0. */
|
|
switch (rr->space_id) {
|
|
case ACPI_ADR_SPACE_PCI_CONFIG:
|
|
/* The reset register can only live on bus 0. */
|
|
bus0 = pci_find_bus(0, 0);
|
|
if (!bus0)
|
|
return;
|
|
/* Form PCI device/function pair. */
|
|
devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
|
|
(rr->address >> 16) & 0xffff);
|
|
printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.");
|
|
/* Write the value that resets us. */
|
|
pci_bus_write_config_byte(bus0, devfn,
|
|
(rr->address & 0xffff), reset_value);
|
|
break;
|
|
|
|
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
|
case ACPI_ADR_SPACE_SYSTEM_IO:
|
|
printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
|
|
acpi_write(reset_value, rr);
|
|
break;
|
|
}
|
|
/* Wait ten seconds */
|
|
acpi_os_stall(10000000);
|
|
}
|