diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index b12eeee0e9748f841d85de87dfe2f7a7c3503d69..27fc1843423e8d9b5e6f2900a59c8cd815f37172 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -588,6 +588,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
 		c->options |= MIPS_CPU_VEIC;
 	if (config3 & MIPS_CONF3_MT)
 	        c->ases |= MIPS_ASE_MIPSMT;
+	if (config3 & MIPS_CONF3_ULRI)
+		c->options |= MIPS_CPU_ULRI;
 
 	return config3 & MIPS_CONF_M;
 }
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 9dd5a2df8eac344c7701b2b7dab734c30d25d770..b947c61c0cc817f3d154f15c05d33d9fb27bdbae 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -272,9 +272,8 @@ asmlinkage int sys_set_thread_area(unsigned long addr)
 	struct thread_info *ti = task_thread_info(current);
 
 	ti->tp_value = addr;
-
-	/* If some future MIPS implementation has this register in hardware,
-	 * we will need to update it here (and in context switches).  */
+	if (cpu_has_userlocal)
+		write_c0_userlocal(addr);
 
 	return 0;
 }
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index c598e890a880103ea0af04f5f4f7b85221d1f55f..9b19a84d11ef2f006aedab7f66edc5901860a26c 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1341,7 +1341,14 @@ void __init per_cpu_trap_init(void)
 		set_c0_status(ST0_MX);
 
 #ifdef CONFIG_CPU_MIPSR2
-	write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
+	if (cpu_has_mips_r2) {
+		unsigned int enable = 0x0000000f;
+
+		if (cpu_has_userlocal)
+			enable |= (1 << 29);
+
+		write_c0_hwrena(enable);
+	}
 #endif
 
 #ifdef CONFIG_MIPS_MT_SMTC
diff --git a/include/asm-mips/cpu-features.h b/include/asm-mips/cpu-features.h
index 5e4bed123b487640f13541f3153e5d1e43960ab1..d95a83e3e1d72e4111005764e5e0825610b0f372 100644
--- a/include/asm-mips/cpu-features.h
+++ b/include/asm-mips/cpu-features.h
@@ -150,6 +150,10 @@
 #define cpu_has_mipsmt		(cpu_data[0].ases & MIPS_ASE_MIPSMT)
 #endif
 
+#ifndef cpu_has_userlocal
+#define cpu_has_userlocal	(cpu_data[0].options & MIPS_CPU_ULRI)
+#endif
+
 #ifdef CONFIG_32BIT
 # ifndef cpu_has_nofpuex
 # define cpu_has_nofpuex	(cpu_data[0].options & MIPS_CPU_NOFPUEX)
diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h
index 2924069075e0a3b3a3342868d593de128ed880cc..49c1f0011863d2a12ced0aef961087e040924d94 100644
--- a/include/asm-mips/cpu.h
+++ b/include/asm-mips/cpu.h
@@ -257,6 +257,7 @@
 #define MIPS_CPU_PREFETCH	0x00080000 /* CPU has usable prefetch */
 #define MIPS_CPU_VINT		0x00100000 /* CPU supports MIPSR2 vectored interrupts */
 #define MIPS_CPU_VEIC		0x00200000 /* CPU supports MIPSR2 external interrupt controller mode */
+#define MIPS_CPU_ULRI		0x00400000 /* CPU has ULRI feature */
 
 /*
  * CPU ASE encodings
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 89c81922d47cea5c5ea229cc6c87f1b5e525b9b7..668db02c28043d796f9663838f8e66c6f544d490 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -7,7 +7,7 @@
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Modified for further R[236]000 support by Paul M. Antoine, 1996.
  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2000, 07 MIPS Technologies, Inc.
  * Copyright (C) 2003, 2004  Maciej W. Rozycki
  */
 #ifndef _ASM_MIPSREGS_H
@@ -533,6 +533,7 @@
 #define MIPS_CONF3_VEIC		(_ULCAST_(1) <<  6)
 #define MIPS_CONF3_LPA		(_ULCAST_(1) <<  7)
 #define MIPS_CONF3_DSP		(_ULCAST_(1) << 10)
+#define MIPS_CONF3_ULRI		(_ULCAST_(1) << 13)
 
 #define MIPS_CONF7_WII		(_ULCAST_(1) << 31)
 
@@ -772,6 +773,9 @@ do {									\
 #define read_c0_context()	__read_ulong_c0_register($4, 0)
 #define write_c0_context(val)	__write_ulong_c0_register($4, 0, val)
 
+#define read_c0_userlocal()	__read_ulong_c0_register($4, 2)
+#define write_c0_userlocal(val)	__write_ulong_c0_register($4, 2, val)
+
 #define read_c0_pagemask()	__read_32bit_c0_register($5, 0)
 #define write_c0_pagemask(val)	__write_32bit_c0_register($5, 0, val)
 
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 9b3a8dd2c3db5ec0c1d2bc1520057ccff3dd6e75..be64fc55562ae2928d98275ff9c9634ac74959a1 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -67,6 +67,8 @@ do {									\
 	(last) = resume(prev, next, task_thread_info(next));		\
 	if (cpu_has_dsp)						\
 		__restore_dsp(current);					\
+	if (cpu_has_userlocal)						\
+		write_c0_userlocal(task_thread_info(current)->tp_value);\
 } while(0)
 
 /*