162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __SPARC_SWITCH_TO_H
362306a36Sopenharmony_ci#define __SPARC_SWITCH_TO_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/smp.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciextern struct thread_info *current_set[NR_CPUS];
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Flush windows so that the VM switch which follows
1162306a36Sopenharmony_ci * would not pull the stack from under us.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * SWITCH_ENTER and SWITCH_DO_LAZY_FPU do not work yet (e.g. SMP does not work)
1462306a36Sopenharmony_ci * XXX WTF is the above comment? Found in late teen 2.4.x.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#ifdef CONFIG_SMP
1762306a36Sopenharmony_ci#define SWITCH_ENTER(prv) \
1862306a36Sopenharmony_ci	do {			\
1962306a36Sopenharmony_ci	if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \
2062306a36Sopenharmony_ci		put_psr(get_psr() | PSR_EF); \
2162306a36Sopenharmony_ci		fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \
2262306a36Sopenharmony_ci		       &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \
2362306a36Sopenharmony_ci		clear_tsk_thread_flag(prv, TIF_USEDFPU); \
2462306a36Sopenharmony_ci		(prv)->thread.kregs->psr &= ~PSR_EF; \
2562306a36Sopenharmony_ci	} \
2662306a36Sopenharmony_ci	} while(0)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define SWITCH_DO_LAZY_FPU(next)	/* */
2962306a36Sopenharmony_ci#else
3062306a36Sopenharmony_ci#define SWITCH_ENTER(prv)		/* */
3162306a36Sopenharmony_ci#define SWITCH_DO_LAZY_FPU(nxt)	\
3262306a36Sopenharmony_ci	do {			\
3362306a36Sopenharmony_ci	if (last_task_used_math != (nxt))		\
3462306a36Sopenharmony_ci		(nxt)->thread.kregs->psr&=~PSR_EF;	\
3562306a36Sopenharmony_ci	} while(0)
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define prepare_arch_switch(next) do { \
3962306a36Sopenharmony_ci	__asm__ __volatile__( \
4062306a36Sopenharmony_ci	".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
4162306a36Sopenharmony_ci	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
4262306a36Sopenharmony_ci	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
4362306a36Sopenharmony_ci	"save %sp, -0x40, %sp\n\t" \
4462306a36Sopenharmony_ci	"restore; restore; restore; restore; restore; restore; restore"); \
4562306a36Sopenharmony_ci} while(0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* Much care has gone into this code, do not touch it.
4862306a36Sopenharmony_ci	 *
4962306a36Sopenharmony_ci	 * We need to loadup regs l0/l1 for the newly forked child
5062306a36Sopenharmony_ci	 * case because the trap return path relies on those registers
5162306a36Sopenharmony_ci	 * holding certain values, gcc is told that they are clobbered.
5262306a36Sopenharmony_ci	 * Gcc needs registers for 3 values in and 1 value out, so we
5362306a36Sopenharmony_ci	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
5462306a36Sopenharmony_ci	 *
5562306a36Sopenharmony_ci	 * Hey Dave, that do not touch sign is too much of an incentive
5662306a36Sopenharmony_ci	 * - Anton & Pete
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci#define switch_to(prev, next, last) do {						\
5962306a36Sopenharmony_ci	SWITCH_ENTER(prev);								\
6062306a36Sopenharmony_ci	SWITCH_DO_LAZY_FPU(next);							\
6162306a36Sopenharmony_ci	cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm));		\
6262306a36Sopenharmony_ci	__asm__ __volatile__(								\
6362306a36Sopenharmony_ci	"sethi	%%hi(here - 0x8), %%o7\n\t"						\
6462306a36Sopenharmony_ci	"mov	%%g6, %%g3\n\t"								\
6562306a36Sopenharmony_ci	"or	%%o7, %%lo(here - 0x8), %%o7\n\t"					\
6662306a36Sopenharmony_ci	"rd	%%psr, %%g4\n\t"							\
6762306a36Sopenharmony_ci	"std	%%sp, [%%g6 + %4]\n\t"							\
6862306a36Sopenharmony_ci	"rd	%%wim, %%g5\n\t"							\
6962306a36Sopenharmony_ci	"wr	%%g4, 0x20, %%psr\n\t"							\
7062306a36Sopenharmony_ci	"nop\n\t"									\
7162306a36Sopenharmony_ci	"std	%%g4, [%%g6 + %3]\n\t"							\
7262306a36Sopenharmony_ci	"ldd	[%2 + %3], %%g4\n\t"							\
7362306a36Sopenharmony_ci	"mov	%2, %%g6\n\t"								\
7462306a36Sopenharmony_ci	".globl	patchme_store_new_current\n"						\
7562306a36Sopenharmony_ci"patchme_store_new_current:\n\t"							\
7662306a36Sopenharmony_ci	"st	%2, [%1]\n\t"								\
7762306a36Sopenharmony_ci	"wr	%%g4, 0x20, %%psr\n\t"							\
7862306a36Sopenharmony_ci	"nop\n\t"									\
7962306a36Sopenharmony_ci	"nop\n\t"									\
8062306a36Sopenharmony_ci	"nop\n\t"	/* LEON needs all 3 nops: load to %sp depends on CWP. */		\
8162306a36Sopenharmony_ci	"ldd	[%%g6 + %4], %%sp\n\t"							\
8262306a36Sopenharmony_ci	"wr	%%g5, 0x0, %%wim\n\t"							\
8362306a36Sopenharmony_ci	"ldd	[%%sp + 0x00], %%l0\n\t"						\
8462306a36Sopenharmony_ci	"ldd	[%%sp + 0x38], %%i6\n\t"						\
8562306a36Sopenharmony_ci	"wr	%%g4, 0x0, %%psr\n\t"							\
8662306a36Sopenharmony_ci	"nop\n\t"									\
8762306a36Sopenharmony_ci	"nop\n\t"									\
8862306a36Sopenharmony_ci	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
8962306a36Sopenharmony_ci	" ld	[%%g3 + %5], %0\n\t"							\
9062306a36Sopenharmony_ci	"here:\n"									\
9162306a36Sopenharmony_ci        : "=&r" (last)									\
9262306a36Sopenharmony_ci        : "r" (&(current_set[hard_smp_processor_id()])),	\
9362306a36Sopenharmony_ci	  "r" (task_thread_info(next)),				\
9462306a36Sopenharmony_ci	  "i" (TI_KPSR),					\
9562306a36Sopenharmony_ci	  "i" (TI_KSP),						\
9662306a36Sopenharmony_ci	  "i" (TI_TASK)						\
9762306a36Sopenharmony_ci	:       "g1", "g2", "g3", "g4", "g5",       "g7",	\
9862306a36Sopenharmony_ci	  "l0", "l1",       "l3", "l4", "l5", "l6", "l7",	\
9962306a36Sopenharmony_ci	  "i0", "i1", "i2", "i3", "i4", "i5",			\
10062306a36Sopenharmony_ci	  "o0", "o1", "o2", "o3",                   "o7");	\
10162306a36Sopenharmony_ci	} while(0)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_civoid fpsave(unsigned long *fpregs, unsigned long *fsr,
10462306a36Sopenharmony_ci	    void *fpqueue, unsigned long *fpqdepth);
10562306a36Sopenharmony_civoid synchronize_user_stack(void);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#endif /* __SPARC_SWITCH_TO_H */
108