diff options
author | Xin Xie <xxie@nvidia.com> | 2011-03-09 16:42:11 -0800 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-03-22 16:39:32 -0800 |
commit | 184b3ea36d5878b69c79bc190f4c395a40bc81e6 (patch) | |
tree | fc87aa6046b1c9446046fa09c45794b78780898d /arch | |
parent | 3218d13d46522296c952ce1fe23b95f99dbcaa50 (diff) |
ARM: SMP: remove per_cpu based spinlock in do_IPI()
The spinlock used in the do_IPI function is declared in per_cpu section,
and it does not have the cache snooping which can cause the spinlock
failure.
This fix is based on the main kernel tree:
- ARM: SMP: avoid using bitmasks and locks for IPIs, use hardware
instead
commit 24480d980e9063b3ebd0dfdf2f396c305956c356
- ARM: SMP: remove IRQ-disabling for smp_cross_call()
commit 0df7095205cbf6ea1cdfe6254e0d6a3b823caa3b
BUG 798775
Change-Id: I6e03027cb3f586803a260e216c71fc2fd74d09f2
Reviewed-on: http://git-master/r/23779
Reviewed-by: Xin Xie <xxie@nvidia.com>
Tested-by: Xin Xie <xxie@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/smp.h | 4 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 101 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/smp.h | 4 |
4 files changed, 32 insertions, 79 deletions
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 3d05190797cb..da7e7ca53cc1 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -38,7 +38,7 @@ extern void show_ipi_list(struct seq_file *p); /* * Called from assembly code, this handles an IPI. */ -asmlinkage void do_IPI(struct pt_regs *regs); +asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); /* * Setup the set of possible CPUs (via set_cpu_possible) @@ -53,7 +53,7 @@ extern void smp_store_cpu_info(unsigned int cpuid); /* * Raise an IPI cross call on CPUs in callmap. */ -extern void smp_cross_call(const struct cpumask *mask); +extern void smp_cross_call(const struct cpumask *mask, int ipi); /* * Boot a secondary CPU, and assign it the specified idle task. diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 44cb9db8dd50..0db42186a769 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -47,7 +47,7 @@ * preserved from get_irqnr_and_base above */ test_for_ipi r0, r6, r5, lr - movne r0, sp + movne r1, sp adrne lr, BSYM(1b) bne do_IPI diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 40dc74f2b27f..7c5ddb111897 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -47,20 +47,15 @@ struct secondary_data secondary_data; /* * structures for inter-processor calls - * - A collection of single bit ipi messages. */ struct ipi_data { - spinlock_t lock; unsigned long ipi_count; - unsigned long bits; }; -static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { - .lock = SPIN_LOCK_UNLOCKED, -}; +static DEFINE_PER_CPU(struct ipi_data, ipi_data); enum ipi_msg_type { - IPI_TIMER, + IPI_TIMER = 2, IPI_RESCHEDULE, IPI_CALL_FUNC, IPI_CALL_FUNC_SINGLE, @@ -341,25 +336,10 @@ void __init smp_prepare_boot_cpu(void) static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) { - unsigned long flags; - unsigned int cpu; - - local_irq_save(flags); - - for_each_cpu(cpu, mask) { - struct ipi_data *ipi = &per_cpu(ipi_data, cpu); - - spin_lock(&ipi->lock); - ipi->bits |= 1 << msg; - spin_unlock(&ipi->lock); - } - /* * Call the platform specific cross-CPU call function. */ - smp_cross_call(mask); - - local_irq_restore(flags); + smp_cross_call(mask, msg); } void arch_send_call_function_ipi_mask(const struct cpumask *mask) @@ -490,14 +470,8 @@ static void ipi_cpu_stop(unsigned int cpu) /* * Main handler for inter-processor interrupts - * - * For ARM, the ipimask now only identifies a single - * category of IPI (Bit 1 IPIs have been replaced by a - * different mechanism): - * - * Bit 0 - Inter-processor function call */ -asmlinkage void __exception do_IPI(struct pt_regs *regs) +asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) { unsigned int cpu = smp_processor_id(); struct ipi_data *ipi = &per_cpu(ipi_data, cpu); @@ -505,56 +479,35 @@ asmlinkage void __exception do_IPI(struct pt_regs *regs) ipi->ipi_count++; - for (;;) { - unsigned long msgs; - - spin_lock(&ipi->lock); - msgs = ipi->bits; - ipi->bits = 0; - spin_unlock(&ipi->lock); - - if (!msgs) - break; - - do { - unsigned nextmsg; - - nextmsg = msgs & -msgs; - msgs &= ~nextmsg; - nextmsg = ffz(~nextmsg); - - switch (nextmsg) { - case IPI_TIMER: - ipi_timer(); - break; + switch (ipinr) { + case IPI_TIMER: + ipi_timer(); + break; - case IPI_RESCHEDULE: - /* - * nothing more to do - eveything is - * done on the interrupt return path - */ - break; + case IPI_RESCHEDULE: + /* + * nothing more to do - eveything is + * done on the interrupt return path + */ + break; - case IPI_CALL_FUNC: - generic_smp_call_function_interrupt(); - break; + case IPI_CALL_FUNC: + generic_smp_call_function_interrupt(); + break; - case IPI_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; + case IPI_CALL_FUNC_SINGLE: + generic_smp_call_function_single_interrupt(); + break; - case IPI_CPU_STOP: - ipi_cpu_stop(cpu); - break; + case IPI_CPU_STOP: + ipi_cpu_stop(cpu); + break; - default: - printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", - cpu, nextmsg); - break; - } - } while (msgs); + default: + printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", + cpu, ipinr); + break; } - set_irq_regs(old_regs); } diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h index cd6a3fc567f1..97b460134a5e 100644 --- a/arch/arm/mach-tegra/include/mach/smp.h +++ b/arch/arm/mach-tegra/include/mach/smp.h @@ -15,10 +15,10 @@ /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { dsb(); - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } /* |