aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/smp.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/smp.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/smp.c')
-rw-r--r--arch/x86_64/kernel/smp.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 6ee74db52303..e5958220d6b8 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -293,6 +293,69 @@ void unlock_ipi_call_lock(void)
293} 293}
294 294
295/* 295/*
296 * this function sends a 'generic call function' IPI to one other CPU
297 * in the system.
298 */
299static void __smp_call_function_single (int cpu, void (*func) (void *info), void *info,
300 int nonatomic, int wait)
301{
302 struct call_data_struct data;
303 int cpus = 1;
304
305 data.func = func;
306 data.info = info;
307 atomic_set(&data.started, 0);
308 data.wait = wait;
309 if (wait)
310 atomic_set(&data.finished, 0);
311
312 call_data = &data;
313 wmb();
314 /* Send a message to all other CPUs and wait for them to respond */
315 send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);
316
317 /* Wait for response */
318 while (atomic_read(&data.started) != cpus)
319 cpu_relax();
320
321 if (!wait)
322 return;
323
324 while (atomic_read(&data.finished) != cpus)
325 cpu_relax();
326}
327
328/*
329 * smp_call_function_single - Run a function on another CPU
330 * @func: The function to run. This must be fast and non-blocking.
331 * @info: An arbitrary pointer to pass to the function.
332 * @nonatomic: Currently unused.
333 * @wait: If true, wait until function has completed on other CPUs.
334 *
335 * Retrurns 0 on success, else a negative status code.
336 *
337 * Does not return until the remote CPU is nearly ready to execute <func>
338 * or is or has executed.
339 */
340
341int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
342 int nonatomic, int wait)
343{
344 /* prevent preemption and reschedule on another processor */
345 int me = get_cpu();
346 if (cpu == me) {
347 WARN_ON(1);
348 put_cpu();
349 return -EBUSY;
350 }
351 spin_lock_bh(&call_lock);
352 __smp_call_function_single(cpu, func, info, nonatomic, wait);
353 spin_unlock_bh(&call_lock);
354 put_cpu();
355 return 0;
356}
357
358/*
296 * this function sends a 'generic call function' IPI to all other CPUs 359 * this function sends a 'generic call function' IPI to all other CPUs
297 * in the system. 360 * in the system.
298 */ 361 */