18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012 Regents of the University of California 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#ifndef _ASM_RISCV_SWITCH_TO_H 78c2ecf20Sopenharmony_ci#define _ASM_RISCV_SWITCH_TO_H 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 108c2ecf20Sopenharmony_ci#include <asm/processor.h> 118c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 128c2ecf20Sopenharmony_ci#include <asm/csr.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#ifdef CONFIG_FPU 158c2ecf20Sopenharmony_ciextern void __fstate_save(struct task_struct *save_to); 168c2ecf20Sopenharmony_ciextern void __fstate_restore(struct task_struct *restore_from); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic inline void __fstate_clean(struct pt_regs *regs) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci regs->status = (regs->status & ~SR_FS) | SR_FS_CLEAN; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic inline void fstate_off(struct task_struct *task, 248c2ecf20Sopenharmony_ci struct pt_regs *regs) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci regs->status = (regs->status & ~SR_FS) | SR_FS_OFF; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic inline void fstate_save(struct task_struct *task, 308c2ecf20Sopenharmony_ci struct pt_regs *regs) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci if ((regs->status & SR_FS) == SR_FS_DIRTY) { 338c2ecf20Sopenharmony_ci __fstate_save(task); 348c2ecf20Sopenharmony_ci __fstate_clean(regs); 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline void fstate_restore(struct task_struct *task, 398c2ecf20Sopenharmony_ci struct pt_regs *regs) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci if ((regs->status & SR_FS) != SR_FS_OFF) { 428c2ecf20Sopenharmony_ci __fstate_restore(task); 438c2ecf20Sopenharmony_ci __fstate_clean(regs); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline void __switch_to_aux(struct task_struct *prev, 488c2ecf20Sopenharmony_ci struct task_struct *next) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct pt_regs *regs; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci regs = task_pt_regs(prev); 538c2ecf20Sopenharmony_ci if (unlikely(regs->status & SR_SD)) 548c2ecf20Sopenharmony_ci fstate_save(prev, regs); 558c2ecf20Sopenharmony_ci fstate_restore(next, task_pt_regs(next)); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciextern bool has_fpu; 598c2ecf20Sopenharmony_ci#else 608c2ecf20Sopenharmony_ci#define has_fpu false 618c2ecf20Sopenharmony_ci#define fstate_save(task, regs) do { } while (0) 628c2ecf20Sopenharmony_ci#define fstate_restore(task, regs) do { } while (0) 638c2ecf20Sopenharmony_ci#define __switch_to_aux(__prev, __next) do { } while (0) 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciextern struct task_struct *__switch_to(struct task_struct *, 678c2ecf20Sopenharmony_ci struct task_struct *); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define switch_to(prev, next, last) \ 708c2ecf20Sopenharmony_cido { \ 718c2ecf20Sopenharmony_ci struct task_struct *__prev = (prev); \ 728c2ecf20Sopenharmony_ci struct task_struct *__next = (next); \ 738c2ecf20Sopenharmony_ci if (has_fpu) \ 748c2ecf20Sopenharmony_ci __switch_to_aux(__prev, __next); \ 758c2ecf20Sopenharmony_ci ((last) = __switch_to(__prev, __next)); \ 768c2ecf20Sopenharmony_ci} while (0) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#endif /* _ASM_RISCV_SWITCH_TO_H */ 79