2019-05-29 07:18:00 -07:00
/* SPDX-License-Identifier: GPL-2.0-only */
2017-07-10 18:04:30 -07:00
/*
* Copyright ( C ) 2012 Regents of the University of California
*/
# ifndef _ASM_RISCV_SWITCH_TO_H
# define _ASM_RISCV_SWITCH_TO_H
2021-05-12 22:55:45 +08:00
# include <linux/jump_label.h>
2019-10-17 15:21:28 -07:00
# include <linux/sched/task_stack.h>
2023-06-05 11:07:07 +00:00
# include <asm/vector.h>
2023-10-31 14:45:52 +08:00
# include <asm/cpufeature.h>
2017-07-10 18:04:30 -07:00
# include <asm/processor.h>
# include <asm/ptrace.h>
# include <asm/csr.h>
2018-10-09 10:18:33 +08:00
# ifdef CONFIG_FPU
2017-07-10 18:04:30 -07:00
extern void __fstate_save ( struct task_struct * save_to ) ;
extern void __fstate_restore ( struct task_struct * restore_from ) ;
static inline void __fstate_clean ( struct pt_regs * regs )
{
2019-10-28 13:10:32 +01:00
regs - > status = ( regs - > status & ~ SR_FS ) | SR_FS_CLEAN ;
2017-07-10 18:04:30 -07:00
}
2019-08-14 16:23:52 +08:00
static inline void fstate_off ( struct task_struct * task ,
struct pt_regs * regs )
{
2019-10-28 13:10:32 +01:00
regs - > status = ( regs - > status & ~ SR_FS ) | SR_FS_OFF ;
2019-08-14 16:23:52 +08:00
}
2017-07-10 18:04:30 -07:00
static inline void fstate_save ( struct task_struct * task ,
struct pt_regs * regs )
{
2019-10-28 13:10:32 +01:00
if ( ( regs - > status & SR_FS ) = = SR_FS_DIRTY ) {
2017-07-10 18:04:30 -07:00
__fstate_save ( task ) ;
__fstate_clean ( regs ) ;
}
}
static inline void fstate_restore ( struct task_struct * task ,
struct pt_regs * regs )
{
2019-10-28 13:10:32 +01:00
if ( ( regs - > status & SR_FS ) ! = SR_FS_OFF ) {
2017-07-10 18:04:30 -07:00
__fstate_restore ( task ) ;
__fstate_clean ( regs ) ;
}
}
2023-06-05 11:06:58 +00:00
static inline void __switch_to_fpu ( struct task_struct * prev ,
2017-07-10 18:04:30 -07:00
struct task_struct * next )
{
struct pt_regs * regs ;
regs = task_pt_regs ( prev ) ;
2019-10-28 13:10:32 +01:00
if ( unlikely ( regs - > status & SR_SD ) )
2017-07-10 18:04:30 -07:00
fstate_save ( prev , regs ) ;
fstate_restore ( next , task_pt_regs ( next ) ) ;
}
2021-05-12 22:55:45 +08:00
static __always_inline bool has_fpu ( void )
{
2023-01-29 01:28:49 +08:00
return riscv_has_extension_likely ( RISCV_ISA_EXT_f ) | |
riscv_has_extension_likely ( RISCV_ISA_EXT_d ) ;
2021-05-12 22:55:45 +08:00
}
2018-10-09 10:18:33 +08:00
# else
2021-05-12 22:55:45 +08:00
static __always_inline bool has_fpu ( void ) { return false ; }
2018-10-09 10:18:33 +08:00
# define fstate_save(task, regs) do { } while (0)
# define fstate_restore(task, regs) do { } while (0)
2023-06-05 11:06:58 +00:00
# define __switch_to_fpu(__prev, __next) do { } while (0)
2018-10-09 10:18:33 +08:00
# endif
2017-07-10 18:04:30 -07:00
extern struct task_struct * __switch_to ( struct task_struct * ,
struct task_struct * ) ;
# define switch_to(prev, next, last) \
do { \
struct task_struct * __prev = ( prev ) ; \
struct task_struct * __next = ( next ) ; \
2021-05-12 22:55:45 +08:00
if ( has_fpu ( ) ) \
2023-06-05 11:06:58 +00:00
__switch_to_fpu ( __prev , __next ) ; \
2023-06-05 11:07:07 +00:00
if ( has_vector ( ) ) \
__switch_to_vector ( __prev , __next ) ; \
2017-07-10 18:04:30 -07:00
( ( last ) = __switch_to ( __prev , __next ) ) ; \
} while ( 0 )
# endif /* _ASM_RISCV_SWITCH_TO_H */