[POWERPC] Add smp_call_function_map and smp_call_function_single
Add a new function named smp_call_function_single(). This matches a generic prototype from include/linux/smp.h. Add a function smp_call_function_map(). This is, for the most part, a rename of smp_call_function, with some added cpumask support. smp_call_function and smp_call_function_single call into smp_call_function_map. Lightly tested on 970mp (blade), power4 and power5. Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com> cc: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
e9e77ce871
commit
44755d11a3
1 changed files with 52 additions and 21 deletions
|
@ -176,10 +176,10 @@ static struct call_data_struct {
|
|||
#define SMP_CALL_TIMEOUT 8
|
||||
|
||||
/*
|
||||
* This function sends a 'generic call function' IPI to all other CPUs
|
||||
* in the system.
|
||||
* These functions send a 'generic call function' IPI to other online
|
||||
* CPUS in the system.
|
||||
*
|
||||
* [SUMMARY] Run a function on all other CPUs.
|
||||
* [SUMMARY] Run a function on other CPUs.
|
||||
* <func> The function to run. This must be fast and non-blocking.
|
||||
* <info> An arbitrary pointer to pass to the function.
|
||||
* <nonatomic> currently unused.
|
||||
|
@ -190,18 +190,26 @@ static struct call_data_struct {
|
|||
* You must not call this function with disabled interrupts or from a
|
||||
* hardware interrupt handler or from a bottom half handler.
|
||||
*/
|
||||
int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
{
|
||||
int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait, cpumask_t map)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int ret = -1, cpus;
|
||||
int ret = -1, num_cpus;
|
||||
int cpu;
|
||||
u64 timeout;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
/* remove 'self' from the map */
|
||||
if (cpu_isset(smp_processor_id(), map))
|
||||
cpu_clear(smp_processor_id(), map);
|
||||
|
||||
/* sanity check the map, remove any non-online processors. */
|
||||
cpus_and(map, map, cpu_online_map);
|
||||
|
||||
if (unlikely(smp_ops == NULL))
|
||||
return -1;
|
||||
return ret;
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
|
@ -213,40 +221,42 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
|
|||
spin_lock(&call_lock);
|
||||
/* Must grab online cpu count with preempt disabled, otherwise
|
||||
* it can change. */
|
||||
cpus = num_online_cpus() - 1;
|
||||
if (!cpus) {
|
||||
num_cpus = num_online_cpus() - 1;
|
||||
if (!num_cpus || cpus_empty(map)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
call_data = &data;
|
||||
smp_wmb();
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION);
|
||||
/* Send a message to all CPUs in the map */
|
||||
for_each_cpu_mask(cpu, map)
|
||||
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
|
||||
|
||||
timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec;
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus) {
|
||||
/* Wait for indication that they have received the message */
|
||||
while (atomic_read(&data.started) != num_cpus) {
|
||||
HMT_low();
|
||||
if (get_tb() >= timeout) {
|
||||
printk("smp_call_function on cpu %d: other cpus not "
|
||||
"responding (%d)\n", smp_processor_id(),
|
||||
atomic_read(&data.started));
|
||||
"responding (%d)\n", smp_processor_id(),
|
||||
atomic_read(&data.started));
|
||||
debugger(NULL);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* optionally wait for the CPUs to complete */
|
||||
if (wait) {
|
||||
while (atomic_read(&data.finished) != cpus) {
|
||||
while (atomic_read(&data.finished) != num_cpus) {
|
||||
HMT_low();
|
||||
if (get_tb() >= timeout) {
|
||||
printk("smp_call_function on cpu %d: other "
|
||||
"cpus not finishing (%d/%d)\n",
|
||||
smp_processor_id(),
|
||||
atomic_read(&data.finished),
|
||||
atomic_read(&data.started));
|
||||
"cpus not finishing (%d/%d)\n",
|
||||
smp_processor_id(),
|
||||
atomic_read(&data.finished),
|
||||
atomic_read(&data.started));
|
||||
debugger(NULL);
|
||||
goto out;
|
||||
}
|
||||
|
@ -262,8 +272,29 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
{
|
||||
return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
|
||||
int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
{
|
||||
cpumask_t map=CPU_MASK_NONE;
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
return -EINVAL;
|
||||
|
||||
if (cpu == smp_processor_id())
|
||||
return -EBUSY;
|
||||
|
||||
cpu_set(cpu, map);
|
||||
return smp_call_function_map(func,info,nonatomic,wait,map);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_single);
|
||||
|
||||
void smp_call_function_interrupt(void)
|
||||
{
|
||||
void (*func) (void *info);
|
||||
|
|
Reference in a new issue