Loading Documentation/sysrq.txt +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'w' - Dumps tasks that are in uninterruptable (blocked) state. 'x' - Used by xmon interface on ppc/powerpc platforms. Show global PMU Registers on sparc64. 'y' - Show global CPU Registers [SPARC-64 specific] Loading arch/sparc/include/asm/ptrace.h +12 −1 Original line number Diff line number Diff line Loading @@ -42,7 +42,18 @@ struct global_reg_snapshot { struct thread_info *thread; unsigned long pad1; }; extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; struct global_pmu_snapshot { unsigned long pcr[4]; unsigned long pic[4]; }; union global_cpu_snapshot { struct global_reg_snapshot reg; struct global_pmu_snapshot pmu; }; extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; #define force_successful_syscall_return() \ do { current_thread_info()->syscall_noerror = 1; \ Loading arch/sparc/include/asm/smp_64.h +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ extern void smp_fill_in_sib_core_maps(void); extern void cpu_play_dead(void); extern void smp_fetch_global_regs(void); extern void smp_fetch_global_pmu(void); struct seq_file; void smp_bogo(struct seq_file *); Loading @@ -65,6 +66,7 @@ extern void __cpu_die(unsigned int cpu); #define hard_smp_processor_id() 0 #define smp_fill_in_sib_core_maps() do { } while (0) #define smp_fetch_global_regs() do { } while (0) #define smp_fetch_global_pmu() do { } while (0) #endif /* !(CONFIG_SMP) */ Loading arch/sparc/kernel/process_64.c +100 −20 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/tick.h> #include <linux/init.h> #include <linux/cpu.h> #include <linux/perf_event.h> #include <linux/elfcore.h> #include <linux/sysrq.h> #include <linux/nmi.h> Loading @@ -47,6 +48,7 @@ #include <asm/syscalls.h> #include <asm/irq_regs.h> #include <asm/smp.h> #include <asm/pcr.h> #include "kstack.h" Loading Loading @@ -204,18 +206,22 @@ void show_regs(struct pt_regs *regs) show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]); } struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_reg_snapshot_lock); union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_cpu_snapshot_lock); static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, int this_cpu) { struct global_reg_snapshot *rp; flushw_all(); global_reg_snapshot[this_cpu].tstate = regs->tstate; global_reg_snapshot[this_cpu].tpc = regs->tpc; global_reg_snapshot[this_cpu].tnpc = regs->tnpc; global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; rp = &global_cpu_snapshot[this_cpu].reg; rp->tstate = regs->tstate; rp->tpc = regs->tpc; rp->tnpc = regs->tnpc; rp->o7 = regs->u_regs[UREG_I7]; if (regs->tstate & TSTATE_PRIV) { struct reg_window *rw; Loading @@ -223,17 +229,17 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); if (kstack_valid(tp, (unsigned long) rw)) { global_reg_snapshot[this_cpu].i7 = rw->ins[7]; rp->i7 = rw->ins[7]; rw = (struct reg_window *) (rw->ins[6] + STACK_BIAS); if (kstack_valid(tp, (unsigned long) rw)) global_reg_snapshot[this_cpu].rpc = rw->ins[7]; rp->rpc = rw->ins[7]; } } else { global_reg_snapshot[this_cpu].i7 = 0; global_reg_snapshot[this_cpu].rpc = 0; rp->i7 = 0; rp->rpc = 0; } global_reg_snapshot[this_cpu].thread = tp; rp->thread = tp; } /* In order to avoid hangs we do not try to synchronize with the Loading Loading @@ -261,9 +267,9 @@ void arch_trigger_all_cpu_backtrace(void) if (!regs) regs = tp->kregs; spin_lock_irqsave(&global_reg_snapshot_lock, flags); spin_lock_irqsave(&global_cpu_snapshot_lock, flags); memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); this_cpu = raw_smp_processor_id(); Loading @@ -272,7 +278,7 @@ void arch_trigger_all_cpu_backtrace(void) smp_fetch_global_regs(); for_each_online_cpu(cpu) { struct global_reg_snapshot *gp = &global_reg_snapshot[cpu]; struct global_reg_snapshot *gp = &global_cpu_snapshot[cpu].reg; __global_reg_poll(gp); Loading @@ -295,9 +301,9 @@ void arch_trigger_all_cpu_backtrace(void) } } memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); spin_unlock_irqrestore(&global_reg_snapshot_lock, flags); spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); } #ifdef CONFIG_MAGIC_SYSRQ Loading @@ -309,16 +315,90 @@ static void sysrq_handle_globreg(int key) static struct sysrq_key_op sparc_globalreg_op = { .handler = sysrq_handle_globreg, .help_msg = "Globalregs", .help_msg = "global-regs(Y)", .action_msg = "Show Global CPU Regs", }; static int __init sparc_globreg_init(void) static void __global_pmu_self(int this_cpu) { struct global_pmu_snapshot *pp; int i, num; pp = &global_cpu_snapshot[this_cpu].pmu; num = 1; if (tlb_type == hypervisor && sun4v_chip_type >= SUN4V_CHIP_NIAGARA4) num = 4; for (i = 0; i < num; i++) { pp->pcr[i] = pcr_ops->read_pcr(i); pp->pic[i] = pcr_ops->read_pic(i); } } static void __global_pmu_poll(struct global_pmu_snapshot *pp) { int limit = 0; while (!pp->pcr[0] && ++limit < 100) { barrier(); udelay(1); } } static void pmu_snapshot_all_cpus(void) { return register_sysrq_key('y', &sparc_globalreg_op); unsigned long flags; int this_cpu, cpu; spin_lock_irqsave(&global_cpu_snapshot_lock, flags); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); this_cpu = raw_smp_processor_id(); __global_pmu_self(this_cpu); smp_fetch_global_pmu(); for_each_online_cpu(cpu) { struct global_pmu_snapshot *pp = &global_cpu_snapshot[cpu].pmu; __global_pmu_poll(pp); printk("%c CPU[%3d]: PCR[%08lx:%08lx:%08lx:%08lx] PIC[%08lx:%08lx:%08lx:%08lx]\n", (cpu == this_cpu ? '*' : ' '), cpu, pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3], pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]); } memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); } static void sysrq_handle_globpmu(int key) { pmu_snapshot_all_cpus(); } static struct sysrq_key_op sparc_globalpmu_op = { .handler = sysrq_handle_globpmu, .help_msg = "global-pmu(X)", .action_msg = "Show Global PMU Regs", }; static int __init sparc_sysrq_init(void) { int ret = register_sysrq_key('y', &sparc_globalreg_op); if (!ret) ret = register_sysrq_key('x', &sparc_globalpmu_op); return ret; } core_initcall(sparc_globreg_init); core_initcall(sparc_sysrq_init); #endif Loading arch/sparc/kernel/smp_64.c +11 −0 Original line number Diff line number Diff line Loading @@ -852,6 +852,8 @@ extern unsigned long xcall_flush_tlb_mm; extern unsigned long xcall_flush_tlb_pending; extern unsigned long xcall_flush_tlb_kernel_range; extern unsigned long xcall_fetch_glob_regs; extern unsigned long xcall_fetch_glob_pmu; extern unsigned long xcall_fetch_glob_pmu_n4; extern unsigned long xcall_receive_signal; extern unsigned long xcall_new_mmu_context_version; #ifdef CONFIG_KGDB Loading Loading @@ -1000,6 +1002,15 @@ void smp_fetch_global_regs(void) smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0); } void smp_fetch_global_pmu(void) { if (tlb_type == hypervisor && sun4v_chip_type >= SUN4V_CHIP_NIAGARA4) smp_cross_call(&xcall_fetch_glob_pmu_n4, 0, 0, 0); else smp_cross_call(&xcall_fetch_glob_pmu, 0, 0, 0); } /* We know that the window frames of the user have been flushed * to the stack before we get here because all callers of us * are flush_tlb_*() routines, and these run after flush_cache_*() Loading Loading
Documentation/sysrq.txt +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'w' - Dumps tasks that are in uninterruptable (blocked) state. 'x' - Used by xmon interface on ppc/powerpc platforms. Show global PMU Registers on sparc64. 'y' - Show global CPU Registers [SPARC-64 specific] Loading
arch/sparc/include/asm/ptrace.h +12 −1 Original line number Diff line number Diff line Loading @@ -42,7 +42,18 @@ struct global_reg_snapshot { struct thread_info *thread; unsigned long pad1; }; extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; struct global_pmu_snapshot { unsigned long pcr[4]; unsigned long pic[4]; }; union global_cpu_snapshot { struct global_reg_snapshot reg; struct global_pmu_snapshot pmu; }; extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; #define force_successful_syscall_return() \ do { current_thread_info()->syscall_noerror = 1; \ Loading
arch/sparc/include/asm/smp_64.h +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ extern void smp_fill_in_sib_core_maps(void); extern void cpu_play_dead(void); extern void smp_fetch_global_regs(void); extern void smp_fetch_global_pmu(void); struct seq_file; void smp_bogo(struct seq_file *); Loading @@ -65,6 +66,7 @@ extern void __cpu_die(unsigned int cpu); #define hard_smp_processor_id() 0 #define smp_fill_in_sib_core_maps() do { } while (0) #define smp_fetch_global_regs() do { } while (0) #define smp_fetch_global_pmu() do { } while (0) #endif /* !(CONFIG_SMP) */ Loading
arch/sparc/kernel/process_64.c +100 −20 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/tick.h> #include <linux/init.h> #include <linux/cpu.h> #include <linux/perf_event.h> #include <linux/elfcore.h> #include <linux/sysrq.h> #include <linux/nmi.h> Loading @@ -47,6 +48,7 @@ #include <asm/syscalls.h> #include <asm/irq_regs.h> #include <asm/smp.h> #include <asm/pcr.h> #include "kstack.h" Loading Loading @@ -204,18 +206,22 @@ void show_regs(struct pt_regs *regs) show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]); } struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_reg_snapshot_lock); union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_cpu_snapshot_lock); static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, int this_cpu) { struct global_reg_snapshot *rp; flushw_all(); global_reg_snapshot[this_cpu].tstate = regs->tstate; global_reg_snapshot[this_cpu].tpc = regs->tpc; global_reg_snapshot[this_cpu].tnpc = regs->tnpc; global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; rp = &global_cpu_snapshot[this_cpu].reg; rp->tstate = regs->tstate; rp->tpc = regs->tpc; rp->tnpc = regs->tnpc; rp->o7 = regs->u_regs[UREG_I7]; if (regs->tstate & TSTATE_PRIV) { struct reg_window *rw; Loading @@ -223,17 +229,17 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); if (kstack_valid(tp, (unsigned long) rw)) { global_reg_snapshot[this_cpu].i7 = rw->ins[7]; rp->i7 = rw->ins[7]; rw = (struct reg_window *) (rw->ins[6] + STACK_BIAS); if (kstack_valid(tp, (unsigned long) rw)) global_reg_snapshot[this_cpu].rpc = rw->ins[7]; rp->rpc = rw->ins[7]; } } else { global_reg_snapshot[this_cpu].i7 = 0; global_reg_snapshot[this_cpu].rpc = 0; rp->i7 = 0; rp->rpc = 0; } global_reg_snapshot[this_cpu].thread = tp; rp->thread = tp; } /* In order to avoid hangs we do not try to synchronize with the Loading Loading @@ -261,9 +267,9 @@ void arch_trigger_all_cpu_backtrace(void) if (!regs) regs = tp->kregs; spin_lock_irqsave(&global_reg_snapshot_lock, flags); spin_lock_irqsave(&global_cpu_snapshot_lock, flags); memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); this_cpu = raw_smp_processor_id(); Loading @@ -272,7 +278,7 @@ void arch_trigger_all_cpu_backtrace(void) smp_fetch_global_regs(); for_each_online_cpu(cpu) { struct global_reg_snapshot *gp = &global_reg_snapshot[cpu]; struct global_reg_snapshot *gp = &global_cpu_snapshot[cpu].reg; __global_reg_poll(gp); Loading @@ -295,9 +301,9 @@ void arch_trigger_all_cpu_backtrace(void) } } memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); spin_unlock_irqrestore(&global_reg_snapshot_lock, flags); spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); } #ifdef CONFIG_MAGIC_SYSRQ Loading @@ -309,16 +315,90 @@ static void sysrq_handle_globreg(int key) static struct sysrq_key_op sparc_globalreg_op = { .handler = sysrq_handle_globreg, .help_msg = "Globalregs", .help_msg = "global-regs(Y)", .action_msg = "Show Global CPU Regs", }; static int __init sparc_globreg_init(void) static void __global_pmu_self(int this_cpu) { struct global_pmu_snapshot *pp; int i, num; pp = &global_cpu_snapshot[this_cpu].pmu; num = 1; if (tlb_type == hypervisor && sun4v_chip_type >= SUN4V_CHIP_NIAGARA4) num = 4; for (i = 0; i < num; i++) { pp->pcr[i] = pcr_ops->read_pcr(i); pp->pic[i] = pcr_ops->read_pic(i); } } static void __global_pmu_poll(struct global_pmu_snapshot *pp) { int limit = 0; while (!pp->pcr[0] && ++limit < 100) { barrier(); udelay(1); } } static void pmu_snapshot_all_cpus(void) { return register_sysrq_key('y', &sparc_globalreg_op); unsigned long flags; int this_cpu, cpu; spin_lock_irqsave(&global_cpu_snapshot_lock, flags); memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); this_cpu = raw_smp_processor_id(); __global_pmu_self(this_cpu); smp_fetch_global_pmu(); for_each_online_cpu(cpu) { struct global_pmu_snapshot *pp = &global_cpu_snapshot[cpu].pmu; __global_pmu_poll(pp); printk("%c CPU[%3d]: PCR[%08lx:%08lx:%08lx:%08lx] PIC[%08lx:%08lx:%08lx:%08lx]\n", (cpu == this_cpu ? '*' : ' '), cpu, pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3], pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]); } memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); } static void sysrq_handle_globpmu(int key) { pmu_snapshot_all_cpus(); } static struct sysrq_key_op sparc_globalpmu_op = { .handler = sysrq_handle_globpmu, .help_msg = "global-pmu(X)", .action_msg = "Show Global PMU Regs", }; static int __init sparc_sysrq_init(void) { int ret = register_sysrq_key('y', &sparc_globalreg_op); if (!ret) ret = register_sysrq_key('x', &sparc_globalpmu_op); return ret; } core_initcall(sparc_globreg_init); core_initcall(sparc_sysrq_init); #endif Loading
arch/sparc/kernel/smp_64.c +11 −0 Original line number Diff line number Diff line Loading @@ -852,6 +852,8 @@ extern unsigned long xcall_flush_tlb_mm; extern unsigned long xcall_flush_tlb_pending; extern unsigned long xcall_flush_tlb_kernel_range; extern unsigned long xcall_fetch_glob_regs; extern unsigned long xcall_fetch_glob_pmu; extern unsigned long xcall_fetch_glob_pmu_n4; extern unsigned long xcall_receive_signal; extern unsigned long xcall_new_mmu_context_version; #ifdef CONFIG_KGDB Loading Loading @@ -1000,6 +1002,15 @@ void smp_fetch_global_regs(void) smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0); } void smp_fetch_global_pmu(void) { if (tlb_type == hypervisor && sun4v_chip_type >= SUN4V_CHIP_NIAGARA4) smp_cross_call(&xcall_fetch_glob_pmu_n4, 0, 0, 0); else smp_cross_call(&xcall_fetch_glob_pmu, 0, 0, 0); } /* We know that the window frames of the user have been flushed * to the stack before we get here because all callers of us * are flush_tlb_*() routines, and these run after flush_cache_*() Loading