This patch series makes suspend support in qemu alot more useful. Right now the guest can put itself into s3, but qemu will wakeup the guest instantly. With this patch series applied the guest will stay suspended instead and there are a few events which can kick the guest out of suspend state: A monitor command, ps/2 input, serial input, rtc. Not much yet, but it''s a start with the low hanging fruits ;) Changes in v3: * Rename monitor command to ''system_wakeup''. * Fix tyops in documentation. Changes in v2: * Add a suspend notifier. * Replace the cmos_s3 qemu_irq with the notifier, zap a bunch of hackish cmos_s3 windup code (this touches xen-all.c, thus cc xen-devel). * Add rtc wakeup support. Gerd Hoffmann (6): suspend: add infrastructure suspend: switch acpi s3 to new infrastructure. suspend: add system_wakeup monitor command suspend: make ps/2 devices wakeup the guest suspend: make serial ports wakeup the guest. suspend: make rtc alarm wakeup the guest. hmp-commands.hx | 14 ++++++++++++++ hmp.c | 5 +++++ hmp.h | 1 + hw/acpi.c | 11 +---------- hw/acpi.h | 2 -- hw/acpi_piix4.c | 3 +-- hw/mc146818rtc.c | 17 +++++++++++++++++ hw/mips_malta.c | 2 +- hw/pc.c | 11 ----------- hw/pc.h | 3 +-- hw/pc_piix.c | 8 +------- hw/ps2.c | 6 ++++++ hw/serial.c | 6 ++++++ hw/vt82c686.c | 1 - qapi-schema.json | 11 +++++++++++ qmp-commands.hx | 21 +++++++++++++++++++++ qmp.c | 5 +++++ sysemu.h | 3 +++ vl.c | 28 ++++++++++++++++++++++++++++ xen-all.c | 11 ++++++----- 20 files changed, 128 insertions(+), 41 deletions(-)
This patch adds some infrastructure to handle suspend and resume to qemu. First there are two functions to switch state and second there is a suspend notifier: * qemu_system_suspend_request() is supposed to be called when the guest asks for being be suspended, for example via ACPI. * qemu_system_wakeup_request is supposed to be called on events which should wake up the guest. * qemu_register_suspend_notifier can be used to register a notifier which will be called when the guest is suspended. Machine types and device models can hook in there to modify state if needed. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- sysemu.h | 3 +++ vl.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 0 deletions(-) diff --git a/sysemu.h b/sysemu.h index 9d5ce33..3b9d7f5 100644 --- a/sysemu.h +++ b/sysemu.h @@ -39,6 +39,9 @@ void vm_stop(RunState state); void vm_stop_force_state(RunState state); void qemu_system_reset_request(void); +void qemu_system_suspend_request(void); +void qemu_register_suspend_notifier(Notifier *notifier); +void qemu_system_wakeup_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); void qemu_system_debug_request(void); diff --git a/vl.c b/vl.c index 63dd725..822fd58 100644 --- a/vl.c +++ b/vl.c @@ -1283,6 +1283,9 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; +static bool is_suspended; +static NotifierList suspend_notifiers + NOTIFIER_LIST_INITIALIZER(suspend_notifiers); static RunState vmstop_requested = RUN_STATE_MAX; int qemu_shutdown_requested_get(void) @@ -1398,6 +1401,31 @@ void qemu_system_reset_request(void) qemu_notify_event(); } +void qemu_system_suspend_request(void) +{ + if (is_suspended) { + return; + } + cpu_stop_current(); + notifier_list_notify(&suspend_notifiers, NULL); + is_suspended = true; +} + +void qemu_register_suspend_notifier(Notifier *notifier) +{ + notifier_list_add(&suspend_notifiers, notifier); +} + +void qemu_system_wakeup_request(void) +{ + if (!is_suspended) { + return; + } + reset_requested = 1; + qemu_notify_event(); + is_suspended = false; +} + void qemu_system_killed(int signal, pid_t pid) { shutdown_signal = signal; -- 1.7.1
Gerd Hoffmann
2012-Feb-08 11:00 UTC
[PATCH v3 2/6] 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> --- hw/acpi.c | 11 +---------- hw/acpi.h | 2 -- hw/acpi_piix4.c | 3 +-- hw/mc146818rtc.c | 12 ++++++++++++ hw/mips_malta.c | 2 +- hw/pc.c | 11 ----------- hw/pc.h | 3 +-- hw/pc_piix.c | 8 +------- hw/vt82c686.c | 1 - xen-all.c | 11 ++++++----- 10 files changed, 23 insertions(+), 41 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 79b179b..67dcd43 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -330,11 +330,6 @@ void acpi_pm_tmr_reset(ACPIPMTimer *tmr) } /* ACPI PM1aCNT */ -void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3) -{ - pm1_cnt->cmos_s3 = cmos_s3; -} - void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) { pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); @@ -351,8 +346,7 @@ void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) Pretend that resume was caused by power button */ pm1a->sts | (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); - qemu_system_reset_request(); - qemu_irq_raise(pm1_cnt->cmos_s3); + qemu_system_suspend_request(); default: break; } @@ -373,9 +367,6 @@ void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt) { pm1_cnt->cnt = 0; - if (pm1_cnt->cmos_s3) { - qemu_irq_lower(pm1_cnt->cmos_s3); - } } /* ACPI GPE */ diff --git a/hw/acpi.h b/hw/acpi.h index c141e65..e0c7dbe 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -115,8 +115,6 @@ void acpi_pm1_evt_reset(ACPIPM1EVT *pm1); /* PM1a_CNT: piix and ich9 don''t implement PM1b CNT. */ struct ACPIPM1CNT { uint16_t cnt; - - qemu_irq cmos_s3; }; typedef struct ACPIPM1CNT ACPIPM1CNT; diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 21484ae..bc77dc5 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -376,7 +376,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; @@ -387,7 +387,6 @@ 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->pm1_cnt, cmos_s3); s->smi_irq = smi_irq; s->kvm_enabled = kvm_enabled; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 4a43225..314ed52 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -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); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index d232630..fe02c93 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -966,7 +966,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); diff --git a/hw/pc.c b/hw/pc.c index 7f3aa65..7b93aee 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -915,17 +915,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; diff --git a/hw/pc.h b/hw/pc.h index c666ec9..571c915 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -128,7 +128,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); @@ -167,7 +166,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); diff --git a/hw/pc_piix.c b/hw/pc_piix.c index c06f1b5..918f5ac 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -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); } diff --git a/hw/vt82c686.c b/hw/vt82c686.c index aa0954f..8beb6c5 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -446,7 +446,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) apm_init(&s->apm, NULL, s); acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); - acpi_pm1_cnt_init(&s->pm1_cnt, NULL); pm_smbus_init(&s->dev.qdev, &s->smb); diff --git a/xen-all.c b/xen-all.c index fd39168..b0ed1ed 100644 --- a/xen-all.c +++ b/xen-all.c @@ -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, -- 1.7.1
Gerd Hoffmann
2012-Feb-08 11:00 UTC
[PATCH v3 3/6] suspend: add system_wakeup monitor command
This patch adds the system_wakeup monitor command which will simply wake up suspended guests. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- hmp-commands.hx | 14 ++++++++++++++ hmp.c | 5 +++++ hmp.h | 1 + qapi-schema.json | 11 +++++++++++ qmp-commands.hx | 21 +++++++++++++++++++++ qmp.c | 5 +++++ 6 files changed, 57 insertions(+), 0 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 573b823..64b3656 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -352,6 +352,20 @@ Resume emulation. ETEXI { + .name = "system_wakeup", + .args_type = "", + .params = "", + .help = "wakeup guest from suspend", + .mhandler.cmd = hmp_system_wakeup, + }, + +STEXI +@item system_wakeup +@findex system_wakeup +Wakeup guest from suspend. +ETEXI + + { .name = "gdbserver", .args_type = "device:s?", .params = "[device]", diff --git a/hmp.c b/hmp.c index 8ff8c94..3a54455 100644 --- a/hmp.c +++ b/hmp.c @@ -632,6 +632,11 @@ void hmp_cont(Monitor *mon, const QDict *qdict) } } +void hmp_system_wakeup(Monitor *mon, const QDict *qdict) +{ + qmp_system_wakeup(NULL); +} + void hmp_inject_nmi(Monitor *mon, const QDict *qdict) { Error *errp = NULL; diff --git a/hmp.h b/hmp.h index 18eecbd..5409464 100644 --- a/hmp.h +++ b/hmp.h @@ -41,6 +41,7 @@ void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); +void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_inject_nmi(Monitor *mon, const QDict *qdict); void hmp_set_link(Monitor *mon, const QDict *qdict); void hmp_block_passwd(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index d02ee86..226c1da 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -999,6 +999,17 @@ { ''command'': ''cont'' } ## +# @system_wakeup: +# +# Wakeup guest from suspend +# +# Since: 1.1 +# +# Returns: nothing. +## +{ ''command'': ''system_wakeup'' } + +## # @inject-nmi: # # Injects an Non-Maskable Interrupt into all guest''s VCPUs. diff --git a/qmp-commands.hx b/qmp-commands.hx index b5e2ab8..f5081e2 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -212,6 +212,27 @@ Example: EQMP { + .name = "system_wakeup", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_system_wakeup, + }, + +SQMP +system_wakeup +------------- + +Wakeup guest from suspend. + +Arguments: None. + +Example: + +-> { "execute": "system_wakeup" } +<- { "return": {} } + +EQMP + + { .name = "system_reset", .args_type = "", .mhandler.cmd_new = qmp_marshal_input_system_reset, diff --git a/qmp.c b/qmp.c index 45052cc..9ff5ec3 100644 --- a/qmp.c +++ b/qmp.c @@ -164,6 +164,11 @@ void qmp_cont(Error **errp) vm_start(); } +void qmp_system_wakeup(Error **errp) +{ + qemu_system_wakeup_request(); +} + ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) { Object *obj; -- 1.7.1
Gerd Hoffmann
2012-Feb-08 11:00 UTC
[PATCH v3 4/6] suspend: make ps/2 devices wakeup the guest
This patch adds wakeup support to ps/2 emulation. Any key press on the ps/2 keyboard will wakeup the guest. Likewise any mouse button press will wakeup the guest. Mouse moves are ignored, so the guest will not wakeup in case your mouse crosses the vnc window of a suspended guest by accident. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- hw/ps2.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/hw/ps2.c b/hw/ps2.c index 1d9057b..d1b2505 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -24,6 +24,7 @@ #include "hw.h" #include "ps2.h" #include "console.h" +#include "sysemu.h" /* debug PC keyboard */ //#define DEBUG_KBD @@ -154,6 +155,7 @@ static void ps2_put_keycode(void *opaque, int keycode) { PS2KbdState *s = opaque; + qemu_system_wakeup_request(); /* XXX: add support for scancode set 1 */ if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) { if (keycode & 0x80) { @@ -368,6 +370,10 @@ static void ps2_mouse_event(void *opaque, return; s->mouse_buttons = buttons_state; + if (buttons_state) { + qemu_system_wakeup_request(); + } + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { for(;;) { -- 1.7.1
Gerd Hoffmann
2012-Feb-08 11:00 UTC
[PATCH v3 5/6] suspend: make serial ports wakeup the guest.
Add a ''wakeup'' property to the serial port. It is off by default. When enabled any incoming character on the serial line will wake up the guest. Useful for guests which have a serial console configured. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- hw/serial.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index 82917e2..108bb94 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -139,6 +139,7 @@ struct SerialState { int it_shift; int baudbase; int tsr_retry; + uint32_t wakeup; uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */ SerialFIFO recv_fifo; @@ -635,6 +636,10 @@ static int serial_can_receive1(void *opaque) static void serial_receive1(void *opaque, const uint8_t *buf, int size) { SerialState *s = opaque; + + if (s->wakeup) { + qemu_system_wakeup_request(); + } if(s->fcr & UART_FCR_FE) { int i; for (i = 0; i < size; i++) { @@ -884,6 +889,7 @@ static Property serial_isa_properties[] = { DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), + DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), DEFINE_PROP_END_OF_LIST(), }; -- 1.7.1
Gerd Hoffmann
2012-Feb-08 11:00 UTC
[PATCH v3 6/6] suspend: make rtc alarm wakeup the guest.
Add a ''wakeup'' property to the mc146818rtc. It is on by default. When enabled the rtc will wake up the guest when the alarm fires. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- hw/mc146818rtc.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 314ed52..3b912c6 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -86,6 +86,7 @@ typedef struct RTCState { uint8_t cmos_index; struct tm current_tm; int32_t base_year; + uint32_t wakeup; qemu_irq irq; qemu_irq sqw_irq; int it_shift; @@ -437,6 +438,9 @@ static void rtc_update_second2(void *opaque) s->cmos_data[RTC_REG_C] |= REG_C_AF; if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { + if (s->wakeup) { + qemu_system_wakeup_request(); + } qemu_irq_raise(s->irq); s->cmos_data[RTC_REG_C] |= REG_C_IRQF; } @@ -725,6 +729,7 @@ static Property mc146818rtc_properties[] = { DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, lost_tick_policy, LOST_TICK_DISCARD), + DEFINE_PROP_UINT32("wakeup", RTCState, wakeup, 1), DEFINE_PROP_END_OF_LIST(), }; -- 1.7.1
On Wed, Feb 08, 2012 at 12:00:14PM +0100, Gerd Hoffmann wrote:> This patch adds some infrastructure to handle suspend and resume to > qemu. First there are two functions to switch state and second there > is a suspend notifier: > > * qemu_system_suspend_request() is supposed to be called when the > guest asks for being be suspended, for example via ACPI. > > * qemu_system_wakeup_request is supposed to be called on events which > should wake up the guest. >qemu_system_wakeup_request() should get wakeup source as a parameter. There are ways to report it to a guest.> * qemu_register_suspend_notifier can be used to register a notifier > which will be called when the guest is suspended. Machine types > and device models can hook in there to modify state if needed. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > sysemu.h | 3 +++ > vl.c | 28 ++++++++++++++++++++++++++++ > 2 files changed, 31 insertions(+), 0 deletions(-) > > diff --git a/sysemu.h b/sysemu.h > index 9d5ce33..3b9d7f5 100644 > --- a/sysemu.h > +++ b/sysemu.h > @@ -39,6 +39,9 @@ void vm_stop(RunState state); > void vm_stop_force_state(RunState state); > > void qemu_system_reset_request(void); > +void qemu_system_suspend_request(void); > +void qemu_register_suspend_notifier(Notifier *notifier); > +void qemu_system_wakeup_request(void); > void qemu_system_shutdown_request(void); > void qemu_system_powerdown_request(void); > void qemu_system_debug_request(void); > diff --git a/vl.c b/vl.c > index 63dd725..822fd58 100644 > --- a/vl.c > +++ b/vl.c > @@ -1283,6 +1283,9 @@ static int shutdown_requested, shutdown_signal = -1; > static pid_t shutdown_pid; > static int powerdown_requested; > static int debug_requested; > +static bool is_suspended; > +static NotifierList suspend_notifiers > + NOTIFIER_LIST_INITIALIZER(suspend_notifiers); > static RunState vmstop_requested = RUN_STATE_MAX; > > int qemu_shutdown_requested_get(void) > @@ -1398,6 +1401,31 @@ void qemu_system_reset_request(void) > qemu_notify_event(); > } > > +void qemu_system_suspend_request(void) > +{ > + if (is_suspended) { > + return; > + } > + cpu_stop_current(); > + notifier_list_notify(&suspend_notifiers, NULL); > + is_suspended = true; > +} > + > +void qemu_register_suspend_notifier(Notifier *notifier) > +{ > + notifier_list_add(&suspend_notifiers, notifier); > +} > + > +void qemu_system_wakeup_request(void) > +{ > + if (!is_suspended) { > + return; > + } > + reset_requested = 1; > + qemu_notify_event(); > + is_suspended = false; > +} > + > void qemu_system_killed(int signal, pid_t pid) > { > shutdown_signal = signal; > -- > 1.7.1 > >-- Gleb.
Gleb Natapov
2012-Feb-09 08:53 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On Wed, Feb 08, 2012 at 12:00:15PM +0100, Gerd Hoffmann wrote:> 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> > --- > hw/acpi.c | 11 +---------- > hw/acpi.h | 2 -- > hw/acpi_piix4.c | 3 +-- > hw/mc146818rtc.c | 12 ++++++++++++ > hw/mips_malta.c | 2 +- > hw/pc.c | 11 ----------- > hw/pc.h | 3 +-- > hw/pc_piix.c | 8 +------- > hw/vt82c686.c | 1 - > xen-all.c | 11 ++++++----- > 10 files changed, 23 insertions(+), 41 deletions(-) > > diff --git a/hw/acpi.c b/hw/acpi.c > index 79b179b..67dcd43 100644 > --- a/hw/acpi.c > +++ b/hw/acpi.c > @@ -330,11 +330,6 @@ void acpi_pm_tmr_reset(ACPIPMTimer *tmr) > } > > /* ACPI PM1aCNT */ > -void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3) > -{ > - pm1_cnt->cmos_s3 = cmos_s3; > -} > - > void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) > { > pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); > @@ -351,8 +346,7 @@ void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) > Pretend that resume was caused by power button */ > pm1a->sts |> (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);Here we should report real reason for a wakeup (if it can be reported in mp1sts that is).> - qemu_system_reset_request(); > - qemu_irq_raise(pm1_cnt->cmos_s3); > + qemu_system_suspend_request(); > default: > break; > } > @@ -373,9 +367,6 @@ void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, > void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt) > { > pm1_cnt->cnt = 0; > - if (pm1_cnt->cmos_s3) { > - qemu_irq_lower(pm1_cnt->cmos_s3); > - } > } > > /* ACPI GPE */ > diff --git a/hw/acpi.h b/hw/acpi.h > index c141e65..e0c7dbe 100644 > --- a/hw/acpi.h > +++ b/hw/acpi.h > @@ -115,8 +115,6 @@ void acpi_pm1_evt_reset(ACPIPM1EVT *pm1); > /* PM1a_CNT: piix and ich9 don''t implement PM1b CNT. */ > struct ACPIPM1CNT { > uint16_t cnt; > - > - qemu_irq cmos_s3; > }; > typedef struct ACPIPM1CNT ACPIPM1CNT; > > diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c > index 21484ae..bc77dc5 100644 > --- a/hw/acpi_piix4.c > +++ b/hw/acpi_piix4.c > @@ -376,7 +376,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; > @@ -387,7 +387,6 @@ 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->pm1_cnt, cmos_s3); > s->smi_irq = smi_irq; > s->kvm_enabled = kvm_enabled; > > diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c > index 4a43225..314ed52 100644 > --- a/hw/mc146818rtc.c > +++ b/hw/mc146818rtc.c > @@ -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); > diff --git a/hw/mips_malta.c b/hw/mips_malta.c > index d232630..fe02c93 100644 > --- a/hw/mips_malta.c > +++ b/hw/mips_malta.c > @@ -966,7 +966,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); > diff --git a/hw/pc.c b/hw/pc.c > index 7f3aa65..7b93aee 100644 > --- a/hw/pc.c > +++ b/hw/pc.c > @@ -915,17 +915,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; > diff --git a/hw/pc.h b/hw/pc.h > index c666ec9..571c915 100644 > --- a/hw/pc.h > +++ b/hw/pc.h > @@ -128,7 +128,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); > @@ -167,7 +166,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); > > diff --git a/hw/pc_piix.c b/hw/pc_piix.c > index c06f1b5..918f5ac 100644 > --- a/hw/pc_piix.c > +++ b/hw/pc_piix.c > @@ -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); > } > diff --git a/hw/vt82c686.c b/hw/vt82c686.c > index aa0954f..8beb6c5 100644 > --- a/hw/vt82c686.c > +++ b/hw/vt82c686.c > @@ -446,7 +446,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) > apm_init(&s->apm, NULL, s); > > acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); > - acpi_pm1_cnt_init(&s->pm1_cnt, NULL); > > pm_smbus_init(&s->dev.qdev, &s->smb); > > diff --git a/xen-all.c b/xen-all.c > index fd39168..b0ed1ed 100644 > --- a/xen-all.c > +++ b/xen-all.c > @@ -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, > -- > 1.7.1 > >-- Gleb.
Gleb Natapov
2012-Feb-09 08:54 UTC
Re: [PATCH v3 3/6] suspend: add system_wakeup monitor command
On Wed, Feb 08, 2012 at 12:00:16PM +0100, Gerd Hoffmann wrote:> This patch adds the system_wakeup monitor command which will simply > wake up suspended guests. >We can report this one as power button wakeup.> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > hmp-commands.hx | 14 ++++++++++++++ > hmp.c | 5 +++++ > hmp.h | 1 + > qapi-schema.json | 11 +++++++++++ > qmp-commands.hx | 21 +++++++++++++++++++++ > qmp.c | 5 +++++ > 6 files changed, 57 insertions(+), 0 deletions(-) > > diff --git a/hmp-commands.hx b/hmp-commands.hx > index 573b823..64b3656 100644 > --- a/hmp-commands.hx > +++ b/hmp-commands.hx > @@ -352,6 +352,20 @@ Resume emulation. > ETEXI > > { > + .name = "system_wakeup", > + .args_type = "", > + .params = "", > + .help = "wakeup guest from suspend", > + .mhandler.cmd = hmp_system_wakeup, > + }, > + > +STEXI > +@item system_wakeup > +@findex system_wakeup > +Wakeup guest from suspend. > +ETEXI > + > + { > .name = "gdbserver", > .args_type = "device:s?", > .params = "[device]", > diff --git a/hmp.c b/hmp.c > index 8ff8c94..3a54455 100644 > --- a/hmp.c > +++ b/hmp.c > @@ -632,6 +632,11 @@ void hmp_cont(Monitor *mon, const QDict *qdict) > } > } > > +void hmp_system_wakeup(Monitor *mon, const QDict *qdict) > +{ > + qmp_system_wakeup(NULL); > +} > + > void hmp_inject_nmi(Monitor *mon, const QDict *qdict) > { > Error *errp = NULL; > diff --git a/hmp.h b/hmp.h > index 18eecbd..5409464 100644 > --- a/hmp.h > +++ b/hmp.h > @@ -41,6 +41,7 @@ void hmp_cpu(Monitor *mon, const QDict *qdict); > void hmp_memsave(Monitor *mon, const QDict *qdict); > void hmp_pmemsave(Monitor *mon, const QDict *qdict); > void hmp_cont(Monitor *mon, const QDict *qdict); > +void hmp_system_wakeup(Monitor *mon, const QDict *qdict); > void hmp_inject_nmi(Monitor *mon, const QDict *qdict); > void hmp_set_link(Monitor *mon, const QDict *qdict); > void hmp_block_passwd(Monitor *mon, const QDict *qdict); > diff --git a/qapi-schema.json b/qapi-schema.json > index d02ee86..226c1da 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -999,6 +999,17 @@ > { ''command'': ''cont'' } > > ## > +# @system_wakeup: > +# > +# Wakeup guest from suspend > +# > +# Since: 1.1 > +# > +# Returns: nothing. > +## > +{ ''command'': ''system_wakeup'' } > + > +## > # @inject-nmi: > # > # Injects an Non-Maskable Interrupt into all guest''s VCPUs. > diff --git a/qmp-commands.hx b/qmp-commands.hx > index b5e2ab8..f5081e2 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -212,6 +212,27 @@ Example: > EQMP > > { > + .name = "system_wakeup", > + .args_type = "", > + .mhandler.cmd_new = qmp_marshal_input_system_wakeup, > + }, > + > +SQMP > +system_wakeup > +------------- > + > +Wakeup guest from suspend. > + > +Arguments: None. > + > +Example: > + > +-> { "execute": "system_wakeup" } > +<- { "return": {} } > + > +EQMP > + > + { > .name = "system_reset", > .args_type = "", > .mhandler.cmd_new = qmp_marshal_input_system_reset, > diff --git a/qmp.c b/qmp.c > index 45052cc..9ff5ec3 100644 > --- a/qmp.c > +++ b/qmp.c > @@ -164,6 +164,11 @@ void qmp_cont(Error **errp) > vm_start(); > } > > +void qmp_system_wakeup(Error **errp) > +{ > + qemu_system_wakeup_request(); > +} > + > ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) > { > Object *obj; > -- > 1.7.1 > >-- Gleb.
Gleb Natapov
2012-Feb-09 08:56 UTC
Re: [PATCH v3 6/6] suspend: make rtc alarm wakeup the guest.
On Wed, Feb 08, 2012 at 12:00:19PM +0100, Gerd Hoffmann wrote:> Add a ''wakeup'' property to the mc146818rtc. It is on by default. > When enabled the rtc will wake up the guest when the alarm fires. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > hw/mc146818rtc.c | 5 +++++ > 1 files changed, 5 insertions(+), 0 deletions(-) > > diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c > index 314ed52..3b912c6 100644 > --- a/hw/mc146818rtc.c > +++ b/hw/mc146818rtc.c > @@ -86,6 +86,7 @@ typedef struct RTCState { > uint8_t cmos_index; > struct tm current_tm; > int32_t base_year; > + uint32_t wakeup; > qemu_irq irq; > qemu_irq sqw_irq; > int it_shift; > @@ -437,6 +438,9 @@ static void rtc_update_second2(void *opaque) > > s->cmos_data[RTC_REG_C] |= REG_C_AF; > if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { > + if (s->wakeup) { > + qemu_system_wakeup_request(); > + }RTC should do wakeup only if RTC_EN bit is set pm1en.> qemu_irq_raise(s->irq); > s->cmos_data[RTC_REG_C] |= REG_C_IRQF; > } > @@ -725,6 +729,7 @@ static Property mc146818rtc_properties[] = { > DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), > DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, > lost_tick_policy, LOST_TICK_DISCARD), > + DEFINE_PROP_UINT32("wakeup", RTCState, wakeup, 1), > DEFINE_PROP_END_OF_LIST(), > }; > > -- > 1.7.1 > >-- Gleb.
On 02/09/12 09:48, Gleb Natapov wrote:> On Wed, Feb 08, 2012 at 12:00:14PM +0100, Gerd Hoffmann wrote: >> * qemu_system_wakeup_request is supposed to be called on events which >> should wake up the guest. >> > qemu_system_wakeup_request() should get wakeup source as a parameter. > There are ways to report it to a guest.Can we do that incrementally, when we actually implement the guest reporting? cheers, Gerd
Gerd Hoffmann
2012-Feb-09 10:51 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
Hi,>> Pretend that resume was caused by power button */ >> pm1a->sts |>> (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); > Here we should report real reason for a wakeup (if it can be reported in > mp1sts that is).These are available I guess? /* PM1x_STS */ #define ACPI_BITMASK_TIMER_STATUS 0x0001 #define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 #define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 #define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 #define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 #define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 #define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ #define ACPI_BITMASK_WAKE_STATUS 0x8000 What do they mean? How would the rtc wakeup be tagged? Set ACPI_BITMASK_RT_CLOCK_STATUS? Anything I can use for ps/2 kbd/mouse wakeup? What do you suggest to do when there is nothing usable (such as qemu monitor command which simply doesn''t exist on real hardware)? thanks, Gerd
Stefano Stabellini
2012-Feb-09 11:13 UTC
Re: [Xen-devel] [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On Wed, 8 Feb 2012, Gerd Hoffmann wrote:> 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.nice cleanup
Gleb Natapov
2012-Feb-09 11:14 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On Thu, Feb 09, 2012 at 11:51:45AM +0100, Gerd Hoffmann wrote:> Hi, > > >> Pretend that resume was caused by power button */ > >> pm1a->sts |> >> (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); > > Here we should report real reason for a wakeup (if it can be reported in > > mp1sts that is). > > These are available I guess? >Yes. Once those defines had the same names as ACPI spec, but some kind soul renamed them to be more "descriptive". So forgive me if I will use names that you actually can lookup in ACPI spec.> /* PM1x_STS */ > #define ACPI_BITMASK_TIMER_STATUS 0x0001 > #define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 > #define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 > #define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 > #define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 > #define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 > #define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ > #define ACPI_BITMASK_WAKE_STATUS 0x8000 >Only three of those are actually wakeup source related: PWRBTN_STS (bit 8) RTC_STS (bit 10) PCIEXP_WAKE_STS (bit 14) And of course if system was awoken WAK_STS (bit 15) should be set too.> What do they mean? How would the rtc wakeup be tagged? Set > ACPI_BITMASK_RT_CLOCK_STATUS? Anything I can use for ps/2 kbd/mouse > wakeup? What do you suggest to do when there is nothing usable (such as > qemu monitor command which simply doesn''t exist on real hardware)? >RTC will set RTC_STS. In other reply I suggested to use PWRBTN_STS for monitor command wakeup. Other devices are more complicated :( They have to provide _PRW (Power Resources for Wake) method in the device description in DSDT. This method, among other things, specifies which bit in GPE (and which GPE) correspond to the device. -- Gleb.
Paolo Bonzini
2012-Feb-09 11:17 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On 02/08/2012 12:00 PM, Gerd Hoffmann wrote:> +/* 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); > +} > +Out of curiosity, who would set this on real hardware? And since RTC memory is nvram, what happens if I remove the mains plug while the system is in S3? Paolo
On Thu, Feb 09, 2012 at 11:45:21AM +0100, Gerd Hoffmann wrote:> On 02/09/12 09:48, Gleb Natapov wrote: > > On Wed, Feb 08, 2012 at 12:00:14PM +0100, Gerd Hoffmann wrote: > >> * qemu_system_wakeup_request is supposed to be called on events which > >> should wake up the guest. > >> > > qemu_system_wakeup_request() should get wakeup source as a parameter. > > There are ways to report it to a guest. > > Can we do that incrementally, when we actually implement the guest > reporting? >What do you mean by "when we actually implement the guest reporting"? The guest reporting is part of ACPI spec and implemented by all relevant guests. I think that adding wakeup source parameter to qemu_system_wakeup_request() and reporting RTC_STS and PWRBTN_STS should not complicate your patch series to much. I agree that DSDT magic required by other devices can wait for later. -- Gleb.
Gerd Hoffmann
2012-Feb-09 12:00 UTC
Re: [PATCH v3 6/6] suspend: make rtc alarm wakeup the guest.
On 02/09/12 09:56, Gleb Natapov wrote:> On Wed, Feb 08, 2012 at 12:00:19PM +0100, Gerd Hoffmann wrote: >> Add a ''wakeup'' property to the mc146818rtc. It is on by default. >> When enabled the rtc will wake up the guest when the alarm fires. >> >> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> >> --- >> hw/mc146818rtc.c | 5 +++++ >> 1 files changed, 5 insertions(+), 0 deletions(-) >> >> diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c >> index 314ed52..3b912c6 100644 >> --- a/hw/mc146818rtc.c >> +++ b/hw/mc146818rtc.c >> @@ -86,6 +86,7 @@ typedef struct RTCState { >> uint8_t cmos_index; >> struct tm current_tm; >> int32_t base_year; >> + uint32_t wakeup; >> qemu_irq irq; >> qemu_irq sqw_irq; >> int it_shift; >> @@ -437,6 +438,9 @@ static void rtc_update_second2(void *opaque) >> >> s->cmos_data[RTC_REG_C] |= REG_C_AF; >> if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { >> + if (s->wakeup) { >> + qemu_system_wakeup_request(); >> + } > RTC should do wakeup only if RTC_EN bit is set pm1en.--verbose please. Which register, which bit? There is no RTC_EN in hw/mc146818rtc.* ... Is this enable bit specifically for wakeup from suspend? thanks, Gerd
On 02/09/12 12:19, Gleb Natapov wrote:> On Thu, Feb 09, 2012 at 11:45:21AM +0100, Gerd Hoffmann wrote: >> On 02/09/12 09:48, Gleb Natapov wrote: >>> On Wed, Feb 08, 2012 at 12:00:14PM +0100, Gerd Hoffmann wrote: >>>> * qemu_system_wakeup_request is supposed to be called on events which >>>> should wake up the guest. >>>> >>> qemu_system_wakeup_request() should get wakeup source as a parameter. >>> There are ways to report it to a guest. >> >> Can we do that incrementally, when we actually implement the guest >> reporting? >> > What do you mean by "when we actually implement the guest > reporting"? The guest reporting is part of ACPI spec and implemented > by all relevant guests. I think that adding wakeup source parameter to > qemu_system_wakeup_request() and reporting RTC_STS and PWRBTN_STS should > not complicate your patch series to much. I agree that DSDT magic required > by other devices can wait for later.Incremental patch (just infrastructure, no acpi windup yet) attached. Something like this? cheers, Gerd
Gleb Natapov
2012-Feb-09 12:24 UTC
Re: [PATCH v3 6/6] suspend: make rtc alarm wakeup the guest.
On Thu, Feb 09, 2012 at 01:00:47PM +0100, Gerd Hoffmann wrote:> On 02/09/12 09:56, Gleb Natapov wrote: > > On Wed, Feb 08, 2012 at 12:00:19PM +0100, Gerd Hoffmann wrote: > >> Add a ''wakeup'' property to the mc146818rtc. It is on by default. > >> When enabled the rtc will wake up the guest when the alarm fires. > >> > >> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > >> --- > >> hw/mc146818rtc.c | 5 +++++ > >> 1 files changed, 5 insertions(+), 0 deletions(-) > >> > >> diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c > >> index 314ed52..3b912c6 100644 > >> --- a/hw/mc146818rtc.c > >> +++ b/hw/mc146818rtc.c > >> @@ -86,6 +86,7 @@ typedef struct RTCState { > >> uint8_t cmos_index; > >> struct tm current_tm; > >> int32_t base_year; > >> + uint32_t wakeup; > >> qemu_irq irq; > >> qemu_irq sqw_irq; > >> int it_shift; > >> @@ -437,6 +438,9 @@ static void rtc_update_second2(void *opaque) > >> > >> s->cmos_data[RTC_REG_C] |= REG_C_AF; > >> if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { > >> + if (s->wakeup) { > >> + qemu_system_wakeup_request(); > >> + } > > RTC should do wakeup only if RTC_EN bit is set pm1en. > > --verbose please. Which register, which bit? There is no RTC_EN in > hw/mc146818rtc.* ... >Entering --verbose mode. Here we are on ACPI territory, not RTC :) RTC just provides one input into ACPI wakeup machinery (Figure 4-11 in ACPI spec version 4). I am talking about ACPI_BITMASK_RT_CLOCK_ENABLE from hw/acpi.h. It is called RTC_EN in ACPI spec (man, we should rename them back!). Spec says that RTC alarm can wakeup the system only if RTC_EN is set in PM1x_EN register. This way OSPM can control which events can do wakeup. Notice that for power button wakeup BWRBTN_EN is ignored.> Is this enable bit specifically for wakeup from suspend? >No, RTC alarm can be configured to generate SCI interrupt while system is running. -- Gleb.
Gleb Natapov
2012-Feb-09 12:31 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On Thu, Feb 09, 2012 at 12:17:33PM +0100, Paolo Bonzini wrote:> On 02/08/2012 12:00 PM, Gerd Hoffmann wrote: > >+/* 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); > >+} > >+ > > Out of curiosity, who would set this on real hardware? And sinceReal HW may have other ways to notify BIOS that system was S3 suspended (special chipset register for instance). I think we can write DSDT magic to write RTC for us, but I prefer to do it from inside QEMU.> RTC memory is nvram, what happens if I remove the mains plug while > the system is in S3? >RTC is battery backed, but what do you expect will happen to main memory where all your data resides during S3 in this case anyway? -- Gleb.
On Thu, Feb 09, 2012 at 01:02:47PM +0100, Gerd Hoffmann wrote:> On 02/09/12 12:19, Gleb Natapov wrote: > > On Thu, Feb 09, 2012 at 11:45:21AM +0100, Gerd Hoffmann wrote: > >> On 02/09/12 09:48, Gleb Natapov wrote: > >>> On Wed, Feb 08, 2012 at 12:00:14PM +0100, Gerd Hoffmann wrote: > >>>> * qemu_system_wakeup_request is supposed to be called on events which > >>>> should wake up the guest. > >>>> > >>> qemu_system_wakeup_request() should get wakeup source as a parameter. > >>> There are ways to report it to a guest. > >> > >> Can we do that incrementally, when we actually implement the guest > >> reporting? > >> > > What do you mean by "when we actually implement the guest > > reporting"? The guest reporting is part of ACPI spec and implemented > > by all relevant guests. I think that adding wakeup source parameter to > > qemu_system_wakeup_request() and reporting RTC_STS and PWRBTN_STS should > > not complicate your patch series to much. I agree that DSDT magic required > > by other devices can wait for later. > > Incremental patch (just infrastructure, no acpi windup yet) attached. > Something like this? >We need to give ACPI ability to prevent wakeup. So, for instance, if RTC alarm calls wakeup but ACPI detects that RTC_EN is cleared it can prevent it.> cheers, > Gerd> commit 78fbd17ddc98a2e96e05db62afbe3a69c5fad5e5 > Author: Gerd Hoffmann <kraxel@redhat.com> > Date: Thu Feb 9 12:52:48 2012 +0100 > > reason: infra > > diff --git a/sysemu.h b/sysemu.h > index 3b9d7f5..e7060aa 100644 > --- a/sysemu.h > +++ b/sysemu.h > @@ -38,10 +38,16 @@ void vm_start(void); > void vm_stop(RunState state); > void vm_stop_force_state(RunState state); > > +typedef enum WakeupReason { > + QEMU_WAKEUP_REASON_OTHER = 0, > + QEMU_WAKEUP_REASON_RTC, > +} WakeupReason; > + > void qemu_system_reset_request(void); > void qemu_system_suspend_request(void); > void qemu_register_suspend_notifier(Notifier *notifier); > -void qemu_system_wakeup_request(void); > +void qemu_system_wakeup_request(WakeupReason reason); > +void qemu_register_wakeup_notifier(Notifier *notifier); > void qemu_system_shutdown_request(void); > void qemu_system_powerdown_request(void); > void qemu_system_debug_request(void); > diff --git a/vl.c b/vl.c > index 822fd58..17d4b72 100644 > --- a/vl.c > +++ b/vl.c > @@ -1286,6 +1286,8 @@ static int debug_requested; > static bool is_suspended; > static NotifierList suspend_notifiers > NOTIFIER_LIST_INITIALIZER(suspend_notifiers); > +static NotifierList wakeup_notifiers > + NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); > static RunState vmstop_requested = RUN_STATE_MAX; > > int qemu_shutdown_requested_get(void) > @@ -1416,16 +1418,22 @@ void qemu_register_suspend_notifier(Notifier *notifier) > notifier_list_add(&suspend_notifiers, notifier); > } > > -void qemu_system_wakeup_request(void) > +void qemu_system_wakeup_request(WakeupReason reason) > { > if (!is_suspended) { > return; > } > + notifier_list_notify(&wakeup_notifiers, &reason); > reset_requested = 1; > qemu_notify_event(); > is_suspended = false; > } > > +void qemu_register_wakeup_notifier(Notifier *notifier) > +{ > + notifier_list_add(&wakeup_notifiers, notifier); > +} > + > void qemu_system_killed(int signal, pid_t pid) > { > shutdown_signal = signal;-- Gleb.
Hi,>> Incremental patch (just infrastructure, no acpi windup yet) attached. >> Something like this? >> > We need to give ACPI ability to prevent wakeup. So, for instance, if RTC > alarm calls wakeup but ACPI detects that RTC_EN is cleared it can > prevent it.Yea, already figured that after reading your rtc reply ... One more incremental attached for review. thanks, Gerd
Paolo Bonzini
2012-Feb-09 12:47 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On 02/09/2012 01:31 PM, Gleb Natapov wrote:> Real HW may have other ways to notify BIOS that system was S3 suspended > (special chipset register for instance). I think we can write DSDT magic > to write RTC for us, but I prefer to do it from inside QEMU.Heh, I would prefer DSDT magic, but I wouldn''t want to write it. ;)> > RTC memory is nvram, what happens if I remove the mains plug while > > the system is in S3? > > RTC is battery backed, but what do you expect will happen to main memory > where all your data resides during S3 in this case anyway?Ah, I confused the ACPI resume vector with the BIOS vector at 0040:0067. No ACPI tables -> no resume vector, and S3 resume will fail. Paolo
Gleb Natapov
2012-Feb-09 12:53 UTC
Re: [PATCH v3 2/6] suspend: switch acpi s3 to new infrastructure.
On Thu, Feb 09, 2012 at 01:47:30PM +0100, Paolo Bonzini wrote:> On 02/09/2012 01:31 PM, Gleb Natapov wrote: > >Real HW may have other ways to notify BIOS that system was S3 suspended > >(special chipset register for instance). I think we can write DSDT magic > >to write RTC for us, but I prefer to do it from inside QEMU. > > Heh, I would prefer DSDT magic, but I wouldn''t want to write it. ;) >The only reason I prefer QEMU doing it is because I have S3 unit test and writing AML interpreter for it would be too much. But on the second thought the test can write to RTC by itself, so if you''ll write DSDT code I''ll ack it :) -- Gleb.
On Thu, Feb 09, 2012 at 01:46:07PM +0100, Gerd Hoffmann wrote:> Hi, > > >> Incremental patch (just infrastructure, no acpi windup yet) attached. > >> Something like this? > >> > > We need to give ACPI ability to prevent wakeup. So, for instance, if RTC > > alarm calls wakeup but ACPI detects that RTC_EN is cleared it can > > prevent it. > > Yea, already figured that after reading your rtc reply ... > > One more incremental attached for review. >We can start from that. But other devices can use STS/EN registers from different GPEs, so they will have same "reason" bit, but in different registers. Also I''d rather hide this logic in ACPI code instead of having it in vl.c.> thanks, > Gerd >> commit ef93688e70bf11313ec89c7e609fc142259dfd74 > Author: Gerd Hoffmann <kraxel@redhat.com> > Date: Thu Feb 9 13:44:37 2012 +0100 > > enable/disable reasons > > diff --git a/sysemu.h b/sysemu.h > index e7060aa..781bdaf 100644 > --- a/sysemu.h > +++ b/sysemu.h > @@ -47,6 +47,7 @@ void qemu_system_reset_request(void); > void qemu_system_suspend_request(void); > void qemu_register_suspend_notifier(Notifier *notifier); > void qemu_system_wakeup_request(WakeupReason reason); > +void qemu_system_wakeup_enable(WakeupReason reason, bool enabled); > void qemu_register_wakeup_notifier(Notifier *notifier); > void qemu_system_shutdown_request(void); > void qemu_system_powerdown_request(void); > diff --git a/vl.c b/vl.c > index 17d4b72..1feac41 100644 > --- a/vl.c > +++ b/vl.c > @@ -1288,6 +1288,7 @@ static NotifierList suspend_notifiers > NOTIFIER_LIST_INITIALIZER(suspend_notifiers); > static NotifierList wakeup_notifiers > NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); > +static uint32_t wakeup_reason_mask; > static RunState vmstop_requested = RUN_STATE_MAX; > > int qemu_shutdown_requested_get(void) > @@ -1423,12 +1424,24 @@ void qemu_system_wakeup_request(WakeupReason reason) > if (!is_suspended) { > return; > } > + if (!(wakeup_reason_mask & (1 << reason))) { > + return; > + } > notifier_list_notify(&wakeup_notifiers, &reason); > reset_requested = 1; > qemu_notify_event(); > is_suspended = false; > } > > +void qemu_system_wakeup_enable(WakeupReason reason, bool enabled) > +{ > + if (enabled) { > + wakeup_reason_mask |= (1 << reason); > + } else { > + wakeup_reason_mask &= ~(1 << reason); > + } > +} > + > void qemu_register_wakeup_notifier(Notifier *notifier) > { > notifier_list_add(&wakeup_notifiers, notifier);-- Gleb.
Hi,>>> We need to give ACPI ability to prevent wakeup. So, for instance, if RTC >>> alarm calls wakeup but ACPI detects that RTC_EN is cleared it can >>> prevent it. >> >> Yea, already figured that after reading your rtc reply ... >> >> One more incremental attached for review. >> > We can start from that. But other devices can use STS/EN registers > from different GPEs, so they will have same "reason" bit, but in > different registers.Yes, we''ll need more reason bits then, basically one per device.> Also I''d rather hide this logic in ACPI code > instead of having it in vl.c.The acpi bits will be in acpi of course. I''ll try to get a complete v4 out of the door later today, that should the direction I''m heading to more clear than these incremental bits. cheers, Gerd
Hi,> I''ll try to get a complete v4 out of the door later today, that should > the direction I''m heading to more clear than these incremental bits.While wading through the acpi mess^Wcode: the acpi timer can s3 wakeups too IIRC, is that correct? cheers, Gerd
On Thu, Feb 09, 2012 at 05:00:52PM +0100, Gerd Hoffmann wrote:> Hi, > > > I''ll try to get a complete v4 out of the door later today, that should > > the direction I''m heading to more clear than these incremental bits. > > While wading through the acpi mess^Wcode: the acpi timer can s3 wakeups > too IIRC, is that correct? >According to ACPI spec^Wmess you are correct. -- Gleb.