From d33aadbf8e9ba0b844c2a4a03723969c913ab03a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 4 Nov 2010 18:22:51 +0100 Subject: ARM: 6468/1: backtrace: fix calculation of thread stack base When unwinding stack frames we must take care not to unwind areas of memory that lie outside of the known extent of the stack. This patch fixes an incorrect calculation of the stack base where THREAD_SIZE is added to the stack pointer after it has already been aligned to this value. Since the ALIGN macro performs this addition internally, we end up overshooting the base by 8k. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/stacktrace.c | 2 +- arch/arm/kernel/unwind.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 20b7411e47f..c2e112e1a05 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -28,7 +28,7 @@ int notrace unwind_frame(struct stackframe *frame) /* only go to a higher address on the stack */ low = frame->sp; - high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE; + high = ALIGN(low, THREAD_SIZE); /* check current frame pointer is within bounds */ if (fp < (low + 12) || fp + 4 >= high) diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 2a161765f6d..d2cb0b3c987 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -279,7 +279,7 @@ int unwind_frame(struct stackframe *frame) /* only go to a higher address on the stack */ low = frame->sp; - high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE; + high = ALIGN(low, THREAD_SIZE); pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, frame->pc, frame->lr, frame->sp); -- cgit v1.2.3-70-g09d2 From c3b291d98878a5f25fee56255bcfa420e85dff59 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 4 Nov 2010 18:23:50 +0100 Subject: ARM: 6469/1: perf-events: squash compiler warning armv7_pmnc_counter_has_overflowed can return uninitialised data if an invalid counter is specified. This patch fixes the code to return 0 in this case, which squashes the compiler warning from GCC 4.5. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 49643b1467e..07a50357492 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -1749,7 +1749,7 @@ static inline int armv7_pmnc_has_overflowed(unsigned long pmnc) static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc, enum armv7_counters counter) { - int ret; + int ret = 0; if (counter == ARMV7_CYCLE_COUNTER) ret = pmnc & ARMV7_FLAG_C; -- cgit v1.2.3-70-g09d2 From 235584b6f3b71bc1381be13a963a16f7107650cf Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 14:21:24 -0700 Subject: ARM: arch/arm/kernel/hw_breakpoint.c: Convert WARN_ON to WARN Message isn't printed by WARN_ON. Signed-off-by: Joe Perches Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 54593b0c241..21e3a4ab3b8 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -748,8 +748,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, breakpoint_handler(addr, regs); break; case ARM_ENTRY_ASYNC_WATCHPOINT: - WARN_ON("Asynchronous watchpoint exception taken. " - "Debugging results may be unreliable"); + WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); case ARM_ENTRY_SYNC_WATCHPOINT: watchpoint_handler(addr, regs); break; -- cgit v1.2.3-70-g09d2 From 69448c2a4d23e5883cbca21a173e3eb89f095746 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 5 Nov 2010 16:12:34 -0700 Subject: ARM: arch/arm/kernel/traps.c: Convert sprintf_symbol to %pS Signed-off-by: Joe Perches Signed-off-by: Russell King --- arch/arm/kernel/traps.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index cda78d59aa3..446aee97436 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -53,10 +53,7 @@ static void dump_mem(const char *, const char *, unsigned long, unsigned long); void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS - char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN]; - sprint_symbol(sym1, where); - sprint_symbol(sym2, from); - printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2); + printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif -- cgit v1.2.3-70-g09d2 From ad3b6993b9c5482e8a2ec5aed181538c921fdcbd Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 09:42:08 +0000 Subject: ARM: SMP: pass an ipi number to smp_cross_call() This allows us to use smp_cross_call() to trigger a number of different software generated interrupts, rather than combining them all on one SGI. Recover the SGI number via do_IPI. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/smp.h | 4 ++-- arch/arm/kernel/entry-armv.S | 2 +- arch/arm/kernel/smp.c | 10 ++-------- arch/arm/mach-msm/include/mach/smp.h | 4 ++-- arch/arm/mach-omap2/omap-smp.c | 2 +- arch/arm/mach-realview/include/mach/smp.h | 4 ++-- arch/arm/mach-realview/platsmp.c | 2 +- arch/arm/mach-s5pv310/include/mach/smp.h | 4 ++-- arch/arm/mach-s5pv310/platsmp.c | 2 +- arch/arm/mach-tegra/include/mach/smp.h | 4 ++-- arch/arm/mach-ux500/include/mach/smp.h | 4 ++-- arch/arm/mach-ux500/platsmp.c | 2 +- arch/arm/mach-vexpress/include/mach/smp.h | 4 ++-- arch/arm/mach-vexpress/platsmp.c | 2 +- arch/arm/plat-omap/include/plat/smp.h | 4 ++-- 15 files changed, 24 insertions(+), 30 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 3d05190797c..da7e7ca53cc 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 c09e3573c5d..955cf5f539e 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -48,7 +48,7 @@ */ ALT_SMP(test_for_ipi r0, r6, r5, lr) ALT_UP_B(9997f) - 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 8c195959025..7a236db03fb 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -404,7 +404,7 @@ static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) /* * Call the platform specific cross-CPU call function. */ - smp_cross_call(mask); + smp_cross_call(mask, 1); local_irq_restore(flags); } @@ -537,14 +537,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); diff --git a/arch/arm/mach-msm/include/mach/smp.h b/arch/arm/mach-msm/include/mach/smp.h index 3ff7bf5e679..a95f7b9efe3 100644 --- a/arch/arm/mach-msm/include/mach/smp.h +++ b/arch/arm/mach-msm/include/mach/smp.h @@ -31,9 +31,9 @@ #include -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 9e9f70e18e3..56a8bce247c 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -76,7 +76,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); /* * Now the secondary core is starting up let it run its diff --git a/arch/arm/mach-realview/include/mach/smp.h b/arch/arm/mach-realview/include/mach/smp.h index d3cd265cb05..d1aa70415a4 100644 --- a/arch/arm/mach-realview/include/mach/smp.h +++ b/arch/arm/mach-realview/include/mach/smp.h @@ -7,9 +7,9 @@ /* * 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 009265818d5..af3d9093390 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -116,7 +116,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * Use smp_cross_call() for this, since there's little * point duplicating the code here */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-s5pv310/include/mach/smp.h b/arch/arm/mach-s5pv310/include/mach/smp.h index b7ec252384f..2897747bcb0 100644 --- a/arch/arm/mach-s5pv310/include/mach/smp.h +++ b/arch/arm/mach-s5pv310/include/mach/smp.h @@ -14,9 +14,9 @@ extern void __iomem *gic_cpu_base_addr; /* * 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index d357c198ede..d474426f37b 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -97,7 +97,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h index d3cd265cb05..d1aa70415a4 100644 --- a/arch/arm/mach-tegra/include/mach/smp.h +++ b/arch/arm/mach-tegra/include/mach/smp.h @@ -7,9 +7,9 @@ /* * 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h index 197e8417375..bd57c50a5b8 100644 --- a/arch/arm/mach-ux500/include/mach/smp.h +++ b/arch/arm/mach-ux500/include/mach/smp.h @@ -18,8 +18,8 @@ extern void u8500_secondary_startup(void); /* * 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de78..b8987bd2124 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -78,7 +78,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-vexpress/include/mach/smp.h b/arch/arm/mach-vexpress/include/mach/smp.h index 5a6da4fd247..721be0f0311 100644 --- a/arch/arm/mach-vexpress/include/mach/smp.h +++ b/arch/arm/mach-vexpress/include/mach/smp.h @@ -7,8 +7,8 @@ /* * 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 670970699ba..276f916014c 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -92,7 +92,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/plat-omap/include/plat/smp.h b/arch/arm/plat-omap/include/plat/smp.h index ecd6a488c49..e5541e5388b 100644 --- a/arch/arm/plat-omap/include/plat/smp.h +++ b/arch/arm/plat-omap/include/plat/smp.h @@ -29,9 +29,9 @@ extern u32 omap_read_auxcoreboot0(void); /* * We use Soft 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) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif -- cgit v1.2.3-70-g09d2 From 24480d980e9063b3ebd0dfdf2f396c305956c356 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 09:54:18 +0000 Subject: ARM: SMP: avoid using bitmasks and locks for IPIs, use hardware instead Avoid using bitmasks and locks in the percpu area for IPIs, and instead use individual software generated interrupts to identify the reason for the IPI. This avoids the problems of having spinlocks in the percpu area. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 87 +++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 61 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 7a236db03fb..78d55c681a4 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -48,20 +48,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, @@ -389,22 +384,13 @@ 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, 1); + smp_cross_call(mask, msg); local_irq_restore(flags); } @@ -546,56 +532,35 @@ asmlinkage void __exception do_IPI(int ipinr, 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); } -- cgit v1.2.3-70-g09d2 From 0df7095205cbf6ea1cdfe6254e0d6a3b823caa3b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 19:16:56 +0000 Subject: ARM: SMP: remove IRQ-disabling for smp_cross_call() As we've now removed the spinlock and bitmask, we have nothing left which requires interrupts to be disabled when sending an IPI. All current IPI-sending implementations use the GIC, which also does not require interrupts disabled when calling gic_raise_softirq(). Remove the now unnecessary IRQ disable. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 78d55c681a4..4878e51561f 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -383,16 +383,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; - - local_irq_save(flags); - /* * Call the platform specific cross-CPU call function. */ smp_cross_call(mask, msg); - - local_irq_restore(flags); } void arch_send_call_function_ipi_mask(const struct cpumask *mask) -- cgit v1.2.3-70-g09d2 From e3fbb087650df130788d8e3ac29875ee56819249 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:47:19 +0000 Subject: ARM: SMP: remove send_ipi_message() send_ipi_message() does nothing except call smp_cross_call(). As this is a static function, nothing external to this file calls it, so we can easily clean up this now unnecessary indirection. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 4878e51561f..3772cfc6953 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -381,22 +381,14 @@ void __init smp_prepare_boot_cpu(void) per_cpu(cpu_data, cpu).idle = current; } -static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) -{ - /* - * Call the platform specific cross-CPU call function. - */ - smp_cross_call(mask, msg); -} - void arch_send_call_function_ipi_mask(const struct cpumask *mask) { - send_ipi_message(mask, IPI_CALL_FUNC); + smp_cross_call(mask, IPI_CALL_FUNC); } void arch_send_call_function_single_ipi(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); + smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } void show_ipi_list(struct seq_file *p) @@ -454,7 +446,7 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast(const struct cpumask *mask) { - send_ipi_message(mask, IPI_TIMER); + smp_cross_call(mask, IPI_TIMER); } #else #define smp_timer_broadcast NULL @@ -560,7 +552,7 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) void smp_send_reschedule(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); + smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } void smp_send_stop(void) @@ -568,7 +560,7 @@ void smp_send_stop(void) cpumask_t mask = cpu_online_map; cpu_clear(smp_processor_id(), mask); if (!cpus_empty(mask)) - send_ipi_message(&mask, IPI_CPU_STOP); + smp_cross_call(&mask, IPI_CPU_STOP); } /* -- cgit v1.2.3-70-g09d2 From ec405ea9fe5fdeb40824edba7082803b3e98f176 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 13:38:06 +0000 Subject: ARM: include local timer irq stats only when local timers configured Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 2 ++ arch/arm/kernel/irq.c | 2 ++ arch/arm/kernel/smp.c | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 12 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 6d7485aff95..522fb23241a 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -7,7 +7,9 @@ typedef struct { unsigned int __softirq_pending; +#ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 36ad3be4692..ea29721ba34 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -93,6 +93,8 @@ unlock: #endif #ifdef CONFIG_SMP show_ipi_list(p); +#endif +#ifdef CONFIG_LOCAL_TIMERS show_local_irqs(p); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 3772cfc6953..36d4b9140dc 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -403,18 +403,6 @@ void show_ipi_list(struct seq_file *p) seq_putc(p, '\n'); } -void show_local_irqs(struct seq_file *p) -{ - unsigned int cpu; - - seq_printf(p, "LOC: "); - - for_each_present_cpu(cpu) - seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); - - seq_putc(p, '\n'); -} - /* * Timer (local or broadcast) support */ @@ -441,6 +429,18 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) set_irq_regs(old_regs); } + +void show_local_irqs(struct seq_file *p) +{ + unsigned int cpu; + + seq_printf(p, "LOC: "); + + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); + + seq_putc(p, '\n'); +} #endif #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -- cgit v1.2.3-70-g09d2 From 46c48f222f568decb881a552caa1c8f9c96c521e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:15:03 +0000 Subject: ARM: SMP: provide accessors for irq_stat data Provide __inc_irq_stat() and __get_irq_stat() to increment and read the irq stat counters. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 3 +++ arch/arm/kernel/smp.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 522fb23241a..923eaa1ba83 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -14,6 +14,9 @@ typedef struct { #include /* Standard mappings for irq_cpustat_t above */ +#define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ +#define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) + #if NR_IRQS > 512 #define HARDIRQ_BITS 10 #elif NR_IRQS > 256 diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 36d4b9140dc..24131264ec2 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -423,7 +423,7 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) int cpu = smp_processor_id(); if (local_timer_ack()) { - irq_stat[cpu].local_timer_irqs++; + __inc_irq_stat(cpu, local_timer_irqs); ipi_timer(); } @@ -437,7 +437,7 @@ void show_local_irqs(struct seq_file *p) seq_printf(p, "LOC: "); for_each_present_cpu(cpu) - seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); + seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); seq_putc(p, '\n'); } -- cgit v1.2.3-70-g09d2 From cab8c6f3053c1b147bba825844c8e208f8b3b9f4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:20:41 +0000 Subject: ARM: SMP: move ipi_count into irq_stat structure Move the ipi_count into irq_stat, which allows the ipi_data structure to be entirely removed. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 3 +++ arch/arm/kernel/smp.c | 14 ++------------ 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 923eaa1ba83..824b08aa3f7 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -10,6 +10,9 @@ typedef struct { #ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; #endif +#ifdef CONFIG_SMP + unsigned int ipi_irqs; +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 24131264ec2..65b5ba86780 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -46,15 +46,6 @@ */ struct secondary_data secondary_data; -/* - * structures for inter-processor calls - */ -struct ipi_data { - unsigned long ipi_count; -}; - -static DEFINE_PER_CPU(struct ipi_data, ipi_data); - enum ipi_msg_type { IPI_TIMER = 2, IPI_RESCHEDULE, @@ -398,7 +389,7 @@ void show_ipi_list(struct seq_file *p) seq_puts(p, "IPI:"); for_each_present_cpu(cpu) - seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count); + seq_printf(p, " %10u", __get_irq_stat(cpu, ipi_irqs)); seq_putc(p, '\n'); } @@ -513,10 +504,9 @@ static void ipi_cpu_stop(unsigned int cpu) 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); struct pt_regs *old_regs = set_irq_regs(regs); - ipi->ipi_count++; + __inc_irq_stat(cpu, ipi_irqs); switch (ipinr) { case IPI_TIMER: -- cgit v1.2.3-70-g09d2 From f13cd4170ee789f63b3c9585c1ae34e028bd549d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:33:51 +0000 Subject: ARM: fix /proc/interrupts formatting As per x86, align the initial column according to how many IRQs we have. Also, provide an english explaination for the 'LOC:' and 'IPI:' lines. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/mach/irq.h | 2 +- arch/arm/include/asm/smp.h | 4 ++-- arch/arm/kernel/fiq.c | 5 +++-- arch/arm/kernel/irq.c | 16 ++++++++++------ arch/arm/kernel/smp.c | 14 +++++++------- 5 files changed, 23 insertions(+), 18 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h index ce3eee9fe26..2bc47fb94d5 100644 --- a/arch/arm/include/asm/mach/irq.h +++ b/arch/arm/include/asm/mach/irq.h @@ -20,7 +20,7 @@ struct seq_file; extern unsigned int arch_nr_irqs; extern void (*init_arch_irq)(void); extern void init_FIQ(void); -extern int show_fiq_list(struct seq_file *, void *); +extern int show_fiq_list(struct seq_file *, int); /* * This is for easy migration, but should be changed in the source diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index da7e7ca53cc..f93d0a63701 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -33,7 +33,7 @@ struct seq_file; /* * generate IPI list text */ -extern void show_ipi_list(struct seq_file *p); +extern void show_ipi_list(struct seq_file *, int); /* * Called from assembly code, this handles an IPI. @@ -97,6 +97,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); /* * show local interrupt info */ -extern void show_local_irqs(struct seq_file *); +extern void show_local_irqs(struct seq_file *, int); #endif /* ifndef __ASM_ARM_SMP_H */ diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6ff7919613d..47837b85c07 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -67,10 +67,11 @@ static struct fiq_handler default_owner = { static struct fiq_handler *current_fiq = &default_owner; -int show_fiq_list(struct seq_file *p, void *v) +int show_fiq_list(struct seq_file *p, int prec) { if (current_fiq != &default_owner) - seq_printf(p, "FIQ: %s\n", current_fiq->name); + seq_printf(p, "%*s: %s\n", prec, "FIQ", + current_fiq->name); return 0; } diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ea29721ba34..4e7a7d27221 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -57,11 +57,15 @@ int show_interrupts(struct seq_file *p, void *v) struct irq_desc *desc; struct irqaction * action; unsigned long flags; + int prec, n; + + for (prec = 3, n = 1000; prec < 10 && n <= nr_irqs; prec++) + n *= 10; if (i == 0) { char cpuname[12]; - seq_printf(p, " "); + seq_printf(p, "%*s ", prec, ""); for_each_present_cpu(cpu) { sprintf(cpuname, "CPU%d", cpu); seq_printf(p, " %10s", cpuname); @@ -76,7 +80,7 @@ int show_interrupts(struct seq_file *p, void *v) if (!action) goto unlock; - seq_printf(p, "%3d: ", i); + seq_printf(p, "%*d: ", prec, i); for_each_present_cpu(cpu) seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); seq_printf(p, " %10s", desc->chip->name ? : "-"); @@ -89,15 +93,15 @@ unlock: raw_spin_unlock_irqrestore(&desc->lock, flags); } else if (i == nr_irqs) { #ifdef CONFIG_FIQ - show_fiq_list(p, v); + show_fiq_list(p, prec); #endif #ifdef CONFIG_SMP - show_ipi_list(p); + show_ipi_list(p, prec); #endif #ifdef CONFIG_LOCAL_TIMERS - show_local_irqs(p); + show_local_irqs(p, prec); #endif - seq_printf(p, "Err: %10lu\n", irq_err_count); + seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); } return 0; } diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 65b5ba86780..269237ed76a 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -382,16 +382,16 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } -void show_ipi_list(struct seq_file *p) +void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu; - seq_puts(p, "IPI:"); + seq_printf(p, "%*s: ", prec, "IPI"); for_each_present_cpu(cpu) - seq_printf(p, " %10u", __get_irq_stat(cpu, ipi_irqs)); + seq_printf(p, "%10u ", __get_irq_stat(cpu, ipi_irqs)); - seq_putc(p, '\n'); + seq_printf(p, " Inter-processor interrupts\n"); } /* @@ -421,16 +421,16 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) set_irq_regs(old_regs); } -void show_local_irqs(struct seq_file *p) +void show_local_irqs(struct seq_file *p, int prec) { unsigned int cpu; - seq_printf(p, "LOC: "); + seq_printf(p, "%*s: ", prec, "LOC"); for_each_present_cpu(cpu) seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); - seq_putc(p, '\n'); + seq_printf(p, " Local timer interrupts\n"); } #endif -- cgit v1.2.3-70-g09d2 From 4a88abd7b48e8ec8084b1252d0f5ebdab43c2508 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:40:29 +0000 Subject: ARM: SMP: provide individual IPI interrupt statistics This separates out the individual IPI interrupt counts from the total IPI count, which allows better visibility of what IPIs are being used for. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 4 +++- arch/arm/kernel/irq.c | 5 +++++ arch/arm/kernel/smp.c | 25 +++++++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 824b08aa3f7..c52e2507c9e 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -5,13 +5,15 @@ #include #include +#define NR_IPI 5 + typedef struct { unsigned int __softirq_pending; #ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; #endif #ifdef CONFIG_SMP - unsigned int ipi_irqs; + unsigned int ipi_irqs[NR_IPI]; #endif } ____cacheline_aligned irq_cpustat_t; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 4e7a7d27221..6276f01df9e 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -62,6 +62,11 @@ int show_interrupts(struct seq_file *p, void *v) for (prec = 3, n = 1000; prec < 10 && n <= nr_irqs; prec++) n *= 10; +#ifdef CONFIG_SMP + if (prec < 4) + prec = 4; +#endif + if (i == 0) { char cpuname[12]; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 269237ed76a..fa0c5f6e158 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -382,16 +382,28 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } +static const char *ipi_types[NR_IPI] = { +#define S(x,s) [x - IPI_TIMER] = s + S(IPI_TIMER, "Timer broadcast interrupts"), + S(IPI_RESCHEDULE, "Rescheduling interrupts"), + S(IPI_CALL_FUNC, "Function call interrupts"), + S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), + S(IPI_CPU_STOP, "CPU stop interrupts"), +}; + void show_ipi_list(struct seq_file *p, int prec) { - unsigned int cpu; + unsigned int cpu, i; - seq_printf(p, "%*s: ", prec, "IPI"); + for (i = 0; i < NR_IPI; i++) { + seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); - for_each_present_cpu(cpu) - seq_printf(p, "%10u ", __get_irq_stat(cpu, ipi_irqs)); + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", + __get_irq_stat(cpu, ipi_irqs[i])); - seq_printf(p, " Inter-processor interrupts\n"); + seq_printf(p, " %s\n", ipi_types[i]); + } } /* @@ -506,7 +518,8 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) unsigned int cpu = smp_processor_id(); struct pt_regs *old_regs = set_irq_regs(regs); - __inc_irq_stat(cpu, ipi_irqs); + if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI) + __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]); switch (ipinr) { case IPI_TIMER: -- cgit v1.2.3-70-g09d2 From b54992fe1b4bad7b7488d58b8696e4e8974fdab0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:46:46 +0000 Subject: ARM: SMP: collect IPI and local timer IRQs for /proc/stat The IPI and local timer interrupts weren't being properly accounted for in /proc/stat. Collect them from the irq_stat structure, and return their sum. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 8 ++++++++ arch/arm/kernel/smp.c | 15 +++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index c52e2507c9e..89ad1805e57 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -22,6 +22,14 @@ typedef struct { #define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ #define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) +#ifdef CONFIG_SMP +u64 smp_irq_stat_cpu(unsigned int cpu); +#else +#define smp_irq_stat_cpu(cpu) 0 +#endif + +#define arch_irq_stat_cpu smp_irq_stat_cpu + #if NR_IRQS > 512 #define HARDIRQ_BITS 10 #elif NR_IRQS > 256 diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index fa0c5f6e158..1de3e13a42a 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -406,6 +406,21 @@ void show_ipi_list(struct seq_file *p, int prec) } } +u64 smp_irq_stat_cpu(unsigned int cpu) +{ + u64 sum = 0; + int i; + + for (i = 0; i < NR_IPI; i++) + sum += __get_irq_stat(cpu, ipi_irqs[i]); + +#ifdef CONFIG_LOCAL_TIMERS + sum += __get_irq_stat(cpu, local_timer_irqs); +#endif + + return sum; +} + /* * Timer (local or broadcast) support */ -- cgit v1.2.3-70-g09d2 From 0eb0511d176534674600a1986c3c766756288908 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 22 Nov 2010 12:06:28 +0000 Subject: ARM: SMP: use more sane register allocation for __fixup_smp_on_up Use r0,r3-r6 rather than r0,r3,r4,r6,r7, which makes it easier to understand which registers can be modified. Also document which registers hold values which must be preserved. Signed-off-by: Russell King --- arch/arm/kernel/head.S | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index dd6b369ac69..fd94e4e82fc 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -89,6 +89,11 @@ ENTRY(stext) bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a' + + /* + * r1 = machine no, r2 = atags, + * r8 = machinfo, r9 = cpuid, r10 = procinfo + */ bl __vet_atags #ifdef CONFIG_SMP_ON_UP bl __fixup_smp @@ -381,19 +386,19 @@ ENDPROC(__turn_mmu_on) #ifdef CONFIG_SMP_ON_UP __fixup_smp: - mov r7, #0x00070000 - orr r6, r7, #0xff000000 @ mask 0xff070000 - orr r7, r7, #0x41000000 @ val 0x41070000 - and r0, r9, r6 - teq r0, r7 @ ARM CPU and ARMv6/v7? + mov r4, #0x00070000 + orr r3, r4, #0xff000000 @ mask 0xff070000 + orr r4, r4, #0x41000000 @ val 0x41070000 + and r0, r9, r3 + teq r0, r4 @ ARM CPU and ARMv6/v7? bne __fixup_smp_on_up @ no, assume UP - orr r6, r6, #0x0000ff00 - orr r6, r6, #0x000000f0 @ mask 0xff07fff0 - orr r7, r7, #0x0000b000 - orr r7, r7, #0x00000020 @ val 0x4107b020 - and r0, r9, r6 - teq r0, r7 @ ARM 11MPCore? + orr r3, r3, #0x0000ff00 + orr r3, r3, #0x000000f0 @ mask 0xff07fff0 + orr r4, r4, #0x0000b000 + orr r4, r4, #0x00000020 @ val 0x4107b020 + and r0, r9, r3 + teq r0, r4 @ ARM 11MPCore? moveq pc, lr @ yes, assume SMP mrc p15, 0, r0, c0, c0, 5 @ read MPIDR @@ -402,13 +407,13 @@ __fixup_smp: __fixup_smp_on_up: adr r0, 1f - ldmia r0, {r3, r6, r7} + ldmia r0, {r3 - r5} sub r3, r0, r3 - add r6, r6, r3 - add r7, r7, r3 -2: cmp r6, r7 - ldmia r6!, {r0, r4} - strlo r4, [r0, r3] + add r4, r4, r3 + add r5, r5, r3 +2: cmp r4, r5 + ldmia r4!, {r0, r6} + strlo r6, [r0, r3] blo 2b mov pc, lr ENDPROC(__fixup_smp) -- cgit v1.2.3-70-g09d2 From 28e18293cf0f8d23a0950d7b1d2212d11af494dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 09:53:54 +0000 Subject: ARM: SMP: ensure smp_send_stop() waits for CPUs to stop Wait for CPUs to indicate that they've stopped, after sending the stop IPI, rather than blindly continuing on and hoping that they've stopped in time. Print a warning if we fail to stop the other CPUs. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 1de3e13a42a..64f2d198c76 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -575,10 +575,22 @@ void smp_send_reschedule(int cpu) void smp_send_stop(void) { - cpumask_t mask = cpu_online_map; - cpu_clear(smp_processor_id(), mask); - if (!cpus_empty(mask)) + unsigned long timeout; + + if (num_online_cpus() > 1) { + cpumask_t mask = cpu_online_map; + cpu_clear(smp_processor_id(), mask); + smp_cross_call(&mask, IPI_CPU_STOP); + } + + /* Wait up to one second for other CPUs to stop */ + timeout = USEC_PER_SEC; + while (num_online_cpus() > 1 && timeout--) + udelay(1); + + if (num_online_cpus() > 1) + pr_warning("SMP: failed to stop secondary CPUs\n"); } /* -- cgit v1.2.3-70-g09d2 From 05c74a6cbcfb416286a947668ba32f63d99fe74a Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 11:09:48 +0000 Subject: ARM: SMP: consolidate the common parts of smp_prepare_cpus() There is a certain amount of smp_prepare_cpus() which doesn't belong in the platform support code - that is, code which is invariant to the SMP implementation. Move this code into arch/arm/kernel/smp.c, and add a platform_ prefix to the original function. Signed-off-by: Russell King --- arch/arm/include/asm/smp.h | 9 ++++---- arch/arm/kernel/smp.c | 49 +++++++++++++++++++++++++++++++--------- arch/arm/mach-omap2/omap-smp.c | 33 ++++++--------------------- arch/arm/mach-realview/platsmp.c | 41 +++++++++------------------------ arch/arm/mach-s5pv310/platsmp.c | 35 ++++++---------------------- arch/arm/mach-tegra/platsmp.c | 18 ++------------- arch/arm/mach-ux500/platsmp.c | 24 +++----------------- arch/arm/mach-vexpress/platsmp.c | 43 ++++++++--------------------------- 8 files changed, 83 insertions(+), 169 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index f93d0a63701..96ed521f240 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -45,10 +45,6 @@ asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); */ extern void smp_init_cpus(void); -/* - * Move global data into per-processor storage. - */ -extern void smp_store_cpu_info(unsigned int cpuid); /* * Raise an IPI cross call on CPUs in callmap. @@ -72,6 +68,11 @@ asmlinkage void secondary_start_kernel(void); */ extern void platform_secondary_init(unsigned int cpu); +/* + * Initialize cpu_possible map, and enable coherency + */ +extern void platform_smp_prepare_cpus(unsigned int); + /* * Initial data for bringing up a secondary CPU. */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 64f2d198c76..c66f2d3f65d 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -281,6 +281,17 @@ void __ref cpu_die(void) } #endif /* CONFIG_HOTPLUG_CPU */ +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static void __cpuinit smp_store_cpu_info(unsigned int cpuid) +{ + struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); + + cpu_info->loops_per_jiffy = loops_per_jiffy; +} + /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. @@ -339,17 +350,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) cpu_idle(); } -/* - * Called by both boot and secondaries to move global data into - * per-processor storage. - */ -void __cpuinit smp_store_cpu_info(unsigned int cpuid) -{ - struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); - - cpu_info->loops_per_jiffy = loops_per_jiffy; -} - void __init smp_cpus_done(unsigned int max_cpus) { int cpu; @@ -372,6 +372,33 @@ void __init smp_prepare_boot_cpu(void) per_cpu(cpu_data, cpu).idle = current; } +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + + smp_store_cpu_info(smp_processor_id()); + + /* + * are we trying to boot more cores than exist? + */ + if (max_cpus > ncores) + max_cpus = ncores; + + if (max_cpus > 1) { + /* + * Enable the local timer or broadcast device for the + * boot CPU, but only if we have more than one CPU. + */ + percpu_timer_setup(); + + /* + * Initialise the SCU if there are more than one CPU + * and let them know where to start. + */ + platform_smp_prepare_cpus(max_cpus); + } +} + void arch_send_call_function_ipi_mask(const struct cpumask *mask) { smp_cross_call(mask, IPI_CALL_FUNC); diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 405a8fc5330..3c3d6796c97 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -123,20 +122,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -144,18 +133,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - /* - * Initialise the SCU and wake up the secondary core using - * wakeup_secondary(). - */ - scu_enable(scu_base); - wakeup_secondary(); - } + /* + * Initialise the SCU and wake up the secondary core using + * wakeup_secondary(). + */ + scu_enable(scu_base); + wakeup_secondary(); } diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index ef3cc86f514..380562cd658 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -147,20 +146,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -168,22 +157,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The BootMonitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), - __io_address(REALVIEW_SYS_FLAGSSET)); - } + scu_enable(scu_base_addr()); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The BootMonitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), + __io_address(REALVIEW_SYS_FLAGSSET)); } diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index 560ada83b0b..51c44d4c989 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -142,18 +141,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* are we trying to boot more cores than exist? */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -161,25 +152,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); + scu_enable(scu_base_addr()); + /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. */ - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM); - } } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 66d0634e7a9..b66a0c2d990 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -127,20 +126,10 @@ void __init smp_init_cpus(void) cpu_set(i, cpu_possible_map); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = scu_get_core_count(scu_base); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -148,8 +137,5 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - percpu_timer_setup(); - scu_enable(scu_base); - } + scu_enable(scu_base); } diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index fd40fa17591..458a288981c 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -138,20 +137,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -159,13 +148,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - scu_enable(__io_address(UX500_SCU_BASE)); - wakeup_secondary(); - } + scu_enable(__io_address(UX500_SCU_BASE)); + wakeup_secondary(); } diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index b5a75868366..a0341d14ff2 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -136,20 +135,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -157,27 +146,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); + scu_enable(scu_base_addr()); + /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. */ - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); - writel(BSYM(virt_to_phys(vexpress_secondary_startup)), - MMIO_P2V(V2M_SYS_FLAGSSET)); - } + writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); + writel(BSYM(virt_to_phys(vexpress_secondary_startup)), + MMIO_P2V(V2M_SYS_FLAGSSET)); } -- cgit v1.2.3-70-g09d2 From 2c0136dba4e43b0916ccc9ecc7f11e6d6b73f046 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 15:00:49 +0000 Subject: ARM: SMP: consolidate trace_hardirqs_off() into common SMP code All platforms call trace_hardirqs_off() in their secondary startup code, so move this into the core SMP code - it doesn't need to be in the per-platform code. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 1 + arch/arm/mach-omap2/omap-smp.c | 2 -- arch/arm/mach-realview/platsmp.c | 2 -- arch/arm/mach-s5pv310/platsmp.c | 2 -- arch/arm/mach-tegra/platsmp.c | 2 -- arch/arm/mach-ux500/platsmp.c | 2 -- arch/arm/mach-vexpress/platsmp.c | 2 -- 7 files changed, 1 insertion(+), 12 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c66f2d3f65d..a30c4094db3 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -317,6 +317,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void) cpu_init(); preempt_disable(); + trace_hardirqs_off(); /* * Give the platform a chance to do its own initialisation. diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 3c3d6796c97..9fed631ba04 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -32,8 +32,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * If any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 380562cd658..226c63102a0 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -53,8 +53,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index 51c44d4c989..18aaf5f5403 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -46,8 +46,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index b66a0c2d990..c729cd72cc3 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -40,8 +40,6 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 458a288981c..ddedbc80c41 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -31,8 +31,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index a0341d14ff2..d7e0cb994e9 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -43,8 +43,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled -- cgit v1.2.3-70-g09d2 From 3c030beabf937b1d3b4ecaedfd1fb2f1e2aa0c70 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 11:07:35 +0000 Subject: ARM: CPU hotplug: move cpu_killed completion to core code We always need to wait for the dying CPU to reach a safe state before taking it down, irrespective of the requirements of the platform. Move the completion code into the ARM SMP hotplug code rather than having each platform re-implement this. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 14 +++++++++++++- arch/arm/mach-omap2/omap-hotplug.c | 8 ++------ arch/arm/mach-realview/hotplug.c | 8 +------- arch/arm/mach-s5pv310/hotplug.c | 8 +------- arch/arm/mach-tegra/hotplug.c | 8 +------- arch/arm/mach-ux500/hotplug.c | 8 +------- 6 files changed, 19 insertions(+), 35 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index a30c4094db3..8c81ff9b373 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -238,12 +239,20 @@ int __cpu_disable(void) return 0; } +static DECLARE_COMPLETION(cpu_died); + /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpu_die(unsigned int cpu) { + if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { + pr_err("CPU%u: cpu didn't die\n", cpu); + return; + } + printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); + if (!platform_cpu_kill(cpu)) printk("CPU%u: unable to kill\n", cpu); } @@ -263,9 +272,12 @@ void __ref cpu_die(void) local_irq_disable(); idle_task_exit(); + /* Tell __cpu_die() that this CPU is now safe to dispose of */ + complete(&cpu_died); + /* * actual CPU shutdown procedure is at least platform (if not - * CPU) specific + * CPU) specific. */ platform_cpu_die(cpu); diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index 6cee456ca54..ace979d74bf 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -17,16 +17,13 @@ #include #include #include -#include #include #include -static DECLARE_COMPLETION(cpu_killed); - int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -42,8 +39,7 @@ void platform_cpu_die(unsigned int cpu) this_cpu, cpu); BUG(); } - pr_notice("CPU%u: shutdown\n", cpu); - complete(&cpu_killed); + flush_cache_all(); dsb(); diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index f95521a5e5c..7d58c16c83a 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -11,14 +11,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -95,7 +92,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -115,9 +112,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c index 03652c3605f..d7be70ac753 100644 --- a/arch/arm/mach-s5pv310/hotplug.c +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -13,14 +13,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -98,7 +95,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -118,9 +115,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 8e7f115aa21..ecaa41ce497 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -11,12 +11,9 @@ #include #include #include -#include #include -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -94,7 +91,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -114,9 +111,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index b782a03024b..7a4890b96e5 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c @@ -11,14 +11,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void platform_do_lowpower(unsigned int cpu) { flush_cache_all(); @@ -38,7 +35,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -58,9 +55,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* directly enter low power state, skipping secure registers */ platform_do_lowpower(cpu); } -- cgit v1.2.3-70-g09d2 From f36d340122ae8744e64af0a92a6f77b97542c0a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 12:21:30 +0000 Subject: ARM: CPU hotplug: ensure correct ordering of unplug Don't call idle_task_exit() with interrupts disabled, and ensure that we have a memory barrier after interrupts are disabled but before signalling that this CPU has shut down. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8c81ff9b373..1a1c5e2b3ef 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -269,9 +269,11 @@ void __ref cpu_die(void) { unsigned int cpu = smp_processor_id(); - local_irq_disable(); idle_task_exit(); + local_irq_disable(); + mb(); + /* Tell __cpu_die() that this CPU is now safe to dispose of */ complete(&cpu_died); -- cgit v1.2.3-70-g09d2 From ed3768a8d9dc2d345d4f27eb44ee1e4825056c08 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Wed, 1 Dec 2010 15:39:23 +0100 Subject: ARM: 6516/1: Allow SMP_ON_UP to work with Thumb-2 kernels. * __fixup_smp_on_up has been modified with support for the THUMB2_KERNEL case. For THUMB2_KERNEL only, fixups are split into halfwords in case of misalignment, since we can't rely on unaligned accesses working before turning the MMU on. No attempt is made to optimise the aligned case, since the number of fixups is typically small, and it seems best to keep the code as simple as possible. * Add a rotate in the fixup_smp code in order to support CPU_BIG_ENDIAN, as suggested by Nicolas Pitre. * Add an assembly-time sanity-check to ALT_UP() to ensure that the content really is the right size (4 bytes). (No check is done for ALT_SMP(). Possibly, this could be fixed by splitting the two uses ot ALT_SMP() (ALT_SMP...SMP_UP versus ALT_SMP...SMP_UP_B) into two macros. In the first case, ALT_SMP needs to expand to >= 4 bytes, not == 4.) * smp_mpidr.h (which implements ALT_SMP()/ALT_UP() manually due to macro limitations) has not been modified: the affected instruction (mov) has no 16-bit encoding, so the correct instruction size is satisfied in this case. * A "mode" parameter has been added to smp_dmb: smp_dmb arm @ assumes 4-byte instructions (for ARM code, e.g. kuser) smp_dmb @ uses W() to ensure 4-byte instructions for ALT_SMP() This avoids assembly failures due to use of W() inside smp_dmb, when assembling pure-ARM code in the vectors page. There might be a better way to achieve this. * Kconfig: make SMP_ON_UP depend on (!THUMB2_KERNEL || !BIG_ENDIAN) i.e., THUMB2_KERNEL is now supported, but only if !BIG_ENDIAN (The fixup code for Thumb-2 currently assumes little-endian order.) Tested using a single generic realview kernel on: ARM RealView PB-A8 (CONFIG_THUMB2_KERNEL={n,y}) ARM RealView PBX-A9 (SMP) Signed-off-by: Dave Martin Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig | 2 +- arch/arm/include/asm/assembler.h | 22 +++++++++++++++++++--- arch/arm/kernel/entry-armv.S | 4 ++-- arch/arm/kernel/head.S | 13 ++++++++++--- 4 files changed, 32 insertions(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index db524e75c4a..290a4b57617 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1229,7 +1229,7 @@ config SMP config SMP_ON_UP bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)" depends on EXPERIMENTAL - depends on SMP && !XIP && !THUMB2_KERNEL + depends on SMP && !XIP default y help SMP kernels contain instructions which fail on non-SMP processors. diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 749bb662240..72d3389e9c1 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -157,16 +157,24 @@ #ifdef CONFIG_SMP #define ALT_SMP(instr...) \ 9998: instr +/* + * Note: if you get assembler errors from ALT_UP() when building with + * CONFIG_THUMB2_KERNEL, you almost certainly need to use + * ALT_SMP( W(instr) ... ) + */ #define ALT_UP(instr...) \ .pushsection ".alt.smp.init", "a" ;\ .long 9998b ;\ - instr ;\ +9997: instr ;\ + .if . - 9997b != 4 ;\ + .error "ALT_UP() content must assemble to exactly 4 bytes";\ + .endif ;\ .popsection #define ALT_UP_B(label) \ .equ up_b_offset, label - 9998b ;\ .pushsection ".alt.smp.init", "a" ;\ .long 9998b ;\ - b . + up_b_offset ;\ + W(b) . + up_b_offset ;\ .popsection #else #define ALT_SMP(instr...) @@ -177,16 +185,24 @@ /* * SMP data memory barrier */ - .macro smp_dmb + .macro smp_dmb mode #ifdef CONFIG_SMP #if __LINUX_ARM_ARCH__ >= 7 + .ifeqs "\mode","arm" ALT_SMP(dmb) + .else + ALT_SMP(W(dmb)) + .endif #elif __LINUX_ARM_ARCH__ == 6 ALT_SMP(mcr p15, 0, r0, c7, c10, 5) @ dmb #else #error Incompatible SMP platform #endif + .ifeqs "\mode","arm" ALT_UP(nop) + .else + ALT_UP(W(nop)) + .endif #endif .endm diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 955cf5f539e..7f22a11a510 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -842,7 +842,7 @@ __kuser_helper_start: */ __kuser_memory_barrier: @ 0xffff0fa0 - smp_dmb + smp_dmb arm usr_ret lr .align 5 @@ -959,7 +959,7 @@ kuser_cmpxchg_fixup: #else - smp_dmb + smp_dmb arm 1: ldrex r3, [r2] subs r3, r3, r0 strexeq r3, r1, [r2] diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index fd94e4e82fc..359e54e83bd 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -412,10 +412,17 @@ __fixup_smp_on_up: add r4, r4, r3 add r5, r5, r3 2: cmp r4, r5 + movhs pc, lr ldmia r4!, {r0, r6} - strlo r6, [r0, r3] - blo 2b - mov pc, lr + ARM( str r6, [r0, r3] ) + THUMB( add r0, r0, r3 ) +#ifdef __ARMEB__ + THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. +#endif + THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords + THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. + THUMB( strh r6, [r0] ) + b 2b ENDPROC(__fixup_smp) 1: .word . -- cgit v1.2.3-70-g09d2 From 58613cd1d4f8c2d5f25b6c57ad7fbed80e75a67b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Dec 2010 12:34:39 +0000 Subject: ARM: smp: improve CPU bringup failure diagnostics We used to print a bland error message which gave no clue as to the failure when we failed to bring up a secondary CPU. Resolve this by separating the two failure cases. If boot_secondary() fails, we print a message indicating the returned error code from boot_secondary(): "CPU%u: failed to boot: %d\n", cpu, ret. However, if boot_secondary() succeeded, but the CPU did not appear to mark itself online within the timeout, indicate that it failed to come online: "CPU%u: failed to come online\n", cpu Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 1a1c5e2b3ef..6afaf6f7306 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -164,8 +164,12 @@ int __cpuinit __cpu_up(unsigned int cpu) barrier(); } - if (!cpu_online(cpu)) + if (!cpu_online(cpu)) { + pr_crit("CPU%u: failed to come online\n", cpu); ret = -EIO; + } + } else { + pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } secondary_data.stack = NULL; @@ -181,14 +185,6 @@ int __cpuinit __cpu_up(unsigned int cpu) pgd_free(&init_mm, pgd); - if (ret) { - printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); - - /* - * FIXME: We need to clean up the new idle thread. --rmk - */ - } - return ret; } -- cgit v1.2.3-70-g09d2 From 10034aabca9032246762daaca3152f3e79380ea0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:28:02 +0000 Subject: ARM: localtimer: clean up local timer on hot unplug When a CPU is hot unplugged, the generic tick code cleans up the clock event device, but fails to call down to the device's set_mode function to actually shut the device down. To work around this, we've historically had a local_timer_stop() callback out of the hotplug code. However, this adds needless complexity when we have the clock event device itself available. Explicitly call the clock event device's set_mode function with CLOCK_EVT_MODE_UNUSED, so that the hardware can be cleanly shutdown without any special external callbacks. When/if the generic code is fixed, percpu_timer_stop() can be killed off. Signed-off-by: Russell King --- arch/arm/include/asm/localtimer.h | 12 ------------ arch/arm/include/asm/smp_twd.h | 1 - arch/arm/kernel/smp.c | 19 ++++++++++++++++++- arch/arm/kernel/smp_twd.c | 10 ---------- 4 files changed, 18 insertions(+), 24 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h index 50c7e7cfd67..6bc63ab498c 100644 --- a/arch/arm/include/asm/localtimer.h +++ b/arch/arm/include/asm/localtimer.h @@ -30,7 +30,6 @@ asmlinkage void do_local_timer(struct pt_regs *); #include "smp_twd.h" #define local_timer_ack() twd_timer_ack() -#define local_timer_stop() twd_timer_stop() #else @@ -40,11 +39,6 @@ asmlinkage void do_local_timer(struct pt_regs *); */ int local_timer_ack(void); -/* - * Stop a local timer interrupt. - */ -void local_timer_stop(void); - #endif /* @@ -52,12 +46,6 @@ void local_timer_stop(void); */ void local_timer_setup(struct clock_event_device *); -#else - -static inline void local_timer_stop(void) -{ -} - #endif #endif diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index 634f357be6b..fed9981fba0 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h @@ -22,7 +22,6 @@ struct clock_event_device; extern void __iomem *twd_base; -void twd_timer_stop(void); int twd_timer_ack(void); void twd_timer_setup(struct clock_event_device *); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6afaf6f7306..4dc864ef9cd 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -189,6 +189,8 @@ int __cpuinit __cpu_up(unsigned int cpu) } #ifdef CONFIG_HOTPLUG_CPU +static void percpu_timer_stop(void); + /* * __cpu_disable runs on the processor to be shutdown. */ @@ -216,7 +218,7 @@ int __cpu_disable(void) /* * Stop the local timer for this CPU. */ - local_timer_stop(); + percpu_timer_stop(); /* * Flush user cache and TLB mappings, and then remove this CPU @@ -539,6 +541,21 @@ void __cpuinit percpu_timer_setup(void) local_timer_setup(evt); } +#ifdef CONFIG_HOTPLUG_CPU +/* + * The generic clock events code purposely does not stop the local timer + * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it + * manually here. + */ +static void percpu_timer_stop(void) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); + + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); +} +#endif + static DEFINE_SPINLOCK(stop_lock); /* diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 35882fbf37f..24585d97c10 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -150,13 +150,3 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clockevents_register_device(clk); } - -#ifdef CONFIG_HOTPLUG_CPU -/* - * take a local timer down - */ -void twd_timer_stop(void) -{ - __raw_writel(0, twd_base + TWD_TIMER_CONTROL); -} -#endif -- cgit v1.2.3-70-g09d2 From 03b505eae6a276b8c38b6222694afb6cea10b1cc Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:44:32 +0000 Subject: ARM: SMP: split out software TLB maintainence broadcasting smp.c is becoming too large, so split out the TLB maintainence broadcasting into a separate smp_tlb.c file. Signed-off-by: Russell King --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/smp.c | 126 ----------------------------------------- arch/arm/kernel/smp_tlb.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 127 deletions(-) create mode 100644 arch/arm/kernel/smp_tlb.c (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5b9b268f4fb..659937b0a89 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 4dc864ef9cd..6d0c66bc434 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -38,7 +38,6 @@ #include #include #include -#include /* * as from 2.5, kernels no longer have an init_tasks structure @@ -655,128 +654,3 @@ int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } - -static void -on_each_cpu_mask(void (*func)(void *), void *info, int wait, - const struct cpumask *mask) -{ - preempt_disable(); - - smp_call_function_many(mask, func, info, wait); - if (cpumask_test_cpu(smp_processor_id(), mask)) - func(info); - - preempt_enable(); -} - -/**********************************************************************/ - -/* - * TLB operations - */ -struct tlb_args { - struct vm_area_struct *ta_vma; - unsigned long ta_start; - unsigned long ta_end; -}; - -static inline void ipi_flush_tlb_all(void *ignored) -{ - local_flush_tlb_all(); -} - -static inline void ipi_flush_tlb_mm(void *arg) -{ - struct mm_struct *mm = (struct mm_struct *)arg; - - local_flush_tlb_mm(mm); -} - -static inline void ipi_flush_tlb_page(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_page(ta->ta_vma, ta->ta_start); -} - -static inline void ipi_flush_tlb_kernel_page(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_kernel_page(ta->ta_start); -} - -static inline void ipi_flush_tlb_range(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); -} - -static inline void ipi_flush_tlb_kernel_range(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); -} - -void flush_tlb_all(void) -{ - if (tlb_ops_need_broadcast()) - on_each_cpu(ipi_flush_tlb_all, NULL, 1); - else - local_flush_tlb_all(); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (tlb_ops_need_broadcast()) - on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); - else - local_flush_tlb_mm(mm); -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_vma = vma; - ta.ta_start = uaddr; - on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); - } else - local_flush_tlb_page(vma, uaddr); -} - -void flush_tlb_kernel_page(unsigned long kaddr) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_start = kaddr; - on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); - } else - local_flush_tlb_kernel_page(kaddr); -} - -void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_vma = vma; - ta.ta_start = start; - ta.ta_end = end; - on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); - } else - local_flush_tlb_range(vma, start, end); -} - -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_start = start; - ta.ta_end = end; - on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); - } else - local_flush_tlb_kernel_range(start, end); -} diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c new file mode 100644 index 00000000000..7dcb35285be --- /dev/null +++ b/arch/arm/kernel/smp_tlb.c @@ -0,0 +1,139 @@ +/* + * linux/arch/arm/kernel/smp_tlb.c + * + * Copyright (C) 2002 ARM Limited, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include + +static void on_each_cpu_mask(void (*func)(void *), void *info, int wait, + const struct cpumask *mask) +{ + preempt_disable(); + + smp_call_function_many(mask, func, info, wait); + if (cpumask_test_cpu(smp_processor_id(), mask)) + func(info); + + preempt_enable(); +} + +/**********************************************************************/ + +/* + * TLB operations + */ +struct tlb_args { + struct vm_area_struct *ta_vma; + unsigned long ta_start; + unsigned long ta_end; +}; + +static inline void ipi_flush_tlb_all(void *ignored) +{ + local_flush_tlb_all(); +} + +static inline void ipi_flush_tlb_mm(void *arg) +{ + struct mm_struct *mm = (struct mm_struct *)arg; + + local_flush_tlb_mm(mm); +} + +static inline void ipi_flush_tlb_page(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_page(ta->ta_vma, ta->ta_start); +} + +static inline void ipi_flush_tlb_kernel_page(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_kernel_page(ta->ta_start); +} + +static inline void ipi_flush_tlb_range(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); +} + +static inline void ipi_flush_tlb_kernel_range(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); +} + +void flush_tlb_all(void) +{ + if (tlb_ops_need_broadcast()) + on_each_cpu(ipi_flush_tlb_all, NULL, 1); + else + local_flush_tlb_all(); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (tlb_ops_need_broadcast()) + on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); + else + local_flush_tlb_mm(mm); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = uaddr; + on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); + } else + local_flush_tlb_page(vma, uaddr); +} + +void flush_tlb_kernel_page(unsigned long kaddr) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = kaddr; + on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); + } else + local_flush_tlb_kernel_page(kaddr); +} + +void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); + } else + local_flush_tlb_range(vma, start, end); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); + } else + local_flush_tlb_kernel_range(start, end); +} + -- cgit v1.2.3-70-g09d2 From faabfa0816916b0a7cfc93f6a9be382830658c80 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 16:58:19 +0000 Subject: ARM: SMP: ensure frame pointer is reinitialized for soft-CPU hotplug When we soft-CPU hotplug a CPU, we reset the stack pointer and jump back to start_secondary(). This allows us to restart as if the CPU was actually reset. However, we weren't resetting the frame pointer, which could cause problems with backtracing. Reset the frame pointer to zero (which means no parent frame) just like the early assembly code also does. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6d0c66bc434..5341b0b1970 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -286,6 +286,7 @@ void __ref cpu_die(void) * to be repeated to undo the effects of taking the CPU offline. */ __asm__("mov sp, %0\n" + " mov fp, #0\n" " b secondary_start_kernel" : : "r" (task_stack_page(current) + THREAD_SIZE - 8)); -- cgit v1.2.3-70-g09d2