mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
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:
parent
95b363b5c6
commit
da98c8eb4c
10 changed files with 47 additions and 42 deletions
32
hw/acpi.c
32
hw/acpi.c
|
@ -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 */
|
/* ACPI PM1a EVT */
|
||||||
uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
|
uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
|
||||||
{
|
{
|
||||||
|
@ -333,9 +349,10 @@ void acpi_pm_tmr_reset(ACPIREGS *ar)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ACPI PM1aCNT */
|
/* 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)
|
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();
|
qemu_system_shutdown_request();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
|
qemu_system_suspend_request();
|
||||||
Pretend that resume was caused by power button */
|
break;
|
||||||
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);
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -376,9 +389,6 @@ void acpi_pm1_cnt_update(ACPIREGS *ar,
|
||||||
void acpi_pm1_cnt_reset(ACPIREGS *ar)
|
void acpi_pm1_cnt_reset(ACPIREGS *ar)
|
||||||
{
|
{
|
||||||
ar->pm1.cnt.cnt = 0;
|
ar->pm1.cnt.cnt = 0;
|
||||||
if (ar->pm1.cnt.cmos_s3) {
|
|
||||||
qemu_irq_lower(ar->pm1.cnt.cmos_s3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ACPI GPE */
|
/* ACPI GPE */
|
||||||
|
|
|
@ -96,7 +96,6 @@ struct ACPIPM1EVT {
|
||||||
|
|
||||||
struct ACPIPM1CNT {
|
struct ACPIPM1CNT {
|
||||||
uint16_t cnt;
|
uint16_t cnt;
|
||||||
qemu_irq cmos_s3;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ACPIGPE {
|
struct ACPIGPE {
|
||||||
|
@ -114,6 +113,7 @@ struct ACPIREGS {
|
||||||
ACPIPM1EVT evt;
|
ACPIPM1EVT evt;
|
||||||
ACPIPM1CNT cnt;
|
ACPIPM1CNT cnt;
|
||||||
} pm1;
|
} pm1;
|
||||||
|
Notifier wakeup;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PM_TMR */
|
/* PM_TMR */
|
||||||
|
@ -138,7 +138,7 @@ void acpi_pm1_evt_power_down(ACPIREGS *ar);
|
||||||
void acpi_pm1_evt_reset(ACPIREGS *ar);
|
void acpi_pm1_evt_reset(ACPIREGS *ar);
|
||||||
|
|
||||||
/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
|
/* 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_write(ACPIREGS *ar, uint16_t val);
|
||||||
void acpi_pm1_cnt_update(ACPIREGS *ar,
|
void acpi_pm1_cnt_update(ACPIREGS *ar,
|
||||||
bool sci_enable, bool sci_disable);
|
bool sci_enable, bool sci_disable);
|
||||||
|
|
|
@ -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,
|
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)
|
int kvm_enabled)
|
||||||
{
|
{
|
||||||
PCIDevice *dev;
|
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 = DO_UPCAST(PIIX4PMState, dev, dev);
|
||||||
s->irq = sci_irq;
|
s->irq = sci_irq;
|
||||||
acpi_pm1_cnt_init(&s->ar, cmos_s3);
|
acpi_pm1_cnt_init(&s->ar);
|
||||||
s->smi_irq = smi_irq;
|
s->smi_irq = smi_irq;
|
||||||
s->kvm_enabled = kvm_enabled;
|
s->kvm_enabled = kvm_enabled;
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ typedef struct RTCState {
|
||||||
QEMUTimer *second_timer2;
|
QEMUTimer *second_timer2;
|
||||||
Notifier clock_reset_notifier;
|
Notifier clock_reset_notifier;
|
||||||
LostTickPolicy lost_tick_policy;
|
LostTickPolicy lost_tick_policy;
|
||||||
|
Notifier suspend_notifier;
|
||||||
} RTCState;
|
} RTCState;
|
||||||
|
|
||||||
static void rtc_set_time(RTCState *s);
|
static void rtc_set_time(RTCState *s);
|
||||||
|
@ -596,6 +597,14 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
|
||||||
#endif
|
#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)
|
static void rtc_reset(void *opaque)
|
||||||
{
|
{
|
||||||
RTCState *s = opaque;
|
RTCState *s = opaque;
|
||||||
|
@ -676,6 +685,9 @@ static int rtc_initfn(ISADevice *dev)
|
||||||
s->clock_reset_notifier.notify = rtc_notify_clock_reset;
|
s->clock_reset_notifier.notify = rtc_notify_clock_reset;
|
||||||
qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
|
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 =
|
s->next_second_time =
|
||||||
qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
|
qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
|
||||||
qemu_mod_timer(s->second_timer2, s->next_second_time);
|
qemu_mod_timer(s->second_timer2, s->next_second_time);
|
||||||
|
|
|
@ -967,7 +967,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||||
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
||||||
usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
|
usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
|
||||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
|
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. */
|
/* TODO: Populate SPD eeprom data. */
|
||||||
smbus_eeprom_init(smbus, 8, NULL, 0);
|
smbus_eeprom_init(smbus, 8, NULL, 0);
|
||||||
pit = pit_init(isa_bus, 0x40, 0, NULL);
|
pit = pit_init(isa_bus, 0x40, 0, NULL);
|
||||||
|
|
11
hw/pc.c
11
hw/pc.c
|
@ -914,17 +914,6 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
|
||||||
return dev;
|
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)
|
void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
|
||||||
{
|
{
|
||||||
CPUState *s = opaque;
|
CPUState *s = opaque;
|
||||||
|
|
3
hw/pc.h
3
hw/pc.h
|
@ -103,7 +103,6 @@ void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
|
||||||
extern int fd_bootchk;
|
extern int fd_bootchk;
|
||||||
|
|
||||||
void pc_register_ferr_irq(qemu_irq irq);
|
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_acpi_smi_interrupt(void *opaque, int irq, int level);
|
||||||
|
|
||||||
void pc_cpus_init(const char *cpu_model);
|
void pc_cpus_init(const char *cpu_model);
|
||||||
|
@ -142,7 +141,7 @@ int acpi_table_add(const char *table_desc);
|
||||||
/* acpi_piix.c */
|
/* acpi_piix.c */
|
||||||
|
|
||||||
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
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);
|
int kvm_enabled);
|
||||||
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
|
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,6 @@ static void pc_init1(MemoryRegion *system_memory,
|
||||||
qemu_irq *cpu_irq;
|
qemu_irq *cpu_irq;
|
||||||
qemu_irq *gsi;
|
qemu_irq *gsi;
|
||||||
qemu_irq *i8259;
|
qemu_irq *i8259;
|
||||||
qemu_irq *cmos_s3;
|
|
||||||
qemu_irq *smi_irq;
|
qemu_irq *smi_irq;
|
||||||
GSIState *gsi_state;
|
GSIState *gsi_state;
|
||||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||||
|
@ -291,15 +290,10 @@ static void pc_init1(MemoryRegion *system_memory,
|
||||||
if (pci_enabled && acpi_enabled) {
|
if (pci_enabled && acpi_enabled) {
|
||||||
i2c_bus *smbus;
|
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);
|
smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
|
||||||
/* TODO: Populate SPD eeprom data. */
|
/* TODO: Populate SPD eeprom data. */
|
||||||
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
||||||
gsi[9], *cmos_s3, *smi_irq,
|
gsi[9], *smi_irq,
|
||||||
kvm_enabled());
|
kvm_enabled());
|
||||||
smbus_eeprom_init(smbus, 8, NULL, 0);
|
smbus_eeprom_init(smbus, 8, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,7 +430,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
|
||||||
apm_init(&s->apm, NULL, s);
|
apm_init(&s->apm, NULL, s);
|
||||||
|
|
||||||
acpi_pm_tmr_init(&s->ar, pm_tmr_timer);
|
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);
|
pm_smbus_init(&s->dev.qdev, &s->smb);
|
||||||
|
|
||||||
|
|
11
xen-all.c
11
xen-all.c
|
@ -89,6 +89,7 @@ typedef struct XenIOState {
|
||||||
const XenPhysmap *log_for_dirtybit;
|
const XenPhysmap *log_for_dirtybit;
|
||||||
|
|
||||||
Notifier exit;
|
Notifier exit;
|
||||||
|
Notifier suspend;
|
||||||
} XenIOState;
|
} XenIOState;
|
||||||
|
|
||||||
/* Xen specific function for piix pci */
|
/* 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);
|
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
|
||||||
if (level) {
|
|
||||||
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Xen Interrupt Controller */
|
/* Xen Interrupt Controller */
|
||||||
|
@ -936,6 +934,9 @@ int xen_hvm_init(void)
|
||||||
state->exit.notify = xen_exit_notifier;
|
state->exit.notify = xen_exit_notifier;
|
||||||
qemu_add_exit_notifier(&state->exit);
|
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);
|
xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
|
||||||
DPRINTF("shared page at pfn %lx\n", 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,
|
state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
|
||||||
|
|
Loading…
Reference in a new issue