Commit 44755d11 authored by will schmidt's avatar will schmidt Committed by Paul Mackerras
Browse files

[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: default avatarWill Schmidt <will_schmidt@vnet.ibm.com>
cc: Anton Blanchard <anton@samba.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent e9e77ce8
Loading
Loading
Loading
Loading
+52 −21
Original line number Diff line number Diff line
@@ -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,21 +221,22 @@ 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 "
@@ -238,8 +247,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
		}
	}

	/* 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 "
@@ -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);