1 #include <linux/version.h>
2 #include <linux/kernel.h>
4 #include <linux/unistd.h>
5 #include <linux/module.h>
6 #include <linux/reboot.h>
7 #include <linux/sysrq.h>
8 #include <linux/stringify.h>
9 #include <linux/stop_machine.h>
11 #include <asm/mmu_context.h>
12 #include <xen/evtchn.h>
13 #include <asm/hypervisor.h>
14 #include <xen/xenbus.h>
15 #include <linux/cpu.h>
16 #include <xen/clock.h>
17 #include <xen/gnttab.h>
18 #include <xen/xencons.h>
19 #include <xen/cpu_hotplug.h>
20 #include <xen/interface/vcpu.h>
21 #include "../../base/base.h"
23 #if defined(__i386__) || defined(__x86_64__)
24 #include <asm/pci_x86.h>
25 /* TBD: Dom0 should propagate the determined value to Xen. */
26 bool port_cf9_safe = false;
29 * Power off function, if any
31 void (*pm_power_off)(void);
32 EXPORT_SYMBOL(pm_power_off);
34 void machine_emergency_restart(void)
36 /* We really want to get pending console data out before we die. */
37 xencons_force_flush();
38 HYPERVISOR_shutdown(SHUTDOWN_reboot);
41 void machine_restart(char * __unused)
43 machine_emergency_restart();
46 void machine_halt(void)
51 void machine_power_off(void)
53 /* We really want to get pending console data out before we die. */
54 xencons_force_flush();
57 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
60 int reboot_thru_bios = 0; /* for dmi_scan.c */
61 EXPORT_SYMBOL(machine_restart);
62 EXPORT_SYMBOL(machine_halt);
63 EXPORT_SYMBOL(machine_power_off);
65 #ifdef CONFIG_PM_SLEEP
66 static void pre_suspend(void)
68 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
69 WARN_ON(HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
72 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
73 xen_start_info->console.domU.mfn =
74 mfn_to_pfn(xen_start_info->console.domU.mfn);
77 static void post_suspend(int suspend_cancelled, int fast_suspend)
80 unsigned long shinfo_mfn;
81 extern unsigned long max_pfn;
82 extern unsigned long *pfn_to_mfn_frame_list_list;
83 extern unsigned long **pfn_to_mfn_frame_list;
85 if (suspend_cancelled) {
86 xen_start_info->store_mfn =
87 pfn_to_mfn(xen_start_info->store_mfn);
88 xen_start_info->console.domU.mfn =
89 pfn_to_mfn(xen_start_info->console.domU.mfn);
92 cpumask_copy(vcpu_initialized_mask, cpu_online_mask);
94 for_each_possible_cpu(i) {
95 setup_runstate_area(i);
97 #ifdef CONFIG_XEN_VCPU_INFO_PLACEMENT
98 if (fast_suspend && i != smp_processor_id()
99 && HYPERVISOR_vcpu_op(VCPUOP_down, i, NULL))
104 if (fast_suspend && i != smp_processor_id()
105 && HYPERVISOR_vcpu_op(VCPUOP_up, i, NULL))
111 shinfo_mfn = xen_start_info->shared_info >> PAGE_SHIFT;
112 if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
113 pfn_pte_ma(shinfo_mfn, PAGE_KERNEL),
116 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
118 clear_page(empty_zero_page);
120 fpp = PAGE_SIZE/sizeof(unsigned long);
121 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
122 if ((j % fpp) == 0) {
124 pfn_to_mfn_frame_list_list[k] =
125 virt_to_mfn(pfn_to_mfn_frame_list[k]);
128 pfn_to_mfn_frame_list[k][j] =
129 virt_to_mfn(&phys_to_machine_mapping[i]);
131 HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
132 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
133 virt_to_mfn(pfn_to_mfn_frame_list_list);
137 #else /* !(defined(__i386__) || defined(__x86_64__)) */
139 #ifndef HAVE_XEN_PRE_SUSPEND
140 #define xen_pre_suspend() ((void)0)
143 #ifndef HAVE_XEN_POST_SUSPEND
144 #define xen_post_suspend(x) ((void)0)
147 #define switch_idle_mm() ((void)0)
148 #define mm_pin_all() ((void)0)
149 #define pre_suspend() xen_pre_suspend()
150 #define post_suspend(x, f) xen_post_suspend(x)
154 #ifdef CONFIG_PM_SLEEP
157 void (*resume_notifier)(int);
160 static int take_machine_down(void *_suspend)
162 struct suspend *suspend = _suspend;
163 int suspend_cancelled;
165 BUG_ON(!irqs_disabled());
168 suspend_cancelled = sysdev_suspend(PMSG_SUSPEND);
169 if (!suspend_cancelled) {
173 * This hypercall returns 1 if suspend was cancelled or the domain was
174 * merely checkpointed, and 0 if it is resuming in a new domain.
176 suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
178 BUG_ON(suspend_cancelled > 0);
179 suspend->resume_notifier(suspend_cancelled);
180 if (suspend_cancelled >= 0)
181 post_suspend(suspend_cancelled, suspend->fast_suspend);
182 if (!suspend_cancelled)
183 xen_clockevents_resume();
184 if (suspend_cancelled >= 0)
186 if (!suspend_cancelled) {
189 * Older versions of Xen do not save/restore the user %cr3.
190 * We do it here just in case, but there's no need if we are
191 * in fast-suspend mode as that implies a new enough Xen.
193 if (!suspend->fast_suspend)
194 xen_new_user_pt(current->active_mm->pgd);
198 return suspend_cancelled;
201 int __xen_suspend(int fast_suspend, void (*resume_notifier)(int))
203 int err, suspend_cancelled;
205 struct suspend suspend;
207 #define _check(fn, args...) ({ \
212 BUG_ON(smp_processor_id() != 0);
213 BUG_ON(in_interrupt());
215 #if defined(__i386__) || defined(__x86_64__)
216 if (xen_feature(XENFEAT_auto_translated_physmap)) {
217 printk(KERN_WARNING "Cannot suspend in "
218 "auto_translated_physmap mode.\n");
223 /* If we are definitely UP then 'slow mode' is actually faster. */
224 if (num_possible_cpus() == 1)
227 if (fast_suspend && _check(stop_machine_create)) {
228 printk(KERN_ERR "%s() failed: %d\n", what, err);
232 suspend.fast_suspend = fast_suspend;
233 suspend.resume_notifier = resume_notifier;
235 if (_check(dpm_suspend_start, PMSG_SUSPEND)) {
237 stop_machine_destroy();
238 printk(KERN_ERR "%s() failed: %d\n", what, err);
245 if (_check(dpm_suspend_noirq, PMSG_SUSPEND)) {
246 xenbus_suspend_cancel();
247 dpm_resume_end(PMSG_RESUME);
248 stop_machine_destroy();
249 printk(KERN_ERR "%s() failed: %d\n", what, err);
253 err = stop_machine(take_machine_down, &suspend,
256 xenbus_suspend_cancel();
258 BUG_ON(irqs_disabled());
263 if (!_check(dpm_suspend_noirq, PMSG_SUSPEND)
264 && _check(smp_suspend))
265 dpm_resume_noirq(PMSG_RESUME);
267 xenbus_suspend_cancel();
268 dpm_resume_end(PMSG_RESUME);
269 printk(KERN_ERR "%s() failed: %d\n",
276 if (num_online_cpus() == 1)
281 dpm_resume_noirq(PMSG_RESUME);
283 xenbus_suspend_cancel();
287 err = take_machine_down(&suspend);
291 dpm_resume_noirq(PMSG_RESUME);
294 suspend_cancelled = err;
295 if (!suspend_cancelled) {
299 xenbus_suspend_cancel();
307 dpm_resume_end(PMSG_RESUME);
310 stop_machine_destroy();