diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 4129c0449856bbe61a34e670ec87996cd71bd19a..0a0c05fc3a33b5f4d314545239594a3198dd3353 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,6 +1,6 @@
 /*  arch/sparc64/kernel/process.c
  *
- *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1995, 1996, 2008 David S. Miller (davem@davemloft.net)
  *  Copyright (C) 1996       Eddie C. Dost   (ecd@skynet.be)
  *  Copyright (C) 1997, 1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/elfcore.h>
+#include <linux/sysrq.h>
 
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
@@ -49,6 +50,8 @@
 #include <asm/sstate.h>
 #include <asm/reboot.h>
 #include <asm/syscalls.h>
+#include <asm/irq_regs.h>
+#include <asm/smp.h>
 
 /* #define VERBOSE_SHOWREGS */
 
@@ -298,6 +301,118 @@ void show_regs(struct pt_regs *regs)
 #endif
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
+struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
+static DEFINE_SPINLOCK(global_reg_snapshot_lock);
+
+static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
+			      int this_cpu)
+{
+	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];
+
+	if (regs->tstate & TSTATE_PRIV) {
+		struct reg_window *rw;
+
+		rw = (struct reg_window *)
+			(regs->u_regs[UREG_FP] + STACK_BIAS);
+		global_reg_snapshot[this_cpu].i7 = rw->ins[6];
+	} else
+		global_reg_snapshot[this_cpu].i7 = 0;
+
+	global_reg_snapshot[this_cpu].thread = tp;
+}
+
+/* In order to avoid hangs we do not try to synchronize with the
+ * global register dump client cpus.  The last store they make is to
+ * the thread pointer, so do a short poll waiting for that to become
+ * non-NULL.
+ */
+static void __global_reg_poll(struct global_reg_snapshot *gp)
+{
+	int limit = 0;
+
+	while (!gp->thread && ++limit < 100) {
+		barrier();
+		udelay(1);
+	}
+}
+
+static void sysrq_handle_globreg(int key, struct tty_struct *tty)
+{
+	struct thread_info *tp = current_thread_info();
+	struct pt_regs *regs = get_irq_regs();
+#ifdef CONFIG_KALLSYMS
+	char buffer[KSYM_SYMBOL_LEN];
+#endif
+	unsigned long flags;
+	int this_cpu, cpu;
+
+	if (!regs)
+		regs = tp->kregs;
+
+	spin_lock_irqsave(&global_reg_snapshot_lock, flags);
+
+	memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
+
+	this_cpu = raw_smp_processor_id();
+
+	__global_reg_self(tp, regs, this_cpu);
+
+	smp_fetch_global_regs();
+
+	for_each_online_cpu(cpu) {
+		struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
+		struct thread_info *tp;
+
+		__global_reg_poll(gp);
+
+		tp = gp->thread;
+		printk("%c CPU[%3d]: TSTATE[%016lx] TPC[%016lx] TNPC[%016lx] TASK[%s:%d]\n",
+		       (cpu == this_cpu ? '*' : ' '), cpu,
+		       gp->tstate, gp->tpc, gp->tnpc,
+		       ((tp && tp->task) ? tp->task->comm : "NULL"),
+		       ((tp && tp->task) ? tp->task->pid : -1));
+#ifdef CONFIG_KALLSYMS
+		if (gp->tstate & TSTATE_PRIV) {
+			sprint_symbol(buffer, gp->tpc);
+			printk("             TPC[%s] ", buffer);
+			sprint_symbol(buffer, gp->o7);
+			printk("O7[%s] ", buffer);
+			sprint_symbol(buffer, gp->i7);
+			printk("I7[%s]\n", buffer);
+		} else
+#endif
+		{
+			printk("             TPC[%lx] O7[%lx] I7[%lx]\n",
+			       gp->tpc, gp->o7, gp->i7);
+		}
+	}
+
+	memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot));
+
+	spin_unlock_irqrestore(&global_reg_snapshot_lock, flags);
+}
+
+static struct sysrq_key_op sparc_globalreg_op = {
+	.handler	= sysrq_handle_globreg,
+	.help_msg	= "Globalregs",
+	.action_msg	= "Show Global CPU Regs",
+};
+
+static int __init sparc_globreg_init(void)
+{
+	return register_sysrq_key('y', &sparc_globalreg_op);
+}
+
+core_initcall(sparc_globreg_init);
+
+#endif
+
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
 	struct thread_info *ti = task_thread_info(tsk);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 0d6403a630acd1f4c2e22201755d67de04a83cc1..fa63c68a181941736a7809553d41538a1c5ab074 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -900,6 +900,9 @@ 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_report_regs;
+#ifdef CONFIG_MAGIC_SYSRQ
+extern unsigned long xcall_fetch_glob_regs;
+#endif
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_new_mmu_context_version;
 #ifdef CONFIG_KGDB
@@ -1080,6 +1083,13 @@ void smp_report_regs(void)
 	smp_cross_call(&xcall_report_regs, 0, 0, 0);
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
+void smp_fetch_global_regs(void)
+{
+	smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0);
+}
+#endif
+
 /* 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_*()
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 15d124963f684237f7599000122f47fe1d9ee342..9bb2d90a9df6ba948e566f6c7c11d92a0a437837 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,7 +1,7 @@
 /*
  * ultra.S: Don't expand these all over the place...
  *
- * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 2000, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <asm/asi.h>
@@ -15,6 +15,7 @@
 #include <asm/thread_info.h>
 #include <asm/cacheflush.h>
 #include <asm/hypervisor.h>
+#include <asm/cpudata.h>
 
 	/* Basically, most of the Spitfire vs. Cheetah madness
 	 * has to do with the fact that Cheetah does not support
@@ -514,6 +515,32 @@ xcall_report_regs:
 	b		rtrap_xcall
 	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 
+#ifdef CONFIG_MAGIC_SYSRQ
+	.globl		xcall_fetch_glob_regs
+xcall_fetch_glob_regs:
+	sethi		%hi(global_reg_snapshot), %g1
+	or		%g1, %lo(global_reg_snapshot), %g1
+	__GET_CPUID(%g2)
+	sllx		%g2, 6, %g3
+	add		%g1, %g3, %g1
+	rdpr		%tstate, %g7
+	stx		%g7, [%g1 + GR_SNAP_TSTATE]
+	rdpr		%tpc, %g7
+	stx		%g7, [%g1 + GR_SNAP_TPC]
+	rdpr		%tnpc, %g7
+	stx		%g7, [%g1 + GR_SNAP_TNPC]
+	stx		%o7, [%g1 + GR_SNAP_O7]
+	stx		%i7, [%g1 + GR_SNAP_I7]
+	sethi		%hi(trap_block), %g7
+	or		%g7, %lo(trap_block), %g7
+	sllx		%g2, TRAP_BLOCK_SZ_SHIFT, %g2
+	add		%g7, %g2, %g7
+	ldx		[%g7 + TRAP_PER_CPU_THREAD], %g3
+	membar		#StoreStore
+	stx		%g3, [%g1 + GR_SNAP_THREAD]
+	retry
+#endif /* CONFIG_MAGIC_SYSRQ */
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 	.align		32
 	.globl		xcall_flush_dcache_page_cheetah
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 9e9bad8bdcf4e6725a982f92522b338bbf9731f3..dbce1263bdff2314ed637d647694b5dae68cc905 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -402,6 +402,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
 	&sysrq_showstate_blocked_op,	/* w */
 	/* x: May be registered on ppc/powerpc for xmon */
 	NULL,				/* x */
+	/* y: May be registered on sparc64 for global register dump */
 	NULL,				/* y */
 	NULL				/* z */
 };
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h
index 90972a5ada59f8e3b324f430587922c7cbb2a562..d8a56cddf7f26c3f20ad4874eb24f81757f66f56 100644
--- a/include/asm-sparc64/ptrace.h
+++ b/include/asm-sparc64/ptrace.h
@@ -126,6 +126,17 @@ struct sparc_trapf {
 #define TRACEREG32_SZ	sizeof(struct pt_regs32)
 #define STACKFRAME32_SZ	sizeof(struct sparc_stackf32)
 
+struct global_reg_snapshot {
+	unsigned long		tstate;
+	unsigned long		tpc;
+	unsigned long		tnpc;
+	unsigned long		o7;
+	unsigned long		i7;
+	struct thread_info	*thread;
+	unsigned long		pad1;
+	unsigned long		pad2;
+};
+
 #ifdef __KERNEL__
 
 #define __ARCH_WANT_COMPAT_SYS_PTRACE
@@ -295,6 +306,16 @@ extern void __show_regs(struct pt_regs *);
 #define SF_XARG5  0x58
 #define SF_XXARG  0x5c
 
+/* global_reg_snapshot offsets */
+#define GR_SNAP_TSTATE	0x00
+#define GR_SNAP_TPC	0x08
+#define GR_SNAP_TNPC	0x10
+#define GR_SNAP_O7	0x18
+#define GR_SNAP_I7	0x20
+#define GR_SNAP_THREAD	0x28
+#define GR_SNAP_PAD1	0x30
+#define GR_SNAP_PAD2	0x38
+
 /* Stuff for the ptrace system call */
 #define PTRACE_SPARC_DETACH       11
 #define PTRACE_GETREGS            12
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index 1c1c5ea5cea5dea69e40cf4c4a96932f4d24d58b..cd0311b2e19dbf63173cde102650b19bea84ddc8 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -1,6 +1,6 @@
 /* smp.h: Sparc64 specific SMP stuff.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #ifndef _SPARC64_SMP_H
@@ -44,6 +44,8 @@ extern int hard_smp_processor_id(void);
 extern void smp_fill_in_sib_core_maps(void);
 extern void cpu_play_dead(void);
 
+extern void smp_fetch_global_regs(void);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
@@ -55,6 +57,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)
 
 #endif /* !(CONFIG_SMP) */