linux/drivers/acpi/reboot.c
<<
>>
Prefs
   1
   2#include <linux/pci.h>
   3#include <linux/acpi.h>
   4#include <acpi/reboot.h>
   5
   6void acpi_reboot(void)
   7{
   8        struct acpi_generic_address *rr;
   9        struct pci_bus *bus0;
  10        u8 reset_value;
  11        unsigned int devfn;
  12
  13        if (acpi_disabled)
  14                return;
  15
  16        rr = &acpi_gbl_FADT.reset_register;
  17
  18        /*
  19         * Is the ACPI reset register supported?
  20         *
  21         * According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates
  22         * whether the ACPI reset mechanism is supported.
  23         *
  24         * However, some boxes have this bit clear, yet a valid
  25         * ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only
  26         * mechanism that works for them after S3.
  27         *
  28         * This suggests that other operating systems may not be checking
  29         * the RESET_REG_SUP bit, and are using other means to decide
  30         * whether to use the ACPI reboot mechanism or not.
  31         *
  32         * So when acpi reboot is requested,
  33         * only the reset_register is checked. If the following
  34         * conditions are met, it indicates that the reset register is supported.
  35         *      a. reset_register is not zero
  36         *      b. the access width is eight
  37         *      c. the bit_offset is zero
  38         */
  39        if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0)
  40                return;
  41
  42        reset_value = acpi_gbl_FADT.reset_value;
  43
  44        /* The reset register can only exist in I/O, Memory or PCI config space
  45         * on a device on bus 0. */
  46        switch (rr->space_id) {
  47        case ACPI_ADR_SPACE_PCI_CONFIG:
  48                /* The reset register can only live on bus 0. */
  49                bus0 = pci_find_bus(0, 0);
  50                if (!bus0)
  51                        return;
  52                /* Form PCI device/function pair. */
  53                devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
  54                                  (rr->address >> 16) & 0xffff);
  55                printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.");
  56                /* Write the value that resets us. */
  57                pci_bus_write_config_byte(bus0, devfn,
  58                                (rr->address & 0xffff), reset_value);
  59                break;
  60
  61        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
  62        case ACPI_ADR_SPACE_SYSTEM_IO:
  63                printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
  64                acpi_hw_low_level_write(8, reset_value, rr);
  65                break;
  66        }
  67        /* Wait ten seconds */
  68        acpi_os_stall(10000000);
  69}
  70
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.