aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/smpboot.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2005-07-29 17:03:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-29 18:01:13 -0400
commit3d483f47579461a4715db33c68ef8752e5a97a2d (patch)
tree6a4c9022074426d3551ff1b47c95f2bfe3f41828 /arch/x86_64/kernel/smpboot.c
parent94d2ac66c12397e2ca7988dbf59f24a966d275cb (diff)
[PATCH] Fix sync_tsc hang
sync_tsc was using smp_call_function to ask the boot processor to report it's tsc value. smp_call_function performs an IPI_send_allbutself which is a broadcast ipi. There is a window during processor startup during which the target cpu has started and before it has initialized it's interrupt vectors so it can properly process an interrupt. Receveing an interrupt during that window will triple fault the cpu and do other nasty things. Why cli does not protect us from that is beyond me. The simple fix is to match ia64 and provide a smp_call_function_single. Which avoids the broadcast and is more efficient. This certainly fixes the problem of getting stuck on boot which was very easy to trigger on my SMP Hyperthreaded Xeon, and I think it fixes it for the right reasons. Minor changes by AK Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/smpboot.c')
-rw-r--r--arch/x86_64/kernel/smpboot.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 6d23354443c0..6e4807d64d46 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -211,9 +211,6 @@ static __cpuinit void sync_master(void *arg)
211{ 211{
212 unsigned long flags, i; 212 unsigned long flags, i;
213 213
214 if (smp_processor_id() != 0)
215 return;
216
217 go[MASTER] = 0; 214 go[MASTER] = 0;
218 215
219 local_irq_save(flags); 216 local_irq_save(flags);
@@ -262,7 +259,7 @@ get_delta(long *rt, long *master)
262 return tcenter - best_tm; 259 return tcenter - best_tm;
263} 260}
264 261
265static __cpuinit void sync_tsc(void) 262static __cpuinit void sync_tsc(unsigned int master)
266{ 263{
267 int i, done = 0; 264 int i, done = 0;
268 long delta, adj, adjust_latency = 0; 265 long delta, adj, adjust_latency = 0;
@@ -276,9 +273,17 @@ static __cpuinit void sync_tsc(void)
276 } t[NUM_ROUNDS] __cpuinitdata; 273 } t[NUM_ROUNDS] __cpuinitdata;
277#endif 274#endif
278 275
276 printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n",
277 smp_processor_id(), master);
278
279 go[MASTER] = 1; 279 go[MASTER] = 1;
280 280
281 smp_call_function(sync_master, NULL, 1, 0); 281 /* It is dangerous to broadcast IPI as cpus are coming up,
282 * as they may not be ready to accept them. So since
283 * we only need to send the ipi to the boot cpu direct
284 * the message, and avoid the race.
285 */
286 smp_call_function_single(master, sync_master, NULL, 1, 0);
282 287
283 while (go[MASTER]) /* wait for master to be ready */ 288 while (go[MASTER]) /* wait for master to be ready */
284 no_cpu_relax(); 289 no_cpu_relax();
@@ -322,16 +327,14 @@ static __cpuinit void sync_tsc(void)
322 printk(KERN_INFO 327 printk(KERN_INFO
323 "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, " 328 "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, "
324 "maxerr %lu cycles)\n", 329 "maxerr %lu cycles)\n",
325 smp_processor_id(), boot_cpu_id, delta, rt); 330 smp_processor_id(), master, delta, rt);
326} 331}
327 332
328static void __cpuinit tsc_sync_wait(void) 333static void __cpuinit tsc_sync_wait(void)
329{ 334{
330 if (notscsync || !cpu_has_tsc) 335 if (notscsync || !cpu_has_tsc)
331 return; 336 return;
332 printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", smp_processor_id(), 337 sync_tsc(boot_cpu_id);
333 boot_cpu_id);
334 sync_tsc();
335} 338}
336 339
337static __init int notscsync_setup(char *s) 340static __init int notscsync_setup(char *s)