ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c @ 14227:29d4bca7a503

linux: Some save/restore simplifications and cleanups.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Fri Mar 02 23:01:36 2007 +0000 (2007-03-02)
parents 1fb5ae0ee453
children 228c3e05eb00
line source
1 #include <linux/version.h>
2 #include <linux/kernel.h>
3 #include <linux/mm.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>
10 #include <asm/irq.h>
11 #include <asm/mmu_context.h>
12 #include <xen/evtchn.h>
13 #include <asm/hypervisor.h>
14 #include <xen/interface/dom0_ops.h>
15 #include <xen/xenbus.h>
16 #include <linux/cpu.h>
17 #include <linux/kthread.h>
18 #include <xen/gnttab.h>
19 #include <xen/xencons.h>
20 #include <xen/cpu_hotplug.h>
21 #include <xen/interface/vcpu.h>
23 #if defined(__i386__) || defined(__x86_64__)
25 /*
26 * Power off function, if any
27 */
28 void (*pm_power_off)(void);
29 EXPORT_SYMBOL(pm_power_off);
31 void machine_emergency_restart(void)
32 {
33 /* We really want to get pending console data out before we die. */
34 xencons_force_flush();
35 HYPERVISOR_shutdown(SHUTDOWN_reboot);
36 }
38 void machine_restart(char * __unused)
39 {
40 machine_emergency_restart();
41 }
43 void machine_halt(void)
44 {
45 machine_power_off();
46 }
48 void machine_power_off(void)
49 {
50 /* We really want to get pending console data out before we die. */
51 xencons_force_flush();
52 if (pm_power_off)
53 pm_power_off();
54 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
55 }
57 int reboot_thru_bios = 0; /* for dmi_scan.c */
58 EXPORT_SYMBOL(machine_restart);
59 EXPORT_SYMBOL(machine_halt);
60 EXPORT_SYMBOL(machine_power_off);
62 static void pre_suspend(void)
63 {
64 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
65 clear_fixmap(FIX_SHARED_INFO);
67 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
68 xen_start_info->console.domU.mfn =
69 mfn_to_pfn(xen_start_info->console.domU.mfn);
70 }
72 static void post_suspend(int suspend_cancelled)
73 {
74 int i, j, k, fpp;
75 extern unsigned long max_pfn;
76 extern unsigned long *pfn_to_mfn_frame_list_list;
77 extern unsigned long *pfn_to_mfn_frame_list[];
79 if (suspend_cancelled) {
80 xen_start_info->store_mfn =
81 pfn_to_mfn(xen_start_info->store_mfn);
82 xen_start_info->console.domU.mfn =
83 pfn_to_mfn(xen_start_info->console.domU.mfn);
84 } else {
85 #ifdef CONFIG_SMP
86 cpu_initialized_map = cpumask_of_cpu(0);
87 #endif
88 }
90 set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
92 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
94 memset(empty_zero_page, 0, PAGE_SIZE);
96 fpp = PAGE_SIZE/sizeof(unsigned long);
97 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
98 if ((j % fpp) == 0) {
99 k++;
100 pfn_to_mfn_frame_list_list[k] =
101 virt_to_mfn(pfn_to_mfn_frame_list[k]);
102 j = 0;
103 }
104 pfn_to_mfn_frame_list[k][j] =
105 virt_to_mfn(&phys_to_machine_mapping[i]);
106 }
107 HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
108 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
109 virt_to_mfn(pfn_to_mfn_frame_list_list);
110 }
112 #else /* !(defined(__i386__) || defined(__x86_64__)) */
114 #define switch_idle_mm() ((void)0)
115 #define mm_pin_all() ((void)0)
116 #define pre_suspend() ((void)0)
117 #define post_suspend(x) ((void)0)
119 #endif
121 static int take_machine_down(void *p_fast_suspend)
122 {
123 int fast_suspend = *(int *)p_fast_suspend;
124 int suspend_cancelled, err, cpu;
125 extern void time_resume(void);
127 if (fast_suspend) {
128 preempt_disable();
129 } else {
130 for (;;) {
131 err = smp_suspend();
132 if (err)
133 return err;
135 xenbus_suspend();
136 preempt_disable();
138 if (num_online_cpus() == 1)
139 break;
141 preempt_enable();
142 xenbus_suspend_cancel();
143 }
144 }
146 mm_pin_all();
147 local_irq_disable();
148 preempt_enable();
149 gnttab_suspend();
150 pre_suspend();
152 /*
153 * This hypercall returns 1 if suspend was cancelled or the domain was
154 * merely checkpointed, and 0 if it is resuming in a new domain.
155 */
156 suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
158 post_suspend(suspend_cancelled);
159 gnttab_resume();
160 if (!suspend_cancelled) {
161 irq_resume();
162 #ifdef __x86_64__
163 /*
164 * Older versions of Xen do not save/restore the user %cr3.
165 * We do it here just in case, but there's no need if we are
166 * in fast-suspend mode as that implies a new enough Xen.
167 */
168 if (!fast_suspend) {
169 struct mmuext_op op;
170 op.cmd = MMUEXT_NEW_USER_BASEPTR;
171 op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd(
172 current->active_mm->pgd)) >> PAGE_SHIFT);
173 if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
174 BUG();
175 }
176 #endif
177 }
178 time_resume();
179 local_irq_enable();
181 if (fast_suspend && !suspend_cancelled) {
182 /*
183 * In fast-suspend mode the APs may not be brought back online
184 * when we resume. In that case we do it here.
185 */
186 for_each_online_cpu(cpu) {
187 if (cpu == 0)
188 continue;
189 cpu_set_initialized(cpu);
190 err = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
191 BUG_ON(err);
192 }
193 }
195 return suspend_cancelled;
196 }
198 int __xen_suspend(int fast_suspend)
199 {
200 int err, suspend_cancelled;
202 BUG_ON(smp_processor_id() != 0);
203 BUG_ON(in_interrupt());
205 #if defined(__i386__) || defined(__x86_64__)
206 if (xen_feature(XENFEAT_auto_translated_physmap)) {
207 printk(KERN_WARNING "Cannot suspend in "
208 "auto_translated_physmap mode.\n");
209 return -EOPNOTSUPP;
210 }
211 #endif
213 /* If we are definitely UP then 'slow mode' is actually faster. */
214 if (num_possible_cpus() == 1)
215 fast_suspend = 0;
217 if (fast_suspend) {
218 xenbus_suspend();
219 err = stop_machine_run(take_machine_down, &fast_suspend, 0);
220 } else {
221 err = take_machine_down(&fast_suspend);
222 }
224 if (err < 0)
225 return err;
227 suspend_cancelled = err;
228 if (!suspend_cancelled) {
229 xencons_resume();
230 xenbus_resume();
231 } else {
232 xenbus_suspend_cancel();
233 }
235 if (!fast_suspend)
236 smp_resume();
238 return 0;
239 }