mirror of https://gitee.com/openkylin/linux.git
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
|
@ -1763,6 +1763,7 @@ config SMP
|
||||||
bool "Multi-Processing support"
|
bool "Multi-Processing support"
|
||||||
depends on SYS_SUPPORTS_SMP
|
depends on SYS_SUPPORTS_SMP
|
||||||
select IRQ_PER_CPU
|
select IRQ_PER_CPU
|
||||||
|
select USE_GENERIC_SMP_HELPERS
|
||||||
help
|
help
|
||||||
This enables support for systems with more than one CPU. If you have
|
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
|
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();
|
cpu_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SPINLOCK(smp_call_lock);
|
void arch_send_call_function_ipi(cpumask_t mask)
|
||||||
|
{
|
||||||
struct call_data_struct *call_data;
|
mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run a function on all other CPUs.
|
* We reuse the same vector for the single IPI
|
||||||
*
|
|
||||||
* <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
|
|
||||||
*/
|
*/
|
||||||
int smp_call_function_mask(cpumask_t mask, void (*func) (void *info),
|
void arch_send_call_function_single_ipi(int cpu)
|
||||||
void *info, int retry, int wait)
|
|
||||||
{
|
{
|
||||||
struct call_data_struct data;
|
mp_ops->send_ipi_mask(cpumask_of_cpu(cpu), SMP_CALL_FUNCTION);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int smp_call_function(void (*func) (void *info), void *info, int retry,
|
/*
|
||||||
int wait)
|
* Call into both interrupt handlers, as we share the IPI for them
|
||||||
{
|
*/
|
||||||
return smp_call_function_mask(cpu_online_map, func, info, retry, wait);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(smp_call_function);
|
|
||||||
|
|
||||||
void smp_call_function_interrupt(void)
|
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();
|
irq_enter();
|
||||||
(*func)(info);
|
generic_smp_call_function_single_interrupt();
|
||||||
|
generic_smp_call_function_interrupt();
|
||||||
irq_exit();
|
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)
|
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 */
|
/* Return from interrupt should be enough to cause scheduler check */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void ipi_call_interrupt(void)
|
static void ipi_call_interrupt(void)
|
||||||
{
|
{
|
||||||
/* Invoke generic function invocation code in smp.c */
|
/* Invoke generic function invocation code in smp.c */
|
||||||
|
|
|
@ -35,16 +35,6 @@ extern int __cpu_logical_map[NR_CPUS];
|
||||||
|
|
||||||
#define NO_PROC_ID (-1)
|
#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_RESCHEDULE_YOURSELF 0x1 /* XXX braindead */
|
||||||
#define SMP_CALL_FUNCTION 0x2
|
#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 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 */
|
#endif /* __ASM_SMP_H */
|
||||||
|
|
Loading…
Reference in New Issue