Commit fd476197 authored by Vineet Gupta's avatar Vineet Gupta

ARC: __switch_to: move ksp to thread_info from thread_struct

task's arch specific bits are carried in 2 places
 - embedded thread_struct in task_struct
 - associated thread_info (hoisted in task's stack page) and
   syntactically: (thread_info *)(task_struct->stack)

ksp (dynamic kernel stack top) currently lives in thread_struct but
given its deep location in task struct likely to cache miss when
accessed from  __switch_to(). Moving it to thread_info would be more
efficient given proximity to frequently accessed items such as
preempt_count thus very likely to be in cache, specially in schedular
code.

Note however that currently tsk.thread.ksp takes 1 memory access (off
of tsk pointer) while new code tsk->stack.ksp would take 2, but likely
to be in cache. Moreover if task is current the 2nd reference can be
elided and instead derived from SP as (SP & ~(THREAD_SIZE - 1))

All of this also makes __switch_to() code simpler and we can see the 2
ways of retirving ksp (descrobed above) in new code.
Signed-off-by: default avatarVineet Gupta <vgupta@kernel.org>
parent b060b7d0
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
* struct thread_info * struct thread_info
*/ */
struct thread_struct { struct thread_struct {
unsigned long ksp; /* kernel mode stack pointer */
unsigned long callee_reg; /* pointer to callee regs */ unsigned long callee_reg; /* pointer to callee regs */
unsigned long fault_address; /* dbls as brkpt holder as well */ unsigned long fault_address; /* dbls as brkpt holder as well */
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
...@@ -54,7 +53,7 @@ struct task_struct; ...@@ -54,7 +53,7 @@ struct task_struct;
* Where about of Task's sp, fp, blink when it was last seen in kernel mode. * Where about of Task's sp, fp, blink when it was last seen in kernel mode.
* Look in process.c for details of kernel stack layout * Look in process.c for details of kernel stack layout
*/ */
#define TSK_K_ESP(tsk) (tsk->thread.ksp) #define TSK_K_ESP(tsk) (task_thread_info(tsk)->ksp)
#define TSK_K_REG(tsk, off) (*((unsigned long *)(TSK_K_ESP(tsk) + \ #define TSK_K_REG(tsk, off) (*((unsigned long *)(TSK_K_ESP(tsk) + \
sizeof(struct callee_regs) + off))) sizeof(struct callee_regs) + off)))
......
...@@ -37,16 +37,16 @@ ...@@ -37,16 +37,16 @@
*/ */
struct thread_info { struct thread_info {
unsigned long flags; /* low level flags */ unsigned long flags; /* low level flags */
unsigned long ksp; /* kernel mode stack top in __switch_to */
int preempt_count; /* 0 => preemptable, <0 => BUG */ int preempt_count; /* 0 => preemptable, <0 => BUG */
struct task_struct *task; /* main task structure */ int cpu; /* current CPU */
__u32 cpu; /* current CPU */
unsigned long thr_ptr; /* TLS ptr */ unsigned long thr_ptr; /* TLS ptr */
struct task_struct *task; /* main task structure */
}; };
/* /*
* macros/functions for gaining access to the thread information structure * initilaize thread_info for any @tsk
* * - this is not related to init_task per se
* preempt_count needs to be 1 initially, until the scheduler is functional.
*/ */
#define INIT_THREAD_INFO(tsk) \ #define INIT_THREAD_INFO(tsk) \
{ \ { \
......
...@@ -20,13 +20,13 @@ int main(void) ...@@ -20,13 +20,13 @@ int main(void)
BLANK(); BLANK();
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg)); DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
DEFINE(THREAD_FAULT_ADDR, DEFINE(THREAD_FAULT_ADDR,
offsetof(struct thread_struct, fault_address)); offsetof(struct thread_struct, fault_address));
BLANK(); BLANK();
DEFINE(THREAD_INFO_KSP, offsetof(struct thread_info, ksp));
DEFINE(THREAD_INFO_FLAGS, offsetof(struct thread_info, flags)); DEFINE(THREAD_INFO_FLAGS, offsetof(struct thread_info, flags));
DEFINE(THREAD_INFO_PREEMPT_COUNT, DEFINE(THREAD_INFO_PREEMPT_COUNT,
offsetof(struct thread_info, preempt_count)); offsetof(struct thread_info, preempt_count));
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include <asm/entry.h> /* For the SAVE_* macros */ #include <asm/entry.h> /* For the SAVE_* macros */
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
; IN ; IN
; - r0: prev task (also current) ; - r0: prev task (also current)
; - r1: next task ; - r1: next task
...@@ -37,19 +35,19 @@ ENTRY_CFI(__switch_to) ...@@ -37,19 +35,19 @@ ENTRY_CFI(__switch_to)
/* kernel mode callee regs of @prev */ /* kernel mode callee regs of @prev */
SAVE_CALLEE_SAVED_KERNEL SAVE_CALLEE_SAVED_KERNEL
/* save final SP to @prev->thread.ksp */ /*
#if KSP_WORD_OFF <= 255 * save final SP to @prev->thread_info.ksp
st.as sp, [r0, KSP_WORD_OFF] * @prev is "current" so thread_info derived from SP
#else */
/* Workaround for NR_CPUS=4k as ST.as can only take s9 offset */ GET_CURR_THR_INFO_FROM_SP r10
add2 r10, r0, KSP_WORD_OFF st sp, [r10, THREAD_INFO_KSP]
st sp, [r10]
#endif
/* update @next in _current_task[] and GP register caching it */ /* update @next in _current_task[] and GP register caching it */
SET_CURR_TASK_ON_CPU r1, r10 SET_CURR_TASK_ON_CPU r1, r10
/* load SP from @next->thread.ksp */ /* load SP from @next->thread_info.ksp */
ld.as sp, [r1, KSP_WORD_OFF] ld r10, [r1, TASK_THREAD_INFO]
ld sp, [r10, THREAD_INFO_KSP]
/* restore callee regs, stack frame regs of @next */ /* restore callee regs, stack frame regs of @next */
RESTORE_CALLEE_SAVED_KERNEL RESTORE_CALLEE_SAVED_KERNEL
......
...@@ -141,7 +141,7 @@ asmlinkage void ret_from_fork(void); ...@@ -141,7 +141,7 @@ asmlinkage void ret_from_fork(void);
* | unused | * | unused |
* | | * | |
* ------------------ * ------------------
* | r25 | <==== top of Stack (thread.ksp) * | r25 | <==== top of Stack (thread_info.ksp)
* ~ ~ * ~ ~
* | --to-- | (CALLEE Regs of kernel mode) * | --to-- | (CALLEE Regs of kernel mode)
* | r13 | * | r13 |
...@@ -181,14 +181,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -181,14 +181,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
c_callee = ((struct callee_regs *)childksp) - 1; c_callee = ((struct callee_regs *)childksp) - 1;
/* /*
* __switch_to() uses thread.ksp to start unwinding stack * __switch_to() uses thread_info.ksp to start unwinding stack
* For kernel threads we don't need to create callee regs, the * For kernel threads we don't need to create callee regs, the
* stack layout nevertheless needs to remain the same. * stack layout nevertheless needs to remain the same.
* Also, since __switch_to anyways unwinds callee regs, we use * Also, since __switch_to anyways unwinds callee regs, we use
* this to populate kernel thread entry-pt/args into callee regs, * this to populate kernel thread entry-pt/args into callee regs,
* so that ret_from_kernel_thread() becomes simpler. * so that ret_from_kernel_thread() becomes simpler.
*/ */
p->thread.ksp = (unsigned long)c_callee; /* THREAD_KSP */ task_thread_info(p)->ksp = (unsigned long)c_callee; /* THREAD_INFO_KSP */
/* __switch_to expects FP(0), BLINK(return addr) at top */ /* __switch_to expects FP(0), BLINK(return addr) at top */
childksp[0] = 0; /* fp */ childksp[0] = 0; /* fp */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment