1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 2020 Loongson Technology Corporation Limited
8  *
9  */
10 #ifndef _ASM_LBT_H
11 #define _ASM_LBT_H
12 
13 #include <asm/asm.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/loongarchregs.h>
16 
17 #ifdef CONFIG_CPU_HAS_LBT
18 
19 #define STR(x)  __STR(x)
20 #define __STR(x)  #x
21 
22 extern void _init_lbt(void);
23 
save_lbt_registers(struct loongarch_lbt *prev)24 static inline void save_lbt_registers(struct loongarch_lbt *prev)
25 {
26 	unsigned long tmp = 0;
27 
28 	__asm__ __volatile__ (
29 	"movscr2gr  %[tmp], $scr0					\n"
30 	"stptr.d %[tmp], %[prev], " STR(THREAD_SCR0) "		\n"
31 	"movscr2gr  %[tmp], $scr1					\n"
32 	"stptr.d %[tmp], %[prev], " STR(THREAD_SCR1) "		\n"
33 	"movscr2gr  %[tmp], $scr2					\n"
34 	"stptr.d %[tmp], %[prev], " STR(THREAD_SCR2) "		\n"
35 	"movscr2gr  %[tmp], $scr3					\n"
36 	"stptr.d %[tmp], %[prev], " STR(THREAD_SCR3) "		\n"
37 	"x86mfflag %[tmp], 0x3f					\n"
38 	"stptr.d %[tmp], %[prev], " STR(THREAD_EFLAGS) "	\n"
39 	:
40 	: [prev] "r" (prev), [tmp] "r" (tmp)
41 	: "memory"
42 	);
43 }
44 
restore_lbt_registers(struct loongarch_lbt *next)45 static inline void restore_lbt_registers(struct loongarch_lbt *next)
46 {
47 	unsigned long tmp = 0;
48 
49 	__asm__ __volatile__ (
50 	"ldptr.d %[tmp], %[next], " STR(THREAD_SCR0) "		\n"
51 	"movgr2scr  $scr0, %[tmp]					\n"
52 	"ldptr.d %[tmp], %[next], " STR(THREAD_SCR1) "		\n"
53 	"movgr2scr  $scr1, %[tmp]					\n"
54 	"ldptr.d %[tmp], %[next], " STR(THREAD_SCR2) "		\n"
55 	"movgr2scr  $scr2, %[tmp]					\n"
56 	"ldptr.d %[tmp], %[next], " STR(THREAD_SCR3) "		\n"
57 	"movgr2scr  $scr3, %[tmp]					\n"
58 	"ldptr.d %[tmp], %[next], " STR(THREAD_EFLAGS) "	\n"
59 	"x86mtflag %[tmp], 0x3f					\n"
60 	:
61 	: [next] "r" (next), [tmp] "r" (tmp)
62 	:
63 	);
64 }
65 
enable_lbt(void)66 static inline void enable_lbt(void)
67 {
68 	if (cpu_has_lbt)
69 		csr_xchg32(CSR_EUEN_LBTEN, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
70 }
71 
disable_lbt(void)72 static inline void disable_lbt(void)
73 {
74 	if (cpu_has_lbt)
75 		csr_xchg32(0, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
76 }
77 
is_lbt_enabled(void)78 static inline int is_lbt_enabled(void)
79 {
80 	if (!cpu_has_lbt)
81 		return 0;
82 
83 	return (csr_read32(LOONGARCH_CSR_EUEN) & CSR_EUEN_LBTEN) ?
84 		1 : 0;
85 }
86 
is_lbt_owner(void)87 static inline int is_lbt_owner(void)
88 {
89 	return test_thread_flag(TIF_USEDLBT);
90 }
91 
__own_lbt(void)92 static inline void __own_lbt(void)
93 {
94 	enable_lbt();
95 	set_thread_flag(TIF_USEDLBT);
96 	KSTK_EUEN(current) |= CSR_EUEN_LBTEN;
97 }
98 
init_lbt(void)99 static inline void init_lbt(void)
100 {
101 	__own_lbt();
102 	_init_lbt();
103 }
104 
own_lbt_inatomic(int restore)105 static inline void own_lbt_inatomic(int restore)
106 {
107 	if (cpu_has_lbt && !is_lbt_owner()) {
108 		__own_lbt();
109 		if (restore)
110 			restore_lbt_registers(&current->thread.lbt);
111 	}
112 }
113 
lose_lbt_inatomic(int save, struct task_struct *tsk)114 static inline void lose_lbt_inatomic(int save, struct task_struct *tsk)
115 {
116 	if (is_lbt_owner()) {
117 		if (save)
118 			save_lbt_registers(&tsk->thread.lbt);
119 
120 		disable_lbt();
121 		clear_tsk_thread_flag(tsk, TIF_USEDLBT);
122 	}
123 	KSTK_EUEN(tsk) &= ~(CSR_EUEN_LBTEN);
124 }
125 
lose_lbt(int save)126 static inline void lose_lbt(int save)
127 {
128 	preempt_disable();
129 	lose_lbt_inatomic(save, current);
130 	preempt_enable();
131 }
132 
133 #else
own_lbt_inatomic(int restore)134 static inline void own_lbt_inatomic(int restore) {}
lose_lbt_inatomic(int save, struct task_struct *tsk)135 static inline void lose_lbt_inatomic(int save, struct task_struct *tsk) {}
init_lbt(void)136 static inline void init_lbt(void) {}
lose_lbt(int save)137 static inline void lose_lbt(int save) {}
138 #endif
139 
thread_lbt_context_live(void)140 static inline int thread_lbt_context_live(void)
141 {
142 	if (__builtin_constant_p(cpu_has_lbt) && !cpu_has_lbt)
143 		return 0;
144 
145 	return test_thread_flag(TIF_LBT_CTX_LIVE);
146 }
147 
148 #endif
149