18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* Copyright (C) 2005-2018 Andes Technology Corporation */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#ifndef __ASM_NDS32_FPU_H 58c2ecf20Sopenharmony_ci#define __ASM_NDS32_FPU_H 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_FPU) 88c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 98c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 108c2ecf20Sopenharmony_ci#include <linux/preempt.h> 118c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciextern bool has_fpu; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciextern void save_fpu(struct task_struct *__tsk); 168c2ecf20Sopenharmony_ciextern void load_fpu(const struct fpu_struct *fpregs); 178c2ecf20Sopenharmony_ciextern bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs); 188c2ecf20Sopenharmony_ciextern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define test_tsk_fpu(regs) (regs->fucop_ctl & FUCOP_CTL_mskCP0EN) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Initially load the FPU with signalling NANS. This bit pattern 248c2ecf20Sopenharmony_ci * has the property that no matter whether considered as single or as 258c2ecf20Sopenharmony_ci * double precision, it still represents a signalling NAN. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define sNAN64 0xFFFFFFFFFFFFFFFFULL 298c2ecf20Sopenharmony_ci#define sNAN32 0xFFFFFFFFUL 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Denormalized number is unsupported by nds32 FPU. Hence the operation 348c2ecf20Sopenharmony_ci * is treated as underflow cases when the final result is a denormalized 358c2ecf20Sopenharmony_ci * number. To enhance precision, underflow exception trap should be 368c2ecf20Sopenharmony_ci * enabled by default and kerenl will re-execute it by fpu emulator 378c2ecf20Sopenharmony_ci * when getting underflow exception. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define FPCSR_INIT (FPCSR_mskUDFE | FPCSR_mskIEXE) 408c2ecf20Sopenharmony_ci#else 418c2ecf20Sopenharmony_ci#define FPCSR_INIT 0x0UL 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciextern const struct fpu_struct init_fpuregs; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline void disable_ptreg_fpu(struct pt_regs *regs) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci regs->fucop_ctl &= ~FUCOP_CTL_mskCP0EN; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic inline void enable_ptreg_fpu(struct pt_regs *regs) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci regs->fucop_ctl |= FUCOP_CTL_mskCP0EN; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline void enable_fpu(void) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned long fucop_ctl; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) | FUCOP_CTL_mskCP0EN; 618c2ecf20Sopenharmony_ci __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL); 628c2ecf20Sopenharmony_ci __nds32__isb(); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline void disable_fpu(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned long fucop_ctl; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) & ~FUCOP_CTL_mskCP0EN; 708c2ecf20Sopenharmony_ci __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL); 718c2ecf20Sopenharmony_ci __nds32__isb(); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline void lose_fpu(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci preempt_disable(); 778c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LAZY_FPU) 788c2ecf20Sopenharmony_ci if (last_task_used_math == current) { 798c2ecf20Sopenharmony_ci last_task_used_math = NULL; 808c2ecf20Sopenharmony_ci#else 818c2ecf20Sopenharmony_ci if (test_tsk_fpu(task_pt_regs(current))) { 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci save_fpu(current); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci disable_ptreg_fpu(task_pt_regs(current)); 868c2ecf20Sopenharmony_ci preempt_enable(); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline void own_fpu(void) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci preempt_disable(); 928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LAZY_FPU) 938c2ecf20Sopenharmony_ci if (last_task_used_math != current) { 948c2ecf20Sopenharmony_ci if (last_task_used_math != NULL) 958c2ecf20Sopenharmony_ci save_fpu(last_task_used_math); 968c2ecf20Sopenharmony_ci load_fpu(¤t->thread.fpu); 978c2ecf20Sopenharmony_ci last_task_used_math = current; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_ci if (!test_tsk_fpu(task_pt_regs(current))) { 1018c2ecf20Sopenharmony_ci load_fpu(¤t->thread.fpu); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci#endif 1048c2ecf20Sopenharmony_ci enable_ptreg_fpu(task_pt_regs(current)); 1058c2ecf20Sopenharmony_ci preempt_enable(); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_LAZY_FPU) 1098c2ecf20Sopenharmony_cistatic inline void unlazy_fpu(struct task_struct *tsk) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci preempt_disable(); 1128c2ecf20Sopenharmony_ci if (test_tsk_fpu(task_pt_regs(tsk))) 1138c2ecf20Sopenharmony_ci save_fpu(tsk); 1148c2ecf20Sopenharmony_ci preempt_enable(); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci#endif /* !CONFIG_LAZY_FPU */ 1178c2ecf20Sopenharmony_cistatic inline void clear_fpu(struct pt_regs *regs) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci preempt_disable(); 1208c2ecf20Sopenharmony_ci if (test_tsk_fpu(regs)) 1218c2ecf20Sopenharmony_ci disable_ptreg_fpu(regs); 1228c2ecf20Sopenharmony_ci preempt_enable(); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci#endif /* CONFIG_FPU */ 1258c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 1268c2ecf20Sopenharmony_ci#endif /* __ASM_NDS32_FPU_H */ 127