Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: add support for DSP-enabled userspace applications

To be able to run DSP-enabled userspace applications we need to
save and restore following DSP-related registers:
At IRQ/exception entry/exit:
* DSP_CTRL (save it and reset to value suitable for kernel)
* ACC0_LO, ACC0_HI (we already save them as r58, r59 pair)
At context switch:
* ACC0_GLO, ACC0_GHI
* DSP_BFLY0, DSP_FFT_CTRL

Reviewed-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

authored by

Eugeniy Paltsev and committed by
Vineet Gupta
7321e2ea 4827d0cf

+127 -1
+12
arch/arc/Kconfig
··· 411 411 config ARC_DSP_HANDLED 412 412 def_bool n 413 413 414 + config ARC_DSP_SAVE_RESTORE_REGS 415 + def_bool n 416 + 414 417 choice 415 418 prompt "DSP support" 416 419 default ARC_DSP_NONE ··· 436 433 DSP extension presence in HW, no support for DSP-enabled userspace 437 434 applications. We don't save / restore DSP registers and only do 438 435 some minimal preparations so userspace won't be able to break kernel 436 + 437 + config ARC_DSP_USERSPACE 438 + bool "Support DSP for userspace apps" 439 + select ARC_HAS_ACCL_REGS 440 + select ARC_DSP_HANDLED 441 + select ARC_DSP_SAVE_RESTORE_REGS 442 + help 443 + DSP extension presence in HW, support save / restore DSP registers to 444 + run DSP-enabled userspace applications 439 445 endchoice 440 446 441 447 config ARC_IRQ_NO_AUTOSAVE
+2
arch/arc/include/asm/arcregs.h
··· 120 120 121 121 /* 122 122 * DSP-related registers 123 + * Registers names must correspond to dsp_callee_regs structure fields names 124 + * for automatic offset calculation in DSP_AUX_SAVE_RESTORE macros. 123 125 */ 124 126 #define ARC_AUX_DSP_BUILD 0x7A 125 127 #define ARC_AUX_ACC0_LO 0x580
+73 -1
arch/arc/include/asm/dsp-impl.h
··· 7 7 #ifndef __ASM_ARC_DSP_IMPL_H 8 8 #define __ASM_ARC_DSP_IMPL_H 9 9 10 + #include <asm/dsp.h> 11 + 10 12 #define DSP_CTRL_DISABLED_ALL 0 11 13 12 14 #ifdef __ASSEMBLY__ ··· 32 30 */ 33 31 mov r10, DSP_CTRL_DISABLED_ALL 34 32 sr r10, [ARC_AUX_DSP_CTRL] 35 - #endif /* ARC_DSP_KERNEL */ 33 + 34 + #elif defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS) 35 + /* 36 + * Save DSP_CTRL register and reset it to value suitable for kernel 37 + * (DSP_CTRL_DISABLED_ALL) 38 + */ 39 + mov r10, DSP_CTRL_DISABLED_ALL 40 + aex r10, [ARC_AUX_DSP_CTRL] 41 + st r10, [sp, PT_DSP_CTRL] 42 + 43 + #endif 44 + .endm 45 + 46 + /* clobbers r10, r11 registers pair */ 47 + .macro DSP_RESTORE_REGFILE_IRQ 48 + #if defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS) 49 + ld r10, [sp, PT_DSP_CTRL] 50 + sr r10, [ARC_AUX_DSP_CTRL] 51 + 52 + #endif 36 53 .endm 37 54 38 55 #else /* __ASEMBLY__ */ 39 56 57 + #include <linux/sched.h> 40 58 #include <asm/asserts.h> 59 + #include <asm/switch_to.h> 60 + 61 + #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS 62 + 63 + /* 64 + * As we save new and restore old AUX register value in the same place we 65 + * can optimize a bit and use AEX instruction (swap contents of an auxiliary 66 + * register with a core register) instead of LR + SR pair. 67 + */ 68 + #define AUX_SAVE_RESTORE(_saveto, _readfrom, _offt, _aux) \ 69 + do { \ 70 + long unsigned int _scratch; \ 71 + \ 72 + __asm__ __volatile__( \ 73 + "ld %0, [%2, %4] \n" \ 74 + "aex %0, [%3] \n" \ 75 + "st %0, [%1, %4] \n" \ 76 + : \ 77 + "=&r" (_scratch) /* must be early clobber */ \ 78 + : \ 79 + "r" (_saveto), \ 80 + "r" (_readfrom), \ 81 + "Ir" (_aux), \ 82 + "Ir" (_offt) \ 83 + : \ 84 + "memory" \ 85 + ); \ 86 + } while (0) 87 + 88 + #define DSP_AUX_SAVE_RESTORE(_saveto, _readfrom, _aux) \ 89 + AUX_SAVE_RESTORE(_saveto, _readfrom, \ 90 + offsetof(struct dsp_callee_regs, _aux), \ 91 + ARC_AUX_##_aux) 92 + 93 + static inline void dsp_save_restore(struct task_struct *prev, 94 + struct task_struct *next) 95 + { 96 + long unsigned int *saveto = &prev->thread.dsp.ACC0_GLO; 97 + long unsigned int *readfrom = &next->thread.dsp.ACC0_GLO; 98 + 99 + DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GLO); 100 + DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GHI); 101 + 102 + DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_BFLY0); 103 + DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_FFT_CTRL); 104 + } 105 + 106 + #else /* !CONFIG_ARC_DSP_SAVE_RESTORE_REGS */ 107 + #define dsp_save_restore(p, n) 108 + #endif /* CONFIG_ARC_DSP_SAVE_RESTORE_REGS */ 41 109 42 110 static inline bool dsp_exist(void) 43 111 {
+24
arch/arc/include/asm/dsp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com) 4 + * 5 + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> 6 + */ 7 + #ifndef __ASM_ARC_DSP_H 8 + #define __ASM_ARC_DSP_H 9 + 10 + #ifndef __ASSEMBLY__ 11 + 12 + /* 13 + * DSP-related saved registers - need to be saved only when you are 14 + * scheduled out. 15 + * structure fields name must correspond to aux register defenitions for 16 + * automatic offset calculation in DSP_AUX_SAVE_RESTORE macros 17 + */ 18 + struct dsp_callee_regs { 19 + unsigned long ACC0_GLO, ACC0_GHI, DSP_BFLY0, DSP_FFT_CTRL; 20 + }; 21 + 22 + #endif /* !__ASSEMBLY__ */ 23 + 24 + #endif /* __ASM_ARC_DSP_H */
+3
arch/arc/include/asm/entry-arcv2.h
··· 192 192 ld r25, [sp, PT_user_r25] 193 193 #endif 194 194 195 + /* clobbers r10, r11 registers pair */ 196 + DSP_RESTORE_REGFILE_IRQ 197 + 195 198 #ifdef CONFIG_ARC_HAS_ACCL_REGS 196 199 LD2 r58, r59, PT_r58 197 200 #endif
+4
arch/arc/include/asm/processor.h
··· 14 14 #ifndef __ASSEMBLY__ 15 15 16 16 #include <asm/ptrace.h> 17 + #include <asm/dsp.h> 17 18 #include <asm/fpu.h> 18 19 19 20 #ifdef CONFIG_ARC_PLAT_EZNPS ··· 32 31 unsigned long ksp; /* kernel mode stack pointer */ 33 32 unsigned long callee_reg; /* pointer to callee regs */ 34 33 unsigned long fault_address; /* dbls as brkpt holder as well */ 34 + #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS 35 + struct dsp_callee_regs dsp; 36 + #endif 35 37 #ifdef CONFIG_ARC_FPU_SAVE_RESTORE 36 38 struct arc_fpu fpu; 37 39 #endif
+3
arch/arc/include/asm/ptrace.h
··· 91 91 #ifdef CONFIG_ARC_HAS_ACCL_REGS 92 92 unsigned long r58, r59; /* ACCL/ACCH used by FPU / DSP MPY */ 93 93 #endif 94 + #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS 95 + unsigned long DSP_CTRL; 96 + #endif 94 97 95 98 /*------- Below list auto saved by h/w -----------*/ 96 99 unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
+2
arch/arc/include/asm/switch_to.h
··· 9 9 #ifndef __ASSEMBLY__ 10 10 11 11 #include <linux/sched.h> 12 + #include <asm/dsp-impl.h> 12 13 #include <asm/fpu.h> 13 14 14 15 #ifdef CONFIG_ARC_PLAT_EZNPS ··· 25 24 #define switch_to(prev, next, last) \ 26 25 do { \ 27 26 ARC_EZNPS_DP_PREV(prev, next); \ 27 + dsp_save_restore(prev, next); \ 28 28 fpu_save_restore(prev, next); \ 29 29 last = __switch_to(prev, next);\ 30 30 mb(); \
+4
arch/arc/kernel/asm-offsets.c
··· 12 12 #include <asm/hardirq.h> 13 13 #include <asm/page.h> 14 14 15 + 15 16 int main(void) 16 17 { 17 18 DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); ··· 75 74 #ifdef CONFIG_ARC_HAS_ACCL_REGS 76 75 OFFSET(PT_r58, pt_regs, r58); 77 76 OFFSET(PT_r59, pt_regs, r59); 77 + #endif 78 + #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS 79 + OFFSET(PT_DSP_CTRL, pt_regs, DSP_CTRL); 78 80 #endif 79 81 80 82 return 0;