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:
parent
7b7426c8a6
commit
2f304c0a0a
4 changed files with 16 additions and 142 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue