diff options
author | Stephane Eranian <eranian@hpl.hp.com> | 2006-09-26 02:32:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:56 -0400 |
commit | eaa70773e750cc09d60938bceacd028bc76b8e3a (patch) | |
tree | c88635294b3e26059e25a0dce573bfb8c6ec14e3 /arch/i386/kernel/smp.c | |
parent | 27d26666fc495166036f4ee2208df25ae7f89ab8 (diff) |
[PATCH] i386: add smp_call_function_single
Continiung the series of small patches necessary for the perfmon subsystem,
here is a patch that adds support for the smp_call_function_single()
function for i386. It exists for almost all other architectures but i386.
The perfmon subsystem needs it in one case to free some state on a
designated remote CPU.
Signed-off-by: Stephane Eranian <eranian@hpl.hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/smp.c')
-rw-r--r-- | arch/i386/kernel/smp.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index c10789d7a9d3..304243ed7a30 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c | |||
@@ -634,3 +634,69 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs) | |||
634 | } | 634 | } |
635 | } | 635 | } |
636 | 636 | ||
637 | /* | ||
638 | * this function sends a 'generic call function' IPI to one other CPU | ||
639 | * in the system. | ||
640 | * | ||
641 | * cpu is a standard Linux logical CPU number. | ||
642 | */ | ||
643 | static void | ||
644 | __smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
645 | int nonatomic, int wait) | ||
646 | { | ||
647 | struct call_data_struct data; | ||
648 | int cpus = 1; | ||
649 | |||
650 | data.func = func; | ||
651 | data.info = info; | ||
652 | atomic_set(&data.started, 0); | ||
653 | data.wait = wait; | ||
654 | if (wait) | ||
655 | atomic_set(&data.finished, 0); | ||
656 | |||
657 | call_data = &data; | ||
658 | wmb(); | ||
659 | /* Send a message to all other CPUs and wait for them to respond */ | ||
660 | send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); | ||
661 | |||
662 | /* Wait for response */ | ||
663 | while (atomic_read(&data.started) != cpus) | ||
664 | cpu_relax(); | ||
665 | |||
666 | if (!wait) | ||
667 | return; | ||
668 | |||
669 | while (atomic_read(&data.finished) != cpus) | ||
670 | cpu_relax(); | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * smp_call_function_single - Run a function on another CPU | ||
675 | * @func: The function to run. This must be fast and non-blocking. | ||
676 | * @info: An arbitrary pointer to pass to the function. | ||
677 | * @nonatomic: Currently unused. | ||
678 | * @wait: If true, wait until function has completed on other CPUs. | ||
679 | * | ||
680 | * Retrurns 0 on success, else a negative status code. | ||
681 | * | ||
682 | * Does not return until the remote CPU is nearly ready to execute <func> | ||
683 | * or is or has executed. | ||
684 | */ | ||
685 | |||
686 | int smp_call_function_single (int cpu, void (*func) (void *info), void *info, | ||
687 | int nonatomic, int wait) | ||
688 | { | ||
689 | /* prevent preemption and reschedule on another processor */ | ||
690 | int me = get_cpu(); | ||
691 | if (cpu == me) { | ||
692 | WARN_ON(1); | ||
693 | put_cpu(); | ||
694 | return -EBUSY; | ||
695 | } | ||
696 | spin_lock_bh(&call_lock); | ||
697 | __smp_call_function_single(cpu, func, info, nonatomic, wait); | ||
698 | spin_unlock_bh(&call_lock); | ||
699 | put_cpu(); | ||
700 | return 0; | ||
701 | } | ||
702 | EXPORT_SYMBOL(smp_call_function_single); | ||