summaryrefslogtreecommitdiff
path: root/arch/mips
diff options
context:
space:
mode:
authorPeter Watkins <pwatkins@sicortex.com>2007-07-31 02:01:29 +0400
committerRalf Baechle <ralf@linux-mips.org>2007-08-01 00:35:37 +0400
commitb4b2917cc8babe8eaf4bc133bca31b11ed7dac13 (patch)
tree31eb7dda7083c083df0b6407f2daa15f9849ae54 /arch/mips
parent185bcd17a5fb4155fba125332efa498be126aa4e (diff)
downloadlinux-b4b2917cc8babe8eaf4bc133bca31b11ed7dac13.tar.xz
[MIPS] Add smp_call_function_single()
In the other archs, there is more factoring of smp call code, and more care in the use of get_cpu(). That can be a follow-up MIPS patch. Signed-off-by: Peter Watkins <pwatkins@sicortex.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/smp.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 04bbbd8d91ab..73b0dab02668 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -194,6 +194,61 @@ void smp_call_function_interrupt(void)
}
}
+int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int retry, int wait)
+{
+ struct call_data_struct data;
+ int me;
+
+ /*
+ * Can die spectacularly if this CPU isn't yet marked online
+ */
+ if (!cpu_online(cpu))
+ return 0;
+
+ me = get_cpu();
+ BUG_ON(!cpu_online(me));
+
+ if (cpu == me) {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
+ put_cpu();
+ return 0;
+ }
+
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ spin_lock(&smp_call_lock);
+ call_data = &data;
+ smp_mb();
+
+ /* Send a message to the other CPU */
+ core_send_ipi(cpu, SMP_CALL_FUNCTION);
+
+ /* Wait for response */
+ /* FIXME: lock-up detection, backtrace on lock-up */
+ while (atomic_read(&data.started) != 1)
+ barrier();
+
+ if (wait)
+ while (atomic_read(&data.finished) != 1)
+ barrier();
+ call_data = NULL;
+ spin_unlock(&smp_call_lock);
+
+ put_cpu();
+ return 0;
+}
+
static void stop_this_cpu(void *dummy)
{
/*