Skip to content

Commit f45ba2b

Browse files
committed
ARCv2: fpu: preserve userspace fpu state
Signed-off-by: Vineet Gupta <[email protected]>
1 parent f05523a commit f45ba2b

File tree

6 files changed

+68
-12
lines changed

6 files changed

+68
-12
lines changed

arch/arc/Kconfig

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,24 +351,19 @@ config NODES_SHIFT
351351
Accessing memory beyond 1GB (with or w/o PAE) requires 2 memory
352352
zones.
353353

354-
if ISA_ARCOMPACT
355-
356354
config ARC_COMPACT_IRQ_LEVELS
355+
depends on ISA_ARCOMPACT
357356
bool "Setup Timer IRQ as high Priority"
358357
# if SMP, LV2 enabled ONLY if ARC implementation has LV2 re-entrancy
359358
depends on !SMP
360359

361360
config ARC_FPU_SAVE_RESTORE
362361
bool "Enable FPU state persistence across context switch"
363362
help
364-
Double Precision Floating Point unit had dedicated regs which
365-
need to be saved/restored across context-switch.
366-
Note that ARC FPU is overly simplistic, unlike say x86, which has
367-
hardware pieces to allow software to conditionally save/restore,
368-
based on actual usage of FPU by a task. Thus our implemn does
369-
this for all tasks in system.
370-
371-
endif #ISA_ARCOMPACT
363+
ARCompact FPU has internal registers to assist with Double precision
364+
Floating Point operations. There are control and stauts registers
365+
for floating point exceptions and rounding modes. These are
366+
preserved across task context switch when enabled.
372367

373368
config ARC_CANT_LLSC
374369
def_bool n

arch/arc/include/asm/arcregs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
#define ARC_REG_CLUSTER_BCR 0xcf
4040
#define ARC_REG_AUX_ICCM 0x208 /* ICCM Base Addr (ARCv2) */
4141
#define ARC_REG_LPB_CTRL 0x488 /* ARCv2 Loop Buffer control */
42+
#define ARC_REG_FPU_CTRL 0x300
43+
#define ARC_REG_FPU_STATUS 0x301
4244

4345
/* Common for ARCompact and ARCv2 status register */
4446
#define ARC_REG_STATUS32 0x0A

arch/arc/include/asm/fpu.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,44 @@
1111

1212
#include <asm/ptrace.h>
1313

14+
#ifdef CONFIG_ISA_ARCOMPACT
15+
1416
/* These DPFP regs need to be saved/restored across ctx-sw */
1517
struct arc_fpu {
1618
struct {
1719
unsigned int l, h;
1820
} aux_dpfp[2];
1921
};
2022

21-
extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
23+
#define fpu_init_task(regs)
2224

2325
#else
2426

27+
/*
28+
* ARCv2 FPU Control aux register
29+
* - bits to enable Traps on Exceptions
30+
* - Rounding mode
31+
*
32+
* ARCv2 FPU Status aux register
33+
* - FPU exceptions flags (Inv, Div-by-Zero, overflow, underflow, inexact)
34+
* - Flag Write Enable to clear flags explicitly (vs. by fpu instructions
35+
* only
36+
*/
37+
38+
struct arc_fpu {
39+
unsigned int ctrl, status;
40+
};
41+
42+
extern void fpu_init_task(struct pt_regs *regs);
43+
44+
#endif /* !CONFIG_ISA_ARCOMPACT */
45+
46+
extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
47+
48+
#else /* !CONFIG_ARC_FPU_SAVE_RESTORE */
49+
2550
#define fpu_save_restore(p, n)
51+
#define fpu_init_task(regs)
2652

2753
#endif /* CONFIG_ARC_FPU_SAVE_RESTORE */
2854

arch/arc/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
2323
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
2424

2525
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
26+
ifdef CONFIG_ISA_ARCOMPACT
2627
CFLAGS_fpu.o += -mdpfp
28+
endif
2729

2830
ifdef CONFIG_ARC_DW2_UNWIND
2931
CFLAGS_ctx_sw.o += -fno-omit-frame-pointer

arch/arc/kernel/fpu.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <linux/sched.h>
99
#include <asm/fpu.h>
1010

11+
#ifdef CONFIG_ISA_ARCOMPACT
12+
1113
/*
1214
* To save/restore FPU regs, simplest scheme would use LR/SR insns.
1315
* 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)
5052
: "r" (zero), "r" (*(readfrom + 3)), "r" (*(readfrom + 2))
5153
);
5254
}
55+
56+
#else
57+
58+
void fpu_init_task(struct pt_regs *regs)
59+
{
60+
/* default rounding mode */
61+
write_aux_reg(ARC_REG_FPU_CTRL, 0x100);
62+
63+
/* set "Write enable" to allow explicit write to exception flags */
64+
write_aux_reg(ARC_REG_FPU_STATUS, 0x80000000);
65+
}
66+
67+
void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
68+
{
69+
struct arc_fpu *save = &prev->thread.fpu;
70+
struct arc_fpu *restore = &next->thread.fpu;
71+
72+
save->ctrl = read_aux_reg(ARC_REG_FPU_CTRL);
73+
save->status = read_aux_reg(ARC_REG_FPU_STATUS);
74+
75+
write_aux_reg(ARC_REG_FPU_CTRL, restore->ctrl);
76+
write_aux_reg(ARC_REG_FPU_STATUS, restore->status);
77+
}
78+
79+
#endif

arch/arc/kernel/process.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <linux/elf.h>
2121
#include <linux/tick.h>
2222

23+
#include <asm/fpu.h>
24+
2325
SYSCALL_DEFINE1(arc_settls, void *, user_tls_data_ptr)
2426
{
2527
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,
263265
/*
264266
* Do necessary setup to start up a new user task
265267
*/
266-
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
268+
void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
267269
{
268270
regs->sp = usp;
269271
regs->ret = pc;
@@ -279,6 +281,8 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
279281
regs->eflags = 0;
280282
#endif
281283

284+
fpu_init_task(regs);
285+
282286
/* bogus seed values for debugging */
283287
regs->lp_start = 0x10;
284288
regs->lp_end = 0x80;

0 commit comments

Comments
 (0)