linux/arch/arc/include/asm/dsp-impl.h
Eugeniy Paltsev 40db9367ec ARC: guard dsp early init against non ARCv2
As of today we guard early DSP init code with
ARC_AUX_DSP_BUILD (0x7A) BCR check to verify that we have
CPU with DSP configured. However that's not enough as in
ARCv1 CPU the same BCR (0x7A) is used for checking MUL/MAC
instructions presence.

So, let's guard DSP early init against non ARCv2.

Fixes: 4827d0cf74 ("ARC: handle DSP presence in HW")
Reported-by: Angelo Ribeiro <angelor@synopsys.com>
Suggested-by: Jose Abreu <oabreu@synopsys.com>
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2020-04-29 11:53:51 -07:00

153 lines
3.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com)
*
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*/
#ifndef __ASM_ARC_DSP_IMPL_H
#define __ASM_ARC_DSP_IMPL_H
#include <asm/dsp.h>
#define DSP_CTRL_DISABLED_ALL 0
#ifdef __ASSEMBLY__
/* clobbers r5 register */
.macro DSP_EARLY_INIT
#ifdef CONFIG_ISA_ARCV2
lr r5, [ARC_AUX_DSP_BUILD]
bmsk r5, r5, 7
breq r5, 0, 1f
mov r5, DSP_CTRL_DISABLED_ALL
sr r5, [ARC_AUX_DSP_CTRL]
1:
#endif
.endm
/* clobbers r10, r11 registers pair */
.macro DSP_SAVE_REGFILE_IRQ
#if defined(CONFIG_ARC_DSP_KERNEL)
/*
* Drop any changes to DSP_CTRL made by userspace so userspace won't be
* able to break kernel - reset it to DSP_CTRL_DISABLED_ALL value
*/
mov r10, DSP_CTRL_DISABLED_ALL
sr r10, [ARC_AUX_DSP_CTRL]
#elif defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
/*
* Save DSP_CTRL register and reset it to value suitable for kernel
* (DSP_CTRL_DISABLED_ALL)
*/
mov r10, DSP_CTRL_DISABLED_ALL
aex r10, [ARC_AUX_DSP_CTRL]
st r10, [sp, PT_DSP_CTRL]
#endif
.endm
/* clobbers r10, r11 registers pair */
.macro DSP_RESTORE_REGFILE_IRQ
#if defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
ld r10, [sp, PT_DSP_CTRL]
sr r10, [ARC_AUX_DSP_CTRL]
#endif
.endm
#else /* __ASEMBLY__ */
#include <linux/sched.h>
#include <asm/asserts.h>
#include <asm/switch_to.h>
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
/*
* As we save new and restore old AUX register value in the same place we
* can optimize a bit and use AEX instruction (swap contents of an auxiliary
* register with a core register) instead of LR + SR pair.
*/
#define AUX_SAVE_RESTORE(_saveto, _readfrom, _offt, _aux) \
do { \
long unsigned int _scratch; \
\
__asm__ __volatile__( \
"ld %0, [%2, %4] \n" \
"aex %0, [%3] \n" \
"st %0, [%1, %4] \n" \
: \
"=&r" (_scratch) /* must be early clobber */ \
: \
"r" (_saveto), \
"r" (_readfrom), \
"Ir" (_aux), \
"Ir" (_offt) \
: \
"memory" \
); \
} while (0)
#define DSP_AUX_SAVE_RESTORE(_saveto, _readfrom, _aux) \
AUX_SAVE_RESTORE(_saveto, _readfrom, \
offsetof(struct dsp_callee_regs, _aux), \
ARC_AUX_##_aux)
static inline void dsp_save_restore(struct task_struct *prev,
struct task_struct *next)
{
long unsigned int *saveto = &prev->thread.dsp.ACC0_GLO;
long unsigned int *readfrom = &next->thread.dsp.ACC0_GLO;
DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GLO);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GHI);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_BFLY0);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_FFT_CTRL);
#ifdef CONFIG_ARC_DSP_AGU_USERSPACE
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP0);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP1);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP2);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP3);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS0);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS1);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD0);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD1);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD2);
DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD3);
#endif /* CONFIG_ARC_DSP_AGU_USERSPACE */
}
#else /* !CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
#define dsp_save_restore(p, n)
#endif /* CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
static inline bool dsp_exist(void)
{
struct bcr_generic bcr;
READ_BCR(ARC_AUX_DSP_BUILD, bcr);
return !!bcr.ver;
}
static inline bool agu_exist(void)
{
struct bcr_generic bcr;
READ_BCR(ARC_AUX_AGU_BUILD, bcr);
return !!bcr.ver;
}
static inline void dsp_config_check(void)
{
CHK_OPT_STRICT(CONFIG_ARC_DSP_HANDLED, dsp_exist());
CHK_OPT_WEAK(CONFIG_ARC_DSP_AGU_USERSPACE, agu_exist());
}
#endif /* __ASEMBLY__ */
#endif /* __ASM_ARC_DSP_IMPL_H */