ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c @ 14220:1fb5ae0ee453

linux: Use old-mode of save/restore for uniproc guests (it's faster).
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Mar 02 16:00:22 2007 +0000 (2007-03-02)
parents 3ac19fda0bc2
children 29d4bca7a503
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 /* Ensure we run on the idle task page tables so that we will
63 switch page tables before running user space. This is needed
64 on architectures with separate kernel and user page tables
65 because the user page table pointer is not saved/restored. */
66 static void switch_idle_mm(void)
67 {
68 struct mm_struct *mm = current->active_mm;
70 if (mm == &init_mm)
71 return;
73 atomic_inc(&init_mm.mm_count);
74 switch_mm(mm, &init_mm, current);
75 current->active_mm = &init_mm;
76 mmdrop(mm);
77 }
79 static void pre_suspend(void)
80 {
81 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
82 clear_fixmap(FIX_SHARED_INFO);
84 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
85 xen_start_info->console.domU.mfn =
86 mfn_to_pfn(xen_start_info->console.domU.mfn);
87 }
89 static void post_suspend(int suspend_cancelled)
90 {
91 int i, j, k, fpp;
92 extern unsigned long max_pfn;
93 extern unsigned long *pfn_to_mfn_frame_list_list;
94 extern unsigned long *pfn_to_mfn_frame_list[];
96 if (suspend_cancelled) {
97 xen_start_info->store_mfn =
98 pfn_to_mfn(xen_start_info->store_mfn);
99 xen_start_info->console.domU.mfn =
100 pfn_to_mfn(xen_start_info->console.domU.mfn);
101 } else {
102 cpu_initialized_map = cpumask_of_cpu(0);
103 }
105 set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
107 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
109 memset(empty_zero_page, 0, PAGE_SIZE);
111 fpp = PAGE_SIZE/sizeof(unsigned long);
112 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
113 if ((j % fpp) == 0) {
114 k++;
115 pfn_to_mfn_frame_list_list[k] =
116 virt_to_mfn(pfn_to_mfn_frame_list[k]);
117 j = 0;
118 }
119 pfn_to_mfn_frame_list[k][j] =
120 virt_to_mfn(&phys_to_machine_mapping[i]);
121 }
122 HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
123 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
124 virt_to_mfn(pfn_to_mfn_frame_list_list);
125 }
127 #else /* !(defined(__i386__) || defined(__x86_64__)) */
129 #define switch_idle_mm() ((void)0)
130 #define mm_pin_all() ((void)0)
131 #define pre_suspend() ((void)0)
132 #define post_suspend(x) ((void)0)
134 #endif
136 static int take_machine_down(void *p_fast_suspend)
137 {
138 int fast_suspend = *(int *)p_fast_suspend;
139 int suspend_cancelled, err, cpu;
140 extern void time_resume(void);
142 if (fast_suspend) {
143 preempt_disable();
144 } else {
145 for (;;) {
146 err = smp_suspend();
147 if (err)
148 return err;
150 xenbus_suspend();
151 preempt_disable();
153 if (num_online_cpus() == 1)
154 break;
156 preempt_enable();
157 xenbus_suspend_cancel();
158 }
159 }
161 mm_pin_all();
162 local_irq_disable();
163 preempt_enable();
164 gnttab_suspend();
165 pre_suspend();
167 /*
168 * This hypercall returns 1 if suspend was cancelled or the domain was
169 * merely checkpointed, and 0 if it is resuming in a new domain.
170 */
171 suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
173 post_suspend(suspend_cancelled);
174 gnttab_resume();
175 if (!suspend_cancelled)
176 irq_resume();
177 time_resume();
178 switch_idle_mm();
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 }