debuggers.hg

view xen/arch/x86/acpi/power.c @ 22803:0e693052c791

x86 acpi: Fix crash in enable_nonboot_cpus() on wakeup from S3/S4

Bringing a CPU back online can require RCU work to be flushed, because
the per-cpu data from last time the CPU was online may not yet be
deallocated. Use the new rcu_barrier() interface function to achieve
this.

Signed-off-by: Keir Fraser <keir@xen.org>
author Keir Fraser <keir@xen.org>
date Fri Jan 14 14:18:31 2011 +0000 (2011-01-14)
parents f2dba7ff0828
children
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 <xen/acpi.h>
16 #include <xen/errno.h>
17 #include <xen/iocap.h>
18 #include <xen/sched.h>
19 #include <asm/acpi.h>
20 #include <asm/irq.h>
21 #include <asm/init.h>
22 #include <xen/spinlock.h>
23 #include <xen/sched.h>
24 #include <xen/domain.h>
25 #include <xen/console.h>
26 #include <xen/iommu.h>
27 #include <xen/cpu.h>
28 #include <public/platform.h>
29 #include <asm/tboot.h>
30 #include <asm/apic.h>
31 #include <asm/io_apic.h>
32 #include <acpi/cpufreq/cpufreq.h>
34 uint32_t system_reset_counter = 1;
36 static char __initdata opt_acpi_sleep[20];
37 string_param("acpi_sleep", opt_acpi_sleep);
39 static u8 sleep_states[ACPI_S_STATE_COUNT];
40 static DEFINE_SPINLOCK(pm_lock);
42 struct acpi_sleep_info acpi_sinfo;
44 void do_suspend_lowlevel(void);
46 static int device_power_down(void)
47 {
48 console_suspend();
50 time_suspend();
52 i8259A_suspend();
54 ioapic_suspend();
56 iommu_suspend();
58 lapic_suspend();
60 return 0;
61 }
63 static void device_power_up(void)
64 {
65 lapic_resume();
67 iommu_resume();
69 ioapic_resume();
71 i8259A_resume();
73 time_resume();
75 console_resume();
76 }
78 static void freeze_domains(void)
79 {
80 struct domain *d;
82 rcu_read_lock(&domlist_read_lock);
83 /*
84 * Note that we iterate in order of domain-id. Hence we will pause dom0
85 * first which is required for correctness (as only dom0 can add domains to
86 * the domain list). Otherwise we could miss concurrently-created domains.
87 */
88 for_each_domain ( d )
89 domain_pause(d);
90 rcu_read_unlock(&domlist_read_lock);
91 }
93 static void thaw_domains(void)
94 {
95 struct domain *d;
97 rcu_read_lock(&domlist_read_lock);
98 for_each_domain ( d )
99 domain_unpause(d);
100 rcu_read_unlock(&domlist_read_lock);
101 }
103 static void acpi_sleep_prepare(u32 state)
104 {
105 void *wakeup_vector_va;
107 if ( state != ACPI_STATE_S3 )
108 return;
110 wakeup_vector_va = __acpi_map_table(
111 acpi_sinfo.wakeup_vector, sizeof(uint64_t));
113 /* TBoot will set resume vector itself (when it is safe to do so). */
114 if ( tboot_in_measured_env() )
115 return;
117 if ( acpi_sinfo.vector_width == 32 )
118 *(uint32_t *)wakeup_vector_va = bootsym_phys(wakeup_start);
119 else
120 *(uint64_t *)wakeup_vector_va = bootsym_phys(wakeup_start);
121 }
123 static void acpi_sleep_post(u32 state) {}
125 /* Main interface to do xen specific suspend/resume */
126 static int enter_state(u32 state)
127 {
128 unsigned long flags;
129 int error;
130 unsigned long cr4;
132 if ( (state <= ACPI_STATE_S0) || (state > ACPI_S_STATES_MAX) )
133 return -EINVAL;
135 if ( !spin_trylock(&pm_lock) )
136 return -EBUSY;
138 printk(XENLOG_INFO "Preparing system for ACPI S%d state.\n", state);
140 freeze_domains();
142 acpi_dmar_reinstate();
144 if ( (error = disable_nonboot_cpus()) )
145 goto enable_cpu;
147 cpufreq_del_cpu(0);
149 hvm_cpu_down();
151 acpi_sleep_prepare(state);
153 console_start_sync();
154 printk("Entering ACPI S%d state.\n", state);
156 local_irq_save(flags);
157 spin_debug_disable();
159 if ( (error = device_power_down()) )
160 {
161 printk(XENLOG_ERR "Some devices failed to power down.");
162 goto done;
163 }
165 ACPI_FLUSH_CPU_CACHE();
167 switch ( state )
168 {
169 case ACPI_STATE_S3:
170 do_suspend_lowlevel();
171 system_reset_counter++;
172 error = tboot_s3_resume();
173 break;
174 case ACPI_STATE_S5:
175 acpi_enter_sleep_state(ACPI_STATE_S5);
176 break;
177 default:
178 error = -EINVAL;
179 break;
180 }
182 /* Restore CR4 and EFER from cached values. */
183 cr4 = read_cr4();
184 write_cr4(cr4 & ~X86_CR4_MCE);
185 if ( cpu_has_efer )
186 write_efer(read_efer());
188 device_power_up();
190 mcheck_init(&boot_cpu_data);
191 write_cr4(cr4);
193 printk(XENLOG_INFO "Finishing wakeup from ACPI S%d state.\n", state);
195 if ( (state == ACPI_STATE_S3) && error )
196 panic("Memory integrity was lost on resume (%d)\n", error);
198 done:
199 spin_debug_enable();
200 local_irq_restore(flags);
201 console_end_sync();
202 acpi_sleep_post(state);
203 if ( hvm_cpu_up() )
204 BUG();
206 enable_cpu:
207 cpufreq_add_cpu(0);
208 microcode_resume_cpu(0);
209 rcu_barrier();
210 mtrr_aps_sync_begin();
211 enable_nonboot_cpus();
212 mtrr_aps_sync_end();
213 acpi_dmar_zap();
214 thaw_domains();
215 spin_unlock(&pm_lock);
216 return error;
217 }
219 static long enter_state_helper(void *data)
220 {
221 struct acpi_sleep_info *sinfo = (struct acpi_sleep_info *)data;
222 return enter_state(sinfo->sleep_state);
223 }
225 /*
226 * Dom0 issues this hypercall in place of writing pm1a_cnt. Xen then
227 * takes over the control and put the system into sleep state really.
228 */
229 int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
230 {
231 if ( !IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt_blk.address )
232 return -EPERM;
234 /* Sanity check */
235 if ( acpi_sinfo.pm1b_cnt_val &&
236 ((sleep->pm1a_cnt_val ^ sleep->pm1b_cnt_val) &
237 ACPI_BITMASK_SLEEP_ENABLE) )
238 {
239 gdprintk(XENLOG_ERR, "Mismatched pm1a/pm1b setting.");
240 return -EINVAL;
241 }
243 if ( sleep->flags )
244 return -EINVAL;
246 acpi_sinfo.pm1a_cnt_val = sleep->pm1a_cnt_val;
247 acpi_sinfo.pm1b_cnt_val = sleep->pm1b_cnt_val;
248 acpi_sinfo.sleep_state = sleep->sleep_state;
250 return continue_hypercall_on_cpu(0, enter_state_helper, &acpi_sinfo);
251 }
253 static int acpi_get_wake_status(void)
254 {
255 uint32_t val;
256 acpi_status status;
258 /* Wake status is the 15th bit of PM1 status register. (ACPI spec 3.0) */
259 status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &val);
260 if ( ACPI_FAILURE(status) )
261 return 0;
263 val &= ACPI_BITMASK_WAKE_STATUS;
264 val >>= ACPI_BITPOSITION_WAKE_STATUS;
265 return val;
266 }
268 static void tboot_sleep(u8 sleep_state)
269 {
270 uint32_t shutdown_type;
272 #define TB_COPY_GAS(tbg, g) \
273 tbg.space_id = g.space_id; \
274 tbg.bit_width = g.bit_width; \
275 tbg.bit_offset = g.bit_offset; \
276 tbg.access_width = g.access_width; \
277 tbg.address = g.address;
279 /* sizes are not same (due to packing) so copy each one */
280 TB_COPY_GAS(g_tboot_shared->acpi_sinfo.pm1a_cnt_blk,
281 acpi_sinfo.pm1a_cnt_blk);
282 TB_COPY_GAS(g_tboot_shared->acpi_sinfo.pm1b_cnt_blk,
283 acpi_sinfo.pm1b_cnt_blk);
284 TB_COPY_GAS(g_tboot_shared->acpi_sinfo.pm1a_evt_blk,
285 acpi_sinfo.pm1a_evt_blk);
286 TB_COPY_GAS(g_tboot_shared->acpi_sinfo.pm1b_evt_blk,
287 acpi_sinfo.pm1b_evt_blk);
288 g_tboot_shared->acpi_sinfo.pm1a_cnt_val = acpi_sinfo.pm1a_cnt_val;
289 g_tboot_shared->acpi_sinfo.pm1b_cnt_val = acpi_sinfo.pm1b_cnt_val;
290 g_tboot_shared->acpi_sinfo.wakeup_vector = acpi_sinfo.wakeup_vector;
291 g_tboot_shared->acpi_sinfo.vector_width = acpi_sinfo.vector_width;
292 g_tboot_shared->acpi_sinfo.kernel_s3_resume_vector =
293 bootsym_phys(wakeup_start);
295 switch ( sleep_state )
296 {
297 case ACPI_STATE_S3:
298 shutdown_type = TB_SHUTDOWN_S3;
299 break;
300 case ACPI_STATE_S4:
301 shutdown_type = TB_SHUTDOWN_S4;
302 break;
303 case ACPI_STATE_S5:
304 shutdown_type = TB_SHUTDOWN_S5;
305 break;
306 default:
307 return;
308 }
310 tboot_shutdown(shutdown_type);
311 }
313 /* System is really put into sleep state by this stub */
314 acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
315 {
316 acpi_status status;
318 if ( tboot_in_measured_env() )
319 {
320 tboot_sleep(sleep_state);
321 printk(XENLOG_ERR "TBOOT failed entering s3 state\n");
322 return_ACPI_STATUS(AE_ERROR);
323 }
325 ACPI_FLUSH_CPU_CACHE();
327 status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL,
328 acpi_sinfo.pm1a_cnt_val);
329 if ( ACPI_FAILURE(status) )
330 return_ACPI_STATUS(AE_ERROR);
332 if ( acpi_sinfo.pm1b_cnt_blk.address )
333 {
334 status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL,
335 acpi_sinfo.pm1b_cnt_val);
336 if ( ACPI_FAILURE(status) )
337 return_ACPI_STATUS(AE_ERROR);
338 }
340 /* Wait until we enter sleep state, and spin until we wake */
341 while ( !acpi_get_wake_status() )
342 continue;
344 return_ACPI_STATUS(AE_OK);
345 }
347 static int __init acpi_sleep_init(void)
348 {
349 int i;
350 char *p = opt_acpi_sleep;
352 while ( (p != NULL) && (*p != '\0') )
353 {
354 if ( !strncmp(p, "s3_bios", 7) )
355 acpi_video_flags |= 1;
356 if ( !strncmp(p, "s3_mode", 7) )
357 acpi_video_flags |= 2;
358 p = strchr(p, ',');
359 if ( p != NULL )
360 p += strspn(p, ", \t");
361 }
363 printk(XENLOG_INFO "ACPI sleep modes:");
364 for ( i = 0; i < ACPI_S_STATE_COUNT; i++ )
365 {
366 if ( i == ACPI_STATE_S3 )
367 {
368 sleep_states[i] = 1;
369 printk(" S%d", i);
370 }
371 else
372 sleep_states[i] = 0;
373 }
374 printk("\n");
376 return 0;
377 }
378 __initcall(acpi_sleep_init);