]> xenbits.xensource.com Git - seabios.git/commitdiff
Add acpi_reboot() reset method using RESET_REG
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 23 Feb 2013 00:24:49 +0000 (00:24 +0000)
committerKevin O'Connor <kevin@koconnor.net>
Sat, 23 Feb 2013 14:52:39 +0000 (09:52 -0500)
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
src/acpi.c
src/acpi.h
src/resume.c

index 36bd39a068c9234ba001e3bb065e9576605cff11..195dc885e8ddf144105a64b604581243838e25e6 100644 (file)
@@ -150,17 +150,6 @@ struct madt_local_nmi {
 } PACKED;
 
 
-/*
- * 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
  */
@@ -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;
 }
index b23717af6885e044452675fb645ebf08a0266556..62899536b8ea234f960b31db7d45be7a7704438f 100644 (file)
@@ -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 "
 
index b30d62eb1025fcee935f61a73df0ff6d5bd4b8b8..784abac00d5ca9859577820a9efed630ae609744 100644 (file)
@@ -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();