]> xenbits.xensource.com Git - seabios.git/commitdiff
apm: fix shutdown
authorGerd Hoffmann <kraxel@redhat.com>
Thu, 25 Jul 2013 07:47:18 +0000 (09:47 +0200)
committerGerd Hoffmann <kraxel@redhat.com>
Tue, 20 Aug 2013 06:55:55 +0000 (08:55 +0200)
Qemu commit 9ee59f3 removed the bochs bios apm interface emulation at
port 0x8900.  That broke poweroff via APM.  Fix it by powering off the
machine using the acpi pm control register.

Old code is left in, so seabios wil try both poweroff methods.  Cleaning
that eventually up is left for another patch, after checking it isn't
needed.  Qemu never implemented "Standby" and "Suspend", only
"Shutdown", so it looks like there might be non-qemu use cases (bochs
probably).

Easiest way to test this is the syslinux poweroff module; modern linux
distros usually have CONFIG_APM turned off.

Reported-by: Sebastian Herbszt <herbszt@gmx.de>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 5b63109242042372c1d6c3d23602e980f1c9637b)

Conflicts:
src/acpi.c
src/pciinit.c

src/acpi.c
src/acpi.h
src/apm.c
src/pciinit.c

index 3699898c2525a9d5b2d5242c780c014d11c78f4b..1994838213b0678eea080b34208969450ef18b7a 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "acpi-dsdt.hex"
 
+u32 acpi_pm1a_cnt VARFSEG;
+
 static void
 build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
 {
@@ -730,9 +732,12 @@ find_acpi_features(void)
     if (!fadt)
         return;
     u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
+    u32 pm1a_cnt = le32_to_cpu(fadt->pm1a_cnt_blk);
     dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
     if (pm_tmr)
         pmtimer_setup(pm_tmr, 3579);
+    if (pm1a_cnt)
+        acpi_pm1a_cnt = pm1a_cnt;
 
     // 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
index 5d1e104188faa5c552ae6a14182883169d77634a..f0d24d436c5dd51e66021c059d28785b13607ea7 100644 (file)
@@ -36,6 +36,7 @@ struct rsdp_descriptor {        /* Root System Descriptor Pointer */
 };
 
 extern struct rsdp_descriptor *RsdpAddr;
+extern u32 acpi_pm1a_cnt;
 
 /* Table structure from Linux kernel (the ACPI tables are under the
    BSD license) */
index b2eac6de63912e647d856ca13f5930a5635ea6aa..de6bd997968aee68e94a9db2bcd6123dee15f6e4 100644 (file)
--- a/src/apm.c
+++ b/src/apm.c
@@ -12,6 +12,7 @@
 #include "config.h" // CONFIG_*
 #include "biosvar.h" // GET_GLOBAL
 #include "paravirt.h" // runningOnQEMU
+#include "acpi.h" // acpi_pm_ctl
 
 static void
 out_str(const char *str_cs)
@@ -108,7 +109,11 @@ handle_155306(struct bregs *regs)
 void
 apm_shutdown(void)
 {
+    u16 pm1a_cnt = GET_GLOBAL(acpi_pm1a_cnt);
+
     irq_disable();
+    if (pm1a_cnt)
+        outw(0x2000, pm1a_cnt);
     out_str("Shutdown");
     for (;;)
         hlt();
index 8370b960e7384d574a64ba3e87546e23e7e9f779..0c6b0cb994cd22b909fc3af6e1943c7127ad9013 100644 (file)
@@ -15,6 +15,7 @@
 #include "paravirt.h" // RamSize
 #include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
 #include "list.h" // struct hlist_node
+#include "acpi.h" // acpi_pm1a_cnt
 
 /* PM Timer ticks per second (HZ) */
 #define PM_TIMER_FREQUENCY  3579545
@@ -194,6 +195,7 @@ void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
     /* acpi enable, SCI: IRQ9 000b = irq9*/
     pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
 
+    acpi_pm1a_cnt = PORT_ACPI_PM_BASE + 0x04;
     pmtimer_setup(PORT_ACPI_PM_BASE + 0x08, PM_TIMER_FREQUENCY / 1000);
 }
 
@@ -238,6 +240,7 @@ static void piix4_pm_setup(struct pci_device *pci, void *arg)
     pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
     pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
 
+    acpi_pm1a_cnt = PORT_ACPI_PM_BASE + 0x04;
     pmtimer_setup(PORT_ACPI_PM_BASE + 0x08, PM_TIMER_FREQUENCY / 1000);
 }