Commit 5364abc5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arc-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc

Pull ARC updates from Vineet Gupta:

 - Support for DSP enabled userspace (save/restore regs)

 - Misc other platform fixes

* tag 'arc-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc:
  ARC: allow userspace DSP applications to use AGU extensions
  ARC: add support for DSP-enabled userspace applications
  ARC: handle DSP presence in HW
  ARC: add helpers to sanitize config options
  ARC: [plat-axs10x]: PGU: remove unused encoder-slave property
parents 854e80bc f09d3174
...@@ -401,13 +401,61 @@ config ARC_HAS_DIV_REM ...@@ -401,13 +401,61 @@ config ARC_HAS_DIV_REM
default y default y
config ARC_HAS_ACCL_REGS config ARC_HAS_ACCL_REGS
bool "Reg Pair ACCL:ACCH (FPU and/or MPY > 6)" bool "Reg Pair ACCL:ACCH (FPU and/or MPY > 6 and/or DSP)"
default y default y
help help
Depending on the configuration, CPU can contain accumulator reg-pair Depending on the configuration, CPU can contain accumulator reg-pair
(also referred to as r58:r59). These can also be used by gcc as GPR so (also referred to as r58:r59). These can also be used by gcc as GPR so
kernel needs to save/restore per process kernel needs to save/restore per process
config ARC_DSP_HANDLED
def_bool n
config ARC_DSP_SAVE_RESTORE_REGS
def_bool n
choice
prompt "DSP support"
default ARC_DSP_NONE
help
Depending on the configuration, CPU can contain DSP registers
(ACC0_GLO, ACC0_GHI, DSP_BFLY0, DSP_CTRL, DSP_FFT_CTRL).
Bellow is options describing how to handle these registers in
interrupt entry / exit and in context switch.
config ARC_DSP_NONE
bool "No DSP extension presence in HW"
help
No DSP extension presence in HW
config ARC_DSP_KERNEL
bool "DSP extension in HW, no support for userspace"
select ARC_HAS_ACCL_REGS
select ARC_DSP_HANDLED
help
DSP extension presence in HW, no support for DSP-enabled userspace
applications. We don't save / restore DSP registers and only do
some minimal preparations so userspace won't be able to break kernel
config ARC_DSP_USERSPACE
bool "Support DSP for userspace apps"
select ARC_HAS_ACCL_REGS
select ARC_DSP_HANDLED
select ARC_DSP_SAVE_RESTORE_REGS
help
DSP extension presence in HW, support save / restore DSP registers to
run DSP-enabled userspace applications
config ARC_DSP_AGU_USERSPACE
bool "Support DSP with AGU for userspace apps"
select ARC_HAS_ACCL_REGS
select ARC_DSP_HANDLED
select ARC_DSP_SAVE_RESTORE_REGS
help
DSP and AGU extensions presence in HW, support save / restore DSP
and AGU registers to run DSP-enabled userspace applications
endchoice
config ARC_IRQ_NO_AUTOSAVE config ARC_IRQ_NO_AUTOSAVE
bool "Disable hardware autosave regfile on interrupts" bool "Disable hardware autosave regfile on interrupts"
default n default n
......
...@@ -305,7 +305,6 @@ gpio1_bankc: gpio-controller@2 { ...@@ -305,7 +305,6 @@ gpio1_bankc: gpio-controller@2 {
pgu@17000 { pgu@17000 {
compatible = "snps,arcpgu"; compatible = "snps,arcpgu";
reg = <0x17000 0x400>; reg = <0x17000 0x400>;
encoder-slave = <&adv7511>;
clocks = <&pguclk>; clocks = <&pguclk>;
clock-names = "pxlclk"; clock-names = "pxlclk";
memory-region = <&frame_buffer>; memory-region = <&frame_buffer>;
......
...@@ -118,6 +118,32 @@ ...@@ -118,6 +118,32 @@
#define ARC_AUX_DPFP_2H 0x304 #define ARC_AUX_DPFP_2H 0x304
#define ARC_AUX_DPFP_STAT 0x305 #define ARC_AUX_DPFP_STAT 0x305
/*
* DSP-related registers
* Registers names must correspond to dsp_callee_regs structure fields names
* for automatic offset calculation in DSP_AUX_SAVE_RESTORE macros.
*/
#define ARC_AUX_DSP_BUILD 0x7A
#define ARC_AUX_ACC0_LO 0x580
#define ARC_AUX_ACC0_GLO 0x581
#define ARC_AUX_ACC0_HI 0x582
#define ARC_AUX_ACC0_GHI 0x583
#define ARC_AUX_DSP_BFLY0 0x598
#define ARC_AUX_DSP_CTRL 0x59F
#define ARC_AUX_DSP_FFT_CTRL 0x59E
#define ARC_AUX_AGU_BUILD 0xCC
#define ARC_AUX_AGU_AP0 0x5C0
#define ARC_AUX_AGU_AP1 0x5C1
#define ARC_AUX_AGU_AP2 0x5C2
#define ARC_AUX_AGU_AP3 0x5C3
#define ARC_AUX_AGU_OS0 0x5D0
#define ARC_AUX_AGU_OS1 0x5D1
#define ARC_AUX_AGU_MOD0 0x5E0
#define ARC_AUX_AGU_MOD1 0x5E1
#define ARC_AUX_AGU_MOD2 0x5E2
#define ARC_AUX_AGU_MOD3 0x5E3
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <soc/arc/aux.h> #include <soc/arc/aux.h>
......
/* 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_ASSERTS_H
#define __ASM_ARC_ASSERTS_H
/* Helpers to sanitize config options. */
void chk_opt_strict(char *opt_name, bool hw_exists, bool opt_ena);
void chk_opt_weak(char *opt_name, bool hw_exists, bool opt_ena);
/*
* Check required config option:
* - panic in case of OPT enabled but corresponding HW absent.
* - warn in case of OPT disabled but corresponding HW exists.
*/
#define CHK_OPT_STRICT(opt_name, hw_exists) \
({ \
chk_opt_strict(#opt_name, hw_exists, IS_ENABLED(opt_name)); \
})
/*
* Check optional config option:
* - panic in case of OPT enabled but corresponding HW absent.
*/
#define CHK_OPT_WEAK(opt_name, hw_exists) \
({ \
chk_opt_weak(#opt_name, hw_exists, IS_ENABLED(opt_name)); \
})
#endif /* __ASM_ARC_ASSERTS_H */
/* 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
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:
.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 */
/* 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_H
#define __ASM_ARC_DSP_H
#ifndef __ASSEMBLY__
/*
* DSP-related saved registers - need to be saved only when you are
* scheduled out.
* structure fields name must correspond to aux register defenitions for
* automatic offset calculation in DSP_AUX_SAVE_RESTORE macros
*/
struct dsp_callee_regs {
unsigned long ACC0_GLO, ACC0_GHI, DSP_BFLY0, DSP_FFT_CTRL;
#ifdef CONFIG_ARC_DSP_AGU_USERSPACE
unsigned long AGU_AP0, AGU_AP1, AGU_AP2, AGU_AP3;
unsigned long AGU_OS0, AGU_OS1;
unsigned long AGU_MOD0, AGU_MOD1, AGU_MOD2, AGU_MOD3;
#endif
};
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_ARC_DSP_H */
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define __ASM_ARC_ENTRY_ARCV2_H #define __ASM_ARC_ENTRY_ARCV2_H
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/dsp-impl.h>
#include <asm/irqflags-arcv2.h> #include <asm/irqflags-arcv2.h>
#include <asm/thread_info.h> /* For THREAD_SIZE */ #include <asm/thread_info.h> /* For THREAD_SIZE */
...@@ -165,6 +166,8 @@ ...@@ -165,6 +166,8 @@
ST2 r58, r59, PT_r58 ST2 r58, r59, PT_r58
#endif #endif
/* clobbers r10, r11 registers pair */
DSP_SAVE_REGFILE_IRQ
.endm .endm
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
...@@ -189,6 +192,9 @@ ...@@ -189,6 +192,9 @@
ld r25, [sp, PT_user_r25] ld r25, [sp, PT_user_r25]
#endif #endif
/* clobbers r10, r11 registers pair */
DSP_RESTORE_REGFILE_IRQ
#ifdef CONFIG_ARC_HAS_ACCL_REGS #ifdef CONFIG_ARC_HAS_ACCL_REGS
LD2 r58, r59, PT_r58 LD2 r58, r59, PT_r58
#endif #endif
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/dsp.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#ifdef CONFIG_ARC_PLAT_EZNPS #ifdef CONFIG_ARC_PLAT_EZNPS
...@@ -31,6 +32,9 @@ struct thread_struct { ...@@ -31,6 +32,9 @@ struct thread_struct {
unsigned long ksp; /* kernel mode stack pointer */ unsigned long ksp; /* kernel mode stack pointer */
unsigned long callee_reg; /* pointer to callee regs */ unsigned long callee_reg; /* pointer to callee regs */
unsigned long fault_address; /* dbls as brkpt holder as well */ unsigned long fault_address; /* dbls as brkpt holder as well */
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
struct dsp_callee_regs dsp;
#endif
#ifdef CONFIG_ARC_FPU_SAVE_RESTORE #ifdef CONFIG_ARC_FPU_SAVE_RESTORE
struct arc_fpu fpu; struct arc_fpu fpu;
#endif #endif
......
...@@ -91,6 +91,9 @@ struct pt_regs { ...@@ -91,6 +91,9 @@ struct pt_regs {
#ifdef CONFIG_ARC_HAS_ACCL_REGS #ifdef CONFIG_ARC_HAS_ACCL_REGS
unsigned long r58, r59; /* ACCL/ACCH used by FPU / DSP MPY */ unsigned long r58, r59; /* ACCL/ACCH used by FPU / DSP MPY */
#endif #endif
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
unsigned long DSP_CTRL;
#endif
/*------- Below list auto saved by h/w -----------*/ /*------- Below list auto saved by h/w -----------*/
unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/dsp-impl.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#ifdef CONFIG_ARC_PLAT_EZNPS #ifdef CONFIG_ARC_PLAT_EZNPS
...@@ -24,6 +25,7 @@ struct task_struct *__switch_to(struct task_struct *p, struct task_struct *n); ...@@ -24,6 +25,7 @@ struct task_struct *__switch_to(struct task_struct *p, struct task_struct *n);
#define switch_to(prev, next, last) \ #define switch_to(prev, next, last) \
do { \ do { \
ARC_EZNPS_DP_PREV(prev, next); \ ARC_EZNPS_DP_PREV(prev, next); \
dsp_save_restore(prev, next); \
fpu_save_restore(prev, next); \ fpu_save_restore(prev, next); \
last = __switch_to(prev, next);\ last = __switch_to(prev, next);\
mb(); \ mb(); \
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <asm/page.h> #include <asm/page.h>
int main(void) int main(void)
{ {
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
...@@ -75,6 +76,9 @@ int main(void) ...@@ -75,6 +76,9 @@ int main(void)
OFFSET(PT_r58, pt_regs, r58); OFFSET(PT_r58, pt_regs, r58);
OFFSET(PT_r59, pt_regs, r59); OFFSET(PT_r59, pt_regs, r59);
#endif #endif
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
OFFSET(PT_DSP_CTRL, pt_regs, DSP_CTRL);
#endif
return 0; return 0;
} }
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <asm/entry.h> #include <asm/entry.h>
#include <asm/arcregs.h> #include <asm/arcregs.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/dsp-impl.h>
#include <asm/irqflags.h> #include <asm/irqflags.h>
.macro CPU_EARLY_SETUP .macro CPU_EARLY_SETUP
...@@ -59,6 +60,9 @@ ...@@ -59,6 +60,9 @@
#endif #endif
kflag r5 kflag r5
#endif #endif
; Config DSP_CTRL properly, so kernel may use integer multiply,
; multiply-accumulate, and divide operations
DSP_EARLY_INIT
.endm .endm
.section .init.text, "ax",@progbits .section .init.text, "ax",@progbits
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <uapi/linux/mount.h> #include <uapi/linux/mount.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/arcregs.h> #include <asm/arcregs.h>
#include <asm/asserts.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#include <asm/unwind.h> #include <asm/unwind.h>
#include <asm/mach_desc.h> #include <asm/mach_desc.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/dsp-impl.h>
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x)) #define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
...@@ -389,11 +391,24 @@ static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len) ...@@ -389,11 +391,24 @@ static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
return buf; return buf;
} }
void chk_opt_strict(char *opt_name, bool hw_exists, bool opt_ena)
{
if (hw_exists && !opt_ena)
pr_warn(" ! Enable %s for working apps\n", opt_name);
else if (!hw_exists && opt_ena)
panic("Disable %s, hardware NOT present\n", opt_name);
}
void chk_opt_weak(char *opt_name, bool hw_exists, bool opt_ena)
{
if (!hw_exists && opt_ena)
panic("Disable %s, hardware NOT present\n", opt_name);
}
static void arc_chk_core_config(void) static void arc_chk_core_config(void)
{ {
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
int saved = 0, present = 0; int present = 0;
char *opt_nm = NULL;
if (!cpu->extn.timer0) if (!cpu->extn.timer0)
panic("Timer0 is not present!\n"); panic("Timer0 is not present!\n");
...@@ -425,23 +440,16 @@ static void arc_chk_core_config(void) ...@@ -425,23 +440,16 @@ static void arc_chk_core_config(void)
*/ */
if (is_isa_arcompact()) { if (is_isa_arcompact()) {
opt_nm = "CONFIG_ARC_FPU_SAVE_RESTORE";
saved = IS_ENABLED(CONFIG_ARC_FPU_SAVE_RESTORE);
/* only DPDP checked since SP has no arch visible regs */ /* only DPDP checked since SP has no arch visible regs */
present = cpu->extn.fpu_dp; present = cpu->extn.fpu_dp;
CHK_OPT_STRICT(CONFIG_ARC_FPU_SAVE_RESTORE, present);
} else { } else {
opt_nm = "CONFIG_ARC_HAS_ACCL_REGS";
saved = IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS);
/* Accumulator Low:High pair (r58:59) present if DSP MPY or FPU */ /* Accumulator Low:High pair (r58:59) present if DSP MPY or FPU */
present = cpu->extn_mpy.dsp | cpu->extn.fpu_sp | cpu->extn.fpu_dp; present = cpu->extn_mpy.dsp | cpu->extn.fpu_sp | cpu->extn.fpu_dp;
} CHK_OPT_STRICT(CONFIG_ARC_HAS_ACCL_REGS, present);
if (present && !saved) dsp_config_check();
pr_warn("Enable %s for working apps\n", opt_nm); }
else if (!present && saved)
panic("Disable %s, hardware NOT present\n", opt_nm);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment