suspend: switch acpi s3 to new infrastructure.

This patch switches pc s3 suspend over to the new infrastructure.
The cmos_s3 qemu_irq is killed, the new notifier is used instead.
The xen hack goes away with that too, the hypercall can simply be
done in a notifier function now.

This patch also makes the guest actually stay suspended instead
of leaving suspend instantly, so it is useful for more than just
testing whenever the suspend/resume cycle actually works.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Gerd Hoffmann 2012-02-23 13:45:20 +01:00 committed by Anthony Liguori
parent 95b363b5c6
commit da98c8eb4c
10 changed files with 47 additions and 42 deletions

View file

@ -248,6 +248,22 @@ int acpi_table_add(const char *t)
}
static void acpi_notify_wakeup(Notifier *notifier, void *data)
{
ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
WakeupReason *reason = data;
switch (*reason) {
case QEMU_WAKEUP_REASON_OTHER:
default:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
ar->pm1.evt.sts |=
(ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
break;
}
}
/* ACPI PM1a EVT */
uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
{
@ -333,9 +349,10 @@ void acpi_pm_tmr_reset(ACPIREGS *ar)
}
/* ACPI PM1aCNT */
void acpi_pm1_cnt_init(ACPIREGS *ar, qemu_irq cmos_s3)
void acpi_pm1_cnt_init(ACPIREGS *ar)
{
ar->pm1.cnt.cmos_s3 = cmos_s3;
ar->wakeup.notify = acpi_notify_wakeup;
qemu_register_wakeup_notifier(&ar->wakeup);
}
void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
@ -350,12 +367,8 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
qemu_system_shutdown_request();
break;
case 1:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
ar->pm1.evt.sts |=
(ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
qemu_system_reset_request();
qemu_irq_raise(ar->pm1.cnt.cmos_s3);
qemu_system_suspend_request();
break;
default:
break;
}
@ -376,9 +389,6 @@ void acpi_pm1_cnt_update(ACPIREGS *ar,
void acpi_pm1_cnt_reset(ACPIREGS *ar)
{
ar->pm1.cnt.cnt = 0;
if (ar->pm1.cnt.cmos_s3) {
qemu_irq_lower(ar->pm1.cnt.cmos_s3);
}
}
/* ACPI GPE */

View file

@ -96,7 +96,6 @@ struct ACPIPM1EVT {
struct ACPIPM1CNT {
uint16_t cnt;
qemu_irq cmos_s3;
};
struct ACPIGPE {
@ -114,6 +113,7 @@ struct ACPIREGS {
ACPIPM1EVT evt;
ACPIPM1CNT cnt;
} pm1;
Notifier wakeup;
};
/* PM_TMR */
@ -138,7 +138,7 @@ void acpi_pm1_evt_power_down(ACPIREGS *ar);
void acpi_pm1_evt_reset(ACPIREGS *ar);
/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
void acpi_pm1_cnt_init(ACPIREGS *ar, qemu_irq cmos_s3);
void acpi_pm1_cnt_init(ACPIREGS *ar);
void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val);
void acpi_pm1_cnt_update(ACPIREGS *ar,
bool sci_enable, bool sci_disable);

View file

@ -372,7 +372,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 cmos_s3, qemu_irq smi_irq,
qemu_irq sci_irq, qemu_irq smi_irq,
int kvm_enabled)
{
PCIDevice *dev;
@ -383,7 +383,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
s = DO_UPCAST(PIIX4PMState, dev, dev);
s->irq = sci_irq;
acpi_pm1_cnt_init(&s->ar, cmos_s3);
acpi_pm1_cnt_init(&s->ar);
s->smi_irq = smi_irq;
s->kvm_enabled = kvm_enabled;

View file

@ -102,6 +102,7 @@ typedef struct RTCState {
QEMUTimer *second_timer2;
Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy;
Notifier suspend_notifier;
} RTCState;
static void rtc_set_time(RTCState *s);
@ -596,6 +597,14 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
#endif
}
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
static void rtc_notify_suspend(Notifier *notifier, void *data)
{
RTCState *s = container_of(notifier, RTCState, suspend_notifier);
rtc_set_memory(&s->dev, 0xF, 0xFE);
}
static void rtc_reset(void *opaque)
{
RTCState *s = opaque;
@ -676,6 +685,9 @@ static int rtc_initfn(ISADevice *dev)
s->clock_reset_notifier.notify = rtc_notify_clock_reset;
qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
s->suspend_notifier.notify = rtc_notify_suspend;
qemu_register_suspend_notifier(&s->suspend_notifier);
s->next_second_time =
qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);

View file

@ -967,7 +967,7 @@ void mips_malta_init (ram_addr_t ram_size,
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
isa_get_irq(NULL, 9), NULL, NULL, 0);
isa_get_irq(NULL, 9), NULL, 0);
/* TODO: Populate SPD eeprom data. */
smbus_eeprom_init(smbus, 8, NULL, 0);
pit = pit_init(isa_bus, 0x40, 0, NULL);

11
hw/pc.c
View file

@ -914,17 +914,6 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
return dev;
}
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
{
ISADevice *s = opaque;
if (level) {
rtc_set_memory(s, 0xF, 0xFE);
}
}
void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
{
CPUState *s = opaque;

View file

@ -103,7 +103,6 @@ void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
extern int fd_bootchk;
void pc_register_ferr_irq(qemu_irq irq);
void pc_cmos_set_s3_resume(void *opaque, int irq, int level);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
void pc_cpus_init(const char *cpu_model);
@ -142,7 +141,7 @@ int acpi_table_add(const char *table_desc);
/* acpi_piix.c */
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
qemu_irq sci_irq, qemu_irq smi_irq,
int kvm_enabled);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);

View file

@ -139,7 +139,6 @@ static void pc_init1(MemoryRegion *system_memory,
qemu_irq *cpu_irq;
qemu_irq *gsi;
qemu_irq *i8259;
qemu_irq *cmos_s3;
qemu_irq *smi_irq;
GSIState *gsi_state;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@ -291,15 +290,10 @@ static void pc_init1(MemoryRegion *system_memory,
if (pci_enabled && acpi_enabled) {
i2c_bus *smbus;
if (!xen_enabled()) {
cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
} else {
cmos_s3 = qemu_allocate_irqs(xen_cmos_set_s3_resume, rtc_state, 1);
}
smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
/* TODO: Populate SPD eeprom data. */
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
gsi[9], *cmos_s3, *smi_irq,
gsi[9], *smi_irq,
kvm_enabled());
smbus_eeprom_init(smbus, 8, NULL, 0);
}

View file

@ -430,7 +430,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
apm_init(&s->apm, NULL, s);
acpi_pm_tmr_init(&s->ar, pm_tmr_timer);
acpi_pm1_cnt_init(&s->ar, NULL);
acpi_pm1_cnt_init(&s->ar);
pm_smbus_init(&s->dev.qdev, &s->smb);

View file

@ -89,6 +89,7 @@ typedef struct XenIOState {
const XenPhysmap *log_for_dirtybit;
Notifier exit;
Notifier suspend;
} XenIOState;
/* Xen specific function for piix pci */
@ -121,12 +122,9 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
}
}
void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
static void xen_suspend_notifier(Notifier *notifier, void *data)
{
pc_cmos_set_s3_resume(opaque, irq, level);
if (level) {
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
}
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
}
/* Xen Interrupt Controller */
@ -936,6 +934,9 @@ int xen_hvm_init(void)
state->exit.notify = xen_exit_notifier;
qemu_add_exit_notifier(&state->exit);
state->suspend.notify = xen_suspend_notifier;
qemu_register_suspend_notifier(&state->suspend);
xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,