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 22extern void _init_lbt(void); 23 24static 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 45static 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 66static 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 72static inline void disable_lbt(void) 73{ 74 if (cpu_has_lbt) 75 csr_xchg32(0, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN); 76} 77 78static 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 87static inline int is_lbt_owner(void) 88{ 89 return test_thread_flag(TIF_USEDLBT); 90} 91 92static inline void __own_lbt(void) 93{ 94 enable_lbt(); 95 set_thread_flag(TIF_USEDLBT); 96 KSTK_EUEN(current) |= CSR_EUEN_LBTEN; 97} 98 99static inline void init_lbt(void) 100{ 101 __own_lbt(); 102 _init_lbt(); 103} 104 105static 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(¤t->thread.lbt); 111 } 112} 113 114static 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 126static inline void lose_lbt(int save) 127{ 128 preempt_disable(); 129 lose_lbt_inatomic(save, current); 130 preempt_enable(); 131} 132 133#else 134static inline void own_lbt_inatomic(int restore) {} 135static inline void lose_lbt_inatomic(int save, struct task_struct *tsk) {} 136static inline void init_lbt(void) {} 137static inline void lose_lbt(int save) {} 138#endif 139 140static 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