From aee45c31f0d7550fbece137470988a54b29542b2 Mon Sep 17 00:00:00 2001 From: Bijan Mottahedeh Date: Wed, 8 Jul 2015 16:35:03 -0700 Subject: [PATCH] SPARC64: LDoms suspend domain service. Signed-off-by: Bijan Mottahedeh Reviewd-by: Alexandre Chartre Reviewd-by: Aaron Young Orabug: 21970743 (cherry picked from commit 21d81b0e030cd18f85f7059ec304b7b8f3833162) --- arch/sparc/Kconfig | 3 + arch/sparc/include/asm/hypervisor.h | 6 ++ arch/sparc/kernel/ds.c | 134 +++++++++++++++++++++++++++- arch/sparc/kernel/hvapi.c | 2 +- arch/sparc/kernel/hvcalls.S | 7 ++ 5 files changed, 150 insertions(+), 2 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index c26416ff64c9..28b3e9b76755 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -109,6 +109,9 @@ config HAVE_LATENCYTOP_SUPPORT config ARCH_HIBERNATION_POSSIBLE def_bool y if SPARC64 +config ARCH_SUSPEND_POSSIBLE + def_bool y if SPARC64 + config AUDIT_ARCH bool default y diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index f5b6537306f0..05d3a120e865 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -2937,6 +2937,12 @@ unsigned long sun4v_reboot_data_set(unsigned long ra, unsigned long len); #endif +#define HV_FAST_GUEST_SUSPEND 0x181 + +#ifndef __ASSEMBLY__ +unsigned long sun4v_guest_suspend(void); +#endif + #define HV_FAST_VT_GET_PERFREG 0x184 #define HV_FAST_VT_SET_PERFREG 0x185 diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index 944620d1e07e..062787045d77 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -483,6 +488,28 @@ struct ds_panic_res { char reason[1]; }; +struct ds_suspend_req { + __u64 req_num; + __u64 req_type; +}; + +struct ds_suspend_res { + __u64 req_num; + __u32 result; + __u32 rec_result; + char reason[1]; +}; + +#define SUSPEND_PRE_SUCCESS 0x0 +#define SUSPEND_PRE_FAILURE 0x1 +#define SUSPEND_INVALID_MSG 0x2 +#define SUSPEND_INPROGRESS 0x3 +#define SUSPEND_FAILURE 0x4 +#define SUSPEND_POST_SUCCESS 0x5 +#define SUSPEND_POST_FAILURE 0x6 + +#define SUSPEND_REC_SUCCESS 0x0 + struct ds_pri_msg { u64 req_num; u64 type; @@ -594,6 +621,8 @@ static void ds_dom_shutdown_data_cb(ds_cb_arg_t arg, ds_svc_hdl_t hdl, void *buf, size_t len); static void ds_dom_panic_data_cb(ds_cb_arg_t arg, ds_svc_hdl_t hdl, void *buf, size_t len); +static void ds_dom_suspend_data_cb(ds_cb_arg_t arg, + ds_svc_hdl_t hdl, void *buf, size_t len); #ifdef CONFIG_HOTPLUG_CPU static void ds_dr_cpu_data_cb(ds_cb_arg_t arg, ds_svc_hdl_t hdl, void *buf, size_t len); @@ -637,7 +666,13 @@ static struct ds_builtin_service ds_primary_builtin_template[] = { NULL, ds_dom_panic_data_cb}, }, - + { + .id = "domain-suspend", + .vers = {DS_CAP_MAJOR, DS_CAP_MINOR}, + .ops = {NULL, + NULL, + ds_dom_suspend_data_cb}, + }, #ifdef CONFIG_HOTPLUG_CPU { .id = "dr-cpu", @@ -1552,6 +1587,103 @@ static void ds_dom_panic_data_cb(ds_cb_arg_t arg, panic("PANIC requested.\n"); } +static int suspend_guest(void *data) +{ + int err; + + err = syscore_suspend(); + if (err) + return err; + + pr_alert("Suspending the guest...\n"); + err = sun4v_guest_suspend(); + + syscore_resume(); + + return err; +} + +/* + * Copied from kernel_kexec(). + * Added freeze_kernel_threads(). + */ +static int suspend(void) +{ + int error = 0; + + lock_system_sleep(); + pm_prepare_console(); + error = freeze_processes(); + if (error) + goto restore_console; + error = freeze_kernel_threads(); + if (error) + goto thaw_processes; + suspend_console(); + error = dpm_suspend_start(PMSG_FREEZE); + if (error) + goto resume_console; + + /* At this point, dpm_suspend_start() has been called, + * but *not* dpm_suspend_end(). We *must* call + * dpm_suspend_end() now. Otherwise, drivers for + * some devices (e.g. interrupt controllers) become + * desynchronized with the actual state of the + * hardware at resume time, and evil weirdness ensues. + */ + error = dpm_suspend_end(PMSG_FREEZE); + if (error) + goto resume_devices; + + error = stop_machine(suspend_guest, NULL, NULL); + +resume_devices: + dpm_resume_start(PMSG_RESTORE); + dpm_resume_end(PMSG_RESTORE); +resume_console: + resume_console(); + thaw_kernel_threads(); +thaw_processes: + thaw_processes(); +restore_console: + pm_restore_console(); + unlock_system_sleep(); + + return error; +} + +static void ds_dom_suspend_data_cb(ds_cb_arg_t arg, + ds_svc_hdl_t handle, void *buf, size_t len) +{ + int rv; + struct ds_dev *ds = (struct ds_dev *)arg; + struct ds_suspend_req *rp; + struct ds_suspend_res res; + + dprintk("entered.\n"); + + rp = (struct ds_suspend_req *)buf; + + pr_alert("ds-%llu: Suspend request received.\n", ds->id); + + res.req_num = rp->req_num; + res.result = SUSPEND_PRE_SUCCESS; + res.rec_result = SUSPEND_REC_SUCCESS; + res.reason[0] = 0; + rv = ds_cap_send(handle, &res, sizeof(struct ds_suspend_res)); + + if (rv) + pr_err("ds-%llu: ds_cap_send failed err=%d\n", ds->id, rv); + else { + rv = suspend(); + dprintk("ds-%llu: rv=%d.\n", ds->id, rv); + } + + res.result = rv ? SUSPEND_FAILURE : SUSPEND_POST_SUCCESS; + res.rec_result = SUSPEND_REC_SUCCESS; + ds_cap_send(handle, &res, sizeof(struct ds_suspend_res)); +} + #ifdef CONFIG_HOTPLUG_CPU static void __dr_cpu_send_error(struct ds_dev *ds, diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c index 662500fa555f..e2e1e527cac4 100644 --- a/arch/sparc/kernel/hvapi.c +++ b/arch/sparc/kernel/hvapi.c @@ -188,7 +188,7 @@ void __init sun4v_hvapi_init(void) group = HV_GRP_CORE; major = 1; - minor = 1; + minor = 2; if (sun4v_hvapi_register(group, major, &minor)) goto bad; diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S index afbaba52d2f1..12a5e6676885 100644 --- a/arch/sparc/kernel/hvcalls.S +++ b/arch/sparc/kernel/hvcalls.S @@ -806,6 +806,13 @@ ENTRY(sun4v_reboot_data_set) nop ENDPROC(sun4v_reboot_data_set) +ENTRY(sun4v_guest_suspend) + mov HV_FAST_GUEST_SUSPEND, %o5 + ta HV_FAST_TRAP + retl + nop +ENDPROC(sun4v_guest_suspend) + ENTRY(sun4v_vt_get_perfreg) mov %o1, %o4 mov HV_FAST_VT_GET_PERFREG, %o5 -- 2.50.1