1/*
2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Vineetg: Aug 2009
9 *  -"C" version of lowest level context switch asm macro called by schedular
10 *   gcc doesn't generate the dward CFI info for hand written asm, hence can't
11 *   backtrace out of it (e.g. tasks sleeping in kernel).
12 *   So we cheat a bit by writing almost similar code in inline-asm.
13 *  -This is a hacky way of doing things, but there is no other simple way.
14 *   I don't want/intend to extend unwinding code to understand raw asm
15 */
16
17#include <asm/asm-offsets.h>
18#include <linux/sched.h>
19
20#define KSP_WORD_OFF 	((TASK_THREAD + THREAD_KSP) / 4)
21
22struct task_struct *__sched
23__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
24{
25	unsigned int tmp;
26	unsigned int prev = (unsigned int)prev_task;
27	unsigned int next = (unsigned int)next_task;
28
29	__asm__ __volatile__(
30		/* FP/BLINK save generated by gcc (standard function prologue */
31		"st.a    r13, [sp, -4]   \n\t"
32		"st.a    r14, [sp, -4]   \n\t"
33		"st.a    r15, [sp, -4]   \n\t"
34		"st.a    r16, [sp, -4]   \n\t"
35		"st.a    r17, [sp, -4]   \n\t"
36		"st.a    r18, [sp, -4]   \n\t"
37		"st.a    r19, [sp, -4]   \n\t"
38		"st.a    r20, [sp, -4]   \n\t"
39		"st.a    r21, [sp, -4]   \n\t"
40		"st.a    r22, [sp, -4]   \n\t"
41		"st.a    r23, [sp, -4]   \n\t"
42		"st.a    r24, [sp, -4]   \n\t"
43#ifndef CONFIG_ARC_CURR_IN_REG
44		"st.a    r25, [sp, -4]   \n\t"
45#else
46		"sub     sp, sp, 4      \n\t"	/* usual r25 placeholder */
47#endif
48
49		/* set ksp of outgoing task in tsk->thread.ksp */
50#if KSP_WORD_OFF <= 255
51		"st.as   sp, [%3, %1]    \n\t"
52#else
53		/*
54		 * Workaround for NR_CPUS=4k
55		 * %1 is bigger than 255 (S9 offset for st.as)
56		 */
57		"add2    r24, %3, %1     \n\t"
58		"st      sp, [r24]       \n\t"
59#endif
60
61		/*
62		 * setup _current_task with incoming tsk.
63		 * optionally, set r25 to that as well
64		 * For SMP extra work to get to &_current_task[cpu]
65		 * (open coded SET_CURR_TASK_ON_CPU)
66		 */
67#ifndef CONFIG_SMP
68		"st  %2, [@_current_task]	\n\t"
69#else
70		"lr   r24, [identity]		\n\t"
71		"lsr  r24, r24, 8		\n\t"
72		"bmsk r24, r24, 7		\n\t"
73		"add2 r24, @_current_task, r24	\n\t"
74		"st   %2,  [r24]		\n\t"
75#endif
76#ifdef CONFIG_ARC_CURR_IN_REG
77		"mov r25, %2   \n\t"
78#endif
79
80		/* get ksp of incoming task from tsk->thread.ksp */
81		"ld.as  sp, [%2, %1]   \n\t"
82
83		/* start loading it's CALLEE reg file */
84
85#ifndef CONFIG_ARC_CURR_IN_REG
86		"ld.ab   r25, [sp, 4]   \n\t"
87#else
88		"add    sp, sp, 4       \n\t"
89#endif
90		"ld.ab   r24, [sp, 4]   \n\t"
91		"ld.ab   r23, [sp, 4]   \n\t"
92		"ld.ab   r22, [sp, 4]   \n\t"
93		"ld.ab   r21, [sp, 4]   \n\t"
94		"ld.ab   r20, [sp, 4]   \n\t"
95		"ld.ab   r19, [sp, 4]   \n\t"
96		"ld.ab   r18, [sp, 4]   \n\t"
97		"ld.ab   r17, [sp, 4]   \n\t"
98		"ld.ab   r16, [sp, 4]   \n\t"
99		"ld.ab   r15, [sp, 4]   \n\t"
100		"ld.ab   r14, [sp, 4]   \n\t"
101		"ld.ab   r13, [sp, 4]   \n\t"
102
103		/* last (ret value) = prev : although for ARC it mov r0, r0 */
104		"mov     %0, %3        \n\t"
105
106		/* FP/BLINK restore generated by gcc (standard func epilogue */
107
108		: "=r"(tmp)
109		: "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
110		: "blink"
111	);
112
113	return (struct task_struct *)tmp;
114}
115