Loading arch/arm64/include/asm/hardirq.h +1 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include <linux/threads.h> #include <asm/irq.h> #define NR_IPI 6 #define NR_IPI 7 typedef struct { unsigned int __softirq_pending; Loading arch/arm64/include/asm/irq.h +3 −0 Original line number Diff line number Diff line Loading @@ -7,4 +7,7 @@ extern void (*handle_arch_irq)(struct pt_regs *); extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); void arch_trigger_all_cpu_backtrace(void); #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace #endif arch/arm64/kernel/smp.c +72 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ enum ipi_msg_type { IPI_CPU_STOP, IPI_TIMER, IPI_WAKEUP, IPI_CPU_BACKTRACE, }; /* Loading Loading @@ -477,6 +478,7 @@ static const char *ipi_types[NR_IPI] = { S(IPI_CPU_STOP, "CPU stop interrupts"), S(IPI_TIMER, "Timer broadcast interrupts"), S(IPI_WAKEUP, "CPU wakeup interrupts"), S(IPI_CPU_BACKTRACE, "CPU backtrace"), }; void show_ipi_list(struct seq_file *p, int prec) Loading Loading @@ -532,6 +534,72 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs) cpu_relax(); } static cpumask_t backtrace_mask; static DEFINE_RAW_SPINLOCK(backtrace_lock); /* "in progress" flag of arch_trigger_all_cpu_backtrace */ static unsigned long backtrace_flag; static void smp_send_all_cpu_backtrace(void) { unsigned int this_cpu = smp_processor_id(); int i; if (test_and_set_bit(0, &backtrace_flag)) /* * If there is already a trigger_all_cpu_backtrace() in progress * (backtrace_flag == 1), don't output double cpu dump infos. */ return; cpumask_copy(&backtrace_mask, cpu_online_mask); cpu_clear(this_cpu, backtrace_mask); pr_info("Backtrace for cpu %d (current):\n", this_cpu); dump_stack(); pr_info("\nsending IPI to all other CPUs:\n"); if (!cpus_empty(backtrace_mask)) smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE); /* Wait for up to 10 seconds for all other CPUs to do the backtrace */ for (i = 0; i < 10 * 1000; i++) { if (cpumask_empty(&backtrace_mask)) break; mdelay(1); } clear_bit(0, &backtrace_flag); smp_mb__after_clear_bit(); } /* * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace() */ static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs) { if (cpu_isset(cpu, backtrace_mask)) { raw_spin_lock(&backtrace_lock); pr_warn("IPI backtrace for cpu %d\n", cpu); show_regs(regs); raw_spin_unlock(&backtrace_lock); cpu_clear(cpu, backtrace_mask); } } #ifdef CONFIG_SMP void arch_trigger_all_cpu_backtrace(void) { smp_send_all_cpu_backtrace(); } #else void arch_trigger_all_cpu_backtrace(void) { dump_stack(); } #endif /* * Main handler for inter-processor interrupts */ Loading Loading @@ -576,6 +644,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs) case IPI_WAKEUP: break; case IPI_CPU_BACKTRACE: ipi_cpu_backtrace(cpu, regs); break; default: pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); break; Loading Loading
arch/arm64/include/asm/hardirq.h +1 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include <linux/threads.h> #include <asm/irq.h> #define NR_IPI 6 #define NR_IPI 7 typedef struct { unsigned int __softirq_pending; Loading
arch/arm64/include/asm/irq.h +3 −0 Original line number Diff line number Diff line Loading @@ -7,4 +7,7 @@ extern void (*handle_arch_irq)(struct pt_regs *); extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); void arch_trigger_all_cpu_backtrace(void); #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace #endif
arch/arm64/kernel/smp.c +72 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ enum ipi_msg_type { IPI_CPU_STOP, IPI_TIMER, IPI_WAKEUP, IPI_CPU_BACKTRACE, }; /* Loading Loading @@ -477,6 +478,7 @@ static const char *ipi_types[NR_IPI] = { S(IPI_CPU_STOP, "CPU stop interrupts"), S(IPI_TIMER, "Timer broadcast interrupts"), S(IPI_WAKEUP, "CPU wakeup interrupts"), S(IPI_CPU_BACKTRACE, "CPU backtrace"), }; void show_ipi_list(struct seq_file *p, int prec) Loading Loading @@ -532,6 +534,72 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs) cpu_relax(); } static cpumask_t backtrace_mask; static DEFINE_RAW_SPINLOCK(backtrace_lock); /* "in progress" flag of arch_trigger_all_cpu_backtrace */ static unsigned long backtrace_flag; static void smp_send_all_cpu_backtrace(void) { unsigned int this_cpu = smp_processor_id(); int i; if (test_and_set_bit(0, &backtrace_flag)) /* * If there is already a trigger_all_cpu_backtrace() in progress * (backtrace_flag == 1), don't output double cpu dump infos. */ return; cpumask_copy(&backtrace_mask, cpu_online_mask); cpu_clear(this_cpu, backtrace_mask); pr_info("Backtrace for cpu %d (current):\n", this_cpu); dump_stack(); pr_info("\nsending IPI to all other CPUs:\n"); if (!cpus_empty(backtrace_mask)) smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE); /* Wait for up to 10 seconds for all other CPUs to do the backtrace */ for (i = 0; i < 10 * 1000; i++) { if (cpumask_empty(&backtrace_mask)) break; mdelay(1); } clear_bit(0, &backtrace_flag); smp_mb__after_clear_bit(); } /* * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace() */ static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs) { if (cpu_isset(cpu, backtrace_mask)) { raw_spin_lock(&backtrace_lock); pr_warn("IPI backtrace for cpu %d\n", cpu); show_regs(regs); raw_spin_unlock(&backtrace_lock); cpu_clear(cpu, backtrace_mask); } } #ifdef CONFIG_SMP void arch_trigger_all_cpu_backtrace(void) { smp_send_all_cpu_backtrace(); } #else void arch_trigger_all_cpu_backtrace(void) { dump_stack(); } #endif /* * Main handler for inter-processor interrupts */ Loading Loading @@ -576,6 +644,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs) case IPI_WAKEUP: break; case IPI_CPU_BACKTRACE: ipi_cpu_backtrace(cpu, regs); break; default: pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); break; Loading