mips: convert to generic helpers for IPI function calls

This converts mips to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
but it compiles.

mips shares the same IPI for smp_call_function() and
smp_call_function_single(), since not all mips platforms have enough
available IPIs to support seperate setups.

Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
Jens Axboe 2008-06-17 10:45:23 +02:00
parent 7b7426c8a6
commit 2f304c0a0a
4 changed files with 16 additions and 142 deletions

View file

@ -1763,6 +1763,7 @@ config SMP
bool "Multi-Processing support"
depends on SYS_SUPPORTS_SMP
select IRQ_PER_CPU
select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If

View file

@ -131,149 +131,30 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_idle();
}
DEFINE_SPINLOCK(smp_call_lock);
struct call_data_struct *call_data;
void arch_send_call_function_ipi(cpumask_t mask)
{
mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION);
}
/*
* Run a function on all other CPUs.
*
* <mask> cpuset_t of all processors to run the function on.
* <func> The function to run. This must be fast and non-blocking.
* <info> An arbitrary pointer to pass to the function.
* <retry> If true, keep retrying until ready.
* <wait> If true, wait until function has completed on other CPUs.
* [RETURNS] 0 on success, else a negative status code.
*
* Does not return until remote CPUs are nearly ready to execute <func>
* or are or have executed.
*
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler:
*
* CPU A CPU B
* Disable interrupts
* smp_call_function()
* Take call_lock
* Send IPIs
* Wait for all cpus to acknowledge IPI
* CPU A has not responded, spin waiting
* for cpu A to respond, holding call_lock
* smp_call_function()
* Spin waiting for call_lock
* Deadlock Deadlock
* We reuse the same vector for the single IPI
*/
int smp_call_function_mask(cpumask_t mask, void (*func) (void *info),
void *info, int retry, int wait)
void arch_send_call_function_single_ipi(int cpu)
{
struct call_data_struct data;
int cpu = smp_processor_id();
int cpus;
/*
* Can die spectacularly if this CPU isn't yet marked online
*/
BUG_ON(!cpu_online(cpu));
cpu_clear(cpu, mask);
cpus = cpus_weight(mask);
if (!cpus)
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 all other CPUs and wait for them to respond */
mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION);
/* Wait for response */
/* FIXME: lock-up detection, backtrace on lock-up */
while (atomic_read(&data.started) != cpus)
barrier();
if (wait)
while (atomic_read(&data.finished) != cpus)
barrier();
call_data = NULL;
spin_unlock(&smp_call_lock);
return 0;
mp_ops->send_ipi_mask(cpumask_of_cpu(cpu), SMP_CALL_FUNCTION);
}
int smp_call_function(void (*func) (void *info), void *info, int retry,
int wait)
{
return smp_call_function_mask(cpu_online_map, func, info, retry, wait);
}
EXPORT_SYMBOL(smp_call_function);
/*
* Call into both interrupt handlers, as we share the IPI for them
*/
void smp_call_function_interrupt(void)
{
void (*func) (void *info) = call_data->func;
void *info = call_data->info;
int wait = call_data->wait;
/*
* Notify initiating CPU that I've grabbed the data and am
* about to execute the function.
*/
smp_mb();
atomic_inc(&call_data->started);
/*
* At this point the info structure may be out of scope unless wait==1.
*/
irq_enter();
(*func)(info);
generic_smp_call_function_single_interrupt();
generic_smp_call_function_interrupt();
irq_exit();
if (wait) {
smp_mb();
atomic_inc(&call_data->finished);
}
}
int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
int retry, int wait)
{
int ret, 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;
}
ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, retry,
wait);
put_cpu();
return 0;
}
EXPORT_SYMBOL(smp_call_function_single);
static void stop_this_cpu(void *dummy)
{
/*

View file

@ -877,7 +877,6 @@ static void ipi_resched_interrupt(void)
/* Return from interrupt should be enough to cause scheduler check */
}
static void ipi_call_interrupt(void)
{
/* Invoke generic function invocation code in smp.c */

View file

@ -35,16 +35,6 @@ extern int __cpu_logical_map[NR_CPUS];
#define NO_PROC_ID (-1)
struct call_data_struct {
void (*func)(void *);
void *info;
atomic_t started;
atomic_t finished;
int wait;
};
extern struct call_data_struct *call_data;
#define SMP_RESCHEDULE_YOURSELF 0x1 /* XXX braindead */
#define SMP_CALL_FUNCTION 0x2
@ -67,4 +57,7 @@ static inline void smp_send_reschedule(int cpu)
extern asmlinkage void smp_call_function_interrupt(void);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi(cpumask_t mask);
#endif /* __ASM_SMP_H */