diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2013-02-23 00:24:49 +0000 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2013-02-23 09:52:39 -0500 |
commit | d338eb94f65c765d43fd9cc9c31e9ec914ca64e3 (patch) | |
tree | 955ffbc87267fce03985581330eae8bacf71b759 | |
parent | d304fe4250934e1ce3f3296f3e538cc7ad05dea6 (diff) | |
download | seabios-d338eb94f65c765d43fd9cc9c31e9ec914ca64e3.tar.gz |
Add acpi_reboot() reset method using RESET_REG
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | src/acpi.c | 58 | ||||
-rw-r--r-- | src/acpi.h | 14 | ||||
-rw-r--r-- | src/resume.c | 3 |
3 files changed, 64 insertions, 11 deletions
@@ -151,17 +151,6 @@ struct madt_local_nmi { /* - * ACPI 2.0 Generic Address Space definition. - */ -struct acpi_20_generic_address { - u8 address_space_id; - u8 register_bit_width; - u8 register_bit_offset; - u8 reserved; - u64 address; -} PACKED; - -/* * HPET Description Table */ struct acpi_20_hpet { @@ -934,4 +923,51 @@ find_acpi_features(void) dprintf(4, "pm_tmr_blk=%x\n", pm_tmr); if (pm_tmr) pmtimer_setup(pm_tmr, 3579); + + // Theoretically we should check the 'reset_reg_sup' flag, but Windows + // doesn't and thus nobody seems to *set* it. If the table is large enough + // to include it, let the sanity checks in acpi_set_reset_reg() suffice. + if (fadt->length >= 129) { + void *p = fadt; + acpi_set_reset_reg(p + 116, *(u8 *)(p + 128)); + } +} + +static struct acpi_20_generic_address acpi_reset_reg; +static u8 acpi_reset_val; + +void +acpi_reboot(void) +{ + // Check it passed the sanity checks in acpi_set_reset_reg() and was set + if (acpi_reset_reg.register_bit_width != 8) + return; + + u64 addr = le64_to_cpu(acpi_reset_reg.address); + + dprintf(1, "ACPI hard reset %d:%llx (%x)\n", + acpi_reset_reg.address_space_id, addr, acpi_reset_val); + + switch (acpi_reset_reg.address_space_id) { + case 0: // System Memory + writeb((void *)(u32)addr, acpi_reset_val); + break; + case 1: // System I/O + outb(acpi_reset_val, addr); + break; + case 2: // PCI config space + pci_config_writeb(acpi_ga_to_bdf(addr), addr & 0xffff, acpi_reset_val); + break; + } +} + +void +acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val) +{ + if (!reg || reg->address_space_id > 2 || + reg->register_bit_width != 8 || reg->register_bit_offset) + return; + + acpi_reset_reg = *reg; + acpi_reset_val = val; } @@ -3,9 +3,23 @@ #include "types.h" // u32 +/* + * ACPI 2.0 Generic Address Space definition. + */ +struct acpi_20_generic_address { + u8 address_space_id; + u8 register_bit_width; + u8 register_bit_offset; + u8 reserved; + u64 address; +} PACKED; +#define acpi_ga_to_bdf(addr) pci_to_bdf(0, (addr >> 32) & 0xffff, (addr >> 16) & 0xffff) + void acpi_setup(void); u32 find_resume_vector(void); void find_acpi_features(void); +void acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val); +void acpi_reboot(void); #define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR " diff --git a/src/resume.c b/src/resume.c index b30d62e..784abac 100644 --- a/src/resume.c +++ b/src/resume.c @@ -132,6 +132,9 @@ tryReboot(void) // Setup for reset on qemu. qemu_prep_reset(); + // Reboot using ACPI RESET_REG + acpi_reboot(); + // Try keyboard controller reboot. i8042_reboot(); |