blob: 0a3f4f95c55554a4d2df08b8515673fbb4c1ee60 [file] [log] [blame]
Thomas Gleixner50acfb22019-05-29 07:18:00 -07001/* SPDX-License-Identifier: GPL-2.0-only */
Palmer Dabbelt7db91e52017-07-10 18:04:30 -07002/*
3 * Copyright (C) 2012 Regents of the University of California
Palmer Dabbelt7db91e52017-07-10 18:04:30 -07004 */
5
6#ifndef _ASM_RISCV_SWITCH_TO_H
7#define _ASM_RISCV_SWITCH_TO_H
8
Jisheng Zhang37a7a2a2021-05-12 22:55:45 +08009#include <linux/jump_label.h>
Paul Walmsley5ed881b2019-10-17 15:21:28 -070010#include <linux/sched/task_stack.h>
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070011#include <asm/processor.h>
12#include <asm/ptrace.h>
13#include <asm/csr.h>
14
Alan Kao9671f702018-10-09 10:18:33 +080015#ifdef CONFIG_FPU
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070016extern void __fstate_save(struct task_struct *save_to);
17extern void __fstate_restore(struct task_struct *restore_from);
18
19static inline void __fstate_clean(struct pt_regs *regs)
20{
Christoph Hellwiga4c37332019-10-28 13:10:32 +010021 regs->status = (regs->status & ~SR_FS) | SR_FS_CLEAN;
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070022}
23
Vincent Chen8ac71d72019-08-14 16:23:52 +080024static inline void fstate_off(struct task_struct *task,
25 struct pt_regs *regs)
26{
Christoph Hellwiga4c37332019-10-28 13:10:32 +010027 regs->status = (regs->status & ~SR_FS) | SR_FS_OFF;
Vincent Chen8ac71d72019-08-14 16:23:52 +080028}
29
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070030static inline void fstate_save(struct task_struct *task,
31 struct pt_regs *regs)
32{
Christoph Hellwiga4c37332019-10-28 13:10:32 +010033 if ((regs->status & SR_FS) == SR_FS_DIRTY) {
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070034 __fstate_save(task);
35 __fstate_clean(regs);
36 }
37}
38
39static inline void fstate_restore(struct task_struct *task,
40 struct pt_regs *regs)
41{
Christoph Hellwiga4c37332019-10-28 13:10:32 +010042 if ((regs->status & SR_FS) != SR_FS_OFF) {
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070043 __fstate_restore(task);
44 __fstate_clean(regs);
45 }
46}
47
48static inline void __switch_to_aux(struct task_struct *prev,
49 struct task_struct *next)
50{
51 struct pt_regs *regs;
52
53 regs = task_pt_regs(prev);
Christoph Hellwiga4c37332019-10-28 13:10:32 +010054 if (unlikely(regs->status & SR_SD))
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070055 fstate_save(prev, regs);
56 fstate_restore(next, task_pt_regs(next));
57}
58
Jisheng Zhang37a7a2a2021-05-12 22:55:45 +080059extern struct static_key_false cpu_hwcap_fpu;
60static __always_inline bool has_fpu(void)
61{
62 return static_branch_likely(&cpu_hwcap_fpu);
63}
Alan Kao9671f702018-10-09 10:18:33 +080064#else
Jisheng Zhang37a7a2a2021-05-12 22:55:45 +080065static __always_inline bool has_fpu(void) { return false; }
Alan Kao9671f702018-10-09 10:18:33 +080066#define fstate_save(task, regs) do { } while (0)
67#define fstate_restore(task, regs) do { } while (0)
68#define __switch_to_aux(__prev, __next) do { } while (0)
Alan Kao9671f702018-10-09 10:18:33 +080069#endif
70
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070071extern struct task_struct *__switch_to(struct task_struct *,
72 struct task_struct *);
73
74#define switch_to(prev, next, last) \
75do { \
76 struct task_struct *__prev = (prev); \
77 struct task_struct *__next = (next); \
Jisheng Zhang37a7a2a2021-05-12 22:55:45 +080078 if (has_fpu()) \
Alan Kao9411ec62018-10-09 10:18:34 +080079 __switch_to_aux(__prev, __next); \
Palmer Dabbelt7db91e52017-07-10 18:04:30 -070080 ((last) = __switch_to(__prev, __next)); \
81} while (0)
82
83#endif /* _ASM_RISCV_SWITCH_TO_H */