1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Author: Qi Hu <huqi@loongson.cn>
4 *         Huacai Chen <chenhuacai@loongson.cn>
5 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
6 */
7#ifndef _ASM_LBT_H
8#define _ASM_LBT_H
9
10#include <asm/cpu.h>
11#include <asm/current.h>
12#include <asm/loongarch.h>
13#include <asm/processor.h>
14
15extern void _init_lbt(void);
16extern void _save_lbt(struct loongarch_lbt *);
17extern void _restore_lbt(struct loongarch_lbt *);
18
19static inline int is_lbt_enabled(void)
20{
21	if (!cpu_has_lbt)
22		return 0;
23
24	return (csr_read32(LOONGARCH_CSR_EUEN) & CSR_EUEN_LBTEN) ?
25		1 : 0;
26}
27
28static inline int is_lbt_owner(void)
29{
30	return test_thread_flag(TIF_USEDLBT);
31}
32
33#ifdef CONFIG_CPU_HAS_LBT
34
35static inline void enable_lbt(void)
36{
37	if (cpu_has_lbt)
38		csr_xchg32(CSR_EUEN_LBTEN, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
39}
40
41static inline void disable_lbt(void)
42{
43	if (cpu_has_lbt)
44		csr_xchg32(0, CSR_EUEN_LBTEN, LOONGARCH_CSR_EUEN);
45}
46
47static inline void __own_lbt(void)
48{
49	enable_lbt();
50	set_thread_flag(TIF_USEDLBT);
51	KSTK_EUEN(current) |= CSR_EUEN_LBTEN;
52}
53
54static inline void own_lbt_inatomic(int restore)
55{
56	if (cpu_has_lbt && !is_lbt_owner()) {
57		__own_lbt();
58		if (restore)
59			_restore_lbt(&current->thread.lbt);
60	}
61}
62
63static inline void own_lbt(int restore)
64{
65	preempt_disable();
66	own_lbt_inatomic(restore);
67	preempt_enable();
68}
69
70static inline void lose_lbt_inatomic(int save, struct task_struct *tsk)
71{
72	if (cpu_has_lbt && is_lbt_owner()) {
73		if (save)
74			_save_lbt(&tsk->thread.lbt);
75
76		disable_lbt();
77		clear_tsk_thread_flag(tsk, TIF_USEDLBT);
78	}
79	KSTK_EUEN(tsk) &= ~(CSR_EUEN_LBTEN);
80}
81
82static inline void lose_lbt(int save)
83{
84	preempt_disable();
85	lose_lbt_inatomic(save, current);
86	preempt_enable();
87}
88
89static inline void init_lbt(void)
90{
91	__own_lbt();
92	_init_lbt();
93}
94#else
95static inline void own_lbt_inatomic(int restore) {}
96static inline void lose_lbt_inatomic(int save, struct task_struct *tsk) {}
97static inline void init_lbt(void) {}
98static inline void lose_lbt(int save) {}
99#endif
100
101static inline int thread_lbt_context_live(void)
102{
103	if (!cpu_has_lbt)
104		return 0;
105
106	return test_thread_flag(TIF_LBT_CTX_LIVE);
107}
108
109#endif /* _ASM_LBT_H */
110