summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/irq.h5
-rw-r--r--arch/arm/kernel/smp.c4
-rw-r--r--arch/mips/include/asm/irq.h5
-rw-r--r--arch/mips/kernel/process.c11
-rw-r--r--arch/sparc/include/asm/irq_64.h5
-rw-r--r--arch/sparc/kernel/process_64.c10
-rw-r--r--arch/x86/include/asm/irq.h5
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c18
-rw-r--r--include/linux/nmi.h31
-rw-r--r--lib/nmi_backtrace.c17
10 files changed, 72 insertions, 39 deletions
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 1bd9510de1b9..e53638c8ed8a 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -36,8 +36,9 @@ extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
36#endif 36#endif
37 37
38#ifdef CONFIG_SMP 38#ifdef CONFIG_SMP
39extern void arch_trigger_all_cpu_backtrace(bool); 39extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
40#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x) 40 bool exclude_self);
41#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
41#endif 42#endif
42 43
43static inline int nr_legacy_irqs(void) 44static inline int nr_legacy_irqs(void)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 937c8920d741..5abc5697e4e5 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -760,7 +760,7 @@ static void raise_nmi(cpumask_t *mask)
760 smp_cross_call(mask, IPI_CPU_BACKTRACE); 760 smp_cross_call(mask, IPI_CPU_BACKTRACE);
761} 761}
762 762
763void arch_trigger_all_cpu_backtrace(bool include_self) 763void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
764{ 764{
765 nmi_trigger_all_cpu_backtrace(include_self, raise_nmi); 765 nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi);
766} 766}
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index 15e0fecbc300..6bf10e796553 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -51,7 +51,8 @@ extern int cp0_fdc_irq;
51 51
52extern int get_c0_fdc_int(void); 52extern int get_c0_fdc_int(void);
53 53
54void arch_trigger_all_cpu_backtrace(bool); 54void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
55#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace 55 bool exclude_self);
56#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
56 57
57#endif /* _ASM_IRQ_H */ 58#endif /* _ASM_IRQ_H */
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index d2d061520a23..9514e5f2209f 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -569,9 +569,16 @@ static void arch_dump_stack(void *info)
569 dump_stack(); 569 dump_stack();
570} 570}
571 571
572void arch_trigger_all_cpu_backtrace(bool include_self) 572void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
573{ 573{
574 smp_call_function(arch_dump_stack, NULL, 1); 574 long this_cpu = get_cpu();
575
576 if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
577 dump_stack();
578
579 smp_call_function_many(mask, arch_dump_stack, NULL, 1);
580
581 put_cpu();
575} 582}
576 583
577int mips_get_process_fp_mode(struct task_struct *task) 584int mips_get_process_fp_mode(struct task_struct *task)
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index 3f70f900e834..1d51a11fb261 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -86,8 +86,9 @@ static inline unsigned long get_softint(void)
86 return retval; 86 return retval;
87} 87}
88 88
89void arch_trigger_all_cpu_backtrace(bool); 89void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
90#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace 90 bool exclude_self);
91#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
91 92
92extern void *hardirq_stack[NR_CPUS]; 93extern void *hardirq_stack[NR_CPUS];
93extern void *softirq_stack[NR_CPUS]; 94extern void *softirq_stack[NR_CPUS];
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index fa14402b33f9..47ff5588e521 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -239,7 +239,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp)
239 } 239 }
240} 240}
241 241
242void arch_trigger_all_cpu_backtrace(bool include_self) 242void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
243{ 243{
244 struct thread_info *tp = current_thread_info(); 244 struct thread_info *tp = current_thread_info();
245 struct pt_regs *regs = get_irq_regs(); 245 struct pt_regs *regs = get_irq_regs();
@@ -255,15 +255,15 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
255 255
256 memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); 256 memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
257 257
258 if (include_self) 258 if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
259 __global_reg_self(tp, regs, this_cpu); 259 __global_reg_self(tp, regs, this_cpu);
260 260
261 smp_fetch_global_regs(); 261 smp_fetch_global_regs();
262 262
263 for_each_online_cpu(cpu) { 263 for_each_cpu(cpu, mask) {
264 struct global_reg_snapshot *gp; 264 struct global_reg_snapshot *gp;
265 265
266 if (!include_self && cpu == this_cpu) 266 if (exclude_self && cpu == this_cpu)
267 continue; 267 continue;
268 268
269 gp = &global_cpu_snapshot[cpu].reg; 269 gp = &global_cpu_snapshot[cpu].reg;
@@ -300,7 +300,7 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
300 300
301static void sysrq_handle_globreg(int key) 301static void sysrq_handle_globreg(int key)
302{ 302{
303 arch_trigger_all_cpu_backtrace(true); 303 trigger_all_cpu_backtrace();
304} 304}
305 305
306static struct sysrq_key_op sparc_globalreg_op = { 306static struct sysrq_key_op sparc_globalreg_op = {
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index e7de5c9a4fbd..16d3fa211962 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -50,8 +50,9 @@ extern int vector_used_by_percpu_irq(unsigned int vector);
50extern void init_ISA_irqs(void); 50extern void init_ISA_irqs(void);
51 51
52#ifdef CONFIG_X86_LOCAL_APIC 52#ifdef CONFIG_X86_LOCAL_APIC
53void arch_trigger_all_cpu_backtrace(bool); 53void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
54#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace 54 bool exclude_self);
55#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
55#endif 56#endif
56 57
57#endif /* _ASM_X86_IRQ_H */ 58#endif /* _ASM_X86_IRQ_H */
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index f29501e1a5c1..c73c9fb281e1 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -26,32 +26,32 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh)
26} 26}
27#endif 27#endif
28 28
29#ifdef arch_trigger_all_cpu_backtrace 29#ifdef arch_trigger_cpumask_backtrace
30static void nmi_raise_cpu_backtrace(cpumask_t *mask) 30static void nmi_raise_cpu_backtrace(cpumask_t *mask)
31{ 31{
32 apic->send_IPI_mask(mask, NMI_VECTOR); 32 apic->send_IPI_mask(mask, NMI_VECTOR);
33} 33}
34 34
35void arch_trigger_all_cpu_backtrace(bool include_self) 35void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
36{ 36{
37 nmi_trigger_all_cpu_backtrace(include_self, nmi_raise_cpu_backtrace); 37 nmi_trigger_cpumask_backtrace(mask, exclude_self,
38 nmi_raise_cpu_backtrace);
38} 39}
39 40
40static int 41static int nmi_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
41arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
42{ 42{
43 if (nmi_cpu_backtrace(regs)) 43 if (nmi_cpu_backtrace(regs))
44 return NMI_HANDLED; 44 return NMI_HANDLED;
45 45
46 return NMI_DONE; 46 return NMI_DONE;
47} 47}
48NOKPROBE_SYMBOL(arch_trigger_all_cpu_backtrace_handler); 48NOKPROBE_SYMBOL(nmi_cpu_backtrace_handler);
49 49
50static int __init register_trigger_all_cpu_backtrace(void) 50static int __init register_nmi_cpu_backtrace_handler(void)
51{ 51{
52 register_nmi_handler(NMI_LOCAL, arch_trigger_all_cpu_backtrace_handler, 52 register_nmi_handler(NMI_LOCAL, nmi_cpu_backtrace_handler,
53 0, "arch_bt"); 53 0, "arch_bt");
54 return 0; 54 return 0;
55} 55}
56early_initcall(register_trigger_all_cpu_backtrace); 56early_initcall(register_nmi_cpu_backtrace_handler);
57#endif 57#endif
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 4630eeae18e0..a78c35cff1ae 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -35,21 +35,34 @@ static inline void hardlockup_detector_disable(void) {}
35 * base function. Return whether such support was available, 35 * base function. Return whether such support was available,
36 * to allow calling code to fall back to some other mechanism: 36 * to allow calling code to fall back to some other mechanism:
37 */ 37 */
38#ifdef arch_trigger_all_cpu_backtrace 38#ifdef arch_trigger_cpumask_backtrace
39static inline bool trigger_all_cpu_backtrace(void) 39static inline bool trigger_all_cpu_backtrace(void)
40{ 40{
41 arch_trigger_all_cpu_backtrace(true); 41 arch_trigger_cpumask_backtrace(cpu_online_mask, false);
42
43 return true; 42 return true;
44} 43}
44
45static inline bool trigger_allbutself_cpu_backtrace(void) 45static inline bool trigger_allbutself_cpu_backtrace(void)
46{ 46{
47 arch_trigger_all_cpu_backtrace(false); 47 arch_trigger_cpumask_backtrace(cpu_online_mask, true);
48 return true;
49}
50
51static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
52{
53 arch_trigger_cpumask_backtrace(mask, false);
54 return true;
55}
56
57static inline bool trigger_single_cpu_backtrace(int cpu)
58{
59 arch_trigger_cpumask_backtrace(cpumask_of(cpu), false);
48 return true; 60 return true;
49} 61}
50 62
51/* generic implementation */ 63/* generic implementation */
52void nmi_trigger_all_cpu_backtrace(bool include_self, 64void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
65 bool exclude_self,
53 void (*raise)(cpumask_t *mask)); 66 void (*raise)(cpumask_t *mask));
54bool nmi_cpu_backtrace(struct pt_regs *regs); 67bool nmi_cpu_backtrace(struct pt_regs *regs);
55 68
@@ -62,6 +75,14 @@ static inline bool trigger_allbutself_cpu_backtrace(void)
62{ 75{
63 return false; 76 return false;
64} 77}
78static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
79{
80 return false;
81}
82static inline bool trigger_single_cpu_backtrace(int cpu)
83{
84 return false;
85}
65#endif 86#endif
66 87
67#ifdef CONFIG_LOCKUP_DETECTOR 88#ifdef CONFIG_LOCKUP_DETECTOR
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index 26caf51cc238..df347e355267 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -17,20 +17,21 @@
17#include <linux/kprobes.h> 17#include <linux/kprobes.h>
18#include <linux/nmi.h> 18#include <linux/nmi.h>
19 19
20#ifdef arch_trigger_all_cpu_backtrace 20#ifdef arch_trigger_cpumask_backtrace
21/* For reliability, we're prepared to waste bits here. */ 21/* For reliability, we're prepared to waste bits here. */
22static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; 22static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
23 23
24/* "in progress" flag of arch_trigger_all_cpu_backtrace */ 24/* "in progress" flag of arch_trigger_cpumask_backtrace */
25static unsigned long backtrace_flag; 25static unsigned long backtrace_flag;
26 26
27/* 27/*
28 * When raise() is called it will be is passed a pointer to the 28 * When raise() is called it will be passed a pointer to the
29 * backtrace_mask. Architectures that call nmi_cpu_backtrace() 29 * backtrace_mask. Architectures that call nmi_cpu_backtrace()
30 * directly from their raise() functions may rely on the mask 30 * directly from their raise() functions may rely on the mask
31 * they are passed being updated as a side effect of this call. 31 * they are passed being updated as a side effect of this call.
32 */ 32 */
33void nmi_trigger_all_cpu_backtrace(bool include_self, 33void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
34 bool exclude_self,
34 void (*raise)(cpumask_t *mask)) 35 void (*raise)(cpumask_t *mask))
35{ 36{
36 int i, this_cpu = get_cpu(); 37 int i, this_cpu = get_cpu();
@@ -44,13 +45,13 @@ void nmi_trigger_all_cpu_backtrace(bool include_self,
44 return; 45 return;
45 } 46 }
46 47
47 cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); 48 cpumask_copy(to_cpumask(backtrace_mask), mask);
48 if (!include_self) 49 if (exclude_self)
49 cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); 50 cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));
50 51
51 if (!cpumask_empty(to_cpumask(backtrace_mask))) { 52 if (!cpumask_empty(to_cpumask(backtrace_mask))) {
52 pr_info("Sending NMI to %s CPUs:\n", 53 pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n",
53 (include_self ? "all" : "other")); 54 this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));
54 raise(to_cpumask(backtrace_mask)); 55 raise(to_cpumask(backtrace_mask));
55 } 56 }
56 57