summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorXin Xie <xxie@nvidia.com>2011-03-09 16:42:11 -0800
committerVarun Colbert <vcolbert@nvidia.com>2011-03-22 16:39:32 -0800
commit184b3ea36d5878b69c79bc190f4c395a40bc81e6 (patch)
treefc87aa6046b1c9446046fa09c45794b78780898d /arch
parent3218d13d46522296c952ce1fe23b95f99dbcaa50 (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.h4
-rw-r--r--arch/arm/kernel/entry-armv.S2
-rw-r--r--arch/arm/kernel/smp.c101
-rw-r--r--arch/arm/mach-tegra/include/mach/smp.h4
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);
}
/*