Commit fd476197 authored by Vineet Gupta's avatar Vineet Gupta
Browse files

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
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
 * struct thread_info
 */
struct thread_struct {
	unsigned long ksp;	/* kernel mode stack pointer */
	unsigned long callee_reg;	/* pointer to callee regs */
	unsigned long fault_address;	/* dbls as brkpt holder as well */
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
@@ -54,7 +53,7 @@ struct task_struct;
 * 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
 */
#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) + \
					sizeof(struct callee_regs) + off)))
+5 −5
Original line number Diff line number Diff line
@@ -37,16 +37,16 @@
 */
struct thread_info {
	unsigned long flags;		/* low level flags */
	unsigned long ksp;		/* kernel mode stack top in __switch_to */
	int preempt_count;		/* 0 => preemptable, <0 => BUG */
	struct task_struct *task;	/* main task structure */
	__u32 cpu;			/* current CPU */
	int cpu;			/* current CPU */
	unsigned long thr_ptr;		/* TLS ptr */
	struct task_struct *task;	/* main task structure */
};

/*
 * macros/functions for gaining access to the thread information structure
 *
 * preempt_count needs to be 1 initially, until the scheduler is functional.
 * initilaize thread_info for any @tsk
 *  - this is not related to init_task per se
 */
#define INIT_THREAD_INFO(tsk)			\
{						\
+1 −1
Original line number Diff line number Diff line
@@ -20,13 +20,13 @@ int main(void)

	BLANK();

	DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
	DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
	DEFINE(THREAD_FAULT_ADDR,
	       offsetof(struct thread_struct, fault_address));

	BLANK();

	DEFINE(THREAD_INFO_KSP, offsetof(struct thread_info, ksp));
	DEFINE(THREAD_INFO_FLAGS, offsetof(struct thread_info, flags));
	DEFINE(THREAD_INFO_PREEMPT_COUNT,
	       offsetof(struct thread_info, preempt_count));
+10 −12
Original line number Diff line number Diff line
@@ -11,8 +11,6 @@
#include <asm/entry.h>       /* For the SAVE_* macros */
#include <asm/asm-offsets.h>

#define KSP_WORD_OFF 	((TASK_THREAD + THREAD_KSP) / 4)

; IN
;  - r0: prev task (also current)
;  - r1: next task
@@ -37,19 +35,19 @@ ENTRY_CFI(__switch_to)
	/* kernel mode callee regs of @prev */
	SAVE_CALLEE_SAVED_KERNEL

	/* save final SP to @prev->thread.ksp */
#if KSP_WORD_OFF  <= 255
	st.as  sp, [r0, KSP_WORD_OFF]
#else
	/* Workaround for NR_CPUS=4k as ST.as can only take s9 offset */
	add2	r10, r0, KSP_WORD_OFF
	st	sp, [r10]
#endif
	/*
	 * save final SP to @prev->thread_info.ksp
	 * @prev is "current" so thread_info derived from SP
	 */
	GET_CURR_THR_INFO_FROM_SP  r10
	st	sp,  [r10, THREAD_INFO_KSP]

	/* update @next in _current_task[] and GP register caching it */
	SET_CURR_TASK_ON_CPU  r1, r10

	/* load SP from @next->thread.ksp */
	ld.as	sp, [r1, KSP_WORD_OFF]
	/* load SP from @next->thread_info.ksp */
	ld	r10, [r1, TASK_THREAD_INFO]
	ld	sp,  [r10, THREAD_INFO_KSP]

	/* restore callee regs, stack frame regs of @next */
	RESTORE_CALLEE_SAVED_KERNEL
+3 −3
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ asmlinkage void ret_from_fork(void);
 * |    unused      |
 * |                |
 * ------------------
 * |     r25        |   <==== top of Stack (thread.ksp)
 * |     r25        |   <==== top of Stack (thread_info.ksp)
 * ~                ~
 * |    --to--      |   (CALLEE Regs of kernel mode)
 * |     r13        |
@@ -181,14 +181,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
	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
	 * stack layout nevertheless needs to remain the same.
	 * Also, since __switch_to anyways unwinds callee regs, we use
	 * this to populate kernel thread entry-pt/args into callee regs,
	 * 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 */
	childksp[0] = 0;			/* fp */