[SPARC64]: Add initial code to twiddle %gl on trap entry/exit.

Instead of setting/clearing PSTATE_AG we have to change
the %gl register value on sun4v.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index f255614..4d64494 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -102,7 +102,14 @@
 2:		mov	%g4, %l4
 		mov	%g5, %l5
 		add	%g7, 4, %l2
-		wrpr	%g0, ETRAP_PSTATE1, %pstate
+
+		/* Go to trap time globals so we can save them.  */
+661:		wrpr	%g0, ETRAP_PSTATE1, %pstate
+		.section .gl_1insn_patch, "ax"
+		.word	661b
+		SET_GL(0)
+		.previous
+
 		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]
 		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]
 		sllx	%l7, 24, %l7
@@ -195,9 +202,15 @@
 		rdpr	%tt, %g3
 		stx	%g3, [%g2 + STACK_BIAS + 0x78]
 
-		wrpr	%g1, %tl
 		stx	%g1, [%g2 + STACK_BIAS + 0x80]
 
+		wrpr	%g0, 1, %tl
+661:		nop
+		.section .gl_1insn_patch, "ax"
+		.word	661b
+		SET_GL(1)
+		.previous
+
 		rdpr	%tstate, %g1
 		sub	%g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2
 		ba,pt	%xcc, 1b
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index ecfbbdc..e613095 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -230,7 +230,14 @@
 1:
 		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G7], %g7
-		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
+
+		/* Normal globals are restored, go to trap globals.  */
+661:		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
+		.section		.gl_1insn_patch, "ax"
+		.word			661b
+		SET_GL(1)
+		.previous
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_I0], %i0
 		ldx			[%sp + PTREGS_OFF + PT_V9_I1], %i1
 
@@ -304,6 +311,13 @@
 		mov	%g6, %l1
 		wrpr	%g0, 0x0, %tl
 		wrpr	%g0, RTRAP_PSTATE, %pstate
+
+661:		nop
+		.section		.gl_1insn_patch, "ax"
+		.word			661b
+		SET_GL(0)
+		.previous
+
 		mov	%l1, %g6
 		ldx	[%g6 + TI_TASK], %g4
 		LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 2918ed3..aaab319 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -545,6 +545,24 @@
 #endif
 }
 
+static void __init gl_patch(void)
+{
+	struct gl_1insn_patch_entry *p;
+
+	if (tlb_type != hypervisor)
+		return;
+
+	p = &__gl_1insn_patch;
+	while (p < &__gl_1insn_patch_end) {
+		unsigned long addr = p->addr;
+
+		*(unsigned int *) (addr +  0) = p->insn;
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		p++;
+	}
+}
+
 void __init setup_arch(char **cmdline_p)
 {
 	/* Initialize PROM console and command line. */
@@ -567,6 +585,8 @@
 	 */
 	per_cpu_patch();
 
+	gl_patch();
+
 	boot_flags_init(*cmdline_p);
 
 	idprom_init();
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 1639d9c..482d1ed 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -77,6 +77,9 @@
   __cpuid_patch = .;
   .cpuid_patch : { *(.cpuid_patch) }
   __cpuid_patch_end = .;
+  __gl_1insn_patch = .;
+  .gl_1insn_patch : { *(.gl_1insn_patch) }
+  __gl_1insn_patch_end = .;
   . = ALIGN(8192); 
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 4f28a85..8666440 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -73,6 +73,11 @@
 extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
 #endif
 
+struct gl_1insn_patch_entry {
+	unsigned int	addr;
+	unsigned int	insn;
+};
+extern struct gl_1insn_patch_entry __gl_1insn_patch, __gl_1insn_patch_end;
 #endif /* !(__ASSEMBLY__) */
 
 #define TRAP_PER_CPU_THREAD	0x00
diff --git a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h
index 731c842..ff76c09 100644
--- a/include/asm-sparc64/head.h
+++ b/include/asm-sparc64/head.h
@@ -4,6 +4,10 @@
 
 #include <asm/pstate.h>
 
+	/* wrpr	%g0, val, %gl */
+#define SET_GL(val)	\
+	.word	0xa1902000 | val
+
 #define KERNBASE	0x400000
 
 #define	PTREGS_OFF	(STACK_BIAS + STACKFRAME_SZ)