From 58655d1efd367711b2297d568360923368361b6b Mon Sep 17 00:00:00 2001 From: Abdelatif Guettouche Date: Mon, 12 Oct 2020 22:45:48 +0100 Subject: [PATCH] arch/xtensa/src/esp32: SMP case of interruptstack. Signed-off-by: Abdelatif Guettouche --- arch/xtensa/src/common/xtensa.h | 9 ++- arch/xtensa/src/common/xtensa_checkstack.c | 10 +++- arch/xtensa/src/common/xtensa_dumpstate.c | 25 ++++++--- arch/xtensa/src/common/xtensa_initialize.c | 16 ++++-- arch/xtensa/src/common/xtensa_int_handlers.S | 8 +-- arch/xtensa/src/esp32/chip_macros.h | 58 ++++++++++++++++++++ arch/xtensa/src/esp32/esp32_irq.c | 58 ++++++++++++++++++++ 7 files changed, 163 insertions(+), 21 deletions(-) diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index 7d3d86c233..27f2de96f3 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -87,9 +87,14 @@ #ifndef CONFIG_ARCH_INTERRUPTSTACK # define CONFIG_ARCH_INTERRUPTSTACK 0 +#else +# define INTSTACK_ALIGNMENT 16 +# define INTSTACK_ALIGN_MASK (INTSTACK_ALIGNMENT - 1) +# define INTSTACK_ALIGNDOWN(s) ((s) & ~INTSTACK_ALIGN_MASK) +# define INTSTACK_ALIGNUP(s) (((s) + INTSTACK_ALIGN_MASK) & ~INTSTACK_ALIGN_MASK) +# define INTSTACK_SIZE INTSTACK_ALIGNUP(CONFIG_ARCH_INTERRUPTSTACK) #endif - /* An IDLE thread stack size for CPU0 must be defined */ #if !defined(CONFIG_IDLETHREAD_STACKSIZE) @@ -177,7 +182,7 @@ extern volatile uint32_t *g_current_regs[1]; #endif -#if CONFIG_ARCH_INTERRUPTSTACK > 15 +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 /* The (optional) interrupt stack */ extern uint32_t g_intstackalloc; /* Allocated interrupt stack */ diff --git a/arch/xtensa/src/common/xtensa_checkstack.c b/arch/xtensa/src/common/xtensa_checkstack.c index cfd08a8d09..6eb8375e55 100644 --- a/arch/xtensa/src/common/xtensa_checkstack.c +++ b/arch/xtensa/src/common/xtensa_checkstack.c @@ -51,6 +51,7 @@ #include "xtensa.h" #include "sched/sched.h" +#include "chip_macros.h" #ifdef CONFIG_STACK_COLORATION @@ -200,13 +201,16 @@ ssize_t up_check_stack_remain(void) #if CONFIG_ARCH_INTERRUPTSTACK > 15 size_t up_check_intstack(void) { - return do_stackcheck((uintptr_t)&g_intstackalloc, - (CONFIG_ARCH_INTERRUPTSTACK & ~15)); +#ifdef CONFIG_SMP + return do_stackcheck(xtensa_intstack_alloc(), INTSTACK_SIZE); +#else + return do_stackcheck((uintptr_t)&g_intstackalloc, INTSTACK_SIZE); +#endif } size_t up_check_intstack_remain(void) { - return (CONFIG_ARCH_INTERRUPTSTACK & ~15) - up_check_intstack(); + return INTSTACK_SIZE - up_check_intstack(); } #endif diff --git a/arch/xtensa/src/common/xtensa_dumpstate.c b/arch/xtensa/src/common/xtensa_dumpstate.c index cf35f15dec..85461760a6 100644 --- a/arch/xtensa/src/common/xtensa_dumpstate.c +++ b/arch/xtensa/src/common/xtensa_dumpstate.c @@ -37,6 +37,7 @@ #include "sched/sched.h" #include "xtensa.h" +#include "chip_macros.h" #ifdef CONFIG_DEBUG_ALERT @@ -186,8 +187,12 @@ void xtensa_dumpstate(void) /* Get the limits on the interrupt stack memory */ #if CONFIG_ARCH_INTERRUPTSTACK > 15 +#ifdef CONFIG_SMP + istackbase = (uint32_t)xtensa_intstack_base(); +#else istackbase = (uint32_t)&g_intstackbase; - istacksize = (CONFIG_ARCH_INTERRUPTSTACK & ~15); +#endif + istacksize = INTSTACK_SIZE; /* Show interrupt stack info */ @@ -208,13 +213,6 @@ void xtensa_dumpstate(void) /* Yes.. dump the interrupt stack */ xtensa_stackdump(sp, istackbase); - - /* Extract the user stack pointer which should lie - * at the base of the interrupt stack. - */ - - sp = g_intstackbase - sizeof(uint32_t); - _alert("sp: %08x\n", sp); } else if (CURRENT_REGS) { @@ -222,6 +220,17 @@ void xtensa_dumpstate(void) xtensa_stackdump(istackbase - istacksize, istackbase); } + /* Extract the user stack pointer if we are in an interrupt handler. + * If we are not in an interrupt handler. Then sp is the user stack + * pointer (and the above range check should have failed). + */ + + if (CURRENT_REGS) + { + sp = CURRENT_REGS[REG_A1]; + _alert("sp: %08x\n", sp); + } + /* Show user stack info */ _alert("User stack:\n"); diff --git a/arch/xtensa/src/common/xtensa_initialize.c b/arch/xtensa/src/common/xtensa_initialize.c index 082b99f389..9a5b8c6a26 100644 --- a/arch/xtensa/src/common/xtensa_initialize.c +++ b/arch/xtensa/src/common/xtensa_initialize.c @@ -57,6 +57,7 @@ #include #include "xtensa.h" +#include "chip_macros.h" /**************************************************************************** * Private Functions @@ -74,12 +75,19 @@ #if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 15 static inline void xtensa_color_intstack(void) { - ssize_t size; +#ifdef CONFIG_SMP + uint32_t *ptr = (uint32_t *)xtensa_intstack_alloc(); +#else uint32_t *ptr = (uint32_t *)&g_intstackalloc; +#endif + ssize_t size; - for (size = (CONFIG_ARCH_INTERRUPTSTACK & ~15); - size > 0; - size -= sizeof(uint32_t)) +#ifdef CONFIG_SMP + for (size = INTSTACK_SIZE * CONFIG_SMP_NCPUS; +#else + for (size = INTSTACK_SIZE; +#endif + size > 0; size -= sizeof(uint32_t)) { *ptr++ = INTSTACK_COLOR; } diff --git a/arch/xtensa/src/common/xtensa_int_handlers.S b/arch/xtensa/src/common/xtensa_int_handlers.S index 02f83c4d7b..16b4a0f637 100644 --- a/arch/xtensa/src/common/xtensa_int_handlers.S +++ b/arch/xtensa/src/common/xtensa_int_handlers.S @@ -76,7 +76,7 @@ .type g_intstackalloc, @object .type g_intstackbase, @object g_intstackalloc: - .skip ((CONFIG_ARCH_INTERRUPTSTACK + 15) & ~15) + .skip INTSTACK_SIZE g_intstackbase: .size g_intstackalloc, .-g_intstackalloc #endif @@ -108,13 +108,13 @@ g_intstackbase: * Name: setintstack * * Description: - * Set the current stack pointer to the "top" the interrupt stack. Single CPU + * Set the current stack pointer to the "top" the interrupt stack. Single CPU * case. Must be provided by MCU-specific logic in the SMP case. * ************************************************************************************/ #if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 - .macro setintstack + .macro setintstack tmp1 tmp2 movi a1, g_intstackbase .endm #endif @@ -296,7 +296,7 @@ _xtensa_level1_handler: /* Switch to an interrupt stack if we have one */ #if CONFIG_ARCH_INTERRUPTSTACK > 15 - setintstack + setintstack a13 a14 #endif /* Set up PS for C, enable interrupts above this level and clear EXCM. */ diff --git a/arch/xtensa/src/esp32/chip_macros.h b/arch/xtensa/src/esp32/chip_macros.h index 07a65a3e4a..de0bf7375d 100644 --- a/arch/xtensa/src/esp32/chip_macros.h +++ b/arch/xtensa/src/esp32/chip_macros.h @@ -49,6 +49,18 @@ #define HANDLER_SECTION .iram1 +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __ASSEMBLY__ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 + .global g_cpu_intstack_top +#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 15 */ + +#endif /* __ASSEMBLY__ */ + /**************************************************************************** * Assembly Language Macros ****************************************************************************/ @@ -71,5 +83,51 @@ 2: .endm +/**************************************************************************** + * Name: setintstack + * + * Description: + * Set the current stack pointer to the "top" of the correct interrupt + * stack for the current CPU. + * + ****************************************************************************/ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 + .macro setintstack tmp1 tmp2 + getcoreid \tmp1 /* tmp1 = Core ID (0 or 1) */ + movi \tmp2, g_cpu_intstack_top /* tmp2 = Array of stack pointers */ + addx4 \tmp2, \tmp1, \tmp2 /* tmp2 = tmp2 + (tmp1 << 2) */ + l32i a1, \tmp2, 0 /* a1 = *tmp2 */ + .endm +#endif #endif /* __ASSEMBLY */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +uintptr_t xtensa_intstack_base(void); +uintptr_t xtensa_intstack_alloc(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ #endif /* __ARCH_XTENSA_SRC_ESP32_CHIP_MACROS_H */ diff --git a/arch/xtensa/src/esp32/esp32_irq.c b/arch/xtensa/src/esp32/esp32_irq.c index 65310a0e31..d4cb943fe7 100644 --- a/arch/xtensa/src/esp32/esp32_irq.c +++ b/arch/xtensa/src/esp32/esp32_irq.c @@ -51,6 +51,16 @@ #include "esp32_smp.h" #include "esp32_gpio.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Interrupt stack definitions for SMP */ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +# define INTSTACK_ALLOC (CONFIG_SMP_NCPUS * INTSTACK_SIZE) +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -74,6 +84,24 @@ volatile uint32_t *g_current_regs[1]; #endif +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +/* In the SMP configuration, we will need custom interrupt stacks. + * These definitions provide the aligned stack allocations. + */ + +static uint32_t g_intstackalloc[INTSTACK_ALLOC >> 2]; + +/* These definitions provide the "top" of the push-down stacks. */ + +uintptr_t g_cpu_intstack_top[CONFIG_SMP_NCPUS] = +{ + (uintptr_t)g_intstackalloc + INTSTACK_SIZE, +#if CONFIG_SMP_NCPUS > 1 + (uintptr_t)g_intstackalloc + (2 * INTSTACK_SIZE), +#endif /* CONFIG_SMP_NCPUS > 1 */ +}; +#endif /* defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -164,3 +192,33 @@ void up_irqinitialize(void) up_irq_enable(); #endif } + +/**************************************************************************** + * Name: xtensa_intstack_base + * + * Description: + * Return a pointer to the "base" of the correct interrupt stack for the + * given CPU. + * + ****************************************************************************/ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +uintptr_t xtensa_intstack_base(void) +{ + return g_cpu_intstack_top[up_cpu_index()]; +} + +/**************************************************************************** + * Name: xtensa_intstack_alloc + * + * Description: + * Return a pointer to the "alloc" the correct interrupt stack allocation + * for the current CPU. + * + ****************************************************************************/ + +uintptr_t xtensa_intstack_alloc(void) +{ + return g_cpu_intstack_top[up_cpu_index()] - INTSTACK_SIZE; +} +#endif