diff options
Diffstat (limited to 'arch/tile')
-rw-r--r-- | arch/tile/Kconfig | 1 | ||||
-rw-r--r-- | arch/tile/include/asm/irq.h | 5 | ||||
-rw-r--r-- | arch/tile/kernel/entry.S | 2 | ||||
-rw-r--r-- | arch/tile/kernel/pmc.c | 3 | ||||
-rw-r--r-- | arch/tile/kernel/process.c | 73 | ||||
-rw-r--r-- | arch/tile/kernel/traps.c | 9 | ||||
-rw-r--r-- | arch/tile/kernel/vmlinux.lds.S | 1 |
7 files changed, 29 insertions, 65 deletions
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 78da75b670bc..4583c0320059 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -3,7 +3,6 @@ config TILE def_bool y - select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_WANT_FRAME_POINTERS diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h index 84a924034bdb..1fa1f2544ff9 100644 --- a/arch/tile/include/asm/irq.h +++ b/arch/tile/include/asm/irq.h @@ -79,8 +79,9 @@ void tile_irq_activate(unsigned int irq, int tile_irq_type); void setup_irq_regs(void); #ifdef __tilegx__ -void arch_trigger_all_cpu_backtrace(bool self); -#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace +void arch_trigger_cpumask_backtrace(const struct cpumask *mask, + bool exclude_self); +#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace #endif #endif /* _ASM_TILE_IRQ_H */ diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S index 670a3569450f..101de132e363 100644 --- a/arch/tile/kernel/entry.S +++ b/arch/tile/kernel/entry.S @@ -50,7 +50,7 @@ STD_ENTRY(smp_nap) * When interrupted at _cpu_idle_nap, we bump the PC forward 8, and * as a result return to the function that called _cpu_idle(). */ -STD_ENTRY(_cpu_idle) +STD_ENTRY_SECTION(_cpu_idle, .cpuidle.text) movei r1, 1 IRQ_ENABLE_LOAD(r2, r3) mtspr INTERRUPT_CRITICAL_SECTION, r1 diff --git a/arch/tile/kernel/pmc.c b/arch/tile/kernel/pmc.c index db62cc34b955..81cf8743a3f3 100644 --- a/arch/tile/kernel/pmc.c +++ b/arch/tile/kernel/pmc.c @@ -16,7 +16,6 @@ #include <linux/spinlock.h> #include <linux/module.h> #include <linux/atomic.h> -#include <linux/interrupt.h> #include <asm/processor.h> #include <asm/pmc.h> @@ -29,9 +28,7 @@ int handle_perf_interrupt(struct pt_regs *regs, int fault) if (!perf_irq) panic("Unexpected PERF_COUNT interrupt %d\n", fault); - nmi_enter(); retval = perf_irq(regs, fault); - nmi_exit(); return retval; } diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index a465d8372edd..9f37106ef93a 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -22,7 +22,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/compat.h> -#include <linux/hardirq.h> +#include <linux/nmi.h> #include <linux/syscalls.h> #include <linux/kernel.h> #include <linux/tracehook.h> @@ -594,66 +594,18 @@ void show_regs(struct pt_regs *regs) tile_show_stack(&kbt); } -/* To ensure stack dump on tiles occurs one by one. */ -static DEFINE_SPINLOCK(backtrace_lock); -/* To ensure no backtrace occurs before all of the stack dump are done. */ -static atomic_t backtrace_cpus; -/* The cpu mask to avoid reentrance. */ -static struct cpumask backtrace_mask; - -void do_nmi_dump_stack(struct pt_regs *regs) -{ - int is_idle = is_idle_task(current) && !in_interrupt(); - int cpu; - - nmi_enter(); - cpu = smp_processor_id(); - if (WARN_ON_ONCE(!cpumask_test_and_clear_cpu(cpu, &backtrace_mask))) - goto done; - - spin_lock(&backtrace_lock); - if (is_idle) - pr_info("CPU: %d idle\n", cpu); - else - show_regs(regs); - spin_unlock(&backtrace_lock); - atomic_dec(&backtrace_cpus); -done: - nmi_exit(); -} - #ifdef __tilegx__ -void arch_trigger_all_cpu_backtrace(bool self) +void nmi_raise_cpu_backtrace(struct cpumask *in_mask) { struct cpumask mask; HV_Coord tile; unsigned int timeout; int cpu; - int ongoing; HV_NMI_Info info[NR_CPUS]; - ongoing = atomic_cmpxchg(&backtrace_cpus, 0, num_online_cpus() - 1); - if (ongoing != 0) { - pr_err("Trying to do all-cpu backtrace.\n"); - pr_err("But another all-cpu backtrace is ongoing (%d cpus left)\n", - ongoing); - if (self) { - pr_err("Reporting the stack on this cpu only.\n"); - dump_stack(); - } - return; - } - - cpumask_copy(&mask, cpu_online_mask); - cpumask_clear_cpu(smp_processor_id(), &mask); - cpumask_copy(&backtrace_mask, &mask); - - /* Backtrace for myself first. */ - if (self) - dump_stack(); - /* Tentatively dump stack on remote tiles via NMI. */ timeout = 100; + cpumask_copy(&mask, in_mask); while (!cpumask_empty(&mask) && timeout) { for_each_cpu(cpu, &mask) { tile.x = cpu_x(cpu); @@ -664,12 +616,17 @@ void arch_trigger_all_cpu_backtrace(bool self) } mdelay(10); + touch_softlockup_watchdog(); timeout--; } - /* Warn about cpus stuck in ICS and decrement their counts here. */ + /* Warn about cpus stuck in ICS. */ if (!cpumask_empty(&mask)) { for_each_cpu(cpu, &mask) { + + /* Clear the bit as if nmi_cpu_backtrace() ran. */ + cpumask_clear_cpu(cpu, in_mask); + switch (info[cpu].result) { case HV_NMI_RESULT_FAIL_ICS: pr_warn("Skipping stack dump of cpu %d in ICS at pc %#llx\n", @@ -680,16 +637,20 @@ void arch_trigger_all_cpu_backtrace(bool self) cpu); break; case HV_ENOSYS: - pr_warn("Hypervisor too old to allow remote stack dumps.\n"); - goto skip_for_each; + WARN_ONCE(1, "Hypervisor too old to allow remote stack dumps.\n"); + break; default: /* should not happen */ pr_warn("Skipping stack dump of cpu %d [%d,%#llx]\n", cpu, info[cpu].result, info[cpu].pc); break; } } -skip_for_each: - atomic_sub(cpumask_weight(&mask), &backtrace_cpus); } } + +void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) +{ + nmi_trigger_cpumask_backtrace(mask, exclude_self, + nmi_raise_cpu_backtrace); +} #endif /* __tilegx_ */ diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 4d9651c5b1ad..39f427bb0de2 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c @@ -20,6 +20,8 @@ #include <linux/reboot.h> #include <linux/uaccess.h> #include <linux/ptrace.h> +#include <linux/hardirq.h> +#include <linux/nmi.h> #include <asm/stack.h> #include <asm/traps.h> #include <asm/setup.h> @@ -392,14 +394,17 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, void do_nmi(struct pt_regs *regs, int fault_num, unsigned long reason) { + nmi_enter(); switch (reason) { +#ifdef arch_trigger_cpumask_backtrace case TILE_NMI_DUMP_STACK: - do_nmi_dump_stack(regs); + nmi_cpu_backtrace(regs); break; +#endif default: panic("Unexpected do_nmi type %ld", reason); - return; } + nmi_exit(); } /* Deprecated function currently only used here. */ diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S index 9d449caf8910..e1baf094fba4 100644 --- a/arch/tile/kernel/vmlinux.lds.S +++ b/arch/tile/kernel/vmlinux.lds.S @@ -42,6 +42,7 @@ SECTIONS .text : AT (ADDR(.text) - LOAD_OFFSET) { HEAD_TEXT SCHED_TEXT + CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT |