162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * include/asm/processor.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef __ASM_SPARC64_PROCESSOR_H
962306a36Sopenharmony_ci#define __ASM_SPARC64_PROCESSOR_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/asi.h>
1262306a36Sopenharmony_ci#include <asm/pstate.h>
1362306a36Sopenharmony_ci#include <asm/ptrace.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * User lives in his very own context, and cannot reference us. Note
1862306a36Sopenharmony_ci * that TASK_SIZE is a misnomer, it really gives maximum user virtual
1962306a36Sopenharmony_ci * address that the kernel will allocate out.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * XXX No longer using virtual page tables, kill this upper limit...
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci#define VA_BITS		44
2462306a36Sopenharmony_ci#ifndef __ASSEMBLY__
2562306a36Sopenharmony_ci#define VPTE_SIZE	(1UL << (VA_BITS - PAGE_SHIFT + 3))
2662306a36Sopenharmony_ci#else
2762306a36Sopenharmony_ci#define VPTE_SIZE	(1 << (VA_BITS - PAGE_SHIFT + 3))
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define TASK_SIZE_OF(tsk) \
3162306a36Sopenharmony_ci	(test_tsk_thread_flag(tsk,TIF_32BIT) ? \
3262306a36Sopenharmony_ci	 (1UL << 32UL) : ((unsigned long)-VPTE_SIZE))
3362306a36Sopenharmony_ci#define TASK_SIZE \
3462306a36Sopenharmony_ci	(test_thread_flag(TIF_32BIT) ? \
3562306a36Sopenharmony_ci	 (1UL << 32UL) : ((unsigned long)-VPTE_SIZE))
3662306a36Sopenharmony_ci#ifdef __KERNEL__
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define STACK_TOP32	((1UL << 32UL) - PAGE_SIZE)
3962306a36Sopenharmony_ci#define STACK_TOP64	(0x0000080000000000UL - (1UL << 32UL))
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define STACK_TOP	(test_thread_flag(TIF_32BIT) ? \
4262306a36Sopenharmony_ci			 STACK_TOP32 : STACK_TOP64)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define STACK_TOP_MAX	STACK_TOP64
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#ifndef __ASSEMBLY__
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* The Sparc processor specific thread struct. */
5162306a36Sopenharmony_ci/* XXX This should die, everything can go into thread_info now. */
5262306a36Sopenharmony_cistruct thread_struct {
5362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_SPINLOCK
5462306a36Sopenharmony_ci	/* How many spinlocks held by this thread.
5562306a36Sopenharmony_ci	 * Used with spin lock debugging to catch tasks
5662306a36Sopenharmony_ci	 * sleeping illegally with locks held.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	int smp_lock_count;
5962306a36Sopenharmony_ci	unsigned int smp_lock_pc;
6062306a36Sopenharmony_ci#else
6162306a36Sopenharmony_ci	int dummy; /* f'in gcc bug... */
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#endif /* !(__ASSEMBLY__) */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#ifndef CONFIG_DEBUG_SPINLOCK
6862306a36Sopenharmony_ci#define INIT_THREAD  {			\
6962306a36Sopenharmony_ci	0,				\
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci#else /* CONFIG_DEBUG_SPINLOCK */
7262306a36Sopenharmony_ci#define INIT_THREAD  {					\
7362306a36Sopenharmony_ci/* smp_lock_count, smp_lock_pc, */			\
7462306a36Sopenharmony_ci   0,		   0,					\
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci#endif /* !(CONFIG_DEBUG_SPINLOCK) */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#ifndef __ASSEMBLY__
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#include <linux/types.h>
8162306a36Sopenharmony_ci#include <asm/fpumacro.h>
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct task_struct;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* On Uniprocessor, even in RMO processes see TSO semantics */
8662306a36Sopenharmony_ci#ifdef CONFIG_SMP
8762306a36Sopenharmony_ci#define TSTATE_INITIAL_MM	TSTATE_TSO
8862306a36Sopenharmony_ci#else
8962306a36Sopenharmony_ci#define TSTATE_INITIAL_MM	TSTATE_RMO
9062306a36Sopenharmony_ci#endif
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Do necessary setup to start up a newly executed thread. */
9362306a36Sopenharmony_ci#define start_thread(regs, pc, sp) \
9462306a36Sopenharmony_cido { \
9562306a36Sopenharmony_ci	unsigned long __asi = ASI_PNF; \
9662306a36Sopenharmony_ci	regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (__asi << 24UL); \
9762306a36Sopenharmony_ci	regs->tpc = ((pc & (~3)) - 4); \
9862306a36Sopenharmony_ci	regs->tnpc = regs->tpc + 4; \
9962306a36Sopenharmony_ci	regs->y = 0; \
10062306a36Sopenharmony_ci	set_thread_wstate(1 << 3); \
10162306a36Sopenharmony_ci	if (current_thread_info()->utraps) { \
10262306a36Sopenharmony_ci		if (*(current_thread_info()->utraps) < 2) \
10362306a36Sopenharmony_ci			kfree(current_thread_info()->utraps); \
10462306a36Sopenharmony_ci		else \
10562306a36Sopenharmony_ci			(*(current_thread_info()->utraps))--; \
10662306a36Sopenharmony_ci		current_thread_info()->utraps = NULL; \
10762306a36Sopenharmony_ci	} \
10862306a36Sopenharmony_ci	__asm__ __volatile__( \
10962306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
11062306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
11162306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x10]\n\t" \
11262306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x18]\n\t" \
11362306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x20]\n\t" \
11462306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x28]\n\t" \
11562306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x30]\n\t" \
11662306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x38]\n\t" \
11762306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x40]\n\t" \
11862306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x48]\n\t" \
11962306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x50]\n\t" \
12062306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x58]\n\t" \
12162306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x60]\n\t" \
12262306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
12362306a36Sopenharmony_ci	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
12462306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
12562306a36Sopenharmony_ci	"wrpr		%%g0, (1 << 3), %%wstate\n\t" \
12662306a36Sopenharmony_ci	: \
12762306a36Sopenharmony_ci	: "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \
12862306a36Sopenharmony_ci	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
12962306a36Sopenharmony_ci	fprs_write(0);	\
13062306a36Sopenharmony_ci	current_thread_info()->xfsr[0] = 0;	\
13162306a36Sopenharmony_ci	current_thread_info()->fpsaved[0] = 0;	\
13262306a36Sopenharmony_ci	regs->tstate &= ~TSTATE_PEF;	\
13362306a36Sopenharmony_ci} while (0)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define start_thread32(regs, pc, sp) \
13662306a36Sopenharmony_cido { \
13762306a36Sopenharmony_ci	unsigned long __asi = ASI_PNF; \
13862306a36Sopenharmony_ci	pc &= 0x00000000ffffffffUL; \
13962306a36Sopenharmony_ci	sp &= 0x00000000ffffffffUL; \
14062306a36Sopenharmony_ci	regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM) | (__asi << 24UL); \
14162306a36Sopenharmony_ci	regs->tpc = ((pc & (~3)) - 4); \
14262306a36Sopenharmony_ci	regs->tnpc = regs->tpc + 4; \
14362306a36Sopenharmony_ci	regs->y = 0; \
14462306a36Sopenharmony_ci	set_thread_wstate(2 << 3); \
14562306a36Sopenharmony_ci	if (current_thread_info()->utraps) { \
14662306a36Sopenharmony_ci		if (*(current_thread_info()->utraps) < 2) \
14762306a36Sopenharmony_ci			kfree(current_thread_info()->utraps); \
14862306a36Sopenharmony_ci		else \
14962306a36Sopenharmony_ci			(*(current_thread_info()->utraps))--; \
15062306a36Sopenharmony_ci		current_thread_info()->utraps = NULL; \
15162306a36Sopenharmony_ci	} \
15262306a36Sopenharmony_ci	__asm__ __volatile__( \
15362306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
15462306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
15562306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x10]\n\t" \
15662306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x18]\n\t" \
15762306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x20]\n\t" \
15862306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x28]\n\t" \
15962306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x30]\n\t" \
16062306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x38]\n\t" \
16162306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x40]\n\t" \
16262306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x48]\n\t" \
16362306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x50]\n\t" \
16462306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x58]\n\t" \
16562306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x60]\n\t" \
16662306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
16762306a36Sopenharmony_ci	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
16862306a36Sopenharmony_ci	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
16962306a36Sopenharmony_ci	"wrpr		%%g0, (2 << 3), %%wstate\n\t" \
17062306a36Sopenharmony_ci	: \
17162306a36Sopenharmony_ci	: "r" (regs), "r" (sp - sizeof(struct reg_window32)), \
17262306a36Sopenharmony_ci	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
17362306a36Sopenharmony_ci	fprs_write(0);	\
17462306a36Sopenharmony_ci	current_thread_info()->xfsr[0] = 0;	\
17562306a36Sopenharmony_ci	current_thread_info()->fpsaved[0] = 0;	\
17662306a36Sopenharmony_ci	regs->tstate &= ~TSTATE_PEF;	\
17762306a36Sopenharmony_ci} while (0)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciunsigned long __get_wchan(struct task_struct *task);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
18262306a36Sopenharmony_ci#define KSTK_EIP(tsk)  (task_pt_regs(tsk)->tpc)
18362306a36Sopenharmony_ci#define KSTK_ESP(tsk)  (task_pt_regs(tsk)->u_regs[UREG_FP])
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/* Please see the commentary in asm/backoff.h for a description of
18662306a36Sopenharmony_ci * what these instructions are doing and how they have been chosen.
18762306a36Sopenharmony_ci * To make a long story short, we are trying to yield the current cpu
18862306a36Sopenharmony_ci * strand during busy loops.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_ci#ifdef	BUILD_VDSO
19162306a36Sopenharmony_ci#define	cpu_relax()	asm volatile("\n99:\n\t"			\
19262306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
19362306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
19462306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
19562306a36Sopenharmony_ci				     ::: "memory")
19662306a36Sopenharmony_ci#else /* ! BUILD_VDSO */
19762306a36Sopenharmony_ci#define cpu_relax()	asm volatile("\n99:\n\t"			\
19862306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
19962306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
20062306a36Sopenharmony_ci				     "rd	%%ccr, %%g0\n\t"	\
20162306a36Sopenharmony_ci				     ".section	.pause_3insn_patch,\"ax\"\n\t"\
20262306a36Sopenharmony_ci				     ".word	99b\n\t"		\
20362306a36Sopenharmony_ci				     "wr	%%g0, 128, %%asr27\n\t"	\
20462306a36Sopenharmony_ci				     "nop\n\t"				\
20562306a36Sopenharmony_ci				     "nop\n\t"				\
20662306a36Sopenharmony_ci				     ".previous"			\
20762306a36Sopenharmony_ci				     ::: "memory")
20862306a36Sopenharmony_ci#endif
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/* Prefetch support.  This is tuned for UltraSPARC-III and later.
21162306a36Sopenharmony_ci * UltraSPARC-I will treat these as nops, and UltraSPARC-II has
21262306a36Sopenharmony_ci * a shallower prefetch queue than later chips.
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_ci#define ARCH_HAS_PREFETCH
21562306a36Sopenharmony_ci#define ARCH_HAS_PREFETCHW
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic inline void prefetch(const void *x)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	/* We do not use the read prefetch mnemonic because that
22062306a36Sopenharmony_ci	 * prefetches into the prefetch-cache which only is accessible
22162306a36Sopenharmony_ci	 * by floating point operations in UltraSPARC-III and later.
22262306a36Sopenharmony_ci	 * By contrast, "#one_write" prefetches into the L2 cache
22362306a36Sopenharmony_ci	 * in shared state.
22462306a36Sopenharmony_ci	 */
22562306a36Sopenharmony_ci	__asm__ __volatile__("prefetch [%0], #one_write"
22662306a36Sopenharmony_ci			     : /* no outputs */
22762306a36Sopenharmony_ci			     : "r" (x));
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline void prefetchw(const void *x)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	/* The most optimal prefetch to use for writes is
23362306a36Sopenharmony_ci	 * "#n_writes".  This brings the cacheline into the
23462306a36Sopenharmony_ci	 * L2 cache in "owned" state.
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	__asm__ __volatile__("prefetch [%0], #n_writes"
23762306a36Sopenharmony_ci			     : /* no outputs */
23862306a36Sopenharmony_ci			     : "r" (x));
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#define HAVE_ARCH_PICK_MMAP_LAYOUT
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciint do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#endif /* !(__ASSEMBLY__) */
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#endif /* !(__ASM_SPARC64_PROCESSOR_H) */
248