From: Anthony PERARD <anthony.perard@xxxxxxxxxx>
Some change have been introduced in the firmware to match QEMU's BIOS.
So this patch adds the new sleep state values and handle old and new
ACPI IOPort mapping.
QEMU-Xen uses new ioport by default, but if it's a saved state with old
firmware, it unmaps the new ioport and maps the old one.
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
hw/piix4acpi.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 80 insertions(+), 17 deletions(-)
diff --git a/hw/piix4acpi.c b/hw/piix4acpi.c
index 1efa77d..589d4a4 100644
--- a/hw/piix4acpi.c
+++ b/hw/piix4acpi.c
@@ -52,9 +52,12 @@
/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */
/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */
-#define SLP_TYP_S4 (6 << 10)
-#define SLP_TYP_S3 (5 << 10)
-#define SLP_TYP_S5 (7 << 10)
+#define SLP_TYP_S4_OLD (6 << 10)
+#define SLP_TYP_S3_OLD (5 << 10)
+#define SLP_TYP_S5_OLD (7 << 10)
+#define SLP_TYP_S4 (0 << 10)
+#define SLP_TYP_S3 (1 << 10)
+#define SLP_TYP_S5 (0 << 10)
#define ACPI_DBG_IO_ADDR 0xb044
#define ACPI_PHP_IO_ADDR 0x10c0
@@ -75,12 +78,15 @@
typedef struct PCIAcpiState {
PCIDevice dev;
uint16_t pm1_control; /* pm1a_ECNT_BLK */
+
+ /* if true, use old ioport of the firmware. */
+ uint8_t use_old_ioport;
} PCIAcpiState;
typedef struct GPEState {
/* GPE0 block */
- uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
- uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
+ uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN_OLD / 2];
+ uint8_t gpe0_en[ACPI_GPE0_BLK_LEN_OLD / 2];
/* CPU bitmap */
uint8_t cpus_sts[32];
@@ -88,6 +94,8 @@ typedef struct GPEState {
/* SCI IRQ level */
uint8_t sci_asserted;
+ /* if true, use old ioport of the firmware. */
+ uint8_t use_old_ioport;
} GPEState;
static GPEState gpe_state;
@@ -100,6 +108,9 @@ typedef struct PHPDevFn {
* PSTB in ASL */
} PHPDevFn;
+static void acpi_map(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type);
+
static PHPDevFn php_devfn;
int s3_shutdown_flag;
static qemu_irq sci_irq;
@@ -138,18 +149,34 @@ static void piix4acpi_save(QEMUFile *f, void *opaque)
PCIAcpiState *s = opaque;
pci_device_save(&s->dev, f);
qemu_put_be16s(f, &s->pm1_control);
+ qemu_put_8s(f, &s->use_old_ioport);
}
static int piix4acpi_load(QEMUFile *f, void *opaque, int version_id)
{
PCIAcpiState *s = opaque;
int ret;
- if (version_id > 1)
+
+ if (version_id > 2)
return -EINVAL;
ret = pci_device_load(&s->dev, f);
if (ret < 0)
return ret;
qemu_get_be16s(f, &s->pm1_control);
+
+ if (version_id <= 1) {
+ /* map to old ioport instead of the new one */
+ s->use_old_ioport = 1;
+ } else {
+ qemu_get_8s(f, &s->use_old_ioport);
+ }
+
+ if (s->use_old_ioport) {
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI: Use old firmware IOPorts.\n");
+ /* unmap new ioport to use old ioport */
+ isa_unassign_ioport(ACPI_PM1A_EVT_BLK_ADDRESS + 4, 2);
+ acpi_map((PCIDevice *)s, 0, ACPI_PM1A_EVT_BLK_ADDRESS_OLD, 0x10,
PCI_ADDRESS_SPACE_IO);
+ }
return 0;
}
@@ -172,6 +199,7 @@ static void acpi_shutdown(uint32_t val)
return;
switch (val & SLP_TYP_Sx) {
+ case SLP_TYP_S3_OLD:
case SLP_TYP_S3:
s3_shutdown_flag = 1;
qemu_system_reset();
@@ -179,7 +207,8 @@ static void acpi_shutdown(uint32_t val)
cmos_set_s3_resume();
xc_set_hvm_param(xc_handle, domid, HVM_PARAM_ACPI_S_STATE, 3);
break;
- case SLP_TYP_S4:
+ case SLP_TYP_S4_OLD:
+ case SLP_TYP_S5_OLD:
case SLP_TYP_S5:
qemu_system_shutdown_request();
break;
@@ -403,7 +432,10 @@ static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
{
GPEState *s = opaque;
- return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
+ if (s->use_old_ioport)
+ return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS_OLD];
+ else
+ return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
}
/* write 1 to clear specific GPE bits */
@@ -415,7 +447,10 @@ static void gpe_sts_write(void *opaque, uint32_t addr,
uint32_t val)
PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x,
val=0x%x.\n", addr, val);
hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
- s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
+ if (s->use_old_ioport)
+ s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS_OLD] &= ~val;
+ else
+ s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
if ( s->sci_asserted &&
hotplugged &&
!test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) {
@@ -429,7 +464,10 @@ static uint32_t gpe_en_read(void *opaque, uint32_t addr)
{
GPEState *s = opaque;
- return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)];
+ if (s->use_old_ioport)
+ return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS_OLD +
ACPI_GPE0_BLK_LEN_OLD / 2)];
+ else
+ return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN /
2)];
}
/* write 0 to clear en bit */
@@ -439,7 +477,10 @@ static void gpe_en_write(void *opaque, uint32_t addr,
uint32_t val)
int reg_count;
PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n",
addr, val);
- reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
+ if (s->use_old_ioport)
+ reg_count = addr - (ACPI_GPE0_BLK_ADDRESS_OLD + ACPI_GPE0_BLK_LEN_OLD
/ 2);
+ else
+ reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
s->gpe0_en[reg_count] = val;
/* If disable GPE bit right after generating SCI on it,
* need deassert the intr to avoid redundant intrs
@@ -459,7 +500,7 @@ static void gpe_save(QEMUFile* f, void* opaque)
GPEState *s = (GPEState*)opaque;
int i;
- for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+ for ( i = 0; i < ACPI_GPE0_BLK_LEN_OLD / 2; i++ ) {
qemu_put_8s(f, &s->gpe0_sts[i]);
qemu_put_8s(f, &s->gpe0_en[i]);
}
@@ -468,21 +509,43 @@ static void gpe_save(QEMUFile* f, void* opaque)
if ( s->sci_asserted ) {
PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
}
+
+ qemu_put_8s(f, &s->use_old_ioport);
}
static int gpe_load(QEMUFile* f, void* opaque, int version_id)
{
GPEState *s = (GPEState*)opaque;
int i;
- if (version_id != 1)
+ if (version_id > 2)
return -EINVAL;
- for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+ for ( i = 0; i < ACPI_GPE0_BLK_LEN_OLD / 2; i++ ) {
qemu_get_8s(f, &s->gpe0_sts[i]);
qemu_get_8s(f, &s->gpe0_en[i]);
}
qemu_get_8s(f, &s->sci_asserted);
+
+ if (version_id <= 1) {
+ s->use_old_ioport = 1;
+ } else {
+ qemu_get_8s(f, &s->use_old_ioport);
+ }
+
+ if (s->use_old_ioport) {
+ isa_unassign_ioport(ACPI_GPE0_BLK_ADDRESS, ACPI_GPE0_BLK_LEN);
+
+ register_ioport_read(ACPI_GPE0_BLK_ADDRESS_OLD, ACPI_GPE0_BLK_LEN_OLD
/ 2,
+ 1, gpe_sts_read, s);
+ register_ioport_read(ACPI_GPE0_BLK_ADDRESS_OLD + ACPI_GPE0_BLK_LEN_OLD
/ 2,
+ ACPI_GPE0_BLK_LEN_OLD / 2, 1, gpe_en_read, s);
+ register_ioport_write(ACPI_GPE0_BLK_ADDRESS_OLD, ACPI_GPE0_BLK_LEN_OLD
/ 2,
+ 1, gpe_sts_write, s);
+ register_ioport_write(ACPI_GPE0_BLK_ADDRESS_OLD +
ACPI_GPE0_BLK_LEN_OLD / 2,
+ ACPI_GPE0_BLK_LEN_OLD / 2, 1, gpe_en_write, s);
+ }
+
return 0;
}
@@ -551,7 +614,7 @@ static void gpe_acpi_init(void)
gpe_en_write,
s);
- register_savevm("gpe", 0, 1, gpe_save, gpe_load, s);
+ register_savevm("gpe", 0, 2, gpe_save, gpe_load, s);
}
#ifdef CONFIG_PASSTHROUGH
@@ -703,7 +766,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t
smb_io_base,
pci_conf[0x43] = 0x00;
d->pm1_control = SCI_EN;
- acpi_map((PCIDevice *)d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO);
+ acpi_map((PCIDevice *)d, 0, ACPI_PM1A_EVT_BLK_ADDRESS, 0x10,
PCI_ADDRESS_SPACE_IO);
gpe_acpi_init();
#ifdef CONFIG_PASSTHROUGH
@@ -711,7 +774,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t
smb_io_base,
#endif
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, d);
- register_savevm("piix4acpi", 0, 1, piix4acpi_save, piix4acpi_load, d);
+ register_savevm("piix4acpi", 0, 2, piix4acpi_save, piix4acpi_load, d);
return NULL;
}
--
1.7.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|