diff options
author | Pasha <pasha@member.fsf.org> | 2024-02-20 18:55:36 +0000 |
---|---|---|
committer | Pasha <pasha@member.fsf.org> | 2024-02-20 18:55:36 +0000 |
commit | 6fca8abef7e6d7be1a9e6d93dd0f2b7fbc5b28e5 (patch) | |
tree | 9f5ccbaa6ec19ff5a42d9b3cde01f739e1d7c77d /riscv/include/asm/switch_to.h | |
parent | 5e0b8d508ed51004bd836384293be00950ee62c9 (diff) | |
download | gnumach-riscv-6fca8abef7e6d7be1a9e6d93dd0f2b7fbc5b28e5.tar.gz gnumach-riscv-6fca8abef7e6d7be1a9e6d93dd0f2b7fbc5b28e5.tar.bz2 |
Diffstat (limited to 'riscv/include/asm/switch_to.h')
-rw-r--r-- | riscv/include/asm/switch_to.h | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/riscv/include/asm/switch_to.h b/riscv/include/asm/switch_to.h new file mode 100644 index 0000000..f90d8e4 --- /dev/null +++ b/riscv/include/asm/switch_to.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2012 Regents of the University of California + */ + +#ifndef _ASM_RISCV_SWITCH_TO_H +#define _ASM_RISCV_SWITCH_TO_H + +#include <linux/jump_label.h> +#include <linux/sched/task_stack.h> +#include <asm/vector.h> +#include <asm/cpufeature.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/csr.h> + +#ifdef CONFIG_FPU +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) +{ + regs->status = (regs->status & ~SR_FS) | SR_FS_CLEAN; +} + +static inline void fstate_off(struct task_struct *task, + struct pt_regs *regs) +{ + regs->status = (regs->status & ~SR_FS) | SR_FS_OFF; +} + +static inline void fstate_save(struct task_struct *task, + struct pt_regs *regs) +{ + if ((regs->status & SR_FS) == SR_FS_DIRTY) { + __fstate_save(task); + __fstate_clean(regs); + } +} + +static inline void fstate_restore(struct task_struct *task, + struct pt_regs *regs) +{ + if ((regs->status & SR_FS) != SR_FS_OFF) { + __fstate_restore(task); + __fstate_clean(regs); + } +} + +static inline void __switch_to_fpu(struct task_struct *prev, + struct task_struct *next) +{ + struct pt_regs *regs; + + regs = task_pt_regs(prev); + if (unlikely(regs->status & SR_SD)) + fstate_save(prev, regs); + fstate_restore(next, task_pt_regs(next)); +} + +static __always_inline bool has_fpu(void) +{ + return riscv_has_extension_likely(RISCV_ISA_EXT_f) || + riscv_has_extension_likely(RISCV_ISA_EXT_d); +} +#else +static __always_inline bool has_fpu(void) { return false; } +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_fpu(__prev, __next) do { } while (0) +#endif + +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); \ + if (has_fpu()) \ + __switch_to_fpu(__prev, __next); \ + if (has_vector()) \ + __switch_to_vector(__prev, __next); \ + ((last) = __switch_to(__prev, __next)); \ +} while (0) + +#endif /* _ASM_RISCV_SWITCH_TO_H */ |