]> xenbits.xensource.com Git - people/julieng/linux-arm.git/commitdiff
Add support for guest OS suspend/resume under Xen/ARM.
authorBhupinder Thakur <bhupinder.thakur@linaro.org>
Wed, 6 Sep 2017 09:16:28 +0000 (14:46 +0530)
committerBhupinder Thakur <bhupinder.thakur@linaro.org>
Wed, 6 Sep 2017 09:16:28 +0000 (14:46 +0530)
Replace various stub functions with real functionality, including
reestablishing the shared info page and the per-vcpu info pages on
restore.

Reestablishing the vcpu info page is a little subtle. The
VCPUOP_register_vcpu_info hypercall can only be called on either the
current VCPU or on an offline different VCPU. Since migration occurs
with all VCPUS online they are all therefore online at the point of
resume.

Therefore we must perform a cross VCPU call to each non-boot VCPU,
which cannot be done in the xen_arch_post_suspend() callback since
that is run from stop_machine() with interrupts disabled.

Furthermore VCPUOP_register_vcpu_info can only be called once per-VCPU
in a given domain, so it must not be called after a cancelled suspend
(which resumes in the same domain).

Therefore xen_arch_resume() gains a suspend_cancelled parameter and we
resume the secondary VCPUs there only if needed.

The VCPU which is running the suspend is resumed earlier in the
xen_arch_post_suspend callback, again conditionally only for
non-cancelled suspends.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
arch/arm/xen/Makefile
arch/arm/xen/enlighten.c
arch/arm/xen/suspend.c [new file with mode: 0644]
arch/arm/xen/xen-ops.h [new file with mode: 0644]
arch/arm64/xen/Makefile
arch/x86/xen/suspend.c
drivers/xen/manage.c
include/xen/xen-ops.h

index 227952103b0bbff28a21d74ce6b10b975233e6c1..d6888279c8e664a2626454ddecf130b93a440a10 100644 (file)
@@ -1,2 +1,2 @@
-obj-y          := enlighten.o hypercall.o grant-table.o p2m.o mm.o
+obj-y  := enlighten.o hypercall.o grant-table.o p2m.o mm.o suspend.o
 obj-$(CONFIG_XEN_EFI) += efi.o
index ba7f4c8f5c3e4c9e6fac7282016ec2d33b32005c..a5bac7d6db0ee4c9b18bcc4a29f090423bbe023d 100644 (file)
@@ -290,6 +290,39 @@ void __init xen_early_init(void)
                add_preferred_console("hvc", 0, NULL);
 }
 
+static struct shared_info *shared_info_page;
+
+int xen_register_shared_info(void)
+{
+        struct xen_add_to_physmap xatp;
+
+        /*
+         * This function is called on boot and on restore. On boot we
+         * allocate this page immediately before calling this function
+         * and bail on failure. On resume that allocation must have
+         * succeeded or we couldn't be doing a save/restore.
+         */
+        BUG_ON(!shared_info_page);
+
+        xatp.domid = DOMID_SELF;
+        xatp.idx = 0;
+        xatp.space = XENMAPSPACE_shared_info;
+        xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
+        if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+                BUG();
+
+        HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+        return 0;
+}
+
+void xen_vcpu_restore(void)
+{
+       xen_percpu_init();
+
+       /* XXX TODO: xen_setup_runstate_info(cpu); */
+}
+
 static void __init xen_acpi_guest_init(void)
 {
 #ifdef CONFIG_ACPI
@@ -329,8 +362,6 @@ static void __init xen_dt_guest_init(void)
 
 static int __init xen_guest_init(void)
 {
-       struct xen_add_to_physmap xatp;
-       struct shared_info *shared_info_page = NULL;
        int cpu;
 
        if (!xen_domain())
@@ -359,14 +390,8 @@ static int __init xen_guest_init(void)
                pr_err("not enough memory\n");
                return -ENOMEM;
        }
-       xatp.domid = DOMID_SELF;
-       xatp.idx = 0;
-       xatp.space = XENMAPSPACE_shared_info;
-       xatp.gpfn = virt_to_gfn(shared_info_page);
-       if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
-               BUG();
 
-       HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+       xen_register_shared_info();
 
        /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
         * page, we use it in the event channel upcall and in some pvclock
@@ -439,14 +464,6 @@ static int __init xen_pm_init(void)
 late_initcall(xen_pm_init);
 
 
-/* empty stubs */
-void xen_arch_pre_suspend(void) { }
-void xen_arch_post_suspend(int suspend_cancelled) { }
-void xen_timer_resume(void) { }
-void xen_arch_resume(void) { }
-void xen_arch_suspend(void) { }
-
-
 /* In the hypercall.S file. */
 EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
diff --git a/arch/arm/xen/suspend.c b/arch/arm/xen/suspend.c
new file mode 100644 (file)
index 0000000..0811a06
--- /dev/null
@@ -0,0 +1,54 @@
+#include <linux/types.h>
+#include <linux/tick.h>
+
+#include <xen/interface/xen.h>
+
+#include <asm/xen/hypercall.h>
+
+#include "xen-ops.h"
+
+void xen_arch_pre_suspend(void) {
+       /* Nothing to do */
+}
+
+void xen_arch_post_suspend(int suspend_cancelled)
+{
+       xen_register_shared_info();
+       if (!suspend_cancelled)
+               xen_vcpu_restore();
+}
+
+static void xen_vcpu_notify_suspend(void *data)
+{
+       tick_suspend_local();
+}
+
+static void xen_vcpu_notify_resume(void *data)
+{
+       int suspend_cancelled = *(int *)data;
+
+       if (smp_processor_id() == 0)
+               return;
+
+       /* Boot processor done in post_suspend */
+       if (!suspend_cancelled)
+               xen_vcpu_restore();
+
+       /* Boot processor notified via generic timekeeping_resume() */
+       tick_resume_local();
+}
+
+void xen_arch_suspend(void)
+{
+       on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
+}
+
+void xen_arch_resume(int suspend_cancelled)
+{
+       on_each_cpu(xen_vcpu_notify_resume, &suspend_cancelled, 1);
+}
+
+void xen_timer_resume(void)
+{
+       /* Nothing to do */
+}
diff --git a/arch/arm/xen/xen-ops.h b/arch/arm/xen/xen-ops.h
new file mode 100644 (file)
index 0000000..de23e91
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <xen/xen-ops.h>
+
+void xen_register_shared_info(void);
+void xen_vcpu_restore(void);
+
+#endif /* XEN_OPS_H */
index 8ff8aa9c62285c130af721aeb4299709ef1a33bb..2ba160448bc065c69fd043c6a01bc4a72486db17 100644 (file)
@@ -1,3 +1,3 @@
-xen-arm-y      += $(addprefix ../../arm/xen/, enlighten.o grant-table.o p2m.o mm.o)
+xen-arm-y      += $(addprefix ../../arm/xen/, enlighten.o grant-table.o p2m.o mm.o suspend.o)
 obj-y          := xen-arm.o hypercall.o
 obj-$(CONFIG_XEN_EFI) += $(addprefix ../../arm/xen/, efi.o)
index d6b1680693a9b7114e7d87e59b52d871e28a6b27..c570f037904b0f201df5df1b569e4d2529d2fe2a 100644 (file)
@@ -42,7 +42,7 @@ static void xen_vcpu_notify_suspend(void *data)
        tick_suspend_local();
 }
 
-void xen_arch_resume(void)
+void xen_arch_resume(int suspend_cancelled)
 {
        int cpu;
 
index c425d03d37d2700de084b920416fef0465d918f8..1a53e035f576b215989f687b57bb874ec82d2e42 100644 (file)
@@ -150,7 +150,7 @@ static void do_suspend(void)
                si.cancelled = 1;
        }
 
-       xen_arch_resume();
+       xen_arch_resume(si.cancelled);
 
 out_resume:
        if (!si.cancelled)
index 218e6aae54335bd83238413da8a37d7a740c016d..61d055c529dc99c7af2dbad7b104c312b6d6c957 100644 (file)
@@ -21,7 +21,7 @@ void xen_arch_pre_suspend(void);
 void xen_arch_post_suspend(int suspend_cancelled);
 
 void xen_timer_resume(void);
-void xen_arch_resume(void);
+void xen_arch_resume(int suspend_cancelled);
 void xen_arch_suspend(void);
 
 void xen_reboot(int reason);