mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ARCv2: fpu: preserve userspace fpu state
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
This commit is contained in:
		
							parent
							
								
									f05523aa7a
								
							
						
					
					
						commit
						f45ba2bd6d
					
				
					 6 changed files with 68 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -351,9 +351,8 @@ config NODES_SHIFT
 | 
			
		|||
	  Accessing memory beyond 1GB (with or w/o PAE) requires 2 memory
 | 
			
		||||
	  zones.
 | 
			
		||||
 | 
			
		||||
if ISA_ARCOMPACT
 | 
			
		||||
 | 
			
		||||
config ARC_COMPACT_IRQ_LEVELS
 | 
			
		||||
	depends on ISA_ARCOMPACT
 | 
			
		||||
	bool "Setup Timer IRQ as high Priority"
 | 
			
		||||
	# if SMP, LV2 enabled ONLY if ARC implementation has LV2 re-entrancy
 | 
			
		||||
	depends on !SMP
 | 
			
		||||
| 
						 | 
				
			
			@ -361,14 +360,10 @@ config ARC_COMPACT_IRQ_LEVELS
 | 
			
		|||
config ARC_FPU_SAVE_RESTORE
 | 
			
		||||
	bool "Enable FPU state persistence across context switch"
 | 
			
		||||
	help
 | 
			
		||||
	  Double Precision Floating Point unit had dedicated regs which
 | 
			
		||||
	  need to be saved/restored across context-switch.
 | 
			
		||||
	  Note that ARC FPU is overly simplistic, unlike say x86, which has
 | 
			
		||||
	  hardware pieces to allow software to conditionally save/restore,
 | 
			
		||||
	  based on actual usage of FPU by a task. Thus our implemn does
 | 
			
		||||
	  this for all tasks in system.
 | 
			
		||||
 | 
			
		||||
endif #ISA_ARCOMPACT
 | 
			
		||||
	  ARCompact FPU has internal registers to assist with Double precision
 | 
			
		||||
	  Floating Point operations. There are control and stauts registers
 | 
			
		||||
	  for floating point exceptions and rounding modes. These are
 | 
			
		||||
	  preserved across task context switch when enabled.
 | 
			
		||||
 | 
			
		||||
config ARC_CANT_LLSC
 | 
			
		||||
	def_bool n
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,8 @@
 | 
			
		|||
#define ARC_REG_CLUSTER_BCR	0xcf
 | 
			
		||||
#define ARC_REG_AUX_ICCM	0x208	/* ICCM Base Addr (ARCv2) */
 | 
			
		||||
#define ARC_REG_LPB_CTRL	0x488	/* ARCv2 Loop Buffer control */
 | 
			
		||||
#define ARC_REG_FPU_CTRL	0x300
 | 
			
		||||
#define ARC_REG_FPU_STATUS	0x301
 | 
			
		||||
 | 
			
		||||
/* Common for ARCompact and ARCv2 status register */
 | 
			
		||||
#define ARC_REG_STATUS32	0x0A
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@
 | 
			
		|||
 | 
			
		||||
#include <asm/ptrace.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ISA_ARCOMPACT
 | 
			
		||||
 | 
			
		||||
/* These DPFP regs need to be saved/restored across ctx-sw */
 | 
			
		||||
struct arc_fpu {
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -18,11 +20,35 @@ struct arc_fpu {
 | 
			
		|||
	} aux_dpfp[2];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
 | 
			
		||||
#define fpu_init_task(regs)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ARCv2 FPU Control aux register
 | 
			
		||||
 *   - bits to enable Traps on Exceptions
 | 
			
		||||
 *   - Rounding mode
 | 
			
		||||
 *
 | 
			
		||||
 * ARCv2 FPU Status aux register
 | 
			
		||||
 *   - FPU exceptions flags (Inv, Div-by-Zero, overflow, underflow, inexact)
 | 
			
		||||
 *   - Flag Write Enable to clear flags explicitly (vs. by fpu instructions
 | 
			
		||||
 *     only
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct arc_fpu {
 | 
			
		||||
	unsigned int ctrl, status;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern void fpu_init_task(struct pt_regs *regs);
 | 
			
		||||
 | 
			
		||||
#endif	/* !CONFIG_ISA_ARCOMPACT */
 | 
			
		||||
 | 
			
		||||
extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
 | 
			
		||||
 | 
			
		||||
#else	/* !CONFIG_ARC_FPU_SAVE_RESTORE */
 | 
			
		||||
 | 
			
		||||
#define fpu_save_restore(p, n)
 | 
			
		||||
#define fpu_init_task(regs)
 | 
			
		||||
 | 
			
		||||
#endif	/* CONFIG_ARC_FPU_SAVE_RESTORE */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,9 @@ obj-$(CONFIG_PERF_EVENTS)		+= perf_event.o
 | 
			
		|||
obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE)	+= fpu.o
 | 
			
		||||
ifdef CONFIG_ISA_ARCOMPACT
 | 
			
		||||
CFLAGS_fpu.o   += -mdpfp
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_ARC_DW2_UNWIND
 | 
			
		||||
CFLAGS_ctx_sw.o += -fno-omit-frame-pointer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@
 | 
			
		|||
#include <linux/sched.h>
 | 
			
		||||
#include <asm/fpu.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ISA_ARCOMPACT
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * To save/restore FPU regs, simplest scheme would use LR/SR insns.
 | 
			
		||||
 * However since SR serializes the pipeline, an alternate "hack" can be used
 | 
			
		||||
| 
						 | 
				
			
			@ -50,3 +52,28 @@ void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
 | 
			
		|||
		: "r" (zero), "r" (*(readfrom + 3)), "r" (*(readfrom + 2))
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
void fpu_init_task(struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	/* default rounding mode */
 | 
			
		||||
	write_aux_reg(ARC_REG_FPU_CTRL, 0x100);
 | 
			
		||||
 | 
			
		||||
	/* set "Write enable" to allow explicit write to exception flags */
 | 
			
		||||
	write_aux_reg(ARC_REG_FPU_STATUS, 0x80000000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
 | 
			
		||||
{
 | 
			
		||||
	struct arc_fpu *save = &prev->thread.fpu;
 | 
			
		||||
	struct arc_fpu *restore = &next->thread.fpu;
 | 
			
		||||
 | 
			
		||||
	save->ctrl = read_aux_reg(ARC_REG_FPU_CTRL);
 | 
			
		||||
	save->status = read_aux_reg(ARC_REG_FPU_STATUS);
 | 
			
		||||
 | 
			
		||||
	write_aux_reg(ARC_REG_FPU_CTRL, restore->ctrl);
 | 
			
		||||
	write_aux_reg(ARC_REG_FPU_STATUS, restore->status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@
 | 
			
		|||
#include <linux/elf.h>
 | 
			
		||||
#include <linux/tick.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/fpu.h>
 | 
			
		||||
 | 
			
		||||
SYSCALL_DEFINE1(arc_settls, void *, user_tls_data_ptr)
 | 
			
		||||
{
 | 
			
		||||
	task_thread_info(current)->thr_ptr = (unsigned int)user_tls_data_ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +265,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
 | 
			
		|||
/*
 | 
			
		||||
 * Do necessary setup to start up a new user task
 | 
			
		||||
 */
 | 
			
		||||
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
 | 
			
		||||
void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
 | 
			
		||||
{
 | 
			
		||||
	regs->sp = usp;
 | 
			
		||||
	regs->ret = pc;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +281,8 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
 | 
			
		|||
	regs->eflags = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	fpu_init_task(regs);
 | 
			
		||||
 | 
			
		||||
	/* bogus seed values for debugging */
 | 
			
		||||
	regs->lp_start = 0x10;
 | 
			
		||||
	regs->lp_end = 0x80;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue