ia64/xen-unstable

view xen/arch/x86/acpi/power.c @ 18819:db7a713071fe

x86: freeze non-current vCPUs of dom0 before entering S5

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Nov 20 14:21:17 2008 +0000 (2008-11-20)
parents 876bffced2b8
children 9f9ba1a7cc92
line source
1 /* drivers/acpi/sleep/power.c - PM core functionality for Xen
2 *
3 * Copyrights from Linux side:
4 * Copyright (c) 2000-2003 Patrick Mochel
5 * Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz>
6 * Copyright (c) 2003 Open Source Development Lab
7 * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
8 * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
9 *
10 * Slimmed with Xen specific support.
11 */
13 #include <xen/config.h>
14 #include <asm/io.h>
15 #include <asm/acpi.h>
16 #include <xen/acpi.h>
17 #include <xen/errno.h>
18 #include <xen/iocap.h>
19 #include <xen/sched.h>
20 #include <asm/acpi.h>
21 #include <asm/irq.h>
22 #include <asm/init.h>
23 #include <xen/spinlock.h>
24 #include <xen/sched.h>
25 #include <xen/domain.h>
26 #include <xen/console.h>
27 #include <xen/iommu.h>
28 #include <public/platform.h>
29 #include <asm/tboot.h>
31 #include <acpi/cpufreq/cpufreq.h>
33 uint32_t system_reset_counter = 1;
35 static char opt_acpi_sleep[20];
36 string_param("acpi_sleep", opt_acpi_sleep);
38 static u8 sleep_states[ACPI_S_STATE_COUNT];
39 static DEFINE_SPINLOCK(pm_lock);
41 struct acpi_sleep_info acpi_sinfo;
43 void do_suspend_lowlevel(void);
45 static int device_power_down(void)
46 {
47 iommu_suspend();
49 console_suspend();
51 time_suspend();
53 i8259A_suspend();
55 ioapic_suspend();
57 lapic_suspend();
59 return 0;
60 }
62 static void device_power_up(void)
63 {
64 lapic_resume();
66 ioapic_resume();
68 i8259A_resume();
70 time_resume();
72 console_resume();
74 iommu_resume();
75 }
77 static void freeze_domains(void)
78 {
79 struct domain *d;
80 struct vcpu *v;
82 rcu_read_lock(&domlist_read_lock);
83 for_each_domain ( d )
84 {
85 switch ( d->domain_id )
86 {
87 case 0:
88 for_each_vcpu ( d, v )
89 if ( v != current )
90 vcpu_pause(v);
91 break;
92 default:
93 domain_pause(d);
94 break;
95 }
96 }
97 rcu_read_unlock(&domlist_read_lock);
98 }
100 static void thaw_domains(void)
101 {
102 struct domain *d;
103 struct vcpu *v;
105 rcu_read_lock(&domlist_read_lock);
106 for_each_domain ( d )
107 {
108 switch ( d->domain_id )
109 {
110 case 0:
111 for_each_vcpu ( d, v )
112 if ( v != current )
113 vcpu_unpause(v);
114 break;
115 default:
116 domain_unpause(d);
117 break;
118 }
119 }
120 rcu_read_unlock(&domlist_read_lock);
121 }
123 static void acpi_sleep_prepare(u32 state)
124 {
125 void *wakeup_vector_va;
127 if ( state != ACPI_STATE_S3 )
128 return;
130 wakeup_vector_va = __acpi_map_table(
131 acpi_sinfo.wakeup_vector, sizeof(uint64_t));
132 if ( acpi_sinfo.vector_width == 32 )
133 {
134 *(uint32_t *)wakeup_vector_va =
135 tboot_in_measured_env() ?
136 (uint32_t)g_tboot_shared->s3_tb_wakeup_entry :
137 (uint32_t)bootsym_phys(wakeup_start);
138 }
139 else
140 {
141 *(uint64_t *)wakeup_vector_va =
142 tboot_in_measured_env() ?
143 (uint64_t)g_tboot_shared->s3_tb_wakeup_entry :
144 (uint64_t)bootsym_phys(wakeup_start);
145 }
146 }
148 static void acpi_sleep_post(u32 state) {}
150 /* Main interface to do xen specific suspend/resume */
151 static int enter_state(u32 state)
152 {
153 unsigned long flags;
154 int error;
156 if ( (state <= ACPI_STATE_S0) || (state > ACPI_S_STATES_MAX) )
157 return -EINVAL;
159 if ( !spin_trylock(&pm_lock) )
160 return -EBUSY;
162 printk(XENLOG_INFO "Preparing system for ACPI S%d state.", state);
164 freeze_domains();
166 disable_nonboot_cpus();
167 if ( num_online_cpus() != 1 )
168 {
169 error = -EBUSY;
170 goto enable_cpu;
171 }
173 cpufreq_del_cpu(0);
175 hvm_cpu_down();
177 acpi_sleep_prepare(state);
179 console_start_sync();
180 printk("Entering ACPI S%d state.\n", state);
182 local_irq_save(flags);
184 if ( (error = device_power_down()) )
185 {
186 printk(XENLOG_ERR "Some devices failed to power down.");
187 goto done;
188 }
190 ACPI_FLUSH_CPU_CACHE();
192 switch ( state )
193 {
194 case ACPI_STATE_S3:
195 do_suspend_lowlevel();
196 system_reset_counter++;
197 break;
198 case ACPI_STATE_S5:
199 acpi_enter_sleep_state(ACPI_STATE_S5);
200 break;
201 default:
202 error = -EINVAL;
203 break;
204 }
206 /* Restore CR4 and EFER from cached values. */
207 write_cr4(read_cr4());
208 if ( cpu_has_efer )
209 write_efer(read_efer());
211 device_power_up();
213 printk(XENLOG_INFO "Finishing wakeup from ACPI S%d state.", state);
215 done:
216 local_irq_restore(flags);
217 console_end_sync();
218 acpi_sleep_post(state);
219 if ( !hvm_cpu_up() )
220 BUG();
222 enable_cpu:
223 cpufreq_add_cpu(0);
224 enable_nonboot_cpus();
225 thaw_domains();
226 spin_unlock(&pm_lock);
227 return error;
228 }
230 static long enter_state_helper(void *data)
231 {
232 struct acpi_sleep_info *sinfo = (struct acpi_sleep_info *)data;
233 return enter_state(sinfo->sleep_state);
234 }
236 /*
237 * Dom0 issues this hypercall in place of writing pm1a_cnt. Xen then
238 * takes over the control and put the system into sleep state really.
239 */
240 int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
241 {
242 if ( !IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt_blk.address )
243 return -EPERM;
245 /* Sanity check */
246 if ( acpi_sinfo.pm1b_cnt_val &&
247 ((sleep->pm1a_cnt_val ^ sleep->pm1b_cnt_val) &
248 ACPI_BITMASK_SLEEP_ENABLE) )
249 {
250 gdprintk(XENLOG_ERR, "Mismatched pm1a/pm1b setting.");
251 return -EINVAL;
252 }
254 if ( sleep->flags )
255 return -EINVAL;
257 acpi_sinfo.pm1a_cnt_val = sleep->pm1a_cnt_val;
258 acpi_sinfo.pm1b_cnt_val = sleep->pm1b_cnt_val;
259 acpi_sinfo.sleep_state = sleep->sleep_state;
261 return continue_hypercall_on_cpu(0, enter_state_helper, &acpi_sinfo);
262 }
264 static int acpi_get_wake_status(void)
265 {
266 uint32_t val;
267 acpi_status status;
269 /* Wake status is the 15th bit of PM1 status register. (ACPI spec 3.0) */
270 status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &val);
271 if ( ACPI_FAILURE(status) )
272 return 0;
274 val &= ACPI_BITMASK_WAKE_STATUS;
275 val >>= ACPI_BITPOSITION_WAKE_STATUS;
276 return val;
277 }
279 static void tboot_sleep(u8 sleep_state)
280 {
281 uint32_t shutdown_type;
283 g_tboot_shared->acpi_sinfo.pm1a_cnt =
284 (uint16_t)acpi_sinfo.pm1a_cnt_blk.address;
285 g_tboot_shared->acpi_sinfo.pm1b_cnt =
286 (uint16_t)acpi_sinfo.pm1b_cnt_blk.address;
287 g_tboot_shared->acpi_sinfo.pm1a_evt =
288 (uint16_t)acpi_sinfo.pm1a_evt_blk.address;
289 g_tboot_shared->acpi_sinfo.pm1b_evt =
290 (uint16_t)acpi_sinfo.pm1b_evt_blk.address;
291 g_tboot_shared->acpi_sinfo.pm1a_cnt_val = acpi_sinfo.pm1a_cnt_val;
292 g_tboot_shared->acpi_sinfo.pm1b_cnt_val = acpi_sinfo.pm1b_cnt_val;
294 switch ( sleep_state )
295 {
296 case ACPI_STATE_S3:
297 shutdown_type = TB_SHUTDOWN_S3;
298 g_tboot_shared->s3_k_wakeup_entry =
299 (uint32_t)bootsym_phys(wakeup_start);
300 break;
301 case ACPI_STATE_S4:
302 shutdown_type = TB_SHUTDOWN_S4;
303 break;
304 case ACPI_STATE_S5:
305 shutdown_type = TB_SHUTDOWN_S5;
306 break;
307 default:
308 return;
309 }
311 tboot_shutdown(shutdown_type);
312 }
314 /* System is really put into sleep state by this stub */
315 acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
316 {
317 acpi_status status;
319 if ( tboot_in_measured_env() )
320 {
321 tboot_sleep(sleep_state);
322 printk(XENLOG_ERR "TBOOT failed entering s3 state\n");
323 return_ACPI_STATUS(AE_ERROR);
324 }
326 ACPI_FLUSH_CPU_CACHE();
328 status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL,
329 acpi_sinfo.pm1a_cnt_val);
330 if ( ACPI_FAILURE(status) )
331 return_ACPI_STATUS(AE_ERROR);
333 if ( acpi_sinfo.pm1b_cnt_blk.address )
334 {
335 status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL,
336 acpi_sinfo.pm1b_cnt_val);
337 if ( ACPI_FAILURE(status) )
338 return_ACPI_STATUS(AE_ERROR);
339 }
341 /* Wait until we enter sleep state, and spin until we wake */
342 while ( !acpi_get_wake_status() )
343 continue;
345 return_ACPI_STATUS(AE_OK);
346 }
348 static int __init acpi_sleep_init(void)
349 {
350 int i;
351 char *p = opt_acpi_sleep;
353 while ( (p != NULL) && (*p != '\0') )
354 {
355 if ( !strncmp(p, "s3_bios", 7) )
356 acpi_video_flags |= 1;
357 if ( !strncmp(p, "s3_mode", 7) )
358 acpi_video_flags |= 2;
359 p = strchr(p, ',');
360 if ( p != NULL )
361 p += strspn(p, ", \t");
362 }
364 printk(XENLOG_INFO "ACPI sleep modes:");
365 for ( i = 0; i < ACPI_S_STATE_COUNT; i++ )
366 {
367 if ( i == ACPI_STATE_S3 )
368 {
369 sleep_states[i] = 1;
370 printk(" S%d", i);
371 }
372 else
373 sleep_states[i] = 0;
374 }
375 printk("\n");
377 return 0;
378 }
379 __initcall(acpi_sleep_init);