Merge branch 'generic-ipi' into generic-ipi-for-linus
Conflicts: arch/powerpc/Kconfig arch/s390/kernel/time.c arch/x86/kernel/apic_32.c arch/x86/kernel/cpu/perfctr-watchdog.c arch/x86/kernel/i8259_64.c arch/x86/kernel/ldt.c arch/x86/kernel/nmi_64.c arch/x86/kernel/smpboot.c arch/x86/xen/smp.c include/asm-x86/hw_irq_32.h include/asm-x86/hw_irq_64.h include/asm-x86/mach-default/irq_vectors.h include/asm-x86/mach-voyager/irq_vectors.h include/asm-x86/smp.h kernel/Makefile Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
commit
1a781a777b
125 changed files with 881 additions and 1787 deletions
|
@ -39,3 +39,6 @@ config HAVE_KRETPROBES
|
|||
|
||||
config HAVE_DMA_ATTRS
|
||||
def_bool n
|
||||
|
||||
config USE_GENERIC_SMP_HELPERS
|
||||
def_bool n
|
||||
|
|
|
@ -528,6 +528,7 @@ config ARCH_MAY_HAVE_PC_FDC
|
|||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
|
||||
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
|
||||
|
|
|
@ -660,9 +660,9 @@ __marvel_rtc_io(u8 b, unsigned long addr, int write)
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
if (smp_processor_id() != boot_cpuid)
|
||||
smp_call_function_on_cpu(__marvel_access_rtc,
|
||||
&rtc_access, 1, 1,
|
||||
cpumask_of_cpu(boot_cpuid));
|
||||
smp_call_function_single(boot_cpuid,
|
||||
__marvel_access_rtc,
|
||||
&rtc_access, 1);
|
||||
else
|
||||
__marvel_access_rtc(&rtc_access);
|
||||
#else
|
||||
|
|
|
@ -160,7 +160,7 @@ common_shutdown(int mode, char *restart_cmd)
|
|||
struct halt_info args;
|
||||
args.mode = mode;
|
||||
args.restart_cmd = restart_cmd;
|
||||
on_each_cpu(common_shutdown_1, &args, 1, 0);
|
||||
on_each_cpu(common_shutdown_1, &args, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -62,6 +62,7 @@ static struct {
|
|||
enum ipi_message_type {
|
||||
IPI_RESCHEDULE,
|
||||
IPI_CALL_FUNC,
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
IPI_CPU_STOP,
|
||||
};
|
||||
|
||||
|
@ -558,51 +559,6 @@ send_ipi_message(cpumask_t to_whom, enum ipi_message_type operation)
|
|||
wripir(i);
|
||||
}
|
||||
|
||||
/* Structure and data for smp_call_function. This is designed to
|
||||
minimize static memory requirements. Plus it looks cleaner. */
|
||||
|
||||
struct smp_call_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
long wait;
|
||||
atomic_t unstarted_count;
|
||||
atomic_t unfinished_count;
|
||||
};
|
||||
|
||||
static struct smp_call_struct *smp_call_function_data;
|
||||
|
||||
/* Atomicly drop data into a shared pointer. The pointer is free if
|
||||
it is initially locked. If retry, spin until free. */
|
||||
|
||||
static int
|
||||
pointer_lock (void *lock, void *data, int retry)
|
||||
{
|
||||
void *old, *tmp;
|
||||
|
||||
mb();
|
||||
again:
|
||||
/* Compare and swap with zero. */
|
||||
asm volatile (
|
||||
"1: ldq_l %0,%1\n"
|
||||
" mov %3,%2\n"
|
||||
" bne %0,2f\n"
|
||||
" stq_c %2,%1\n"
|
||||
" beq %2,1b\n"
|
||||
"2:"
|
||||
: "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
|
||||
: "r"(data)
|
||||
: "memory");
|
||||
|
||||
if (old == 0)
|
||||
return 0;
|
||||
if (! retry)
|
||||
return -EBUSY;
|
||||
|
||||
while (*(void **)lock)
|
||||
barrier();
|
||||
goto again;
|
||||
}
|
||||
|
||||
void
|
||||
handle_ipi(struct pt_regs *regs)
|
||||
{
|
||||
|
@ -632,31 +588,12 @@ handle_ipi(struct pt_regs *regs)
|
|||
break;
|
||||
|
||||
case IPI_CALL_FUNC:
|
||||
{
|
||||
struct smp_call_struct *data;
|
||||
void (*func)(void *info);
|
||||
void *info;
|
||||
int wait;
|
||||
|
||||
data = smp_call_function_data;
|
||||
func = data->func;
|
||||
info = data->info;
|
||||
wait = data->wait;
|
||||
|
||||
/* Notify the sending CPU that the data has been
|
||||
received, and execution is about to begin. */
|
||||
mb();
|
||||
atomic_dec (&data->unstarted_count);
|
||||
|
||||
/* At this point the structure may be gone unless
|
||||
wait is true. */
|
||||
(*func)(info);
|
||||
|
||||
/* Notify the sending CPU that the task is done. */
|
||||
mb();
|
||||
if (wait) atomic_dec (&data->unfinished_count);
|
||||
generic_smp_call_function_interrupt();
|
||||
break;
|
||||
|
||||
case IPI_CALL_FUNC_SINGLE:
|
||||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
}
|
||||
|
||||
case IPI_CPU_STOP:
|
||||
halt();
|
||||
|
@ -700,102 +637,15 @@ smp_send_stop(void)
|
|||
send_ipi_message(to_whom, IPI_CPU_STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* <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.
|
||||
*/
|
||||
|
||||
int
|
||||
smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
|
||||
int wait, cpumask_t to_whom)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
struct smp_call_struct data;
|
||||
unsigned long timeout;
|
||||
int num_cpus_to_call;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
data.wait = wait;
|
||||
|
||||
cpu_clear(smp_processor_id(), to_whom);
|
||||
num_cpus_to_call = cpus_weight(to_whom);
|
||||
|
||||
atomic_set(&data.unstarted_count, num_cpus_to_call);
|
||||
atomic_set(&data.unfinished_count, num_cpus_to_call);
|
||||
|
||||
/* Acquire the smp_call_function_data mutex. */
|
||||
if (pointer_lock(&smp_call_function_data, &data, retry))
|
||||
return -EBUSY;
|
||||
|
||||
/* Send a message to the requested CPUs. */
|
||||
send_ipi_message(to_whom, IPI_CALL_FUNC);
|
||||
|
||||
/* Wait for a minimal response. */
|
||||
timeout = jiffies + HZ;
|
||||
while (atomic_read (&data.unstarted_count) > 0
|
||||
&& time_before (jiffies, timeout))
|
||||
barrier();
|
||||
|
||||
/* If there's no response yet, log a message but allow a longer
|
||||
* timeout period -- if we get a response this time, log
|
||||
* a message saying when we got it..
|
||||
*/
|
||||
if (atomic_read(&data.unstarted_count) > 0) {
|
||||
long start_time = jiffies;
|
||||
printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
|
||||
__func__);
|
||||
timeout = jiffies + 30 * HZ;
|
||||
while (atomic_read(&data.unstarted_count) > 0
|
||||
&& time_before(jiffies, timeout))
|
||||
barrier();
|
||||
if (atomic_read(&data.unstarted_count) <= 0) {
|
||||
long delta = jiffies - start_time;
|
||||
printk(KERN_ERR
|
||||
"%s: response %ld.%ld seconds into long wait\n",
|
||||
__func__, delta / HZ,
|
||||
(100 * (delta - ((delta / HZ) * HZ))) / HZ);
|
||||
}
|
||||
}
|
||||
|
||||
/* We either got one or timed out -- clear the lock. */
|
||||
mb();
|
||||
smp_call_function_data = NULL;
|
||||
|
||||
/*
|
||||
* If after both the initial and long timeout periods we still don't
|
||||
* have a response, something is very wrong...
|
||||
*/
|
||||
BUG_ON(atomic_read (&data.unstarted_count) > 0);
|
||||
|
||||
/* Wait for a complete response, if needed. */
|
||||
if (wait) {
|
||||
while (atomic_read (&data.unfinished_count) > 0)
|
||||
barrier();
|
||||
}
|
||||
|
||||
return 0;
|
||||
send_ipi_message(mask, IPI_CALL_FUNC);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_on_cpu);
|
||||
|
||||
int
|
||||
smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
return smp_call_function_on_cpu (func, info, retry, wait,
|
||||
cpu_online_map);
|
||||
send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
|
||||
static void
|
||||
ipi_imb(void *ignored)
|
||||
|
@ -807,7 +657,7 @@ void
|
|||
smp_imb(void)
|
||||
{
|
||||
/* Must wait other processors to flush their icache before continue. */
|
||||
if (on_each_cpu(ipi_imb, NULL, 1, 1))
|
||||
if (on_each_cpu(ipi_imb, NULL, 1))
|
||||
printk(KERN_CRIT "smp_imb: timed out\n");
|
||||
}
|
||||
EXPORT_SYMBOL(smp_imb);
|
||||
|
@ -823,7 +673,7 @@ flush_tlb_all(void)
|
|||
{
|
||||
/* Although we don't have any data to pass, we do want to
|
||||
synchronize with the other processors. */
|
||||
if (on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1)) {
|
||||
if (on_each_cpu(ipi_flush_tlb_all, NULL, 1)) {
|
||||
printk(KERN_CRIT "flush_tlb_all: timed out\n");
|
||||
}
|
||||
}
|
||||
|
@ -860,7 +710,7 @@ flush_tlb_mm(struct mm_struct *mm)
|
|||
}
|
||||
}
|
||||
|
||||
if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
|
||||
if (smp_call_function(ipi_flush_tlb_mm, mm, 1)) {
|
||||
printk(KERN_CRIT "flush_tlb_mm: timed out\n");
|
||||
}
|
||||
|
||||
|
@ -913,7 +763,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
|
|||
data.mm = mm;
|
||||
data.addr = addr;
|
||||
|
||||
if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
|
||||
if (smp_call_function(ipi_flush_tlb_page, &data, 1)) {
|
||||
printk(KERN_CRIT "flush_tlb_page: timed out\n");
|
||||
}
|
||||
|
||||
|
@ -965,7 +815,7 @@ flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
|
|||
}
|
||||
}
|
||||
|
||||
if (smp_call_function(ipi_flush_icache_page, mm, 1, 1)) {
|
||||
if (smp_call_function(ipi_flush_icache_page, mm, 1)) {
|
||||
printk(KERN_CRIT "flush_icache_page: timed out\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ op_axp_setup(void)
|
|||
model->reg_setup(®, ctr, &sys);
|
||||
|
||||
/* Configure the registers on all cpus. */
|
||||
(void)smp_call_function(model->cpu_setup, ®, 0, 1);
|
||||
(void)smp_call_function(model->cpu_setup, ®, 1);
|
||||
model->cpu_setup(®);
|
||||
return 0;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ op_axp_cpu_start(void *dummy)
|
|||
static int
|
||||
op_axp_start(void)
|
||||
{
|
||||
(void)smp_call_function(op_axp_cpu_start, NULL, 0, 1);
|
||||
(void)smp_call_function(op_axp_cpu_start, NULL, 1);
|
||||
op_axp_cpu_start(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ op_axp_cpu_stop(void *dummy)
|
|||
static void
|
||||
op_axp_stop(void)
|
||||
{
|
||||
(void)smp_call_function(op_axp_cpu_stop, NULL, 0, 1);
|
||||
(void)smp_call_function(op_axp_cpu_stop, NULL, 1);
|
||||
op_axp_cpu_stop(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -701,6 +701,7 @@ source "kernel/time/Kconfig"
|
|||
config SMP
|
||||
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
|
||||
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
|
||||
|
|
|
@ -68,20 +68,10 @@ enum ipi_msg_type {
|
|||
IPI_TIMER,
|
||||
IPI_RESCHEDULE,
|
||||
IPI_CALL_FUNC,
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
IPI_CPU_STOP,
|
||||
};
|
||||
|
||||
struct smp_call_struct {
|
||||
void (*func)(void *info);
|
||||
void *info;
|
||||
int wait;
|
||||
cpumask_t pending;
|
||||
cpumask_t unfinished;
|
||||
};
|
||||
|
||||
static struct smp_call_struct * volatile smp_call_function_data;
|
||||
static DEFINE_SPINLOCK(smp_call_function_lock);
|
||||
|
||||
int __cpuinit __cpu_up(unsigned int cpu)
|
||||
{
|
||||
struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
|
||||
|
@ -366,114 +356,15 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg)
|
|||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* You must not call this function with disabled interrupts, from a
|
||||
* hardware interrupt handler, nor from a bottom half handler.
|
||||
*/
|
||||
static int smp_call_function_on_cpu(void (*func)(void *info), void *info,
|
||||
int retry, int wait, cpumask_t callmap)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
struct smp_call_struct data;
|
||||
unsigned long timeout;
|
||||
int ret = 0;
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
data.wait = wait;
|
||||
|
||||
cpu_clear(smp_processor_id(), callmap);
|
||||
if (cpus_empty(callmap))
|
||||
goto out;
|
||||
|
||||
data.pending = callmap;
|
||||
if (wait)
|
||||
data.unfinished = callmap;
|
||||
|
||||
/*
|
||||
* try to get the mutex on smp_call_function_data
|
||||
*/
|
||||
spin_lock(&smp_call_function_lock);
|
||||
smp_call_function_data = &data;
|
||||
|
||||
send_ipi_message(callmap, IPI_CALL_FUNC);
|
||||
|
||||
timeout = jiffies + HZ;
|
||||
while (!cpus_empty(data.pending) && time_before(jiffies, timeout))
|
||||
barrier();
|
||||
|
||||
/*
|
||||
* did we time out?
|
||||
*/
|
||||
if (!cpus_empty(data.pending)) {
|
||||
/*
|
||||
* this may be causing our panic - report it
|
||||
*/
|
||||
printk(KERN_CRIT
|
||||
"CPU%u: smp_call_function timeout for %p(%p)\n"
|
||||
" callmap %lx pending %lx, %swait\n",
|
||||
smp_processor_id(), func, info, *cpus_addr(callmap),
|
||||
*cpus_addr(data.pending), wait ? "" : "no ");
|
||||
|
||||
/*
|
||||
* TRACE
|
||||
*/
|
||||
timeout = jiffies + (5 * HZ);
|
||||
while (!cpus_empty(data.pending) && time_before(jiffies, timeout))
|
||||
barrier();
|
||||
|
||||
if (cpus_empty(data.pending))
|
||||
printk(KERN_CRIT " RESOLVED\n");
|
||||
else
|
||||
printk(KERN_CRIT " STILL STUCK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* whatever happened, we're done with the data, so release it
|
||||
*/
|
||||
smp_call_function_data = NULL;
|
||||
spin_unlock(&smp_call_function_lock);
|
||||
|
||||
if (!cpus_empty(data.pending)) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wait)
|
||||
while (!cpus_empty(data.unfinished))
|
||||
barrier();
|
||||
out:
|
||||
|
||||
return 0;
|
||||
send_ipi_message(mask, IPI_CALL_FUNC);
|
||||
}
|
||||
|
||||
int smp_call_function(void (*func)(void *info), void *info, int retry,
|
||||
int wait)
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
return smp_call_function_on_cpu(func, info, retry, wait,
|
||||
cpu_online_map);
|
||||
send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(smp_call_function);
|
||||
|
||||
int smp_call_function_single(int cpu, void (*func)(void *info), void *info,
|
||||
int retry, int wait)
|
||||
{
|
||||
/* prevent preemption and reschedule on another processor */
|
||||
int current_cpu = get_cpu();
|
||||
int ret = 0;
|
||||
|
||||
if (cpu == current_cpu) {
|
||||
local_irq_disable();
|
||||
func(info);
|
||||
local_irq_enable();
|
||||
} else
|
||||
ret = smp_call_function_on_cpu(func, info, retry, wait,
|
||||
cpumask_of_cpu(cpu));
|
||||
|
||||
put_cpu();
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(smp_call_function_single);
|
||||
|
||||
void show_ipi_list(struct seq_file *p)
|
||||
{
|
||||
|
@ -521,27 +412,6 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ipi_call_function - handle IPI from smp_call_function()
|
||||
*
|
||||
* Note that we copy data out of the cross-call structure and then
|
||||
* let the caller know that we're here and have done with their data
|
||||
*/
|
||||
static void ipi_call_function(unsigned int cpu)
|
||||
{
|
||||
struct smp_call_struct *data = smp_call_function_data;
|
||||
void (*func)(void *info) = data->func;
|
||||
void *info = data->info;
|
||||
int wait = data->wait;
|
||||
|
||||
cpu_clear(cpu, data->pending);
|
||||
|
||||
func(info);
|
||||
|
||||
if (wait)
|
||||
cpu_clear(cpu, data->unfinished);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(stop_lock);
|
||||
|
||||
/*
|
||||
|
@ -611,7 +481,11 @@ asmlinkage void __exception do_IPI(struct pt_regs *regs)
|
|||
break;
|
||||
|
||||
case IPI_CALL_FUNC:
|
||||
ipi_call_function(cpu);
|
||||
generic_smp_call_function_interrupt();
|
||||
break;
|
||||
|
||||
case IPI_CALL_FUNC_SINGLE:
|
||||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
|
||||
case IPI_CPU_STOP:
|
||||
|
@ -662,14 +536,13 @@ int setup_profiling_timer(unsigned int multiplier)
|
|||
}
|
||||
|
||||
static int
|
||||
on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait,
|
||||
cpumask_t mask)
|
||||
on_each_cpu_mask(void (*func)(void *), void *info, int wait, cpumask_t mask)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
ret = smp_call_function_on_cpu(func, info, retry, wait, mask);
|
||||
ret = smp_call_function_mask(mask, func, info, wait);
|
||||
if (cpu_isset(smp_processor_id(), mask))
|
||||
func(info);
|
||||
|
||||
|
@ -731,14 +604,14 @@ static inline void ipi_flush_tlb_kernel_range(void *arg)
|
|||
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1);
|
||||
on_each_cpu(ipi_flush_tlb_all, NULL, 1);
|
||||
}
|
||||
|
||||
void flush_tlb_mm(struct mm_struct *mm)
|
||||
{
|
||||
cpumask_t mask = mm->cpu_vm_mask;
|
||||
|
||||
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask);
|
||||
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mask);
|
||||
}
|
||||
|
||||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
|
||||
|
@ -749,7 +622,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
|
|||
ta.ta_vma = vma;
|
||||
ta.ta_start = uaddr;
|
||||
|
||||
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask);
|
||||
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mask);
|
||||
}
|
||||
|
||||
void flush_tlb_kernel_page(unsigned long kaddr)
|
||||
|
@ -758,7 +631,7 @@ void flush_tlb_kernel_page(unsigned long kaddr)
|
|||
|
||||
ta.ta_start = kaddr;
|
||||
|
||||
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1);
|
||||
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
|
||||
}
|
||||
|
||||
void flush_tlb_range(struct vm_area_struct *vma,
|
||||
|
@ -771,7 +644,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
|
|||
ta.ta_start = start;
|
||||
ta.ta_end = end;
|
||||
|
||||
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask);
|
||||
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mask);
|
||||
}
|
||||
|
||||
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
|
@ -781,5 +654,5 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|||
ta.ta_start = start;
|
||||
ta.ta_end = end;
|
||||
|
||||
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1);
|
||||
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ static int em_call_function(int (*fn)(void))
|
|||
data.ret = 0;
|
||||
|
||||
preempt_disable();
|
||||
smp_call_function(em_func, &data, 1, 1);
|
||||
smp_call_function(em_func, &data, 1);
|
||||
em_func(&data);
|
||||
preempt_enable();
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ static int __init vfp_init(void)
|
|||
else if (vfpsid & FPSID_NODOUBLE) {
|
||||
printk("no double precision support\n");
|
||||
} else {
|
||||
smp_call_function(vfp_enable, NULL, 1, 1);
|
||||
smp_call_function(vfp_enable, NULL, 1);
|
||||
|
||||
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
|
||||
printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
|
||||
|
|
|
@ -194,7 +194,7 @@ void stop_this_cpu(void* dummy)
|
|||
/* Other calls */
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(stop_this_cpu, NULL, 1, 0);
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
}
|
||||
|
||||
int setup_profiling_timer(unsigned int multiplier)
|
||||
|
@ -316,8 +316,7 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
|
|||
* 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(void (*func)(void *info), void *info, int wait)
|
||||
{
|
||||
cpumask_t cpu_mask = CPU_MASK_ALL;
|
||||
struct call_data_struct data;
|
||||
|
|
|
@ -303,6 +303,7 @@ config VIRT_CPU_ACCOUNTING
|
|||
|
||||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
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, say N. If you have a system with more
|
||||
|
|
|
@ -707,7 +707,7 @@ ia64_mca_cmc_vector_enable (void *dummy)
|
|||
static void
|
||||
ia64_mca_cmc_vector_disable_keventd(struct work_struct *unused)
|
||||
{
|
||||
on_each_cpu(ia64_mca_cmc_vector_disable, NULL, 1, 0);
|
||||
on_each_cpu(ia64_mca_cmc_vector_disable, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -719,7 +719,7 @@ ia64_mca_cmc_vector_disable_keventd(struct work_struct *unused)
|
|||
static void
|
||||
ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused)
|
||||
{
|
||||
on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0);
|
||||
on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1881,7 +1881,7 @@ static int __cpuinit mca_cpu_callback(struct notifier_block *nfb,
|
|||
case CPU_ONLINE:
|
||||
case CPU_ONLINE_FROZEN:
|
||||
smp_call_function_single(hotcpu, ia64_mca_cmc_vector_adjust,
|
||||
NULL, 1, 0);
|
||||
NULL, 0);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
|
|
|
@ -921,7 +921,7 @@ int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
|
|||
|
||||
|
||||
/* will send IPI to other CPU and wait for completion of remote call */
|
||||
if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
|
||||
if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
|
||||
printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
|
||||
"error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
|
||||
return 0;
|
||||
|
|
|
@ -1820,7 +1820,7 @@ pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx)
|
|||
int ret;
|
||||
|
||||
DPRINT(("calling CPU%d for cleanup\n", ctx->ctx_cpu));
|
||||
ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 0, 1);
|
||||
ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 1);
|
||||
DPRINT(("called CPU%d for cleanup ret=%d\n", ctx->ctx_cpu, ret));
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
@ -6508,7 +6508,7 @@ pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
|
|||
}
|
||||
|
||||
/* save the current system wide pmu states */
|
||||
ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1);
|
||||
ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 1);
|
||||
if (ret) {
|
||||
DPRINT(("on_each_cpu() failed: %d\n", ret));
|
||||
goto cleanup_reserve;
|
||||
|
@ -6553,7 +6553,7 @@ pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
|
|||
|
||||
pfm_alt_intr_handler = NULL;
|
||||
|
||||
ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1);
|
||||
ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 1);
|
||||
if (ret) {
|
||||
DPRINT(("on_each_cpu() failed: %d\n", ret));
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ void cpu_idle_wait(void)
|
|||
{
|
||||
smp_mb();
|
||||
/* kick all the CPUs so that they exit out of pm_idle */
|
||||
smp_call_function(do_nothing, NULL, 0, 1);
|
||||
smp_call_function(do_nothing, NULL, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_idle_wait);
|
||||
|
||||
|
|
|
@ -60,25 +60,9 @@ static struct local_tlb_flush_counts {
|
|||
|
||||
static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
|
||||
|
||||
|
||||
/*
|
||||
* Structure and data for smp_call_function(). This is designed to minimise static memory
|
||||
* requirements. It also looks cleaner.
|
||||
*/
|
||||
static __cacheline_aligned DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
long wait;
|
||||
atomic_t started;
|
||||
atomic_t finished;
|
||||
};
|
||||
|
||||
static volatile struct call_data_struct *call_data;
|
||||
|
||||
#define IPI_CALL_FUNC 0
|
||||
#define IPI_CPU_STOP 1
|
||||
#define IPI_CALL_FUNC_SINGLE 2
|
||||
#define IPI_KDUMP_CPU_STOP 3
|
||||
|
||||
/* This needs to be cacheline aligned because it is written to by *other* CPUs. */
|
||||
|
@ -86,43 +70,6 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation);
|
|||
|
||||
extern void cpu_halt (void);
|
||||
|
||||
void
|
||||
lock_ipi_calllock(void)
|
||||
{
|
||||
spin_lock_irq(&call_lock);
|
||||
}
|
||||
|
||||
void
|
||||
unlock_ipi_calllock(void)
|
||||
{
|
||||
spin_unlock_irq(&call_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
handle_call_data(void)
|
||||
{
|
||||
struct call_data_struct *data;
|
||||
void (*func)(void *info);
|
||||
void *info;
|
||||
int wait;
|
||||
|
||||
/* release the 'pointer lock' */
|
||||
data = (struct call_data_struct *)call_data;
|
||||
func = data->func;
|
||||
info = data->info;
|
||||
wait = data->wait;
|
||||
|
||||
mb();
|
||||
atomic_inc(&data->started);
|
||||
/* At this point the structure may be gone unless wait is true. */
|
||||
(*func)(info);
|
||||
|
||||
/* Notify the sending CPU that the task is done. */
|
||||
mb();
|
||||
if (wait)
|
||||
atomic_inc(&data->finished);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_this_cpu(void)
|
||||
{
|
||||
|
@ -163,13 +110,15 @@ handle_IPI (int irq, void *dev_id)
|
|||
ops &= ~(1 << which);
|
||||
|
||||
switch (which) {
|
||||
case IPI_CALL_FUNC:
|
||||
handle_call_data();
|
||||
break;
|
||||
|
||||
case IPI_CPU_STOP:
|
||||
stop_this_cpu();
|
||||
break;
|
||||
case IPI_CALL_FUNC:
|
||||
generic_smp_call_function_interrupt();
|
||||
break;
|
||||
case IPI_CALL_FUNC_SINGLE:
|
||||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
#ifdef CONFIG_KEXEC
|
||||
case IPI_KDUMP_CPU_STOP:
|
||||
unw_init_running(kdump_cpu_freeze, NULL);
|
||||
|
@ -187,6 +136,8 @@ handle_IPI (int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called with preemption disabled.
|
||||
*/
|
||||
|
@ -334,7 +285,7 @@ smp_flush_tlb_cpumask(cpumask_t xcpumask)
|
|||
void
|
||||
smp_flush_tlb_all (void)
|
||||
{
|
||||
on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1);
|
||||
on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -357,193 +308,18 @@ smp_flush_tlb_mm (struct mm_struct *mm)
|
|||
* anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is
|
||||
* rather trivial.
|
||||
*/
|
||||
on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1, 1);
|
||||
on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run a function on a specific 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.
|
||||
* [RETURNS] 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 cpuid, void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus = 1;
|
||||
int me = get_cpu(); /* prevent preemption and reschedule on another processor */
|
||||
|
||||
if (cpuid == me) {
|
||||
local_irq_disable();
|
||||
func(info);
|
||||
local_irq_enable();
|
||||
put_cpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
atomic_set(&data.started, 0);
|
||||
data.wait = wait;
|
||||
if (wait)
|
||||
atomic_set(&data.finished, 0);
|
||||
|
||||
spin_lock_bh(&call_lock);
|
||||
|
||||
call_data = &data;
|
||||
mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */
|
||||
send_IPI_single(cpuid, IPI_CALL_FUNC);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
cpu_relax();
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
cpu_relax();
|
||||
call_data = NULL;
|
||||
|
||||
spin_unlock_bh(&call_lock);
|
||||
put_cpu();
|
||||
return 0;
|
||||
send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_single);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <info> An arbitrary pointer to pass to the function.
|
||||
* <wait> If true, wait (atomically) until function
|
||||
* has completed on other CPUs.
|
||||
*
|
||||
* Returns 0 on success, else a negative status code.
|
||||
*
|
||||
* If @wait is true, then returns once @func has returned; otherwise
|
||||
* it returns just before the target cpu calls @func.
|
||||
*
|
||||
* 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_mask(cpumask_t mask,
|
||||
void (*func)(void *), void *info,
|
||||
int wait)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
cpumask_t allbutself;
|
||||
int cpus;
|
||||
|
||||
spin_lock(&call_lock);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
call_data = &data;
|
||||
mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC*/
|
||||
|
||||
/* Send a message to other CPUs */
|
||||
if (cpus_equal(mask, allbutself))
|
||||
send_IPI_allbutself(IPI_CALL_FUNC);
|
||||
else
|
||||
send_IPI_mask(mask, IPI_CALL_FUNC);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
cpu_relax();
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
cpu_relax();
|
||||
call_data = NULL;
|
||||
|
||||
spin_unlock(&call_lock);
|
||||
return 0;
|
||||
|
||||
send_IPI_mask(mask, IPI_CALL_FUNC);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_mask);
|
||||
|
||||
/*
|
||||
* this function sends a 'generic call function' IPI to all other CPUs
|
||||
* in the system.
|
||||
*/
|
||||
|
||||
/*
|
||||
* [SUMMARY] 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)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus;
|
||||
|
||||
spin_lock(&call_lock);
|
||||
cpus = num_online_cpus() - 1;
|
||||
if (!cpus) {
|
||||
spin_unlock(&call_lock);
|
||||
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);
|
||||
|
||||
call_data = &data;
|
||||
mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */
|
||||
send_IPI_allbutself(IPI_CALL_FUNC);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
cpu_relax();
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
cpu_relax();
|
||||
call_data = NULL;
|
||||
|
||||
spin_unlock(&call_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
|
||||
/*
|
||||
* this function calls the 'stop' function on all other CPUs in the system.
|
||||
|
|
|
@ -317,7 +317,7 @@ ia64_sync_itc (unsigned int master)
|
|||
|
||||
go[MASTER] = 1;
|
||||
|
||||
if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) {
|
||||
if (smp_call_function_single(master, sync_master, NULL, 0) < 0) {
|
||||
printk(KERN_ERR "sync_itc: failed to get attention of CPU %u!\n", master);
|
||||
return;
|
||||
}
|
||||
|
@ -395,14 +395,14 @@ smp_callin (void)
|
|||
|
||||
fix_b0_for_bsp();
|
||||
|
||||
lock_ipi_calllock();
|
||||
ipi_call_lock_irq();
|
||||
spin_lock(&vector_lock);
|
||||
/* Setup the per cpu irq handling data structures */
|
||||
__setup_vector_irq(cpuid);
|
||||
cpu_set(cpuid, cpu_online_map);
|
||||
per_cpu(cpu_state, cpuid) = CPU_ONLINE;
|
||||
spin_unlock(&vector_lock);
|
||||
unlock_ipi_calllock();
|
||||
ipi_call_unlock_irq();
|
||||
|
||||
smp_setup_percpu_timer();
|
||||
|
||||
|
|
|
@ -123,8 +123,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
|
|||
status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL);
|
||||
if (status == PAL_VISIBILITY_OK_REMOTE_NEEDED) {
|
||||
atomic_set(&uc_pool->status, 0);
|
||||
status = smp_call_function(uncached_ipi_visibility, uc_pool,
|
||||
0, 1);
|
||||
status = smp_call_function(uncached_ipi_visibility, uc_pool, 1);
|
||||
if (status || atomic_read(&uc_pool->status))
|
||||
goto failed;
|
||||
} else if (status != PAL_VISIBILITY_OK)
|
||||
|
@ -146,7 +145,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
|
|||
if (status != PAL_STATUS_SUCCESS)
|
||||
goto failed;
|
||||
atomic_set(&uc_pool->status, 0);
|
||||
status = smp_call_function(uncached_ipi_mc_drain, uc_pool, 0, 1);
|
||||
status = smp_call_function(uncached_ipi_mc_drain, uc_pool, 1);
|
||||
if (status || atomic_read(&uc_pool->status))
|
||||
goto failed;
|
||||
|
||||
|
|
|
@ -629,7 +629,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
|
|||
if (use_ipi) {
|
||||
/* use an interprocessor interrupt to call SAL */
|
||||
smp_call_function_single(cpu, sn_hwperf_call_sal,
|
||||
op_info, 1, 1);
|
||||
op_info, 1);
|
||||
}
|
||||
else {
|
||||
/* migrate the task before calling SAL */
|
||||
|
|
|
@ -296,6 +296,7 @@ config PREEMPT
|
|||
|
||||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
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
|
||||
|
|
|
@ -43,9 +43,6 @@ EXPORT_SYMBOL(dcache_dummy);
|
|||
#endif
|
||||
EXPORT_SYMBOL(cpu_data);
|
||||
|
||||
/* Global SMP stuff */
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
|
||||
/* TLB flushing */
|
||||
EXPORT_SYMBOL(smp_flush_tlb_page);
|
||||
#endif
|
||||
|
|
|
@ -34,22 +34,6 @@
|
|||
/* Data structures and variables */
|
||||
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
||||
|
||||
/*
|
||||
* Structure and data for smp_call_function(). This is designed to minimise
|
||||
* static memory requirements. It also looks cleaner.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
atomic_t started;
|
||||
atomic_t finished;
|
||||
int wait;
|
||||
} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
|
||||
|
||||
static struct call_data_struct *call_data;
|
||||
|
||||
/*
|
||||
* For flush_cache_all()
|
||||
*/
|
||||
|
@ -96,9 +80,6 @@ void smp_invalidate_interrupt(void);
|
|||
void smp_send_stop(void);
|
||||
static void stop_this_cpu(void *);
|
||||
|
||||
int smp_call_function(void (*) (void *), void *, int, int);
|
||||
void smp_call_function_interrupt(void);
|
||||
|
||||
void smp_send_timer(void);
|
||||
void smp_ipi_timer_interrupt(struct pt_regs *);
|
||||
void smp_local_timer_interrupt(void);
|
||||
|
@ -231,7 +212,7 @@ void smp_flush_tlb_all(void)
|
|||
local_irq_save(flags);
|
||||
__flush_tlb_all();
|
||||
local_irq_restore(flags);
|
||||
smp_call_function(flush_tlb_all_ipi, NULL, 1, 1);
|
||||
smp_call_function(flush_tlb_all_ipi, NULL, 1);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
|
@ -524,7 +505,7 @@ void smp_invalidate_interrupt(void)
|
|||
*==========================================================================*/
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(stop_this_cpu, NULL, 1, 0);
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
|
@ -565,86 +546,14 @@ static void stop_this_cpu(void *dummy)
|
|||
for ( ; ; );
|
||||
}
|
||||
|
||||
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
||||
/* Call function Routines */
|
||||
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
||||
|
||||
/*==========================================================================*
|
||||
* Name: smp_call_function
|
||||
*
|
||||
* Description: This routine sends a 'CALL_FUNCTION_IPI' to all other CPUs
|
||||
* in the system.
|
||||
*
|
||||
* Born on Date: 2002.02.05
|
||||
*
|
||||
* Arguments: *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.
|
||||
*
|
||||
* Cautions: You must not call this function with disabled interrupts or
|
||||
* from a hardware interrupt handler, you may call it from a
|
||||
* bottom half handler.
|
||||
*
|
||||
* Modification log:
|
||||
* Date Who Description
|
||||
* ---------- --- --------------------------------------------------------
|
||||
*
|
||||
*==========================================================================*/
|
||||
int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus;
|
||||
send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SMP
|
||||
unsigned long flags;
|
||||
__save_flags(flags);
|
||||
if (!(flags & 0x0040)) /* Interrupt Disable NONONO */
|
||||
BUG();
|
||||
#endif /* DEBUG_SMP */
|
||||
|
||||
/* Holding any lock stops cpus from going down. */
|
||||
spin_lock(&call_lock);
|
||||
cpus = num_online_cpus() - 1;
|
||||
|
||||
if (!cpus) {
|
||||
spin_unlock(&call_lock);
|
||||
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);
|
||||
|
||||
call_data = &data;
|
||||
mb();
|
||||
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
send_IPI_allbutself(CALL_FUNCTION_IPI, 0);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
barrier();
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
barrier();
|
||||
spin_unlock(&call_lock);
|
||||
|
||||
return 0;
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNC_SINGLE_IPI, 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
|
@ -666,27 +575,16 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
|
|||
*==========================================================================*/
|
||||
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
|
||||
*/
|
||||
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_interrupt();
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
mb();
|
||||
atomic_inc(&call_data->finished);
|
||||
}
|
||||
void smp_call_function_single_interrupt(void)
|
||||
{
|
||||
irq_enter();
|
||||
generic_smp_call_function_single_interrupt();
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
||||
|
|
|
@ -40,6 +40,7 @@ extern void smp_invalidate_interrupt(void);
|
|||
extern void smp_call_function_interrupt(void);
|
||||
extern void smp_ipi_timer_interrupt(void);
|
||||
extern void smp_flush_cache_all_interrupt(void);
|
||||
extern void smp_call_function_single_interrupt(void);
|
||||
|
||||
/*
|
||||
* for Boot AP function
|
||||
|
@ -103,7 +104,7 @@ void set_eit_vector_entries(void)
|
|||
eit_vector[186] = (unsigned long)smp_call_function_interrupt;
|
||||
eit_vector[187] = (unsigned long)smp_ipi_timer_interrupt;
|
||||
eit_vector[188] = (unsigned long)smp_flush_cache_all_interrupt;
|
||||
eit_vector[189] = 0;
|
||||
eit_vector[189] = (unsigned long)smp_call_function_single_interrupt;
|
||||
eit_vector[190] = 0;
|
||||
eit_vector[191] = 0;
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -49,7 +49,7 @@ static void local_rm9k_perfcounter_irq_startup(void *args)
|
|||
|
||||
static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq)
|
||||
{
|
||||
on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1);
|
||||
on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ static void local_rm9k_perfcounter_irq_shutdown(void *args)
|
|||
|
||||
static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
|
||||
{
|
||||
on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1);
|
||||
on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 1);
|
||||
}
|
||||
|
||||
static struct irq_chip rm9k_irq_controller = {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -286,7 +167,7 @@ static void stop_this_cpu(void *dummy)
|
|||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(stop_this_cpu, NULL, 1, 0);
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
}
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
|
@ -365,7 +246,7 @@ static void flush_tlb_all_ipi(void *info)
|
|||
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(flush_tlb_all_ipi, NULL, 1, 1);
|
||||
on_each_cpu(flush_tlb_all_ipi, NULL, 1);
|
||||
}
|
||||
|
||||
static void flush_tlb_mm_ipi(void *mm)
|
||||
|
@ -385,7 +266,7 @@ static void flush_tlb_mm_ipi(void *mm)
|
|||
static inline void smp_on_other_tlbs(void (*func) (void *info), void *info)
|
||||
{
|
||||
#ifndef CONFIG_MIPS_MT_SMTC
|
||||
smp_call_function(func, info, 1, 1);
|
||||
smp_call_function(func, info, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -485,7 +366,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|||
.addr2 = end,
|
||||
};
|
||||
|
||||
on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1, 1);
|
||||
on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1);
|
||||
}
|
||||
|
||||
static void flush_tlb_page_ipi(void *info)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -43,12 +43,12 @@
|
|||
* primary cache.
|
||||
*/
|
||||
static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
|
||||
int retry, int wait)
|
||||
int wait)
|
||||
{
|
||||
preempt_disable();
|
||||
|
||||
#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
|
||||
smp_call_function(func, info, retry, wait);
|
||||
smp_call_function(func, info, wait);
|
||||
#endif
|
||||
func(info);
|
||||
preempt_enable();
|
||||
|
@ -350,7 +350,7 @@ static inline void local_r4k___flush_cache_all(void * args)
|
|||
|
||||
static void r4k___flush_cache_all(void)
|
||||
{
|
||||
r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1);
|
||||
}
|
||||
|
||||
static inline int has_valid_asid(const struct mm_struct *mm)
|
||||
|
@ -397,7 +397,7 @@ static void r4k_flush_cache_range(struct vm_area_struct *vma,
|
|||
int exec = vma->vm_flags & VM_EXEC;
|
||||
|
||||
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1);
|
||||
}
|
||||
|
||||
static inline void local_r4k_flush_cache_mm(void * args)
|
||||
|
@ -429,7 +429,7 @@ static void r4k_flush_cache_mm(struct mm_struct *mm)
|
|||
if (!cpu_has_dc_aliases)
|
||||
return;
|
||||
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1);
|
||||
}
|
||||
|
||||
struct flush_cache_page_args {
|
||||
|
@ -521,7 +521,7 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
|
|||
args.addr = addr;
|
||||
args.pfn = pfn;
|
||||
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1);
|
||||
}
|
||||
|
||||
static inline void local_r4k_flush_data_cache_page(void * addr)
|
||||
|
@ -535,7 +535,7 @@ static void r4k_flush_data_cache_page(unsigned long addr)
|
|||
local_r4k_flush_data_cache_page((void *)addr);
|
||||
else
|
||||
r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr,
|
||||
1, 1);
|
||||
1);
|
||||
}
|
||||
|
||||
struct flush_icache_range_args {
|
||||
|
@ -571,7 +571,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
|
|||
args.start = start;
|
||||
args.end = end;
|
||||
|
||||
r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1);
|
||||
instruction_hazard();
|
||||
}
|
||||
|
||||
|
@ -672,7 +672,7 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
|
|||
|
||||
static void r4k_flush_cache_sigtramp(unsigned long addr)
|
||||
{
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1, 1);
|
||||
r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1);
|
||||
}
|
||||
|
||||
static void r4k_flush_icache_all(void)
|
||||
|
|
|
@ -27,7 +27,7 @@ static int op_mips_setup(void)
|
|||
model->reg_setup(ctr);
|
||||
|
||||
/* Configure the registers on all cpus. */
|
||||
on_each_cpu(model->cpu_setup, NULL, 0, 1);
|
||||
on_each_cpu(model->cpu_setup, NULL, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ static int op_mips_create_files(struct super_block * sb, struct dentry * root)
|
|||
|
||||
static int op_mips_start(void)
|
||||
{
|
||||
on_each_cpu(model->cpu_start, NULL, 0, 1);
|
||||
on_each_cpu(model->cpu_start, NULL, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ static int op_mips_start(void)
|
|||
static void op_mips_stop(void)
|
||||
{
|
||||
/* Disable performance monitoring for all counters. */
|
||||
on_each_cpu(model->cpu_stop, NULL, 0, 1);
|
||||
on_each_cpu(model->cpu_stop, NULL, 1);
|
||||
}
|
||||
|
||||
int __init oprofile_arch_init(struct oprofile_operations *ops)
|
||||
|
|
|
@ -64,7 +64,7 @@ static void prom_exit(void)
|
|||
#ifdef CONFIG_SMP
|
||||
if (smp_processor_id())
|
||||
/* CPU 1 */
|
||||
smp_call_function(prom_cpu0_exit, NULL, 1, 1);
|
||||
smp_call_function(prom_cpu0_exit, NULL, 1);
|
||||
#endif
|
||||
prom_cpu0_exit(NULL);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ static void __noreturn cfe_linux_exit(void *arg)
|
|||
if (!reboot_smp) {
|
||||
/* Get CPU 0 to do the cfe_exit */
|
||||
reboot_smp = 1;
|
||||
smp_call_function(cfe_linux_exit, arg, 1, 0);
|
||||
smp_call_function(cfe_linux_exit, arg, 0);
|
||||
}
|
||||
} else {
|
||||
printk("Passing control back to CFE...\n");
|
||||
|
|
|
@ -66,7 +66,7 @@ static void prom_linux_exit(void)
|
|||
{
|
||||
#ifdef CONFIG_SMP
|
||||
if (smp_processor_id()) {
|
||||
smp_call_function(prom_cpu0_exit, NULL, 1, 1);
|
||||
smp_call_function(prom_cpu0_exit, NULL, 1);
|
||||
}
|
||||
#endif
|
||||
while(1);
|
||||
|
|
|
@ -199,6 +199,7 @@ endchoice
|
|||
|
||||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
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
|
||||
|
|
|
@ -51,12 +51,12 @@ static struct pdc_btlb_info btlb_info __read_mostly;
|
|||
void
|
||||
flush_data_cache(void)
|
||||
{
|
||||
on_each_cpu(flush_data_cache_local, NULL, 1, 1);
|
||||
on_each_cpu(flush_data_cache_local, NULL, 1);
|
||||
}
|
||||
void
|
||||
flush_instruction_cache(void)
|
||||
{
|
||||
on_each_cpu(flush_instruction_cache_local, NULL, 1, 1);
|
||||
on_each_cpu(flush_instruction_cache_local, NULL, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -515,7 +515,7 @@ static void cacheflush_h_tmp_function(void *dummy)
|
|||
|
||||
void flush_cache_all(void)
|
||||
{
|
||||
on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1);
|
||||
on_each_cpu(cacheflush_h_tmp_function, NULL, 1);
|
||||
}
|
||||
|
||||
void flush_cache_mm(struct mm_struct *mm)
|
||||
|
|
|
@ -84,19 +84,11 @@ EXPORT_SYMBOL(cpu_possible_map);
|
|||
|
||||
DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
struct smp_call_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
long wait;
|
||||
atomic_t unstarted_count;
|
||||
atomic_t unfinished_count;
|
||||
};
|
||||
static volatile struct smp_call_struct *smp_call_function_data;
|
||||
|
||||
enum ipi_message_type {
|
||||
IPI_NOP=0,
|
||||
IPI_RESCHEDULE=1,
|
||||
IPI_CALL_FUNC,
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
IPI_CPU_START,
|
||||
IPI_CPU_STOP,
|
||||
IPI_CPU_TEST
|
||||
|
@ -187,33 +179,12 @@ ipi_interrupt(int irq, void *dev_id)
|
|||
|
||||
case IPI_CALL_FUNC:
|
||||
smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC\n", this_cpu);
|
||||
{
|
||||
volatile struct smp_call_struct *data;
|
||||
void (*func)(void *info);
|
||||
void *info;
|
||||
int wait;
|
||||
generic_smp_call_function_interrupt();
|
||||
break;
|
||||
|
||||
data = smp_call_function_data;
|
||||
func = data->func;
|
||||
info = data->info;
|
||||
wait = data->wait;
|
||||
|
||||
mb();
|
||||
atomic_dec ((atomic_t *)&data->unstarted_count);
|
||||
|
||||
/* At this point, *data can't
|
||||
* be relied upon.
|
||||
*/
|
||||
|
||||
(*func)(info);
|
||||
|
||||
/* Notify the sending CPU that the
|
||||
* task is done.
|
||||
*/
|
||||
mb();
|
||||
if (wait)
|
||||
atomic_dec ((atomic_t *)&data->unfinished_count);
|
||||
}
|
||||
case IPI_CALL_FUNC_SINGLE:
|
||||
smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC_SINGLE\n", this_cpu);
|
||||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
|
||||
case IPI_CPU_START:
|
||||
|
@ -256,6 +227,14 @@ ipi_send(int cpu, enum ipi_message_type op)
|
|||
spin_unlock_irqrestore(lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
send_IPI_mask(cpumask_t mask, enum ipi_message_type op)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu_mask(cpu, mask)
|
||||
ipi_send(cpu, op);
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_IPI_single(int dest_cpu, enum ipi_message_type op)
|
||||
|
@ -295,86 +274,15 @@ smp_send_all_nop(void)
|
|||
send_IPI_allbutself(IPI_NOP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <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 have executed.
|
||||
*/
|
||||
|
||||
int
|
||||
smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
struct smp_call_struct data;
|
||||
unsigned long timeout;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
int retries = 0;
|
||||
|
||||
if (num_online_cpus() < 2)
|
||||
return 0;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
/* can also deadlock if IPIs are disabled */
|
||||
WARN_ON((get_eiem() & (1UL<<(CPU_IRQ_MAX - IPI_IRQ))) == 0);
|
||||
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
data.wait = wait;
|
||||
atomic_set(&data.unstarted_count, num_online_cpus() - 1);
|
||||
atomic_set(&data.unfinished_count, num_online_cpus() - 1);
|
||||
|
||||
if (retry) {
|
||||
spin_lock (&lock);
|
||||
while (smp_call_function_data != 0)
|
||||
barrier();
|
||||
}
|
||||
else {
|
||||
spin_lock (&lock);
|
||||
if (smp_call_function_data) {
|
||||
spin_unlock (&lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
smp_call_function_data = &data;
|
||||
spin_unlock (&lock);
|
||||
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
send_IPI_allbutself(IPI_CALL_FUNC);
|
||||
|
||||
retry:
|
||||
/* Wait for response */
|
||||
timeout = jiffies + HZ;
|
||||
while ( (atomic_read (&data.unstarted_count) > 0) &&
|
||||
time_before (jiffies, timeout) )
|
||||
barrier ();
|
||||
|
||||
if (atomic_read (&data.unstarted_count) > 0) {
|
||||
printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d), try %d\n",
|
||||
smp_processor_id(), ++retries);
|
||||
goto retry;
|
||||
}
|
||||
/* We either got one or timed out. Release the lock */
|
||||
|
||||
mb();
|
||||
smp_call_function_data = NULL;
|
||||
|
||||
while (wait && atomic_read (&data.unfinished_count) > 0)
|
||||
barrier ();
|
||||
|
||||
return 0;
|
||||
send_IPI_mask(mask, IPI_CALL_FUNC);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all other CPU's tlb and then mine. Do this with on_each_cpu()
|
||||
|
@ -384,7 +292,7 @@ EXPORT_SYMBOL(smp_call_function);
|
|||
void
|
||||
smp_flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
|
||||
on_each_cpu(flush_tlb_all_local, NULL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1053,7 +1053,7 @@ void flush_tlb_all(void)
|
|||
do_recycle++;
|
||||
}
|
||||
spin_unlock(&sid_lock);
|
||||
on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
|
||||
on_each_cpu(flush_tlb_all_local, NULL, 1);
|
||||
if (do_recycle) {
|
||||
spin_lock(&sid_lock);
|
||||
recycle_sids(recycle_ndirty,recycle_dirty_array);
|
||||
|
|
|
@ -111,6 +111,7 @@ config PPC
|
|||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_LMB
|
||||
select USE_GENERIC_SMP_HELPERS if SMP
|
||||
select HAVE_OPROFILE
|
||||
|
||||
config EARLY_PRINTK
|
||||
|
|
|
@ -172,7 +172,7 @@ static void kexec_prepare_cpus(void)
|
|||
{
|
||||
int my_cpu, i, notified=-1;
|
||||
|
||||
smp_call_function(kexec_smp_down, NULL, 0, /* wait */0);
|
||||
smp_call_function(kexec_smp_down, NULL, /* wait */0);
|
||||
my_cpu = get_cpu();
|
||||
|
||||
/* check the others cpus are now down (via paca hw cpu id == -1) */
|
||||
|
|
|
@ -747,7 +747,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
|
|||
/* Call function on all CPUs. One of us will make the
|
||||
* rtas call
|
||||
*/
|
||||
if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
|
||||
if (on_each_cpu(rtas_percpu_suspend_me, &data, 0))
|
||||
data.error = -EINVAL;
|
||||
|
||||
wait_for_completion(&done);
|
||||
|
|
|
@ -72,12 +72,8 @@ struct smp_ops_t *smp_ops;
|
|||
|
||||
static volatile unsigned int cpu_callin_map[NR_CPUS];
|
||||
|
||||
void smp_call_function_interrupt(void);
|
||||
|
||||
int smt_enabled_at_boot = 1;
|
||||
|
||||
static int ipi_fail_ok;
|
||||
|
||||
static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
|
@ -99,12 +95,15 @@ void smp_message_recv(int msg)
|
|||
{
|
||||
switch(msg) {
|
||||
case PPC_MSG_CALL_FUNCTION:
|
||||
smp_call_function_interrupt();
|
||||
generic_smp_call_function_interrupt();
|
||||
break;
|
||||
case PPC_MSG_RESCHEDULE:
|
||||
/* XXX Do we have to do this? */
|
||||
set_need_resched();
|
||||
break;
|
||||
case PPC_MSG_CALL_FUNC_SINGLE:
|
||||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
case PPC_MSG_DEBUGGER_BREAK:
|
||||
if (crash_ipi_function_ptr) {
|
||||
crash_ipi_function_ptr(get_irq_regs());
|
||||
|
@ -128,6 +127,19 @@ void smp_send_reschedule(int cpu)
|
|||
smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE);
|
||||
}
|
||||
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE);
|
||||
}
|
||||
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
for_each_cpu_mask(cpu, mask)
|
||||
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUGGER
|
||||
void smp_send_debugger_break(int cpu)
|
||||
{
|
||||
|
@ -154,215 +166,9 @@ static void stop_this_cpu(void *dummy)
|
|||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure and data for smp_call_function(). This is designed to minimise
|
||||
* static memory requirements. It also looks cleaner.
|
||||
* Stolen from the i386 version.
|
||||
*/
|
||||
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
static struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
atomic_t started;
|
||||
atomic_t finished;
|
||||
int wait;
|
||||
} *call_data;
|
||||
|
||||
/* delay of at least 8 seconds */
|
||||
#define SMP_CALL_TIMEOUT 8
|
||||
|
||||
/*
|
||||
* These functions send a 'generic call function' IPI to other online
|
||||
* CPUS in the system.
|
||||
*
|
||||
* [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.
|
||||
* <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.
|
||||
* <map> is a cpu map of the cpus to send IPI to.
|
||||
*
|
||||
* You must not call this function with disabled interrupts or from a
|
||||
* hardware interrupt handler or from a bottom half handler.
|
||||
*/
|
||||
static 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, num_cpus;
|
||||
int cpu;
|
||||
u64 timeout;
|
||||
|
||||
if (unlikely(smp_ops == NULL))
|
||||
return ret;
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
atomic_set(&data.started, 0);
|
||||
data.wait = wait;
|
||||
if (wait)
|
||||
atomic_set(&data.finished, 0);
|
||||
|
||||
/* 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);
|
||||
|
||||
num_cpus = cpus_weight(map);
|
||||
if (!num_cpus)
|
||||
goto done;
|
||||
|
||||
call_data = &data;
|
||||
smp_wmb();
|
||||
/* 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 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));
|
||||
if (!ipi_fail_ok)
|
||||
debugger(NULL);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* optionally wait for the CPUs to complete */
|
||||
if (wait) {
|
||||
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));
|
||||
debugger(NULL);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
call_data = NULL;
|
||||
HMT_medium();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __smp_call_function(void (*func)(void *info), void *info,
|
||||
int nonatomic, int wait)
|
||||
{
|
||||
int ret;
|
||||
spin_lock(&call_lock);
|
||||
ret =__smp_call_function_map(func, info, nonatomic, wait,
|
||||
cpu_online_map);
|
||||
spin_unlock(&call_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
{
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
return __smp_call_function(func, info, nonatomic, wait);
|
||||
}
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
return -EINVAL;
|
||||
|
||||
cpu_set(cpu, map);
|
||||
if (cpu != get_cpu()) {
|
||||
spin_lock(&call_lock);
|
||||
ret = __smp_call_function_map(func, info, nonatomic, wait, map);
|
||||
spin_unlock(&call_lock);
|
||||
} else {
|
||||
local_irq_disable();
|
||||
func(info);
|
||||
local_irq_enable();
|
||||
}
|
||||
put_cpu();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_single);
|
||||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
int nolock;
|
||||
|
||||
/* It's OK to fail sending the IPI, since the alternative is to
|
||||
* be stuck forever waiting on the other CPU to take the interrupt.
|
||||
*
|
||||
* It's better to at least continue and go through reboot, since this
|
||||
* function is usually called at panic or reboot time in the first
|
||||
* place.
|
||||
*/
|
||||
ipi_fail_ok = 1;
|
||||
|
||||
/* Don't deadlock in case we got called through panic */
|
||||
nolock = !spin_trylock(&call_lock);
|
||||
__smp_call_function_map(stop_this_cpu, NULL, 1, 0, cpu_online_map);
|
||||
if (!nolock)
|
||||
spin_unlock(&call_lock);
|
||||
}
|
||||
|
||||
void smp_call_function_interrupt(void)
|
||||
{
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
int wait;
|
||||
|
||||
/* call_data will be NULL if the sender timed out while
|
||||
* waiting on us to receive the call.
|
||||
*/
|
||||
if (!call_data)
|
||||
return;
|
||||
|
||||
func = call_data->func;
|
||||
info = call_data->info;
|
||||
wait = call_data->wait;
|
||||
|
||||
if (!wait)
|
||||
smp_mb__before_atomic_inc();
|
||||
|
||||
/*
|
||||
* Notify initiating CPU that I've grabbed the data and am
|
||||
* about to execute the function
|
||||
*/
|
||||
atomic_inc(&call_data->started);
|
||||
/*
|
||||
* At this point the info structure may be out of scope unless wait==1
|
||||
*/
|
||||
(*func)(info);
|
||||
if (wait) {
|
||||
smp_mb__before_atomic_inc();
|
||||
atomic_inc(&call_data->finished);
|
||||
}
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
}
|
||||
|
||||
extern struct gettimeofday_struct do_gtod;
|
||||
|
@ -596,9 +402,9 @@ int __devinit start_secondary(void *unused)
|
|||
|
||||
secondary_cpu_time_init();
|
||||
|
||||
spin_lock(&call_lock);
|
||||
ipi_call_lock();
|
||||
cpu_set(cpu, cpu_online_map);
|
||||
spin_unlock(&call_lock);
|
||||
ipi_call_unlock();
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ static void tau_timeout_smp(unsigned long unused)
|
|||
|
||||
/* schedule ourselves to be run again */
|
||||
mod_timer(&tau_timer, jiffies + shrink_timer) ;
|
||||
on_each_cpu(tau_timeout, NULL, 1, 0);
|
||||
on_each_cpu(tau_timeout, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -234,7 +234,7 @@ int __init TAU_init(void)
|
|||
tau_timer.expires = jiffies + shrink_timer;
|
||||
add_timer(&tau_timer);
|
||||
|
||||
on_each_cpu(TAU_init_smp, NULL, 1, 0);
|
||||
on_each_cpu(TAU_init_smp, NULL, 0);
|
||||
|
||||
printk("Thermal assist unit ");
|
||||
#ifdef CONFIG_TAU_INT
|
||||
|
|
|
@ -322,7 +322,7 @@ void snapshot_timebases(void)
|
|||
{
|
||||
if (!cpu_has_feature(CPU_FTR_PURR))
|
||||
return;
|
||||
on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1);
|
||||
on_each_cpu(snapshot_tb_and_purr, NULL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -218,7 +218,7 @@ static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psiz
|
|||
mb();
|
||||
|
||||
/* XXX this is sub-optimal but will do for now */
|
||||
on_each_cpu(slice_flush_segments, mm, 0, 1);
|
||||
on_each_cpu(slice_flush_segments, mm, 1);
|
||||
#ifdef CONFIG_SPU_BASE
|
||||
spu_flush_all_slbs(mm);
|
||||
#endif
|
||||
|
|
|
@ -66,7 +66,7 @@ static void pgtable_free_now(pgtable_free_t pgf)
|
|||
{
|
||||
pte_freelist_forced_free++;
|
||||
|
||||
smp_call_function(pte_free_smp_sync, NULL, 0, 1);
|
||||
smp_call_function(pte_free_smp_sync, NULL, 1);
|
||||
|
||||
pgtable_free(pgf);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ static int op_powerpc_setup(void)
|
|||
|
||||
/* Configure the registers on all cpus. If an error occurs on one
|
||||
* of the cpus, op_per_cpu_rc will be set to the error */
|
||||
on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
|
||||
on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
|
||||
|
||||
out: if (op_per_cpu_rc) {
|
||||
/* error on setup release the performance counter hardware */
|
||||
|
@ -100,7 +100,7 @@ static int op_powerpc_start(void)
|
|||
if (model->global_start)
|
||||
return model->global_start(ctr);
|
||||
if (model->start) {
|
||||
on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
|
||||
on_each_cpu(op_powerpc_cpu_start, NULL, 1);
|
||||
return op_per_cpu_rc;
|
||||
}
|
||||
return -EIO; /* No start function is defined for this
|
||||
|
@ -115,7 +115,7 @@ static inline void op_powerpc_cpu_stop(void *dummy)
|
|||
static void op_powerpc_stop(void)
|
||||
{
|
||||
if (model->stop)
|
||||
on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1);
|
||||
on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
|
||||
if (model->global_stop)
|
||||
model->global_stop();
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ void iic_request_IPIs(void)
|
|||
{
|
||||
iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call");
|
||||
iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched");
|
||||
iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE, "IPI-call-single");
|
||||
#ifdef CONFIG_DEBUGGER
|
||||
iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
|
||||
#endif /* CONFIG_DEBUGGER */
|
||||
|
|
|
@ -105,9 +105,10 @@ static void __init ps3_smp_setup_cpu(int cpu)
|
|||
* to index needs to be setup.
|
||||
*/
|
||||
|
||||
BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
|
||||
BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
|
||||
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
|
||||
BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
|
||||
BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
|
||||
BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
|
||||
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
|
||||
|
||||
for (i = 0; i < MSG_COUNT; i++) {
|
||||
result = ps3_event_receive_port_setup(cpu, &virqs[i]);
|
||||
|
|
|
@ -383,13 +383,11 @@ static irqreturn_t xics_ipi_dispatch(int cpu)
|
|||
mb();
|
||||
smp_message_recv(PPC_MSG_RESCHEDULE);
|
||||
}
|
||||
#if 0
|
||||
if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
|
||||
if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
|
||||
&xics_ipi_message[cpu].value)) {
|
||||
mb();
|
||||
smp_message_recv(PPC_MSG_MIGRATE_TASK);
|
||||
smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||
if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
|
||||
&xics_ipi_message[cpu].value)) {
|
||||
|
|
|
@ -1494,7 +1494,7 @@ void mpic_request_ipis(void)
|
|||
static char *ipi_names[] = {
|
||||
"IPI0 (call function)",
|
||||
"IPI1 (reschedule)",
|
||||
"IPI2 (unused)",
|
||||
"IPI2 (call function single)",
|
||||
"IPI3 (debugger break)",
|
||||
};
|
||||
BUG_ON(mpic == NULL);
|
||||
|
|
|
@ -203,7 +203,7 @@ __appldata_vtimer_setup(int cmd)
|
|||
per_cpu(appldata_timer, i).expires = per_cpu_interval;
|
||||
smp_call_function_single(i, add_virt_timer_periodic,
|
||||
&per_cpu(appldata_timer, i),
|
||||
0, 1);
|
||||
1);
|
||||
}
|
||||
appldata_timer_active = 1;
|
||||
break;
|
||||
|
@ -228,7 +228,7 @@ __appldata_vtimer_setup(int cmd)
|
|||
args.timer = &per_cpu(appldata_timer, i);
|
||||
args.expires = per_cpu_interval;
|
||||
smp_call_function_single(i, __appldata_mod_vtimer_wrap,
|
||||
&args, 0, 1);
|
||||
&args, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ static void do_call_function(void)
|
|||
}
|
||||
|
||||
static void __smp_call_function_map(void (*func) (void *info), void *info,
|
||||
int nonatomic, int wait, cpumask_t map)
|
||||
int wait, cpumask_t map)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpu, local = 0;
|
||||
|
@ -162,7 +162,6 @@ static void __smp_call_function_map(void (*func) (void *info), void *info,
|
|||
* smp_call_function:
|
||||
* @func: the function to run; this must be fast and non-blocking
|
||||
* @info: an arbitrary pointer to pass to the function
|
||||
* @nonatomic: unused
|
||||
* @wait: if true, wait (atomically) until function has completed on other CPUs
|
||||
*
|
||||
* Run a function on all other CPUs.
|
||||
|
@ -170,15 +169,14 @@ static void __smp_call_function_map(void (*func) (void *info), void *info,
|
|||
* You must not call this function with disabled interrupts, from a
|
||||
* hardware interrupt handler or from a bottom half.
|
||||
*/
|
||||
int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait)
|
||||
int smp_call_function(void (*func) (void *info), void *info, int wait)
|
||||
{
|
||||
cpumask_t map;
|
||||
|
||||
spin_lock(&call_lock);
|
||||
map = cpu_online_map;
|
||||
cpu_clear(smp_processor_id(), map);
|
||||
__smp_call_function_map(func, info, nonatomic, wait, map);
|
||||
__smp_call_function_map(func, info, wait, map);
|
||||
spin_unlock(&call_lock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -189,7 +187,6 @@ EXPORT_SYMBOL(smp_call_function);
|
|||
* @cpu: the CPU where func should run
|
||||
* @func: the function to run; this must be fast and non-blocking
|
||||
* @info: an arbitrary pointer to pass to the function
|
||||
* @nonatomic: unused
|
||||
* @wait: if true, wait (atomically) until function has completed on other CPUs
|
||||
*
|
||||
* Run a function on one processor.
|
||||
|
@ -198,11 +195,10 @@ EXPORT_SYMBOL(smp_call_function);
|
|||
* hardware interrupt handler or from a bottom half.
|
||||
*/
|
||||
int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
|
||||
int nonatomic, int wait)
|
||||
int wait)
|
||||
{
|
||||
spin_lock(&call_lock);
|
||||
__smp_call_function_map(func, info, nonatomic, wait,
|
||||
cpumask_of_cpu(cpu));
|
||||
__smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu));
|
||||
spin_unlock(&call_lock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -228,7 +224,7 @@ int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
|
|||
{
|
||||
spin_lock(&call_lock);
|
||||
cpu_clear(smp_processor_id(), mask);
|
||||
__smp_call_function_map(func, info, 0, wait, mask);
|
||||
__smp_call_function_map(func, info, wait, mask);
|
||||
spin_unlock(&call_lock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -303,7 +299,7 @@ static void smp_ptlb_callback(void *info)
|
|||
|
||||
void smp_ptlb_all(void)
|
||||
{
|
||||
on_each_cpu(smp_ptlb_callback, NULL, 0, 1);
|
||||
on_each_cpu(smp_ptlb_callback, NULL, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_ptlb_all);
|
||||
#endif /* ! CONFIG_64BIT */
|
||||
|
@ -351,7 +347,7 @@ void smp_ctl_set_bit(int cr, int bit)
|
|||
memset(&parms.orvals, 0, sizeof(parms.orvals));
|
||||
memset(&parms.andvals, 0xff, sizeof(parms.andvals));
|
||||
parms.orvals[cr] = 1 << bit;
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_ctl_set_bit);
|
||||
|
||||
|
@ -365,7 +361,7 @@ void smp_ctl_clear_bit(int cr, int bit)
|
|||
memset(&parms.orvals, 0, sizeof(parms.orvals));
|
||||
memset(&parms.andvals, 0xff, sizeof(parms.andvals));
|
||||
parms.andvals[cr] = ~(1L << bit);
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_ctl_clear_bit);
|
||||
|
||||
|
|
|
@ -707,7 +707,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
|
|||
*/
|
||||
memset(&etr_sync, 0, sizeof(etr_sync));
|
||||
preempt_disable();
|
||||
smp_call_function(clock_sync_cpu_start, &etr_sync, 0, 0);
|
||||
smp_call_function(clock_sync_cpu_start, &etr_sync, 0);
|
||||
local_irq_disable();
|
||||
enable_sync_clock();
|
||||
|
||||
|
@ -746,7 +746,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
|
|||
rc = -EAGAIN;
|
||||
}
|
||||
local_irq_enable();
|
||||
smp_call_function(clock_sync_cpu_end, NULL, 0, 0);
|
||||
smp_call_function(clock_sync_cpu_end, NULL, 0);
|
||||
preempt_enable();
|
||||
return rc;
|
||||
}
|
||||
|
@ -926,7 +926,7 @@ static void etr_work_fn(struct work_struct *work)
|
|||
if (!eacr.ea) {
|
||||
/* Both ports offline. Reset everything. */
|
||||
eacr.dp = eacr.es = eacr.sl = 0;
|
||||
on_each_cpu(disable_sync_clock, NULL, 0, 1);
|
||||
on_each_cpu(disable_sync_clock, NULL, 1);
|
||||
del_timer_sync(&etr_timer);
|
||||
etr_update_eacr(eacr);
|
||||
clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
|
||||
|
|
|
@ -688,6 +688,7 @@ config CRASH_DUMP
|
|||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
depends on SYS_SUPPORTS_SMP
|
||||
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
|
||||
|
|
|
@ -36,13 +36,6 @@ EXPORT_SYMBOL(cpu_possible_map);
|
|||
cpumask_t cpu_online_map;
|
||||
EXPORT_SYMBOL(cpu_online_map);
|
||||
|
||||
static atomic_t cpus_booted = ATOMIC_INIT(0);
|
||||
|
||||
/*
|
||||
* Run specified function on a particular processor.
|
||||
*/
|
||||
void __smp_call_function(unsigned int cpu);
|
||||
|
||||
static inline void __init smp_store_cpu_info(unsigned int cpu)
|
||||
{
|
||||
struct sh_cpuinfo *c = cpu_data + cpu;
|
||||
|
@ -175,45 +168,20 @@ static void stop_this_cpu(void *unused)
|
|||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(stop_this_cpu, 0, 1, 0);
|
||||
smp_call_function(stop_this_cpu, 0, 0);
|
||||
}
|
||||
|
||||
struct smp_fn_call_struct smp_fn_call = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(smp_fn_call.lock),
|
||||
.finished = ATOMIC_INIT(0),
|
||||
};
|
||||
|
||||
/*
|
||||
* The caller of this wants the passed function to run on every cpu. If wait
|
||||
* is set, wait until all cpus have finished the function before returning.
|
||||
* The lock is here to protect the call structure.
|
||||
* 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 retry, int wait)
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
unsigned int nr_cpus = atomic_read(&cpus_booted);
|
||||
int i;
|
||||
int cpu;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
for_each_cpu_mask(cpu, mask)
|
||||
plat_send_ipi(cpu, SMP_MSG_FUNCTION);
|
||||
}
|
||||
|
||||
spin_lock(&smp_fn_call.lock);
|
||||
|
||||
atomic_set(&smp_fn_call.finished, 0);
|
||||
smp_fn_call.fn = func;
|
||||
smp_fn_call.data = info;
|
||||
|
||||
for (i = 0; i < nr_cpus; i++)
|
||||
if (i != smp_processor_id())
|
||||
plat_send_ipi(i, SMP_MSG_FUNCTION);
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1));
|
||||
|
||||
spin_unlock(&smp_fn_call.lock);
|
||||
|
||||
return 0;
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
plat_send_ipi(cpu, SMP_MSG_FUNCTION_SINGLE);
|
||||
}
|
||||
|
||||
/* Not really SMP stuff ... */
|
||||
|
@ -229,7 +197,7 @@ static void flush_tlb_all_ipi(void *info)
|
|||
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
|
||||
on_each_cpu(flush_tlb_all_ipi, 0, 1);
|
||||
}
|
||||
|
||||
static void flush_tlb_mm_ipi(void *mm)
|
||||
|
@ -255,7 +223,7 @@ void flush_tlb_mm(struct mm_struct *mm)
|
|||
preempt_disable();
|
||||
|
||||
if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
|
||||
smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
|
||||
smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < num_online_cpus(); i++)
|
||||
|
@ -292,7 +260,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
|
|||
fd.vma = vma;
|
||||
fd.addr1 = start;
|
||||
fd.addr2 = end;
|
||||
smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
|
||||
smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < num_online_cpus(); i++)
|
||||
|
@ -316,7 +284,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|||
|
||||
fd.addr1 = start;
|
||||
fd.addr2 = end;
|
||||
on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1);
|
||||
on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1);
|
||||
}
|
||||
|
||||
static void flush_tlb_page_ipi(void *info)
|
||||
|
@ -335,7 +303,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
|
|||
|
||||
fd.vma = vma;
|
||||
fd.addr1 = page;
|
||||
smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
|
||||
smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < num_online_cpus(); i++)
|
||||
|
@ -359,6 +327,6 @@ void flush_tlb_one(unsigned long asid, unsigned long vaddr)
|
|||
fd.addr1 = asid;
|
||||
fd.addr2 = vaddr;
|
||||
|
||||
smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1, 1);
|
||||
smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1);
|
||||
local_flush_tlb_one(asid, vaddr);
|
||||
}
|
||||
|
|
|
@ -807,7 +807,6 @@ extern unsigned long xcall_call_function;
|
|||
* 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
|
||||
|
@ -816,8 +815,8 @@ extern unsigned long xcall_call_function;
|
|||
* You must not call this function with disabled interrupts or from a
|
||||
* hardware interrupt handler or from a bottom half handler.
|
||||
*/
|
||||
static int smp_call_function_mask(void (*func)(void *info), void *info,
|
||||
int nonatomic, int wait, cpumask_t mask)
|
||||
static int sparc64_smp_call_function_mask(void (*func)(void *info), void *info,
|
||||
int wait, cpumask_t mask)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus;
|
||||
|
@ -852,11 +851,9 @@ static int smp_call_function_mask(void (*func)(void *info), void *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int smp_call_function(void (*func)(void *info), void *info,
|
||||
int nonatomic, int wait)
|
||||
int smp_call_function(void (*func)(void *info), void *info, int wait)
|
||||
{
|
||||
return smp_call_function_mask(func, info, nonatomic, wait,
|
||||
cpu_online_map);
|
||||
return sparc64_smp_call_function_mask(func, info, wait, cpu_online_map);
|
||||
}
|
||||
|
||||
void smp_call_function_client(int irq, struct pt_regs *regs)
|
||||
|
@ -893,7 +890,7 @@ static void tsb_sync(void *info)
|
|||
|
||||
void smp_tsb_sync(struct mm_struct *mm)
|
||||
{
|
||||
smp_call_function_mask(tsb_sync, mm, 0, 1, mm->cpu_vm_mask);
|
||||
sparc64_smp_call_function_mask(tsb_sync, mm, 1, mm->cpu_vm_mask);
|
||||
}
|
||||
|
||||
extern unsigned long xcall_flush_tlb_mm;
|
||||
|
|
|
@ -344,7 +344,7 @@ void hugetlb_prefault_arch_hook(struct mm_struct *mm)
|
|||
* also executing in this address space.
|
||||
*/
|
||||
mm->context.sparc64_ctx_val = ctx;
|
||||
on_each_cpu(context_reload, mm, 0, 0);
|
||||
on_each_cpu(context_reload, mm, 0);
|
||||
}
|
||||
spin_unlock(&ctx_alloc_lock);
|
||||
}
|
||||
|
|
|
@ -214,8 +214,7 @@ void smp_call_function_slave(int cpu)
|
|||
atomic_inc(&scf_finished);
|
||||
}
|
||||
|
||||
int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
|
||||
int wait)
|
||||
int smp_call_function(void (*_func)(void *info), void *_info, int wait)
|
||||
{
|
||||
int cpus = num_online_cpus() - 1;
|
||||
int i;
|
||||
|
|
|
@ -170,6 +170,7 @@ config GENERIC_PENDING_IRQ
|
|||
config X86_SMP
|
||||
bool
|
||||
depends on SMP && ((X86_32 && !X86_VOYAGER) || X86_64)
|
||||
select USE_GENERIC_SMP_HELPERS
|
||||
default y
|
||||
|
||||
config X86_32_SMP
|
||||
|
|
|
@ -1340,6 +1340,10 @@ void __init smp_intr_init(void)
|
|||
|
||||
/* IPI for generic function call */
|
||||
alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
|
||||
|
||||
/* IPI for single call function */
|
||||
set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
|
||||
call_function_single_interrupt);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ static void mcheck_check_cpu(void *info)
|
|||
|
||||
static void mcheck_timer(struct work_struct *work)
|
||||
{
|
||||
on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
|
||||
on_each_cpu(mcheck_check_cpu, NULL, 1);
|
||||
|
||||
/*
|
||||
* Alert userspace if needed. If we logged an MCE, reduce the
|
||||
|
@ -621,7 +621,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
|
|||
* Collect entries that were still getting written before the
|
||||
* synchronize.
|
||||
*/
|
||||
on_each_cpu(collect_tscs, cpu_tsc, 1, 1);
|
||||
on_each_cpu(collect_tscs, cpu_tsc, 1);
|
||||
for (i = next; i < MCE_LOG_LEN; i++) {
|
||||
if (mcelog.entry[i].finished &&
|
||||
mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
|
||||
|
@ -746,7 +746,7 @@ static void mce_restart(void)
|
|||
if (next_interval)
|
||||
cancel_delayed_work(&mcheck_work);
|
||||
/* Timer race is harmless here */
|
||||
on_each_cpu(mce_init, NULL, 1, 1);
|
||||
on_each_cpu(mce_init, NULL, 1);
|
||||
next_interval = check_interval * HZ;
|
||||
if (next_interval)
|
||||
schedule_delayed_work(&mcheck_work,
|
||||
|
|
|
@ -59,7 +59,7 @@ static DECLARE_DELAYED_WORK(mce_work, mce_work_fn);
|
|||
|
||||
static void mce_work_fn(struct work_struct *work)
|
||||
{
|
||||
on_each_cpu(mce_checkregs, NULL, 1, 1);
|
||||
on_each_cpu(mce_checkregs, NULL, 1);
|
||||
schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
|
|||
atomic_set(&data.gate,0);
|
||||
|
||||
/* Start the ball rolling on other CPUs */
|
||||
if (smp_call_function(ipi_handler, &data, 1, 0) != 0)
|
||||
if (smp_call_function(ipi_handler, &data, 0) != 0)
|
||||
panic("mtrr: timed out waiting for other CPUs\n");
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -1682,7 +1682,7 @@ void mtrr_ap_init(void)
|
|||
*/
|
||||
void mtrr_save_state(void)
|
||||
{
|
||||
smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1);
|
||||
smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1);
|
||||
}
|
||||
|
||||
static int __init mtrr_init_finialize(void)
|
||||
|
|
|
@ -189,7 +189,7 @@ void disable_lapic_nmi_watchdog(void)
|
|||
if (atomic_read(&nmi_active) <= 0)
|
||||
return;
|
||||
|
||||
on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
|
||||
on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
|
||||
|
||||
if (wd_ops)
|
||||
wd_ops->unreserve();
|
||||
|
@ -213,7 +213,7 @@ void enable_lapic_nmi_watchdog(void)
|
|||
return;
|
||||
}
|
||||
|
||||
on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
|
||||
on_each_cpu(setup_apic_nmi_watchdog, NULL, 1);
|
||||
touch_nmi_watchdog();
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
|
|||
for (; count; count -= 16) {
|
||||
cmd.eax = pos;
|
||||
cmd.ecx = pos >> 32;
|
||||
smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
|
||||
smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1);
|
||||
if (copy_to_user(tmp, &cmd, 16))
|
||||
return -EFAULT;
|
||||
tmp += 16;
|
||||
|
|
|
@ -816,6 +816,9 @@ END(invalidate_interrupt\num)
|
|||
ENTRY(call_function_interrupt)
|
||||
apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
|
||||
END(call_function_interrupt)
|
||||
ENTRY(call_function_single_interrupt)
|
||||
apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt
|
||||
END(call_function_single_interrupt)
|
||||
ENTRY(irq_move_cleanup_interrupt)
|
||||
apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
|
||||
END(irq_move_cleanup_interrupt)
|
||||
|
|
|
@ -1569,7 +1569,7 @@ void /*__init*/ print_local_APIC(void *dummy)
|
|||
|
||||
void print_all_local_APICs(void)
|
||||
{
|
||||
on_each_cpu(print_local_APIC, NULL, 1, 1);
|
||||
on_each_cpu(print_local_APIC, NULL, 1);
|
||||
}
|
||||
|
||||
void /*__init*/ print_PIC(void)
|
||||
|
|
|
@ -1160,7 +1160,7 @@ void __apicdebuginit print_local_APIC(void * dummy)
|
|||
|
||||
void print_all_local_APICs (void)
|
||||
{
|
||||
on_each_cpu(print_local_APIC, NULL, 1, 1);
|
||||
on_each_cpu(print_local_APIC, NULL, 1);
|
||||
}
|
||||
|
||||
void __apicdebuginit print_PIC(void)
|
||||
|
|
|
@ -199,6 +199,10 @@ void __init native_init_IRQ(void)
|
|||
/* IPI for generic function call */
|
||||
alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
|
||||
|
||||
/* IPI for generic single function call */
|
||||
alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
|
||||
call_function_single_interrupt);
|
||||
|
||||
/* Low priority IPI to cleanup after moving an irq */
|
||||
set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
|
||||
#endif
|
||||
|
|
|
@ -68,7 +68,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
|
|||
load_LDT(pc);
|
||||
mask = cpumask_of_cpu(smp_processor_id());
|
||||
if (!cpus_equal(current->mm->cpu_vm_mask, mask))
|
||||
smp_call_function(flush_ldt, current->mm, 1, 1);
|
||||
smp_call_function(flush_ldt, current->mm, 1);
|
||||
preempt_enable();
|
||||
#else
|
||||
load_LDT(pc);
|
||||
|
|
|
@ -130,7 +130,7 @@ int __init check_nmi_watchdog(void)
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
if (nmi_watchdog == NMI_LOCAL_APIC)
|
||||
smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
|
||||
smp_call_function(nmi_cpu_busy, (void *)&endflag, 0);
|
||||
#endif
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
|
@ -272,7 +272,7 @@ static void __acpi_nmi_enable(void *__unused)
|
|||
void acpi_nmi_enable(void)
|
||||
{
|
||||
if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
|
||||
on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
|
||||
on_each_cpu(__acpi_nmi_enable, NULL, 1);
|
||||
}
|
||||
|
||||
static void __acpi_nmi_disable(void *__unused)
|
||||
|
@ -286,7 +286,7 @@ static void __acpi_nmi_disable(void *__unused)
|
|||
void acpi_nmi_disable(void)
|
||||
{
|
||||
if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
|
||||
on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
|
||||
on_each_cpu(__acpi_nmi_disable, NULL, 1);
|
||||
}
|
||||
|
||||
void setup_apic_nmi_watchdog(void *unused)
|
||||
|
|
|
@ -132,7 +132,7 @@ void cpu_idle_wait(void)
|
|||
{
|
||||
smp_mb();
|
||||
/* kick all the CPUs so that they exit out of pm_idle */
|
||||
smp_call_function(do_nothing, NULL, 0, 1);
|
||||
smp_call_function(do_nothing, NULL, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_idle_wait);
|
||||
|
||||
|
|
|
@ -121,132 +121,23 @@ static void native_smp_send_reschedule(int cpu)
|
|||
send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure and data for smp_call_function(). This is designed to minimise
|
||||
* static memory requirements. It also looks cleaner.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
atomic_t started;
|
||||
atomic_t finished;
|
||||
int wait;
|
||||
};
|
||||
|
||||
void lock_ipi_call_lock(void)
|
||||
void native_send_call_func_single_ipi(int cpu)
|
||||
{
|
||||
spin_lock_irq(&call_lock);
|
||||
send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_SINGLE_VECTOR);
|
||||
}
|
||||
|
||||
void unlock_ipi_call_lock(void)
|
||||
void native_send_call_func_ipi(cpumask_t mask)
|
||||
{
|
||||
spin_unlock_irq(&call_lock);
|
||||
}
|
||||
|
||||
static struct call_data_struct *call_data;
|
||||
|
||||
static void __smp_call_function(void (*func) (void *info), void *info,
|
||||
int nonatomic, int wait)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus = num_online_cpus() - 1;
|
||||
|
||||
if (!cpus)
|
||||
return;
|
||||
|
||||
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 all other CPUs and wait for them to respond */
|
||||
send_IPI_allbutself(CALL_FUNCTION_VECTOR);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus)
|
||||
cpu_relax();
|
||||
|
||||
if (wait)
|
||||
while (atomic_read(&data.finished) != cpus)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @info: An arbitrary pointer to pass to the function.
|
||||
* @wait: If true, wait (atomically) until function has completed on other CPUs.
|
||||
*
|
||||
* Returns 0 on success, else a negative status code.
|
||||
*
|
||||
* If @wait is true, then returns once @func has returned; otherwise
|
||||
* it returns just before the target cpu calls @func.
|
||||
*
|
||||
* You must not call this function with disabled interrupts or from a
|
||||
* hardware interrupt handler or from a bottom half handler.
|
||||
*/
|
||||
static int
|
||||
native_smp_call_function_mask(cpumask_t mask,
|
||||
void (*func)(void *), void *info,
|
||||
int wait)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
cpumask_t allbutself;
|
||||
int cpus;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
/* Holding any lock stops cpus from going down. */
|
||||
spin_lock(&call_lock);
|
||||
|
||||
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;
|
||||
wmb();
|
||||
|
||||
/* Send a message to other CPUs */
|
||||
if (cpus_equal(mask, allbutself) &&
|
||||
cpus_equal(cpu_online_map, cpu_callout_map))
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stop_this_cpu(void *dummy)
|
||||
|
@ -268,18 +159,13 @@ static void stop_this_cpu(void *dummy)
|
|||
|
||||
static void native_smp_send_stop(void)
|
||||
{
|
||||
int nolock;
|
||||
unsigned long flags;
|
||||
|
||||
if (reboot_force)
|
||||
return;
|
||||
|
||||
/* Don't deadlock on the call lock in panic */
|
||||
nolock = !spin_trylock(&call_lock);
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
local_irq_save(flags);
|
||||
__smp_call_function(stop_this_cpu, NULL, 0, 0);
|
||||
if (!nolock)
|
||||
spin_unlock(&call_lock);
|
||||
disable_local_APIC();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
@ -301,33 +187,28 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
|
|||
|
||||
void smp_call_function_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
void (*func) (void *info) = call_data->func;
|
||||
void *info = call_data->info;
|
||||
int wait = call_data->wait;
|
||||
|
||||
ack_APIC_irq();
|
||||
/*
|
||||
* Notify initiating CPU that I've grabbed the data and am
|
||||
* about to execute the function
|
||||
*/
|
||||
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_interrupt();
|
||||
#ifdef CONFIG_X86_32
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
#else
|
||||
add_pda(irq_call_count, 1);
|
||||
#endif
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
mb();
|
||||
atomic_inc(&call_data->finished);
|
||||
}
|
||||
void smp_call_function_single_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
ack_APIC_irq();
|
||||
irq_enter();
|
||||
generic_smp_call_function_single_interrupt();
|
||||
#ifdef CONFIG_X86_32
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
#else
|
||||
add_pda(irq_call_count, 1);
|
||||
#endif
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
struct smp_ops smp_ops = {
|
||||
|
@ -338,7 +219,8 @@ struct smp_ops smp_ops = {
|
|||
|
||||
.smp_send_stop = native_smp_send_stop,
|
||||
.smp_send_reschedule = native_smp_send_reschedule,
|
||||
.smp_call_function_mask = native_smp_call_function_mask,
|
||||
|
||||
.send_call_func_ipi = native_send_call_func_ipi,
|
||||
.send_call_func_single_ipi = native_send_call_func_single_ipi,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(smp_ops);
|
||||
|
||||
|
|
|
@ -327,12 +327,12 @@ static void __cpuinit start_secondary(void *unused)
|
|||
* lock helps us to not include this cpu in a currently in progress
|
||||
* smp_call_function().
|
||||
*/
|
||||
lock_ipi_call_lock();
|
||||
ipi_call_lock_irq();
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
setup_vector_irq(smp_processor_id());
|
||||
#endif
|
||||
cpu_set(smp_processor_id(), cpu_online_map);
|
||||
unlock_ipi_call_lock();
|
||||
ipi_call_unlock_irq();
|
||||
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
|
||||
|
||||
setup_secondary_clock();
|
||||
|
|
|
@ -25,59 +25,3 @@ __cpuinit void init_gdt(int cpu)
|
|||
per_cpu(cpu_number, cpu) = cpu;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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: Unused.
|
||||
* @wait: If true, wait (atomically) until function has completed on other CPUs.
|
||||
*
|
||||
* Returns 0 on success, else a negative status code.
|
||||
*
|
||||
* If @wait is true, then returns once @func has returned; otherwise
|
||||
* it returns just before the target cpu calls @func.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* smp_call_function_single - Run a function on a specific CPU
|
||||
* @cpu: The target CPU. Cannot be the calling CPU.
|
||||
* @func: The function to run. This must be fast and non-blocking.
|
||||
* @info: An arbitrary pointer to pass to the function.
|
||||
* @nonatomic: Unused.
|
||||
* @wait: If true, wait until function has completed on other CPUs.
|
||||
*
|
||||
* Returns 0 on success, else a negative status code.
|
||||
*
|
||||
* If @wait is true, then returns once @func has returned; otherwise
|
||||
* it returns just before the target cpu calls @func.
|
||||
*/
|
||||
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) {
|
||||
local_irq_disable();
|
||||
func(info);
|
||||
local_irq_enable();
|
||||
put_cpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);
|
||||
|
||||
put_cpu();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_single);
|
||||
|
|
|
@ -238,6 +238,6 @@ static void do_flush_tlb_all(void *info)
|
|||
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
|
||||
on_each_cpu(do_flush_tlb_all, NULL, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -275,5 +275,5 @@ static void do_flush_tlb_all(void *info)
|
|||
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
|
||||
on_each_cpu(do_flush_tlb_all, NULL, 1);
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
|
|||
{
|
||||
long cpu = (long)arg;
|
||||
if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
|
||||
smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1);
|
||||
smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 1);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ static int __init vsyscall_init(void)
|
|||
#ifdef CONFIG_SYSCTL
|
||||
register_sysctl_table(kernel_root_table2);
|
||||
#endif
|
||||
on_each_cpu(cpu_vsyscall_init, NULL, 0, 1);
|
||||
on_each_cpu(cpu_vsyscall_init, NULL, 1);
|
||||
hotcpu_notifier(cpu_vsyscall_notifier, 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
|
|||
{
|
||||
if (vmx->vcpu.cpu == -1)
|
||||
return;
|
||||
smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
|
||||
smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1);
|
||||
vmx->launched = 0;
|
||||
}
|
||||
|
||||
|
@ -2968,7 +2968,7 @@ static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
|
|||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
|
||||
if (vmx->vmcs) {
|
||||
on_each_cpu(__vcpu_clear, vmx, 0, 1);
|
||||
on_each_cpu(__vcpu_clear, vmx, 1);
|
||||
free_vmcs(vmx->vmcs);
|
||||
vmx->vmcs = NULL;
|
||||
}
|
||||
|
|
|
@ -4044,6 +4044,6 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
|
|||
* So need not to call smp_call_function_single() in that case.
|
||||
*/
|
||||
if (vcpu->guest_mode && vcpu->cpu != cpu)
|
||||
smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
|
||||
smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
|
||||
put_cpu();
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe)
|
|||
|
||||
rv.msr_no = msr_no;
|
||||
if (safe) {
|
||||
smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 0, 1);
|
||||
smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
|
||||
err = rv.err;
|
||||
} else {
|
||||
smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
|
||||
smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
|
||||
}
|
||||
*l = rv.l;
|
||||
*h = rv.h;
|
||||
|
@ -64,10 +64,10 @@ static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
|
|||
rv.l = l;
|
||||
rv.h = h;
|
||||
if (safe) {
|
||||
smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 0, 1);
|
||||
smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
|
||||
err = rv.err;
|
||||
} else {
|
||||
smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
|
||||
smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -950,94 +950,24 @@ static void smp_stop_cpu_function(void *dummy)
|
|||
halt();
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
volatile unsigned long started;
|
||||
volatile unsigned long finished;
|
||||
int wait;
|
||||
};
|
||||
|
||||
static struct call_data_struct *call_data;
|
||||
|
||||
/* execute a thread on a new CPU. The function to be called must be
|
||||
* previously set up. This is used to schedule a function for
|
||||
* execution on all CPUs - set up the function then broadcast a
|
||||
* function_interrupt CPI to come here on each CPU */
|
||||
static void smp_call_function_interrupt(void)
|
||||
{
|
||||
void (*func) (void *info) = call_data->func;
|
||||
void *info = call_data->info;
|
||||
/* must take copy of wait because call_data may be replaced
|
||||
* unless the function is waiting for us to finish */
|
||||
int wait = call_data->wait;
|
||||
__u8 cpu = smp_processor_id();
|
||||
|
||||
/*
|
||||
* Notify initiating CPU that I've grabbed the data and am
|
||||
* about to execute the function
|
||||
*/
|
||||
mb();
|
||||
if (!test_and_clear_bit(cpu, &call_data->started)) {
|
||||
/* If the bit wasn't set, this could be a replay */
|
||||
printk(KERN_WARNING "VOYAGER SMP: CPU %d received call funtion"
|
||||
" with no call pending\n", cpu);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* At this point the info structure may be out of scope unless wait==1
|
||||
*/
|
||||
irq_enter();
|
||||
(*func) (info);
|
||||
generic_smp_call_function_interrupt();
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
irq_exit();
|
||||
if (wait) {
|
||||
mb();
|
||||
clear_bit(cpu, &call_data->finished);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
voyager_smp_call_function_mask(cpumask_t cpumask,
|
||||
void (*func) (void *info), void *info, int wait)
|
||||
static void smp_call_function_single_interrupt(void)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
u32 mask = cpus_addr(cpumask)[0];
|
||||
|
||||
mask &= ~(1 << smp_processor_id());
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
||||
/* Can deadlock when called with interrupts disabled */
|
||||
WARN_ON(irqs_disabled());
|
||||
|
||||
data.func = func;
|
||||
data.info = info;
|
||||
data.started = mask;
|
||||
data.wait = wait;
|
||||
if (wait)
|
||||
data.finished = mask;
|
||||
|
||||
spin_lock(&call_lock);
|
||||
call_data = &data;
|
||||
wmb();
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
send_CPI(mask, VIC_CALL_FUNCTION_CPI);
|
||||
|
||||
/* Wait for response */
|
||||
while (data.started)
|
||||
barrier();
|
||||
|
||||
if (wait)
|
||||
while (data.finished)
|
||||
barrier();
|
||||
|
||||
spin_unlock(&call_lock);
|
||||
|
||||
return 0;
|
||||
irq_enter();
|
||||
generic_smp_call_function_single_interrupt();
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
/* Sorry about the name. In an APIC based system, the APICs
|
||||
|
@ -1094,6 +1024,12 @@ void smp_qic_call_function_interrupt(struct pt_regs *regs)
|
|||
smp_call_function_interrupt();
|
||||
}
|
||||
|
||||
void smp_qic_call_function_single_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
ack_QIC_CPI(QIC_CALL_FUNCTION_SINGLE_CPI);
|
||||
smp_call_function_single_interrupt();
|
||||
}
|
||||
|
||||
void smp_vic_cpi_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
@ -1114,6 +1050,8 @@ void smp_vic_cpi_interrupt(struct pt_regs *regs)
|
|||
smp_enable_irq_interrupt();
|
||||
if (test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu]))
|
||||
smp_call_function_interrupt();
|
||||
if (test_and_clear_bit(VIC_CALL_FUNCTION_SINGLE_CPI, &vic_cpi_mailbox[cpu]))
|
||||
smp_call_function_single_interrupt();
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
|
@ -1129,7 +1067,7 @@ static void do_flush_tlb_all(void *info)
|
|||
/* flush the TLB of every active CPU in the system */
|
||||
void flush_tlb_all(void)
|
||||
{
|
||||
on_each_cpu(do_flush_tlb_all, 0, 1, 1);
|
||||
on_each_cpu(do_flush_tlb_all, 0, 1);
|
||||
}
|
||||
|
||||
/* send a reschedule CPI to one CPU by physical CPU number*/
|
||||
|
@ -1161,7 +1099,7 @@ int safe_smp_processor_id(void)
|
|||
/* broadcast a halt to all other CPUs */
|
||||
static void voyager_smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(smp_stop_cpu_function, NULL, 1, 1);
|
||||
smp_call_function(smp_stop_cpu_function, NULL, 1);
|
||||
}
|
||||
|
||||
/* this function is triggered in time.c when a clock tick fires
|
||||
|
@ -1848,5 +1786,7 @@ struct smp_ops smp_ops = {
|
|||
|
||||
.smp_send_stop = voyager_smp_send_stop,
|
||||
.smp_send_reschedule = voyager_smp_send_reschedule,
|
||||
.smp_call_function_mask = voyager_smp_call_function_mask,
|
||||
|
||||
.send_call_func_ipi = native_send_call_func_ipi,
|
||||
.send_call_func_single_ipi = native_send_call_func_single_ipi,
|
||||
};
|
||||
|
|
|
@ -141,7 +141,7 @@ static void cpa_flush_all(unsigned long cache)
|
|||
{
|
||||
BUG_ON(irqs_disabled());
|
||||
|
||||
on_each_cpu(__cpa_flush_all, (void *) cache, 1, 1);
|
||||
on_each_cpu(__cpa_flush_all, (void *) cache, 1);
|
||||
}
|
||||
|
||||
static void __cpa_flush_range(void *arg)
|
||||
|
@ -162,7 +162,7 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
|
|||
BUG_ON(irqs_disabled());
|
||||
WARN_ON(PAGE_ALIGN(start) != start);
|
||||
|
||||
on_each_cpu(__cpa_flush_range, NULL, 1, 1);
|
||||
on_each_cpu(__cpa_flush_range, NULL, 1);
|
||||
|
||||
if (!cache)
|
||||
return;
|
||||
|
|
|
@ -218,8 +218,8 @@ static int nmi_setup(void)
|
|||
}
|
||||
|
||||
}
|
||||
on_each_cpu(nmi_save_registers, NULL, 0, 1);
|
||||
on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
|
||||
on_each_cpu(nmi_save_registers, NULL, 1);
|
||||
on_each_cpu(nmi_cpu_setup, NULL, 1);
|
||||
nmi_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ static void nmi_shutdown(void)
|
|||
{
|
||||
struct op_msrs *msrs = &get_cpu_var(cpu_msrs);
|
||||
nmi_enabled = 0;
|
||||
on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
|
||||
on_each_cpu(nmi_cpu_shutdown, NULL, 1);
|
||||
unregister_die_notifier(&profile_exceptions_nb);
|
||||
model->shutdown(msrs);
|
||||
free_msrs();
|
||||
|
@ -286,7 +286,7 @@ static void nmi_cpu_start(void *dummy)
|
|||
|
||||
static int nmi_start(void)
|
||||
{
|
||||
on_each_cpu(nmi_cpu_start, NULL, 0, 1);
|
||||
on_each_cpu(nmi_cpu_start, NULL, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ static void nmi_cpu_stop(void *dummy)
|
|||
|
||||
static void nmi_stop(void)
|
||||
{
|
||||
on_each_cpu(nmi_cpu_stop, NULL, 0, 1);
|
||||
on_each_cpu(nmi_cpu_stop, NULL, 1);
|
||||
}
|
||||
|
||||
struct op_counter_config counter_config[OP_MAX_COUNTER];
|
||||
|
|
|
@ -1214,7 +1214,9 @@ static const struct smp_ops xen_smp_ops __initdata = {
|
|||
|
||||
.smp_send_stop = xen_smp_send_stop,
|
||||
.smp_send_reschedule = xen_smp_send_reschedule,
|
||||
.smp_call_function_mask = xen_smp_call_function_mask,
|
||||
|
||||
.send_call_func_ipi = xen_smp_send_call_function_ipi,
|
||||
.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi,
|
||||
};
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
|
|
@ -796,7 +796,7 @@ static void drop_mm_ref(struct mm_struct *mm)
|
|||
}
|
||||
|
||||
if (!cpus_empty(mask))
|
||||
xen_smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
|
||||
smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
|
||||
}
|
||||
#else
|
||||
static void drop_mm_ref(struct mm_struct *mm)
|
||||
|
|
|
@ -36,27 +36,14 @@
|
|||
#include "mmu.h"
|
||||
|
||||
cpumask_t xen_cpu_initialized_map;
|
||||
static DEFINE_PER_CPU(int, resched_irq) = -1;
|
||||
static DEFINE_PER_CPU(int, callfunc_irq) = -1;
|
||||
|
||||
static DEFINE_PER_CPU(int, resched_irq);
|
||||
static DEFINE_PER_CPU(int, callfunc_irq);
|
||||
static DEFINE_PER_CPU(int, callfuncsingle_irq);
|
||||
static DEFINE_PER_CPU(int, debug_irq) = -1;
|
||||
|
||||
/*
|
||||
* Structure and data for smp_call_function(). This is designed to minimise
|
||||
* static memory requirements. It also looks cleaner.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(call_lock);
|
||||
|
||||
struct call_data_struct {
|
||||
void (*func) (void *info);
|
||||
void *info;
|
||||
atomic_t started;
|
||||
atomic_t finished;
|
||||
int wait;
|
||||
};
|
||||
|
||||
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
|
||||
|
||||
static struct call_data_struct *call_data;
|
||||
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
|
||||
|
||||
/*
|
||||
* Reschedule call back. Nothing to do,
|
||||
|
@ -128,6 +115,17 @@ static int xen_smp_intr_init(unsigned int cpu)
|
|||
goto fail;
|
||||
per_cpu(debug_irq, cpu) = rc;
|
||||
|
||||
callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
|
||||
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
|
||||
cpu,
|
||||
xen_call_function_single_interrupt,
|
||||
IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
|
||||
callfunc_name,
|
||||
NULL);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
per_cpu(callfuncsingle_irq, cpu) = rc;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@ -137,6 +135,9 @@ static int xen_smp_intr_init(unsigned int cpu)
|
|||
unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
|
||||
if (per_cpu(debug_irq, cpu) >= 0)
|
||||
unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
|
||||
if (per_cpu(callfuncsingle_irq, cpu) >= 0)
|
||||
unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -336,7 +337,7 @@ static void stop_self(void *v)
|
|||
|
||||
void xen_smp_send_stop(void)
|
||||
{
|
||||
smp_call_function(stop_self, NULL, 0, 0);
|
||||
smp_call_function(stop_self, NULL, 0);
|
||||
}
|
||||
|
||||
void xen_smp_send_reschedule(int cpu)
|
||||
|
@ -344,7 +345,6 @@ void xen_smp_send_reschedule(int cpu)
|
|||
xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
|
||||
}
|
||||
|
||||
|
||||
static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
|
||||
{
|
||||
unsigned cpu;
|
||||
|
@ -355,83 +355,42 @@ static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
|
|||
xen_send_IPI_one(cpu, vector);
|
||||
}
|
||||
|
||||
void xen_smp_send_call_function_ipi(cpumask_t mask)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
|
||||
|
||||
/* Make sure other vcpus get a chance to run if they need to. */
|
||||
for_each_cpu_mask(cpu, mask) {
|
||||
if (xen_vcpu_stolen(cpu)) {
|
||||
HYPERVISOR_sched_op(SCHEDOP_yield, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xen_smp_send_call_function_single_ipi(int cpu)
|
||||
{
|
||||
xen_send_IPI_mask(cpumask_of_cpu(cpu), XEN_CALL_FUNCTION_SINGLE_VECTOR);
|
||||
}
|
||||
|
||||
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
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
|
||||
*/
|
||||
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_interrupt();
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
irq_exit();
|
||||
|
||||
if (wait) {
|
||||
mb(); /* commit everything before setting finished */
|
||||
atomic_inc(&call_data->finished);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
|
||||
void *info, int wait)
|
||||
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
int cpus, cpu;
|
||||
bool yield;
|
||||
irq_enter();
|
||||
generic_smp_call_function_single_interrupt();
|
||||
__get_cpu_var(irq_stat).irq_call_count++;
|
||||
irq_exit();
|
||||
|
||||
/* Holding any lock stops cpus from going down. */
|
||||
spin_lock(&call_lock);
|
||||
|
||||
cpu_clear(smp_processor_id(), mask);
|
||||
|
||||
cpus = cpus_weight(mask);
|
||||
if (!cpus) {
|
||||
spin_unlock(&call_lock);
|
||||
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);
|
||||
|
||||
call_data = &data;
|
||||
mb(); /* write everything before IPI */
|
||||
|
||||
/* Send a message to other CPUs and wait for them to respond */
|
||||
xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
|
||||
|
||||
/* Make sure other vcpus get a chance to run if they need to. */
|
||||
yield = false;
|
||||
for_each_cpu_mask(cpu, mask)
|
||||
if (xen_vcpu_stolen(cpu))
|
||||
yield = true;
|
||||
|
||||
if (yield)
|
||||
HYPERVISOR_sched_op(SCHEDOP_yield, 0);
|
||||
|
||||
/* Wait for response */
|
||||
while (atomic_read(&data.started) != cpus ||
|
||||
(wait && atomic_read(&data.finished) != cpus))
|
||||
cpu_relax();
|
||||
|
||||
spin_unlock(&call_lock);
|
||||
|
||||
return 0;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
|
@ -55,13 +55,8 @@ void xen_smp_cpus_done(unsigned int max_cpus);
|
|||
|
||||
void xen_smp_send_stop(void);
|
||||
void xen_smp_send_reschedule(int cpu);
|
||||
int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
|
||||
int wait);
|
||||
int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
|
||||
int nonatomic, int wait);
|
||||
|
||||
int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
|
||||
void *info, int wait);
|
||||
void xen_smp_send_call_function_ipi(cpumask_t mask);
|
||||
void xen_smp_send_call_function_single_ipi(int cpu);
|
||||
|
||||
extern cpumask_t xen_cpu_initialized_map;
|
||||
|
||||
|
|
|
@ -1339,7 +1339,7 @@ static void smp_callback(void *v)
|
|||
static int acpi_processor_latency_notify(struct notifier_block *b,
|
||||
unsigned long l, void *v)
|
||||
{
|
||||
smp_call_function(smp_callback, NULL, 0, 1);
|
||||
smp_call_function(smp_callback, NULL, 1);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1249,7 +1249,7 @@ static void ipi_handler(void *null)
|
|||
|
||||
void global_cache_flush(void)
|
||||
{
|
||||
if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0)
|
||||
if (on_each_cpu(ipi_handler, NULL, 1) != 0)
|
||||
panic(PFX "timed out waiting for the other CPUs!\n");
|
||||
}
|
||||
EXPORT_SYMBOL(global_cache_flush);
|
||||
|
|
|
@ -215,7 +215,7 @@ static void showacpu(void *dummy)
|
|||
|
||||
static void sysrq_showregs_othercpus(struct work_struct *dummy)
|
||||
{
|
||||
smp_call_function(showacpu, NULL, 0, 0);
|
||||
smp_call_function(showacpu, NULL, 0);
|
||||
}
|
||||
|
||||
static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
|
||||
|
|
|
@ -340,7 +340,7 @@ static void smp_callback(void *v)
|
|||
static int cpuidle_latency_notify(struct notifier_block *b,
|
||||
unsigned long l, void *v)
|
||||
{
|
||||
smp_call_function(smp_callback, NULL, 0, 1);
|
||||
smp_call_function(smp_callback, NULL, 1);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -478,7 +478,7 @@ void __init lguest_arch_host_init(void)
|
|||
cpu_had_pge = 1;
|
||||
/* adjust_pge is a helper function which sets or unsets the PGE
|
||||
* bit on its CPU, depending on the argument (0 == unset). */
|
||||
on_each_cpu(adjust_pge, (void *)0, 0, 1);
|
||||
on_each_cpu(adjust_pge, (void *)0, 1);
|
||||
/* Turn off the feature in the global feature set. */
|
||||
clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ void __exit lguest_arch_host_fini(void)
|
|||
if (cpu_had_pge) {
|
||||
set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
|
||||
/* adjust_pge's argument "1" means set PGE. */
|
||||
on_each_cpu(adjust_pge, (void *)1, 0, 1);
|
||||
on_each_cpu(adjust_pge, (void *)1, 1);
|
||||
}
|
||||
put_online_cpus();
|
||||
}
|
||||
|
|
|
@ -1464,7 +1464,7 @@ static void invalidate_bh_lru(void *arg)
|
|||
|
||||
void invalidate_bh_lrus(void)
|
||||
{
|
||||
on_each_cpu(invalidate_bh_lru, NULL, 1, 1);
|
||||
on_each_cpu(invalidate_bh_lru, NULL, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
|
||||
|
||||
|
|
|
@ -47,12 +47,13 @@ extern struct cpuinfo_alpha cpu_data[NR_CPUS];
|
|||
extern int smp_num_cpus;
|
||||
#define cpu_possible_map cpu_present_map
|
||||
|
||||
int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, cpumask_t cpu);
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi(cpumask_t mask);
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
|
||||
#define hard_smp_processor_id() 0
|
||||
#define smp_call_function_on_cpu(func,info,retry,wait,cpu) ({ 0; })
|
||||
#define smp_call_function_on_cpu(func,info,wait,cpu) ({ 0; })
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
|
|
@ -101,6 +101,9 @@ extern void platform_cpu_die(unsigned int cpu);
|
|||
extern int platform_cpu_kill(unsigned int cpu);
|
||||
extern void platform_cpu_enable(unsigned int cpu);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi(cpumask_t mask);
|
||||
|
||||
/*
|
||||
* Local timer interrupt handling function (can be IPI'ed).
|
||||
*/
|
||||
|
|
|
@ -38,9 +38,6 @@ ia64_get_lid (void)
|
|||
return lid.f.id << 8 | lid.f.eid;
|
||||
}
|
||||
|
||||
extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
|
||||
void *info, int wait);
|
||||
|
||||
#define hard_smp_processor_id() ia64_get_lid()
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -124,11 +121,12 @@ extern void __init init_smp_config (void);
|
|||
extern void smp_do_timer (struct pt_regs *regs);
|
||||
|
||||
extern void smp_send_reschedule (int cpu);
|
||||
extern void lock_ipi_calllock(void);
|
||||
extern void unlock_ipi_calllock(void);
|
||||
extern void identify_siblings (struct cpuinfo_ia64 *);
|
||||
extern int is_multithreading_enabled(void);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi(cpumask_t mask);
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
|
||||
#define cpu_logical_id(i) 0
|
||||
|
|
|
@ -89,6 +89,9 @@ static __inline__ unsigned int num_booting_cpus(void)
|
|||
extern void smp_send_timer(void);
|
||||
extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi(cpumask_t mask);
|
||||
|
||||
#endif /* not __ASSEMBLY__ */
|
||||
|
||||
#define NO_PROC_ID (0xff) /* No processor magic marker */
|
||||
|
@ -104,6 +107,7 @@ extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
|
|||
#define LOCAL_TIMER_IPI (M32R_IRQ_IPI3-M32R_IRQ_IPI0)
|
||||
#define INVALIDATE_CACHE_IPI (M32R_IRQ_IPI4-M32R_IRQ_IPI0)
|
||||
#define CPU_BOOT_IPI (M32R_IRQ_IPI5-M32R_IRQ_IPI0)
|
||||
#define CALL_FUNC_SINGLE_IPI (M32R_IRQ_IPI6-M32R_IRQ_IPI0)
|
||||
|
||||
#define IPI_SHIFT (0)
|
||||
#define NR_IPIS (8)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -30,6 +30,9 @@ extern cpumask_t cpu_online_map;
|
|||
extern void smp_send_reschedule(int cpu);
|
||||
extern void smp_send_all_nop(void);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi(cpumask_t mask);
|
||||
|
||||
#endif /* !ASSEMBLY */
|
||||
|
||||
/*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue