aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2019-07-22 16:17:52 +1000
committerDavid Gibson <david@gibson.dropbear.id.au>2019-08-21 17:17:39 +1000
commit93eac7b8f44738f7d2f4ba4460d67b04af5b0b99 (patch)
tree9044565ac3d6082ac008cafa39761d394e9242d6 /hw/ppc
parentc508bd12f65e14f82eb62e462bcb64898d8806a6 (diff)
spapr: Implement ibm,suspend-me
This has been useful to modify and test the Linux pseries suspend code but it requires modification to the guest to call it (due to being gated by other unimplemented features). It is not otherwise used by Linux yet, but work is slowly progressing there. This allows a (lightly modified) guest kernel to suspend with `echo mem > /sys/power/state` and be resumed with system_wakeup monitor command. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Message-Id: <20190722061752.22114-2-npiggin@gmail.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/spapr.c7
-rw-r--r--hw/ppc/spapr_rtas.c32
2 files changed, 39 insertions, 0 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 56b33571c5..51e1cb0d46 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3083,6 +3083,13 @@ static void spapr_machine_init(MachineState *machine)
qemu_register_boot_set(spapr_boot_set, spapr);
+ /*
+ * Nothing needs to be done to resume a suspended guest because
+ * suspending does not change the machine state, so no need for
+ * a ->wakeup method.
+ */
+ qemu_register_wakeup_support();
+
if (kvm_enabled()) {
/* to stop and start vmclock */
qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d3f9a69a51..526b489297 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -217,6 +217,36 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
qemu_cpu_kick(cs);
}
+static void rtas_ibm_suspend_me(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ CPUState *cs;
+
+ if (nargs != 0 || nret != 1) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
+ CPUPPCState *e = &c->env;
+ if (c == cpu) {
+ continue;
+ }
+
+ /* See h_join */
+ if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+ rtas_st(rets, 0, H_MULTI_THREADS_ACTIVE);
+ return;
+ }
+ }
+
+ qemu_system_suspend_request();
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
+}
+
static inline int sysparm_st(target_ulong addr, target_ulong len,
const void *val, uint16_t vallen)
{
@@ -484,6 +514,8 @@ static void core_rtas_register_types(void)
rtas_query_cpu_stopped_state);
spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
+ spapr_rtas_register(RTAS_IBM_SUSPEND_ME, "ibm,suspend-me",
+ rtas_ibm_suspend_me);
spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
"ibm,get-system-parameter",
rtas_ibm_get_system_parameter);