In preparation for CONFIG_THREAD_INFO_IN_TASK, where the thread_info is
no longer located at the bottom of the kernel's stack, keep a copy of
each CPU's current thread. Initialise it to the init thread on each CPU,
switch it on context switch, and restore it on entry to kernel space.
Signed-off-by: Matt Redfearn <matt.redfearn@mips.com>
---
arch/mips/include/asm/stackframe.h | 50 ++++++++++++++++++++++++++++++++++---
arch/mips/include/asm/thread_info.h | 3 +++
arch/mips/kernel/genex.S | 8 +++---
arch/mips/kernel/head.S | 2 ++
arch/mips/kernel/octeon_switch.S | 3 ++-
arch/mips/kernel/r2300_switch.S | 3 ++-
arch/mips/kernel/r4k_switch.S | 3 ++-
arch/mips/kernel/setup.c | 1 +
arch/mips/kernel/smp.c | 1 +
9 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/arch/mips/include/asm/stackframe.h
b/arch/mips/include/asm/stackframe.h
index bdcd4088d764..d83d148fec28 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -95,8 +95,7 @@
#endif
/* Set thread_info if we're coming from user mode */
- ori $28, sp, _THREAD_MASK
- xori $28, _THREAD_MASK
+ get_saved_ti $28, v1
#ifdef CONFIG_CPU_CAVIUM_OCTEON
.set push
.set mips64
@@ -165,13 +164,58 @@
.endm
/*
+ * get_saved_ti returns the thread_info for the current CPU by looking in the
+ * thread_info_ptr array for it. It clobbers k0 and returns the value in k1.
+ */
+#ifdef CONFIG_SMP
+ /* SMP variation */
+ .macro get_saved_ti out temp
+ ASM_CPUID_MFC0 \temp, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+ lui \out, %hi(thread_info_ptr)
+#else
+ lui \out, %highest(thread_info_ptr)
+ daddiu \out, %higher(thread_info_ptr)
+ dsll \out, 16
+ daddiu \out, %hi(thread_info_ptr)
+ dsll \out, 16
+#endif
+ LONG_SRL \temp, SMP_CPUID_PTRSHIFT
+ LONG_ADDU \out, \temp
+ LONG_L \out, %lo(thread_info_ptr)(\out)
+ .endm
+
+ .macro set_saved_ti ti temp
+ ASM_CPUID_MFC0 \temp, ASM_SMP_CPUID_REG
+ LONG_SRL \temp, SMP_CPUID_PTRSHIFT
+ LONG_S \ti, thread_info_ptr(\temp)
+ .endm
+#else /* !CONFIG_SMP */
+ .macro get_saved_ti out temp /* Uniprocessor variation */
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+ lui \out, %hi(thread_info_ptr)
+#else
+ lui \out, %highest(thread_info_ptr)
+ daddiu \out, %higher(thread_info_ptr)
+ dsll \out, \out, 16
+ daddiu \out, %hi(thread_info_ptr)
+ dsll \out, \out, 16
+#endif
+ LONG_L \out, %lo(thread_info_ptr)(\out)
+ .endm
+
+ .macro set_saved_ti ti temp
+ LONG_S \ti, thread_info_ptr
+ .endm
+#endif
+
+/*
* get_saved_sp returns the SP for the current CPU by looking in the
* kernelsp array for it. If tosp is set, it stores the current sp in
* k0 and loads the new value in sp. If not, it clobbers k0 and
* stores the new value in k1, leaving sp unaffected.
*/
#ifdef CONFIG_SMP
-
/* SMP variation */
.macro get_saved_sp docfi=0 tosp=0
ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG
diff --git a/arch/mips/include/asm/thread_info.h
b/arch/mips/include/asm/thread_info.h
index 5e8927f99a76..b8cc81055d57 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -55,6 +55,9 @@ struct thread_info {
/* How to get the thread information struct from C. */
register struct thread_info *__current_thread_info __asm__("$28");
+/* thread_info pointer for each CPU */
+extern unsigned long thread_info_ptr[NR_CPUS];
+
static inline struct thread_info *current_thread_info(void)
{
return __current_thread_info;
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 37b9383eacd3..9f7347211ab4 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -581,12 +581,10 @@ docheck:
isrdhwr:
/* The insn is rdhwr. No need to check CAUSE.BD here. */
- get_saved_sp /* k1 := current_thread_info */
+ get_saved_ti k1, k0
.set noreorder
MFC0 k0, CP0_EPC
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
- ori k1, _THREAD_MASK
- xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
LONG_ADDIU k0, 4
jr k0
@@ -601,8 +599,8 @@ isrdhwr:
#endif
MTC0 k0, CP0_EPC
/* I hope three instructions between MTC0 and ERET are enough... */
- ori k1, _THREAD_MASK
- xori k1, _THREAD_MASK
+ nop
+ nop
LONG_L v1, TI_TP_VALUE(k1)
.set arch=r4000
eret
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 0fcb3e048ece..c74f2e1f4b08 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -135,6 +135,7 @@ dtb_found:
PTR_LI sp, _THREAD_SIZE - 32 - PT_SIZE
PTR_ADDU sp, $28
back_to_back_c0_hazard
+ set_saved_ti $28, t0
set_saved_sp sp, t0, t1
PTR_SUBU sp, 4 * SZREG # init stack pointer
@@ -146,6 +147,7 @@ dtb_found:
PTR_ADDU $28, v0
PTR_ADDU sp, v0
+ set_saved_ti $28, t0
set_saved_sp sp, t0, t1
/*
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S
index e42113fe2762..b0ef486ad6c1 100644
--- a/arch/mips/kernel/octeon_switch.S
+++ b/arch/mips/kernel/octeon_switch.S
@@ -69,10 +69,11 @@
/*
* The order of restoring the registers takes care of the race
- * updating $28, $29 and kernelsp without disabling ints.
+ * updating $28, $29 and saved_ti without disabling ints.
*/
move $28, a2
cpu_restore_nonscratch a1
+ set_saved_ti $28, t0
PTR_ADDU t0, $28, _THREAD_SIZE - 32
set_saved_sp t0, t1, t2
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 665897139f30..6e6c012dfc5e 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -44,10 +44,11 @@ LEAF(resume)
/*
* The order of restoring the registers takes care of the race
- * updating $28, $29 and kernelsp without disabling ints.
+ * updating $28, $29 and saved_ti without disabling ints.
*/
move $28, a2
cpu_restore_nonscratch a1
+ set_saved_ti $28, t0
addiu t1, $28, _THREAD_SIZE - 32
sw t1, kernelsp
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 17cf9341c1cf..5afbbc1b4bd3 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -39,10 +39,11 @@
/*
* The order of restoring the registers takes care of the race
- * updating $28, $29 and kernelsp without disabling ints.
+ * updating $28, $29 and saved_ti without disabling ints.
*/
move $28, a2
cpu_restore_nonscratch a1
+ set_saved_ti $28, t0
PTR_ADDU t0, $28, _THREAD_SIZE - 32
set_saved_sp t0, t1, t2
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 702c678de116..d7078589a077 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -1025,6 +1025,7 @@ void __init setup_arch(char **cmdline_p)
}
unsigned long kernelsp[NR_CPUS];
+unsigned long thread_info_ptr[NR_CPUS];
unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
#ifdef CONFIG_USE_OF
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index defec7499ccd..b93e6748f38d 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -458,6 +458,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
int err;
+ thread_info_ptr[cpu] = (unsigned long)task_thread_info(tidle);
err = mp_ops->boot_secondary(cpu, tidle);
if (err)
return err;
--
2.7.4
|