aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2013-02-23 00:24:49 +0000
committerKevin O'Connor <kevin@koconnor.net>2013-02-23 09:52:39 -0500
commitd338eb94f65c765d43fd9cc9c31e9ec914ca64e3 (patch)
tree955ffbc87267fce03985581330eae8bacf71b759
parentd304fe4250934e1ce3f3296f3e538cc7ad05dea6 (diff)
downloadseabios-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.c58
-rw-r--r--src/acpi.h14
-rw-r--r--src/resume.c3
3 files changed, 64 insertions, 11 deletions
diff --git a/src/acpi.c b/src/acpi.c
index 36bd39a..195dc88 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -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;
}
diff --git a/src/acpi.h b/src/acpi.h
index b23717a..6289953 100644
--- a/src/acpi.h
+++ b/src/acpi.h
@@ -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();