Commit e46bf83c authored by Vincent Chen's avatar Vincent Chen Committed by Greentime Hu
Browse files

nds32: nds32 FPU port



This patch set contains basic components for supporting the nds32 FPU,
such as exception handlers and context switch for FPU registers. By
default, the lazy FPU scheme is supported and the user can configure it via
CONFIG_LZAY_FPU.

Signed-off-by: default avatarVincent Chen <vincentc@andestech.com>
Acked-by: default avatarGreentime Hu <greentime@andestech.com>
Signed-off-by: default avatarGreentime Hu <greentime@andestech.com>
parent 4f014a41
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ config NDS32
	select HANDLE_DOMAIN_IRQ
	select HAVE_ARCH_TRACEHOOK
	select HAVE_DEBUG_KMEMLEAK
	select HAVE_EXIT_THREAD
	select HAVE_REGS_AND_STACK_ACCESS_API
	select HAVE_PERF_EVENTS
	select IRQ_DOMAIN
+21 −0
Original line number Diff line number Diff line
@@ -7,6 +7,27 @@ config CPU_LITTLE_ENDIAN
	bool "Little endian"
	default y

config FPU
	bool "FPU support"
	default n
	help
	  If FPU ISA is used in user space, this configuration shall be Y to
          enable required support in kerenl such as fpu context switch and
          fpu exception handler.

	  If no FPU ISA is used in user space, say N.

config LAZY_FPU
	bool "lazy FPU support"
	depends on FPU
	default y
	help
	  Say Y here to enable the lazy FPU scheme. The lazy FPU scheme can
          enhance system performance by reducing the context switch
	  frequency of the FPU register.

	  For nomal case, say Y.

config HWZOL
	bool "hardware zero overhead loop support"
	depends on CPU_D10 || CPU_D15
+4 −0
Original line number Diff line number Diff line
@@ -5,10 +5,14 @@ KBUILD_DEFCONFIG := defconfig

comma = ,


ifdef CONFIG_FUNCTION_TRACER
arch-y += -malways-save-lp -mno-relax
endif

# Avoid generating FPU instructions
arch-y  += -mno-ext-fpu-sp -mno-ext-fpu-dp -mfloat-abi=soft

KBUILD_CFLAGS	+= $(call cc-option, -mno-sched-prolog-epilog)
KBUILD_CFLAGS	+= -mcmodel=large

+15 −0
Original line number Diff line number Diff line
@@ -251,6 +251,11 @@
#define ITYPE_mskSTYPE		( 0xF  << ITYPE_offSTYPE )
#define ITYPE_mskCPID		( 0x3  << ITYPE_offCPID )

/* Additional definitions of ITYPE register for FPU */
#define FPU_DISABLE_EXCEPTION	(0x1  << ITYPE_offSTYPE)
#define FPU_EXCEPTION		(0x2  << ITYPE_offSTYPE)
#define FPU_CPID		0	/* FPU Co-Processor ID is 0 */

#define NDS32_VECTOR_mskNONEXCEPTION	0x78
#define NDS32_VECTOR_offEXCEPTION	8
#define NDS32_VECTOR_offINTERRUPT	9
@@ -926,6 +931,7 @@
#define FPCSR_mskDNIT           ( 0x1  << FPCSR_offDNIT )
#define FPCSR_mskRIT		( 0x1  << FPCSR_offRIT )
#define FPCSR_mskALL		(FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX)
#define FPCSR_mskALLE_NO_UDFE	(FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskIEXE)
#define FPCSR_mskALLE		(FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE)
#define FPCSR_mskALLT           (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT)

@@ -946,6 +952,15 @@
#define FPCFG_mskIMVER		( 0x1F  << FPCFG_offIMVER )
#define FPCFG_mskAVER		( 0x1F  << FPCFG_offAVER )

/* 8 Single precision or 4 double precision registers are available */
#define SP8_DP4_reg		0
/* 16 Single precision or 8 double precision registers are available */
#define SP16_DP8_reg		1
/* 32 Single precision or 16 double precision registers are available */
#define SP32_DP16_reg		2
/* 32 Single precision or 32 double precision registers are available */
#define SP32_DP32_reg		3

/******************************************************************************
 * fucpr: FUCOP_CTL (FPU and Coprocessor Enable Control Register)
 *****************************************************************************/
+114 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2005-2018 Andes Technology Corporation */

#ifndef __ASM_NDS32_FPU_H
#define __ASM_NDS32_FPU_H

#if IS_ENABLED(CONFIG_FPU)
#ifndef __ASSEMBLY__
#include <linux/sched/task_stack.h>
#include <linux/preempt.h>
#include <asm/ptrace.h>

extern bool has_fpu;

extern void save_fpu(struct task_struct *__tsk);
extern void load_fpu(const struct fpu_struct *fpregs);
extern bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs);

#define test_tsk_fpu(regs)	(regs->fucop_ctl & FUCOP_CTL_mskCP0EN)

/*
 * Initially load the FPU with signalling NANS.  This bit pattern
 * has the property that no matter whether considered as single or as
 * double precision, it still represents a signalling NAN.
 */

#define sNAN64    0xFFFFFFFFFFFFFFFFULL
#define sNAN32    0xFFFFFFFFUL

#define FPCSR_INIT  0x0UL

extern const struct fpu_struct init_fpuregs;

static inline void disable_ptreg_fpu(struct pt_regs *regs)
{
	regs->fucop_ctl &= ~FUCOP_CTL_mskCP0EN;
}

static inline void enable_ptreg_fpu(struct pt_regs *regs)
{
	regs->fucop_ctl |= FUCOP_CTL_mskCP0EN;
}

static inline void enable_fpu(void)
{
	unsigned long fucop_ctl;

	fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) | FUCOP_CTL_mskCP0EN;
	__nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
	__nds32__isb();
}

static inline void disable_fpu(void)
{
	unsigned long fucop_ctl;

	fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) & ~FUCOP_CTL_mskCP0EN;
	__nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
	__nds32__isb();
}

static inline void lose_fpu(void)
{
	preempt_disable();
#if IS_ENABLED(CONFIG_LAZY_FPU)
	if (last_task_used_math == current) {
		last_task_used_math = NULL;
#else
	if (test_tsk_fpu(task_pt_regs(current))) {
#endif
		save_fpu(current);
	}
	disable_ptreg_fpu(task_pt_regs(current));
	preempt_enable();
}

static inline void own_fpu(void)
{
	preempt_disable();
#if IS_ENABLED(CONFIG_LAZY_FPU)
	if (last_task_used_math != current) {
		if (last_task_used_math != NULL)
			save_fpu(last_task_used_math);
		load_fpu(&current->thread.fpu);
		last_task_used_math = current;
	}
#else
	if (!test_tsk_fpu(task_pt_regs(current))) {
		load_fpu(&current->thread.fpu);
	}
#endif
	enable_ptreg_fpu(task_pt_regs(current));
	preempt_enable();
}

#if !IS_ENABLED(CONFIG_LAZY_FPU)
static inline void unlazy_fpu(struct task_struct *tsk)
{
	preempt_disable();
	if (test_tsk_fpu(task_pt_regs(tsk)))
		save_fpu(tsk);
	preempt_enable();
}
#endif /* !CONFIG_LAZY_FPU */
static inline void clear_fpu(struct pt_regs *regs)
{
	preempt_disable();
	if (test_tsk_fpu(regs))
		disable_ptreg_fpu(regs);
	preempt_enable();
}
#endif /* CONFIG_FPU */
#endif /* __ASSEMBLY__ */
#endif /* __ASM_NDS32_FPU_H */
Loading