qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/2] Add PIIX4 properties to control PM system state


From: Gleb Natapov
Subject: [Qemu-devel] [PATCH 2/2] Add PIIX4 properties to control PM system states.
Date: Mon, 14 May 2012 15:34:18 +0300

This patch adds two things. First it allows QEMU to distinguish between
regular powerdown and S4 powerdown. Later separate QMP notification will
be added for S4 powerdown. Second it allows S3/S4 states to be disabled
from QEMU command line. Some guests known to be broken with regards to
power management, but allow to use it anyway. Using new properties
management will be able to disable S3/S4 for such guests.

Supported system state are passed to a firmware using new fw_cfg entry.
The entry contains  6 byte array. Each byte represents one system
state. If byte at offset X has its MSB set it means that system state
X is supported and to enter it guest should use the value from lowest 7
bits.

Signed-off-by: Gleb Natapov <address@hidden>
---
 hw/acpi.c       |    5 ++++-
 hw/acpi.h       |    2 +-
 hw/acpi_piix4.c |   21 +++++++++++++++++++--
 hw/mips_malta.c |    3 ++-
 hw/pc.c         |    6 ------
 hw/pc.h         |   10 +++++++++-
 hw/pc_piix.c    |    2 +-
 hw/vt82c686.c   |    2 +-
 8 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/hw/acpi.c b/hw/acpi.c
index 5d521e5..effc7ec 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -370,7 +370,7 @@ void acpi_pm1_cnt_init(ACPIREGS *ar)
     qemu_register_wakeup_notifier(&ar->wakeup);
 }
 
-void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
+void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4)
 {
     ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
 
@@ -385,6 +385,9 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
             qemu_system_suspend_request();
             break;
         default:
+            if (sus_typ == s4) { /* S4 request */
+                qemu_system_shutdown_request();
+            }
             break;
         }
     }
diff --git a/hw/acpi.h b/hw/acpi.h
index fe8cdb4..7337f41 100644
--- a/hw/acpi.h
+++ b/hw/acpi.h
@@ -139,7 +139,7 @@ void acpi_pm1_evt_reset(ACPIREGS *ar);
 
 /* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
 void acpi_pm1_cnt_init(ACPIREGS *ar);
-void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val);
+void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4);
 void acpi_pm1_cnt_update(ACPIREGS *ar,
                          bool sci_enable, bool sci_disable);
 void acpi_pm1_cnt_reset(ACPIREGS *ar);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 585da4e..ce1f5af 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "range.h"
 #include "ioport.h"
+#include "fw_cfg.h"
 
 //#define DEBUG
 
@@ -71,6 +72,10 @@ typedef struct PIIX4PMState {
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
     uint32_t pci0_slot_device_present;
+
+    uint8_t disable_s3;
+    uint8_t disable_s4;
+    uint8_t s4_val;
 } PIIX4PMState;
 
 static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -123,7 +128,7 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, 
unsigned width,
         pm_update_sci(s);
         break;
     case 0x04:
-        acpi_pm1_cnt_write(&s->ar, val);
+        acpi_pm1_cnt_write(&s->ar, val, s->s4_val);
         break;
     default:
         break;
@@ -421,7 +426,7 @@ static int piix4_pm_initfn(PCIDevice *dev)
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled)
+                       int kvm_enabled, uint16_t fw_cfg_key)
 {
     PCIDevice *dev;
     PIIX4PMState *s;
@@ -437,11 +442,23 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t 
smb_io_base,
 
     qdev_init_nofail(&dev->qdev);
 
+    if (fw_cfg_key != FW_CFG_INVALID) {
+        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
+
+       suspend[3] = 1 | ((!s->disable_s3) << 7);
+       suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
+              
+        fw_cfg_add_bytes(fw_cfg_key, g_memdup(suspend, 6), 6);
+    }
+
     return s->smb.smbus;
 }
 
 static Property piix4_pm_properties[] = {
     DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+    DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0),
+    DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0),
+    DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 4752bb2..5f0f5b6 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -48,6 +48,7 @@
 #include "blockdev.h"
 #include "exec-memory.h"
 #include "sysbus.h"             /* SysBusDevice */
+#include "fw_cfg.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -954,7 +955,7 @@ void mips_malta_init (ram_addr_t ram_size,
     pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
     pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
-                          isa_get_irq(NULL, 9), NULL, 0);
+                          isa_get_irq(NULL, 9), NULL, 0, FW_CFG_INVALID);
     /* TODO: Populate SPD eeprom data.  */
     smbus_eeprom_init(smbus, 8, NULL, 0);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
diff --git a/hw/pc.c b/hw/pc.c
index 5d28d3b..3a2c2d2 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -29,7 +29,6 @@
 #include "pci.h"
 #include "vmware_vga.h"
 #include "monitor.h"
-#include "fw_cfg.h"
 #include "hpet_emul.h"
 #include "smbios.h"
 #include "loader.h"
@@ -64,11 +63,6 @@
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
 #define BIOS_CFG_IOPORT 0x510
-#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
-#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
-#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
-#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
-#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
 
 #define MSI_ADDR_BASE 0xfee00000
 
diff --git a/hw/pc.h b/hw/pc.h
index 74d3369..4d23712 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -9,6 +9,7 @@
 #include "net.h"
 #include "memory.h"
 #include "ioapic.h"
+#include "fw_cfg.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
@@ -142,7 +143,7 @@ int acpi_table_add(const char *table_desc);
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled);
+                       int kvm_enabled, uint16_t fw_cfg_key);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 
 /* hpet.c */
@@ -227,4 +228,11 @@ void pc_system_firmware_init(MemoryRegion *rom_memory);
 
 int e820_add_entry(uint64_t, uint64_t, uint32_t);
 
+#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
+#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
+#define FW_CFG_SYSTEM_STATES (FW_CFG_ARCH_LOCAL + 5)
+
 #endif
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 6a75718..6bd2791 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -280,7 +280,7 @@ static void pc_init1(MemoryRegion *system_memory,
         /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
                               gsi[9], *smi_irq,
-                              kvm_enabled());
+                              kvm_enabled(), FW_CFG_SYSTEM_STATES);
         smbus_eeprom_init(smbus, 8, NULL, 0);
     }
 
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 6fb7950..5d7c00c 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -210,7 +210,7 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, 
uint32_t val)
         pm_update_sci(s);
         break;
     case 0x04:
-        acpi_pm1_cnt_write(&s->ar, val);
+        acpi_pm1_cnt_write(&s->ar, val, 0);
         break;
     default:
         break;
-- 
1.7.7.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]