diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index a163955de3d..3c1fcacb827 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -44,6 +44,17 @@ config XTENSA_USE_OVLY ---help--- Enable code overlay support. This option is currently unsupported. +config XTENSA_CP_INITSET + bool "Default co-processor enables" + default 1 + range 0 65535 + ---help--- + Co-processors may be enabled on a thread by calling xtensa_coproc_enable() + and disabled by calling xtensa_coproc_disable(). Some co-processors + should be enabled on all threads by default. That set of co-processors + is provided by CONFIG_XTENSA_CP_INITSET. Each bit corresponds to one + coprocessor with the same bit layout as for the CPENABLE register. + config ARCH_CHIP string default "esp32" if ARCH_CHIP_ESP32 diff --git a/arch/xtensa/include/irq.h b/arch/xtensa/include/irq.h index 863b8ddc610..015bb16fe41 100644 --- a/arch/xtensa/include/irq.h +++ b/arch/xtensa/include/irq.h @@ -162,7 +162,7 @@ struct xcptcontext #if XCHAL_CP_NUM > 0 /* Co-processor save area */ - struct struct xtensa_cpstate_s cpstate; + struct xtensa_cpstate_s cpstate; #endif #ifdef CONFIG_LIB_SYSCALL diff --git a/arch/xtensa/include/xtensa/xtensa_coproc.h b/arch/xtensa/include/xtensa/xtensa_coproc.h index 70bc31e82a1..c744393cbb9 100644 --- a/arch/xtensa/include/xtensa/xtensa_coproc.h +++ b/arch/xtensa/include/xtensa/xtensa_coproc.h @@ -52,6 +52,10 @@ #define _CP_ALIGNUP(n,val) (((val) + _CP_MASK(n)) & ~_CP_MASK(n)) #define _CP_ALIGNDOWN(n,val) ((val) & ~_CP_MASK(n)) +/* A set of all co-processors */ + +#define XTENSA_CP_ALLSET ((1 << XCHAL_CP_NUM) - 1) + /* CO-PROCESSOR STATE SAVE AREA FOR A THREAD * * NuttX provides an area per thread to save the state of co-processors when @@ -93,18 +97,11 @@ * XTENSA_CPSTORED * A bitmask with the same layout as CPENABLE, a bit per co-processor. * Indicates whether the state of each co-processor is saved in the state - * save area. When a thread enters the kernel, only the state of co-procs - * still enabled in CPENABLE is saved. When the co-processor exception - * handler assigns ownership of a co-processor to a thread, it restores - * the saved state only if this bit is set, and clears this bit. - * - * XTENSA_CPCSST - * A bitmask with the same layout as CPENABLE, a bit per co-processor. - * Indicates whether callee-saved state is saved in the state save area. - * Callee-saved state is saved by itself on a solicited context switch, - * and restored when needed by the coprocessor exception handler. - * Unsolicited switches will cause the entire coprocessor to be saved - * when necessary. + * save area. When the state of a thread is saved, only the state of co-procs + * still enabled in CPENABLE is saved. When the co-processor state is + * is restored, the state is only resotred for a co-processor if this bit + * is set. This bist set is cleared after after co-processor state has + * been restored. * * XTENSA_CPASA * Pointer to the aligned save area. Allows it to be aligned more than @@ -129,8 +126,7 @@ #define XTENSA_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */ #define XTENSA_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */ -#define XTENSA_CPCSST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */ -#define XTENSA_CPASA 8 /* (4 bytes) ptr to aligned save area */ +#define XTENSA_CPASA 4 /* (4 bytes) ptr to aligned save area */ /**************************************************************************** * Public Types @@ -140,11 +136,33 @@ struct xtensa_cpstate_s { - uint16_t cpenable; /* (2 bytes) coprocessors active for this thread */ - uint16_t cpstored; /* (2 bytes) coprocessors saved for this thread */ - uint16_t cpcsst /* (2 bytes) coprocessor callee-saved regs stored for this thread */ - uint16_t unused; /* (2 bytes) unused */ - uint32_t *cpasa; /* (4 bytes) ptr to aligned save area */ + uint16_t cpenable; /* (2 bytes) Co-processors active for this thread */ + uint16_t cpstored; /* (2 bytes) Co-processors saved for this thread */ + uint32_t *cpasa; /* (4 bytes) Pointer to aligned save area */ +} + +/* Return the current value of the CPENABLE register */ + +static inline uint32_t xtensa_get_cpenable(void) +{ + uint32_t cpenable; + + __asm__ __volatile__ + ( + "rsr %0, CPENABLE" : "=r"(cpenable) + ); + + return cpenable; +} + +/* Set the value of the CPENABLE register */ + +static inline void xtensa_set_cpenable(uint32_t cpenable) +{ + __asm__ __volatile__ + ( + "wsr %0, PS" : : "r"(cpenable) + ); } #endif /* __ASSEMBLY__ */ diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index c646ca4fca2..5d2448728ef 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -241,6 +241,8 @@ void xtensa_coproc_init(void); struct xtensa_cpstate_s; void xtensa_coproc_release(struct xtensa_cpstate_s *cpstate); +void xtensa_coproc_enable(struct xtensa_cpstate_s *cpstate, int cpset); +void xtensa_coproc_disable(struct xtensa_cpstate_s *cpstate, int cpset); #endif /* IRQs */ diff --git a/arch/xtensa/src/common/xtensa_coproc.S b/arch/xtensa/src/common/xtensa_coproc.S index 434f0906845..419507fbdf0 100644 --- a/arch/xtensa/src/common/xtensa_coproc.S +++ b/arch/xtensa/src/common/xtensa_coproc.S @@ -113,6 +113,7 @@ xtensa_coproc_init: movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */ addi a3, a2, (XTENSA_CP_MAX*portNUM_PROCESSORS) << 2 /* a3 = top+1 of owner array */ movi a4, 0 /* a4 = 0 (unowned) */ + 1: s32i a4, a2, 0 addi a2, a2, 4 bltu a2, a3, 1b @@ -223,7 +224,7 @@ _xtensa_coproc_savestate: rsr a2, CPENABLE /* a2 = which CPs are enabled */ beqz a2, .Ldone1 /* Quick exit if none */ - s16i a2, a15, XTENSA_CPCSST /* Save mask of CPs being stored */ + s16i a2, a15, XTENSA_CPSTORED /* Save mask of CPs being stored */ movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */ l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */ @@ -336,9 +337,9 @@ _xtensa_coproc_restorestate: /* Move the address of the thread state save area to R15 */ mov a15, a2 /* A15 is now the address of the save area */ - l16ui a2, a15, XTENSA_CPCSST /* a3 = which CPs have been saved */ + l16ui a2, a15, XTENSA_CPSTORED /* a2 = which CPs have been saved */ movi a3, 0 /* Clear the ones being restored (all of them) */ - s32i a3, a15, XTENSA_CPCSST /* Update saved CP mask */ + s16i a3, a15, XTENSA_CPSTORED /* Clear saved CP mask */ movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */ l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */ diff --git a/arch/xtensa/src/common/xtensa_cpsave.c b/arch/xtensa/src/common/xtensa_cpsave.c index 3e1f57e5635..7a128c6aa10 100644 --- a/arch/xtensa/src/common/xtensa_cpsave.c +++ b/arch/xtensa/src/common/xtensa_cpsave.c @@ -39,6 +39,8 @@ #include +#include +#include #include #include "xtensa.h" @@ -58,12 +60,22 @@ * is simply a C wrapper around the assembly language call to * _xtensa_coproc_savestate. * - * Entry Conditions: - * - The thread being switched out is still the current thread. - * - CPENABLE state reflects which coprocessors are active. + * Entry Conditions: + * - The thread being switched out is still the current thread. + * - CPENABLE state reflects which coprocessors are active. * - * Exit conditions: - * - All necessary CP callee-saved state has been saved. + * Exit conditions: + * - All necessary CP callee-saved state has been saved. + * + * Input Parameters: + * tcb - A pointer to the TCB of thread whose co-processor state is to + * be saved. + * + * Returned Value: + * None + * + * Assumptions: + * Called with interrupts disabled. * ****************************************************************************/ @@ -89,12 +101,22 @@ void xtensa_coproc_savestate(struct tcb_s *tcb) * xtensa_coproc_restorestate() is simply a C wrapper around the assembly * language call to _xtensa_coproc_restorestate. * - * Entry Conditions: - * - CPENABLE is set up correctly for all required coprocessors. + * Entry Conditions: + * - CPENABLE is set up correctly for all required coprocessors. * - * Exit conditions: - * - All necessary CP callee-saved state has been restored. - * - CPENABLE - unchanged. + * Exit conditions: + * - All necessary CP callee-saved state has been restored. + * - CPENABLE - unchanged. + * + * Input Parameters: + * tcb - A pointer to the TCB of thread whose co-processor state is to + * be restored. + * + * Returned Value: + * None + * + * Assumptions: + * Called with interrupts disabled. * ****************************************************************************/ @@ -113,4 +135,107 @@ void xtensa_coproc_restorestate(struct tcb_s *tcb) ) } +/**************************************************************************** + * Name: xtensa_coproc_enable + * + * Description: + * Enable a set of co-processors. + * + * Input Parameters: + * cpstate - A pointer to the Co-processor state save structure. + * cpset - A bit set of co-processors to be enabled. Matches bit layout + * of the CPENABLE register. Bit 0-XCHAL_CP_NUM: 0 = no change + * 1 = enable + * + * Returned Value: + * None + * + ****************************************************************************/ + +void xtensa_coproc_enable(struct xtensa_cpstate_s *cpstate, int cpset) +{ + irqstate_t flags; + uint32_t cpenable; + + /* These operations must be atomic */ + + flags = enter_critical_section(); + + /* Don't enable co-processors that may already be enabled + * + * cpenable + * 0 1 + * --- --- + * cpset 0 | 0 0 + * 1 | 1 0 + */ + + cpset ^= (cpset & cpstate->cpenable); + if (cpset != 0) + { + /* Enable the co-processors */ + + cpenable = xtensa_get_cpenable(); + cpenable |= cpset; + xtensa_put_cpenable(cpenable); + + cpstate->cpenable = cpenable; + cpsates->cpstored &= ~cpset; + } + + leave_critical_section(); +} + +/**************************************************************************** + * Name: xtensa_coproc_disable + * + * Description: + * Enable a set of co-processors. + * + * Input Parameters: + * cpstate - A pointer to the Co-processor state save structure. + * cpset - A bit set of co-processors to be enabled. Matches bit layout + * of the CPENABLE register. Bit 0-XCHAL_CP_NUM: 0 = no change + * 1 = disable + * + * Returned Value: + * None + * + ****************************************************************************/ + +void xtensa_coproc_disable(struct xtensa_cpstate_s *cpstate, int cpset) +{ + irqstate_t flags; + uint32_t cpenable; + + /* These operations must be atomic */ + + flags = enter_critical_section(); + + /* Don't disable co-processors that are already be disabled. + * + * cpenable + * 0 1 + * --- --- + * cpset 0 | 0 0 + * 1 | 0 1 + */ + + cpset &= cpstate->cpenable; + if (cpset != 0) + { + /* Disable the co-processors */ + + cpenable = xtensa_get_cpenable(); + cpenable &= ~cpset; + xtensa_put_cpenable(cpenable); + + cpstate->cpenable = cpenable; + cpsates->cpstored &= ~cpset; + } + + leave_critical_section(); +} + + #endif /* XCHAL_CP_NUM */ diff --git a/arch/xtensa/src/common/xtensa_createstack.c b/arch/xtensa/src/common/xtensa_createstack.c index 88058eb7f11..000f0dd9906 100644 --- a/arch/xtensa/src/common/xtensa_createstack.c +++ b/arch/xtensa/src/common/xtensa_createstack.c @@ -215,8 +215,6 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) xcp->cpstate.cpenable = 0; /* No coprocessors active for this thread */ xcp->cpstate.cpstored = 0; /* No coprocessors saved for this thread */ - xcp->cpstate.cpcsst = 0; /* No oprocessor callee-saved regs stored for this thread */ - xcp->cpstate.unused = 0; /* unused */ xcp->cpstate.cpasa = (uint32_t *)cpstart; /* Start of aligned save area */ #endif diff --git a/arch/xtensa/src/common/xtensa_exit.c b/arch/xtensa/src/common/xtensa_exit.c index 6eaba07c519..98ec9b6c5a4 100644 --- a/arch/xtensa/src/common/xtensa_exit.c +++ b/arch/xtensa/src/common/xtensa_exit.c @@ -156,10 +156,11 @@ void _exit(int status) #endif #if XCHAL_CP_NUM > 0 - /* Disable preprocessor support fo the task that is exit-ing. */ + /* Disable co-processor support for the task that is exit-ing. */ tcb = this_task(); xtensa_coproc_release(&tcb->xcp.cpstate); + xtensa_coproc_disable(&tcb->xcp.cpstate, XTENSA_CP_ALLSET); #endif /* Destroy the task at the head of the ready to run list. */ diff --git a/arch/xtensa/src/common/xtensa_initialstate.c b/arch/xtensa/src/common/xtensa_initialstate.c index 6c029a881e0..8fc10a6d03c 100644 --- a/arch/xtensa/src/common/xtensa_initialstate.c +++ b/arch/xtensa/src/common/xtensa_initialstate.c @@ -94,4 +94,13 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_PS] = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); #endif + +#if XCHAL_CP_NUM > 0 + /* Set up the co-processors that will be enabled initially when the thread + * starts (see xtensa_coproc.h) + */ + + xcp->cpstate.cpenable = CONFIG_XTENSA_CP_INITSET; + xcp->cpstate.cpstored = 0; /* No coprocessors haved statee saved for this thread */ +#endif } diff --git a/arch/xtensa/src/common/xtensa_vectors.S b/arch/xtensa/src/common/xtensa_vectors.S index 19773e7e8ac..a9b440e7709 100644 --- a/arch/xtensa/src/common/xtensa_vectors.S +++ b/arch/xtensa/src/common/xtensa_vectors.S @@ -174,6 +174,7 @@ _xtensa_level6_vector: .align 4 _xtensa_nmi_vector: + wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ call0 _xt_nmi /* load interrupt handler */