Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19d17433 authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge Committed by Andi Kleen
Browse files

[PATCH] i386: Simplify smp_call_function*() by using common implementation



smp_call_function and smp_call_function_single are almost complete
duplicates of the same logic.  This patch combines them by
implementing them in terms of the more general
smp_call_function_mask().

Signed-off-by: default avatarJeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Cc: Stephane Eranian <eranian@hpl.hp.com>
Cc: Andrew Morton <akpm@osdl.org>
Cc: Andi Kleen <ak@suse.de>
Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
Cc: Ingo Molnar <mingo@elte.hu>
parent 6b37f5a2
Loading
Loading
Loading
Loading
+96 −77
Original line number Original line Diff line number Diff line
@@ -546,34 +546,124 @@ static void __smp_call_function(void (*func) (void *info), void *info,
			cpu_relax();
			cpu_relax();
}
}



/**
/**
 * smp_call_function(): Run a function on all other CPUs.
 * smp_call_function_mask(): Run a function on a set of other CPUs.
 * @mask: The set of cpus to run on.  Must not include the current cpu.
 * @func: The function to run. This must be fast and non-blocking.
 * @func: The function to run. This must be fast and non-blocking.
 * @info: An arbitrary pointer to pass to the function.
 * @info: An arbitrary pointer to pass to the function.
 * @nonatomic: currently unused.
 * @wait: If true, wait (atomically) until function has completed on other CPUs.
 * @wait: If true, wait (atomically) until function has completed on other CPUs.
 *
 *
 * Returns 0 on success, else a negative status code. Does not return until
 * 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.
 * remote CPUs are nearly ready to execute <<func>> or are or have finished.
 *
 *
 * You must not call this function with disabled interrupts or from a
 * You must not call this function with disabled interrupts or from a
 * hardware interrupt handler or from a bottom half handler.
 * hardware interrupt handler or from a bottom half handler.
 */
 */
int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
int smp_call_function_mask(cpumask_t mask,
			   void (*func)(void *), void *info,
			   int wait)
			   int wait)
{
{
	struct call_data_struct data;
	cpumask_t allbutself;
	int cpus;

	/* Can deadlock when called with interrupts disabled */
	/* Can deadlock when called with interrupts disabled */
	WARN_ON(irqs_disabled());
	WARN_ON(irqs_disabled());


	/* Holding any lock stops cpus from going down. */
	/* Holding any lock stops cpus from going down. */
	spin_lock(&call_lock);
	spin_lock(&call_lock);
	__smp_call_function(func, info, nonatomic, wait);

	allbutself = cpu_online_map;
	cpu_clear(smp_processor_id(), allbutself);

	cpus_and(mask, mask, allbutself);
	cpus = cpus_weight(mask);

	if (!cpus) {
		spin_unlock(&call_lock);
		return 0;
	}

	data.func = func;
	data.info = info;
	atomic_set(&data.started, 0);
	data.wait = wait;
	if (wait)
		atomic_set(&data.finished, 0);

	call_data = &data;
	mb();

	/* Send a message to other CPUs */
	if (cpus_equal(mask, allbutself))
		send_IPI_allbutself(CALL_FUNCTION_VECTOR);
	else
		send_IPI_mask(mask, CALL_FUNCTION_VECTOR);

	/* Wait for response */
	while (atomic_read(&data.started) != cpus)
		cpu_relax();

	if (wait)
		while (atomic_read(&data.finished) != cpus)
			cpu_relax();
	spin_unlock(&call_lock);
	spin_unlock(&call_lock);


	return 0;
	return 0;
}
}

/**
 * smp_call_function(): Run a function on all 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.
 * @wait: If true, wait (atomically) 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.
 */
int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
		      int wait)
{
	return smp_call_function_mask(cpu_online_map, func, info, wait);
}
EXPORT_SYMBOL(smp_call_function);
EXPORT_SYMBOL(smp_call_function);


/*
 * smp_call_function_single - Run a function on another CPU
 * @func: The function to run. This must be fast and non-blocking.
 * @info: An arbitrary pointer to pass to the function.
 * @nonatomic: Currently unused.
 * @wait: If true, wait until function has completed on other CPUs.
 *
 * Retrurns 0 on success, else a negative status code.
 *
 * Does not return until the remote CPU is nearly ready to execute <func>
 * or is or has executed.
 */
int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
			     int nonatomic, int wait)
{
	/* prevent preemption and reschedule on another processor */
	int ret;
	int me = get_cpu();
	if (cpu == me) {
		WARN_ON(1);
		put_cpu();
		return -EBUSY;
	}

	ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);

	put_cpu();
	return ret;
}
EXPORT_SYMBOL(smp_call_function_single);

static void stop_this_cpu (void * dummy)
static void stop_this_cpu (void * dummy)
{
{
	local_irq_disable();
	local_irq_disable();
@@ -641,77 +731,6 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
	}
	}
}
}


/*
 * this function sends a 'generic call function' IPI to one other CPU
 * in the system.
 *
 * cpu is a standard Linux logical CPU number.
 */
static void
__smp_call_function_single(int cpu, void (*func) (void *info), void *info,
				int nonatomic, int wait)
{
	struct call_data_struct data;
	int cpus = 1;

	data.func = func;
	data.info = info;
	atomic_set(&data.started, 0);
	data.wait = wait;
	if (wait)
		atomic_set(&data.finished, 0);

	call_data = &data;
	wmb();
	/* Send a message to all other CPUs and wait for them to respond */
	send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);

	/* Wait for response */
	while (atomic_read(&data.started) != cpus)
		cpu_relax();

	if (!wait)
		return;

	while (atomic_read(&data.finished) != cpus)
		cpu_relax();
}

/*
 * smp_call_function_single - Run a function on another CPU
 * @func: The function to run. This must be fast and non-blocking.
 * @info: An arbitrary pointer to pass to the function.
 * @nonatomic: Currently unused.
 * @wait: If true, wait until function has completed on other CPUs.
 *
 * Retrurns 0 on success, else a negative status code.
 *
 * Does not return until the remote CPU is nearly ready to execute <func>
 * or is or has executed.
 */

int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
			int nonatomic, int wait)
{
	/* prevent preemption and reschedule on another processor */
	int me = get_cpu();
	if (cpu == me) {
		WARN_ON(1);
		put_cpu();
		return -EBUSY;
	}

	/* Can deadlock when called with interrupts disabled */
	WARN_ON(irqs_disabled());

	spin_lock_bh(&call_lock);
	__smp_call_function_single(cpu, func, info, nonatomic, wait);
	spin_unlock_bh(&call_lock);
	put_cpu();
	return 0;
}
EXPORT_SYMBOL(smp_call_function_single);

static int convert_apicid_to_cpu(int apic_id)
static int convert_apicid_to_cpu(int apic_id)
{
{
	int i;
	int i;