From 4a29fa903bdd74cb1e6bc871e4de961072fee269 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Nihei Date: Tue, 8 Mar 2022 14:03:25 -0300 Subject: [PATCH] xtensa/esp32s3: Enable SMP support Signed-off-by: Gustavo Henrique Nihei --- arch/xtensa/src/esp32s3/Make.defs | 9 + arch/xtensa/src/esp32s3/chip_macros.h | 55 +++- .../xtensa/src/esp32s3/esp32s3_cpuidlestack.c | 106 +++++++ arch/xtensa/src/esp32s3/esp32s3_cpuindex.S | 64 ++++ arch/xtensa/src/esp32s3/esp32s3_cpustart.c | 286 ++++++++++++++++++ arch/xtensa/src/esp32s3/esp32s3_freerun.c | 17 +- .../src/esp32s3/esp32s3_intercpu_interrupt.c | 127 ++++++++ arch/xtensa/src/esp32s3/esp32s3_irq.c | 215 ++++++++++++- arch/xtensa/src/esp32s3/esp32s3_lowputc.c | 6 +- arch/xtensa/src/esp32s3/esp32s3_lowputc.h | 25 +- .../src/esp32s3/esp32s3_oneshot_lowerhalf.c | 22 +- arch/xtensa/src/esp32s3/esp32s3_serial.c | 6 + arch/xtensa/src/esp32s3/esp32s3_smp.h | 71 +++++ .../src/esp32s3/esp32s3_tim_lowerhalf.c | 14 +- .../src/esp32s3/esp32s3_wdt_lowerhalf.c | 33 +- .../esp32s3-devkit/configs/smp/defconfig | 54 ++++ 16 files changed, 1032 insertions(+), 78 deletions(-) create mode 100644 arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_cpuindex.S create mode 100644 arch/xtensa/src/esp32s3/esp32s3_cpustart.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_smp.h create mode 100644 boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index 25de0f6d69..2854d8c48e 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -52,6 +52,10 @@ ifeq ($(CONFIG_SPINLOCK),y) CMN_CSRCS += xtensa_testset.c endif +ifeq ($(CONFIG_SMP),y) + CMN_CSRCS += xtensa_cpupause.c +endif + ifeq ($(CONFIG_STACK_COLORATION),y) CMN_CSRCS += xtensa_checkstack.c endif @@ -73,6 +77,11 @@ ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y) CHIP_CSRCS += esp32s3_idle.c endif +ifeq ($(CONFIG_SMP),y) +CHIP_ASRCS = esp32s3_cpuindex.S +CHIP_CSRCS += esp32s3_cpuidlestack.c esp32s3_cpustart.c esp32s3_intercpu_interrupt.c +endif + ifeq ($(CONFIG_SCHED_TICKLESS),y) CHIP_CSRCS += esp32s3_tickless.c else diff --git a/arch/xtensa/src/esp32s3/chip_macros.h b/arch/xtensa/src/esp32s3/chip_macros.h index c4e1d3f4eb..91f025329e 100644 --- a/arch/xtensa/src/esp32s3/chip_macros.h +++ b/arch/xtensa/src/esp32s3/chip_macros.h @@ -27,6 +27,12 @@ #include +#ifndef __ASSEMBLY__ +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +#include +#endif +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -41,6 +47,14 @@ * 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 ****************************************************************************/ @@ -48,22 +62,34 @@ #ifdef __ASSEMBLY__ /* Macro to get the current core ID. Only uses the reg given as an argument. - * Reading PRID on the ESP108 architecture gives us 0xcdcd on the PRO - * processor and 0xabab on the APP CPU. We distinguish between the two by - * simply checking bit 1: it's 1 on the APP and 0 on the PRO processor. + * Reading PRID on the ESP32 gives us 0xCDCD on the PRO processor (0) + * and 0xABAB on the APP CPU (1). We can distinguish between the two by + * checking bit 13: it's 1 on the APP and 0 on the PRO processor. */ - .macro getcoreid reg - rsr.prid \reg - bbci \reg, 1, 1f - movi \reg, 1 - j 2f -1: - movi \reg, 0 -2: + .macro getcoreid reg + rsr.prid \reg + extui \reg,\reg,13,1 .endm -#endif /* __ASSEMBLY */ +/**************************************************************************** + * 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 @@ -82,6 +108,11 @@ extern "C" * Public Functions Prototypes ****************************************************************************/ +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +uintptr_t xtensa_intstack_alloc(void); +uintptr_t xtensa_intstack_top(void); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c b/arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c new file mode 100644 index 0000000000..142b9d628c --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "xtensa.h" +#include "esp32s3_smp.h" + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Address of the CPU1 IDLE thread */ + +uint32_t g_cpu1_idlestack[CPU1_IDLETHREAD_STACKWORDS] + aligned_data(16) locate_data(".noinit"); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_idlestack + * + * Description: + * Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and + * setup up stack-related information in the IDLE task's TCB. This + * function is always called before up_cpu_start(). This function is + * only called for the CPU's initial IDLE task; up_create_task is used for + * all normal tasks, pthreads, and kernel threads for all CPUs. + * + * The initial IDLE task is a special case because the CPUs can be started + * in different wans in different environments: + * + * 1. The CPU may already have been started and waiting in a low power + * state for up_cpu_start(). In this case, the IDLE thread's stack + * has already been allocated and is already in use. Here + * up_cpu_idlestack() only has to provide information about the + * already allocated stack. + * + * 2. The CPU may be disabled but started when up_cpu_start() is called. + * In this case, a new stack will need to be created for the IDLE + * thread and this function is then equivalent to: + * + * return up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL); + * + * The following TCB fields must be initialized by this function: + * + * - adj_stack_size: Stack size after adjustment for hardware, processor, + * etc. This value is retained only for debug purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - stack_base_ptr: Adjusted stack base pointer after the TLS Data and + * Arguments has been removed from the stack allocation. + * + * Input Parameters: + * - cpu: CPU index that indicates which CPU the IDLE task is + * being created for. + * - tcb: The TCB of new CPU IDLE task + * - stack_size: The requested stack size for the IDLE task. At least + * this much must be allocated. This should be + * CONFIG_IDLETHREAD_STACKSIZE. + * + ****************************************************************************/ + +int up_cpu_idlestack(int cpu, struct tcb_s *tcb, size_t stack_size) +{ + /* XTENSA uses a push-down stack: the stack grows toward lower* addresses + * in memory. The stack pointer register points to the lowest, valid + * working address (the "top" of the stack). Items on the stack are + * referenced as positive word offsets from sp. + */ + + /* Save information about pre-allocated IDLE thread stack */ + + tcb->stack_alloc_ptr = g_cpu1_idlestack; + tcb->adj_stack_size = CPU1_IDLETHREAD_STACKSIZE; + tcb->stack_base_ptr = tcb->stack_alloc_ptr; + + return OK; +} + +#endif /* CONFIG_SMP */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_cpuindex.S b/arch/xtensa/src/esp32s3/esp32s3_cpuindex.S new file mode 100644 index 0000000000..d35b547274 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_cpuindex.S @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_cpuindex.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + + .file "esp32s3_cpuindex.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip_macros.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_index + * + * Description: + * Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + * If TLS is enabled, then the RTOS can get this information from the TLS + * info structure. Otherwise, the MCU-specific logic must provide some + * mechanism to provide the CPU index. + * + * Input Parameters: + * None + * + * Returned Value: + * An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + ****************************************************************************/ + + .text + .align 4 + .global up_cpu_index + .type up_cpu_index, @function + +up_cpu_index: + ENTRY(16) + getcoreid a2 + RET(16) + + .size up_cpu_index, . - up_cpu_index diff --git a/arch/xtensa/src/esp32s3/esp32s3_cpustart.c b/arch/xtensa/src/esp32s3/esp32s3_cpustart.c new file mode 100644 index 0000000000..9e0e057993 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_cpustart.c @@ -0,0 +1,286 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_cpustart.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "xtensa.h" +#include "esp32s3_irq.h" +#include "esp32s3_region.h" +#include "esp32s3_smp.h" +#include "hardware/esp32s3_rtccntl.h" +#include "hardware/esp32s3_system.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static volatile bool g_appcpu_started; +static volatile spinlock_t g_appcpu_interlock; + +/**************************************************************************** + * ROM function prototypes + ****************************************************************************/ + +extern void ets_set_appcpu_boot_addr(uint32_t start); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_attach_fromcpu0_interrupt + ****************************************************************************/ + +static inline void xtensa_attach_fromcpu0_interrupt(void) +{ + int cpuint; + + /* Connect all CPU peripheral source to allocated CPU interrupt */ + + cpuint = esp32s3_setup_irq(1, ESP32S3_PERIPH_INT_FROM_CPU0, 1, + ESP32S3_CPUINT_LEVEL); + DEBUGASSERT(cpuint >= 0); + + /* Attach the inter-CPU interrupt. */ + + irq_attach(ESP32S3_IRQ_INT_FROM_CPU0, (xcpt_t)esp32s3_fromcpu0_interrupt, + NULL); + + /* Enable the inter 0 CPU interrupts. */ + + up_enable_irq(ESP32S3_IRQ_INT_FROM_CPU0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_appcpu_start + * + * Description: + * This is the entry point used for the APP CPU when it's started via + * up_cpu_start(). The actual start-up logic is in ROM and we boot up + * in C code. + * + * Input Parameters: + * None + * + * Returned Value: + * None, does not return + * + ****************************************************************************/ + +void xtensa_appcpu_start(void) +{ + struct tcb_s *tcb = this_task(); + register uint32_t sp; + +#ifdef CONFIG_STACK_COLORATION + { + register uint32_t *ptr; + register int i; + + /* If stack debug is enabled, then fill the stack with a recognizable + * value that we can use later to test for high water marks. + */ + + for (i = 0, ptr = (uint32_t *)tcb->stack_alloc_ptr; + i < tcb->adj_stack_size; + i += sizeof(uint32_t)) + { + *ptr++ = STACK_COLOR; + } + } +#endif + + /* Move to the stack assigned to us by up_smp_start immediately. Although + * we were give a stack pointer at start-up, we don't know where that stack + * pointer is positioned respect to our memory map. The only safe option + * is to switch to a well-known IDLE thread stack. + */ + + sp = (uint32_t)tcb->stack_base_ptr + tcb->adj_stack_size; + __asm__ __volatile__("mov sp, %0\n" : : "r"(sp)); + + sinfo("CPU%d Started\n", up_cpu_index()); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that this CPU has started */ + + sched_note_cpu_started(tcb); +#endif + + /* Release the spinlock to signal to the PRO CPU that the APP CPU has + * started. + */ + + g_appcpu_started = true; + spin_unlock(&g_appcpu_interlock); + + /* Reset scheduler parameters */ + + nxsched_resume_scheduler(tcb); + + /* Move CPU0 exception vectors to IRAM */ + + __asm__ __volatile__ ("wsr %0, vecbase\n"::"r" (&_init_start)); + + /* Make page 0 access raise an exception */ + + esp32s3_region_protection(); + + /* Initialize CPU interrupts */ + + esp32s3_cpuint_initialize(); + + /* Attach and enable the inter-CPU interrupt */ + + xtensa_attach_fromcpu0_interrupt(); + + /* Enable the software interrupt */ + + up_enable_irq(XTENSA_IRQ_SWINT); + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + /* And Enable interrupts */ + + up_irq_enable(); +#endif + + /* Then switch contexts. This instantiates the exception context of the + * tcb at the head of the assigned task list. In this case, this should + * be the CPUs NULL task. + */ + + xtensa_context_restore(tcb->xcp.regs); +} + +/**************************************************************************** + * Name: up_cpu_start + * + * Description: + * In an SMP configuration, only one CPU is initially active (CPU 0). + * System initialization occurs on that single thread. At the completion of + * the initialization of the OS, just before beginning normal multitasking, + * the additional CPUs would be started by calling this function. + * + * Each CPU is provided the entry point to its IDLE task when started. A + * TCB for each CPU's IDLE task has been initialized and placed in the + * CPU's g_assignedtasks[cpu] list. No stack has been allocated or + * initialized. + * + * The OS initialization logic calls this function repeatedly until each + * CPU has been started, 1 through (CONFIG_SMP_NCPUS-1). + * + * Input Parameters: + * cpu - The index of the CPU being started. This will be a numeric + * value in the range of one to (CONFIG_SMP_NCPUS-1). + * (CPU 0 is already active) + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_cpu_start(int cpu) +{ + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); + + if (!g_appcpu_started) + { + uint32_t regval; + + /* Start CPU1 */ + + sinfo("Starting CPU%d\n", cpu); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the start event */ + + sched_note_cpu_start(this_task(), cpu); +#endif + + /* This spinlock will be used as a handshake between the two CPUs. + * It's first initialized to its locked state, later the PRO CPU will + * try to lock it but spins until the APP CPU starts and unlocks it. + */ + + spin_initialize(&g_appcpu_interlock, SP_LOCKED); + + /* Unstall the APP CPU */ + + regval = getreg32(RTC_CNTL_RTC_SW_CPU_STALL_REG); + regval &= ~RTC_CNTL_SW_STALL_APPCPU_C1_M; + putreg32(regval, RTC_CNTL_RTC_SW_CPU_STALL_REG); + + regval = getreg32(RTC_CNTL_RTC_OPTIONS0_REG); + regval &= ~RTC_CNTL_SW_STALL_APPCPU_C0_M; + putreg32(regval, RTC_CNTL_RTC_OPTIONS0_REG); + + /* Enable clock gating for the APP CPU */ + + regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG); + regval |= SYSTEM_CONTROL_CORE_1_CLKGATE_EN; + putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG); + + regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG); + regval &= ~SYSTEM_CONTROL_CORE_1_RUNSTALL; + putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG); + + /* Reset the APP CPU */ + + regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG); + regval |= SYSTEM_CONTROL_CORE_1_RESETING; + putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG); + + regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG); + regval &= ~SYSTEM_CONTROL_CORE_1_RESETING; + putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG); + + /* Set the CPU1 start address */ + + ets_set_appcpu_boot_addr((uint32_t)xtensa_appcpu_start); + + /* And wait until the APP CPU starts and releases the spinlock. */ + + spin_lock(&g_appcpu_interlock); + DEBUGASSERT(g_appcpu_started); + } + + return OK; +} + diff --git a/arch/xtensa/src/esp32s3/esp32s3_freerun.c b/arch/xtensa/src/esp32s3/esp32s3_freerun.c index 73d6776a78..0c554fbdeb 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_freerun.c +++ b/arch/xtensa/src/esp32s3/esp32s3_freerun.c @@ -34,9 +34,10 @@ #include #include +#include -#include "esp32s3_freerun.h" #include "esp32s3_clockconfig.h" +#include "esp32s3_freerun.h" #include "esp32s3_gpio.h" #ifdef CONFIG_ESP32S3_FREERUN @@ -59,6 +60,12 @@ #define TIMER_WIDTH 54 /* ESP32-S3 timer has 54-bit counter */ +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static spinlock_t g_lock; /* Device specific lock */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -209,9 +216,9 @@ int esp32s3_freerun_initialize(struct esp32s3_freerun_s *freerun, int chan, /* Register the handler */ { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&g_lock); ret = ESP32S3_TIM_SETISR(freerun->tch, freerun_handler, freerun); - leave_critical_section(flags); + spin_unlock_irqrestore(&g_lock, flags); } if (ret == OK) @@ -266,7 +273,7 @@ int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun, /* Temporarily disable the overflow counter. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&g_lock); overflow = freerun->overflow; ESP32S3_TIM_GETCTR(freerun->tch, &counter); @@ -293,7 +300,7 @@ int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun, freerun->overflow = overflow; } - leave_critical_section(flags); + spin_unlock_irqrestore(&g_lock, flags); tmrinfo("counter=%" PRIu64 " (%" PRIu64 ") overflow=%" PRIu32 ", pending=%i\n", diff --git a/arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c b/arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c new file mode 100644 index 0000000000..2ee7601f60 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c @@ -0,0 +1,127 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "xtensa.h" +#include "hardware/esp32s3_system.h" + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_fromcpu_interrupt + * + * Description: + * Common logic called to handle the from CPU0/1 interrupts. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32s3_fromcpu_interrupt(int fromcpu) +{ + uintptr_t regaddr; + + DEBUGASSERT((unsigned)fromcpu < CONFIG_SMP_NCPUS); + DEBUGASSERT(fromcpu != up_cpu_index()); + + /* Clear the interrupt from the other CPU */ + + regaddr = (fromcpu == 0) ? SYSTEM_CPU_INTR_FROM_CPU_0_REG : + SYSTEM_CPU_INTR_FROM_CPU_1_REG; + putreg32(0, regaddr); + + /* Call pause handler */ + + xtensa_pause_handler(); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_fromcpu[0,1]_interrupt + * + * Description: + * Called to handle the from CPU0/1 interrupts. + * + ****************************************************************************/ + +int IRAM_ATTR esp32s3_fromcpu0_interrupt(int irq, void *context, void *arg) +{ + return esp32s3_fromcpu_interrupt(0); +} + +int IRAM_ATTR esp32s3_fromcpu1_interrupt(int irq, void *context, void *arg) +{ + return esp32s3_fromcpu_interrupt(1); +} + +/**************************************************************************** + * Name: xtensa_intercpu_interrupt + * + * Description: + * Called to trigger a CPU interrupt + * + ****************************************************************************/ + +int IRAM_ATTR xtensa_intercpu_interrupt(int tocpu, int intcode) +{ + int fromcpu; + + DEBUGASSERT((unsigned)tocpu < CONFIG_SMP_NCPUS && + (unsigned)intcode <= UINT8_MAX); + + fromcpu = up_cpu_index(); + DEBUGASSERT(fromcpu != tocpu); + + /* Generate an Inter-Processor Interrupt */ + + if (fromcpu == 0) + { + putreg32(SYSTEM_CPU_INTR_FROM_CPU_0, SYSTEM_CPU_INTR_FROM_CPU_0_REG); + } + else + { + putreg32(SYSTEM_CPU_INTR_FROM_CPU_1, SYSTEM_CPU_INTR_FROM_CPU_1_REG); + } + + return OK; +} + +#endif /* CONFIG_SMP */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_irq.c b/arch/xtensa/src/esp32s3/esp32s3_irq.c index 7b45bf771c..5e98d4b63e 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_irq.c +++ b/arch/xtensa/src/esp32s3/esp32s3_irq.c @@ -38,16 +38,27 @@ #include "xtensa.h" +#include "esp32s3_irq.h" +#ifdef CONFIG_SMP +#include "esp32s3_smp.h" +#endif +#include "hardware/esp32s3_interrupt_core0.h" +#ifdef CONFIG_SMP +#include "hardware/esp32s3_interrupt_core1.h" +#endif #include "hardware/esp32s3_soc.h" #include "hardware/esp32s3_system.h" -#include "hardware/esp32s3_interrupt_core0.h" - -#include "esp32s3_irq.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 + /* IRQ to CPU and CPU interrupts mapping: * * Encoding: CIIIIIII @@ -77,6 +88,9 @@ /* Mapping Peripheral IDs to map register addresses. */ #define CORE0_MAP_REGADDR(n) (DR_REG_INTERRUPT_CORE0_BASE + ((n) << 2)) +#ifdef CONFIG_SMP +# define CORE1_MAP_REGADDR(n) (DR_REG_INTERRUPT_CORE1_BASE + ((n) << 2)) +#endif /* CPU interrupts can be detached from any peripheral source by setting the * map register to an internal CPU interrupt (6, 7, 11, 15, 16, or 29). @@ -100,7 +114,29 @@ * CURRENT_REGS for portability. */ -volatile uint32_t *g_current_regs[1]; +/* For the case of architectures with multiple CPUs, then there must be one + * such value for each processor that can receive an interrupt. + */ + +volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS]; + +#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 Data @@ -109,6 +145,9 @@ volatile uint32_t *g_current_regs[1]; /* Maps a CPU interrupt to the IRQ of the attached peripheral interrupt */ static uint8_t g_cpu0_intmap[ESP32S3_NCPUINTS]; +#ifdef CONFIG_SMP +static uint8_t g_cpu1_intmap[ESP32S3_NCPUINTS]; +#endif static volatile uint8_t g_irqmap[NR_IRQS]; @@ -116,13 +155,16 @@ static volatile uint8_t g_irqmap[NR_IRQS]; * content. */ -static uint32_t g_intenable[1]; +static uint32_t g_intenable[CONFIG_SMP_NCPUS]; /* Bitsets for free, unallocated CPU interrupts available to peripheral * devices. */ static uint32_t g_cpu0_freeints = ESP32S3_CPUINT_PERIPHSET; +#ifdef CONFIG_SMP +static uint32_t g_cpu1_freeints = ESP32S3_CPUINT_PERIPHSET; +#endif /* Bitsets for each interrupt priority 1-5 */ @@ -139,6 +181,32 @@ static const uint32_t g_priority[5] = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: xtensa_attach_fromcpu1_interrupt + ****************************************************************************/ + +#ifdef CONFIG_SMP +static inline void xtensa_attach_fromcpu1_interrupt(void) +{ + int cpuint; + + /* Connect all CPU peripheral source to allocated CPU interrupt */ + + cpuint = esp32s3_setup_irq(0, ESP32S3_PERIPH_INT_FROM_CPU1, 1, + ESP32S3_CPUINT_LEVEL); + DEBUGASSERT(cpuint >= 0); + + /* Attach the inter-CPU interrupt. */ + + irq_attach(ESP32S3_IRQ_INT_FROM_CPU1, (xcpt_t)esp32s3_fromcpu1_interrupt, + NULL); + + /* Enable the inter-CPU interrupt. */ + + up_enable_irq(ESP32S3_IRQ_INT_FROM_CPU1); +} +#endif + /**************************************************************************** * Name: esp32s3_intinfo * @@ -151,8 +219,20 @@ static const uint32_t g_priority[5] = static void esp32s3_intinfo(int cpu, int periphid, uintptr_t *regaddr, uint8_t **intmap) { - *regaddr = CORE0_MAP_REGADDR(periphid); - *intmap = g_cpu0_intmap; +#ifdef CONFIG_SMP + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS); + + if (cpu != 0) + { + *regaddr = CORE1_MAP_REGADDR(periphid); + *intmap = g_cpu1_intmap; + } + else +#endif + { + *regaddr = CORE0_MAP_REGADDR(periphid); + *intmap = g_cpu0_intmap; + } } /**************************************************************************** @@ -187,7 +267,16 @@ static int esp32s3_getcpuint(uint32_t intmask) */ cpu = up_cpu_index(); - freeints = &g_cpu0_freeints; +#ifdef CONFIG_SMP + if (cpu != 0) + { + freeints = &g_cpu1_freeints; + } + else +#endif + { + freeints = &g_cpu0_freeints; + } intset = *freeints & intmask; if (intset != 0) @@ -308,7 +397,16 @@ static void esp32s3_free_cpuint(int cpuint) bitmask = 1ul << cpuint; - freeints = &g_cpu0_freeints; +#ifdef CONFIG_SMP + if (up_cpu_index() != 0) + { + freeints = &g_cpu1_freeints; + } + else +#endif + { + freeints = &g_cpu0_freeints; + } DEBUGASSERT((*freeints & bitmask) == 0); *freeints |= bitmask; @@ -342,6 +440,12 @@ void up_irqinitialize(void) esp32s3_cpuint_initialize(); +#ifdef CONFIG_SMP + /* Attach and enable the inter-CPU interrupt */ + + xtensa_attach_fromcpu1_interrupt(); +#endif + #ifndef CONFIG_SUPPRESS_INTERRUPTS /* And finally, enable interrupts. Also clears PS.EXCM */ @@ -378,7 +482,7 @@ void up_disable_irq(int irq) } DEBUGASSERT(cpuint >= 0 && cpuint <= ESP32S3_CPUINT_MAX); - DEBUGASSERT(cpu == 0); + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS); if (irq < XTENSA_NIRQ_INTERNAL) { @@ -386,6 +490,16 @@ void up_disable_irq(int irq) * the Interrupt Matrix. */ +#ifdef CONFIG_SMP + int me = up_cpu_index(); + if (me != cpu) + { + /* It was the other CPU that enabled this interrupt. */ + + return; + } +#endif + xtensa_disable_cpuint(&g_intenable[cpu], 1ul << cpuint); } else @@ -444,7 +558,7 @@ void up_enable_irq(int irq) int cpu = IRQ_GETCPU(g_irqmap[irq]); - DEBUGASSERT(cpu == 0); + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS); /* For peripheral interrupts, attach the interrupt to the peripheral; * the CPU interrupt was already enabled when allocated. @@ -463,6 +577,36 @@ void up_enable_irq(int irq) } } +/**************************************************************************** + * Name: xtensa_intstack_top + * + * Description: + * Return a pointer to the top of the correct interrupt stack for the + * given CPU. + * + ****************************************************************************/ + +#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +uintptr_t xtensa_intstack_top(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 + /**************************************************************************** * Name: esp32s3_cpuint_initialize * @@ -482,8 +626,18 @@ int esp32s3_cpuint_initialize(void) { uintptr_t regaddr; uint8_t *intmap; +#ifdef CONFIG_SMP + int cpu; +#endif int i; +#ifdef CONFIG_SMP + /* Which CPU are we initializing */ + + cpu = up_cpu_index(); + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS); +#endif + /* Disable all CPU interrupts on this CPU */ xtensa_disable_all(); @@ -492,14 +646,32 @@ int esp32s3_cpuint_initialize(void) for (i = 0; i < ESP32S3_NPERIPHERALS; i++) { - regaddr = CORE0_MAP_REGADDR(i); +#ifdef CONFIG_SMP + if (cpu != 0) + { + regaddr = CORE1_MAP_REGADDR(i); + } + else +#endif + { + regaddr = CORE0_MAP_REGADDR(i); + } putreg32(NO_CPUINT, regaddr); } /* Initialize CPU interrupt-to-IRQ mapping table */ - intmap = g_cpu0_intmap; +#ifdef CONFIG_SMP + if (cpu != 0) + { + intmap = g_cpu1_intmap; + } + else +#endif + { + intmap = g_cpu0_intmap; + } /* Indicate that no peripheral interrupts are assigned to CPU interrupts */ @@ -665,12 +837,27 @@ uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs) uint8_t *intmap; uint32_t mask; int bit; +#ifdef CONFIG_SMP + int cpu; +#endif #ifdef CONFIG_ARCH_LEDS_CPU_ACTIVITY board_autoled_on(LED_CPU); #endif - intmap = g_cpu0_intmap; +#ifdef CONFIG_SMP + /* Select PRO or APP CPU interrupt mapping table */ + + cpu = up_cpu_index(); + if (cpu != 0) + { + intmap = g_cpu1_intmap; + } + else +#endif + { + intmap = g_cpu0_intmap; + } /* Skip over zero bits, eight at a time */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_lowputc.c b/arch/xtensa/src/esp32s3/esp32s3_lowputc.c index a1a8650433..c0c1b48fbe 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_lowputc.c +++ b/arch/xtensa/src/esp32s3/esp32s3_lowputc.c @@ -676,12 +676,12 @@ void esp32s3_lowputc_rst_rxfifo(const struct esp32s3_uart_s *priv) * ****************************************************************************/ -void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv, +void esp32s3_lowputc_disable_all_uart_int(struct esp32s3_uart_s *priv, uint32_t *current_status) { irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); if (current_status != NULL) { @@ -698,7 +698,7 @@ void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv, putreg32(0xffffffff, UART_INT_CLR_REG(priv->id)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** diff --git a/arch/xtensa/src/esp32s3/esp32s3_lowputc.h b/arch/xtensa/src/esp32s3/esp32s3_lowputc.h index 226fa7b994..12ff2b5ec9 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_lowputc.h +++ b/arch/xtensa/src/esp32s3/esp32s3_lowputc.h @@ -26,24 +26,24 @@ ****************************************************************************/ #include + +#include +#include +#include +#include +#include +#include +#include + #include #include - -#include -#include -#include -#include -#include -#include -#include +#include #include "chip.h" - +#include "esp32s3_irq.h" #include "hardware/esp32s3_uart.h" #include "hardware/esp32s3_gpio_sigmap.h" -#include "esp32s3_irq.h" - /**************************************************************************** * Public Types ****************************************************************************/ @@ -116,6 +116,7 @@ struct esp32s3_uart_s uint8_t ctssig; /* CTS signal */ bool oflow; /* Output flow control (CTS) enabled */ #endif + spinlock_t lock; /* Device-specific lock */ }; extern struct esp32s3_uart_s g_uart0_config; @@ -424,7 +425,7 @@ void esp32s3_lowputc_rst_rxfifo(const struct esp32s3_uart_s *priv); * ****************************************************************************/ -void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv, +void esp32s3_lowputc_disable_all_uart_int(struct esp32s3_uart_s *priv, uint32_t *current_status); /**************************************************************************** diff --git a/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c b/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c index 215fe9ca1a..bf5fa2414e 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c +++ b/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c @@ -24,17 +24,18 @@ #include -#include -#include -#include #include -#include #include +#include +#include #include +#include +#include #include -#include #include +#include +#include #include "esp32s3_oneshot.h" @@ -58,7 +59,8 @@ struct esp32s3_oneshot_lowerhalf_s struct esp32s3_oneshot_s oneshot; /* ESP32-S3-specific oneshot state */ oneshot_callback_t callback; /* Upper-half Interrupt callback */ void *arg; /* Argument passed to handler */ - uint16_t resolution; + uint16_t resolution; /* Timer's resolution in microseconds */ + spinlock_t lock; /* Device-specific lock */ }; /**************************************************************************** @@ -210,12 +212,12 @@ static int oneshot_lh_start(struct oneshot_lowerhalf_s *lower, /* Save the callback information and start the timer */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->callback = callback; priv->arg = arg; ret = esp32s3_oneshot_start(&priv->oneshot, oneshot_lh_handler, priv, ts); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); if (ret < 0) { @@ -261,11 +263,11 @@ static int oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower, /* Cancel the timer */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); ret = esp32s3_oneshot_cancel(&priv->oneshot, ts); priv->callback = NULL; priv->arg = NULL; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); if (ret < 0) { diff --git a/arch/xtensa/src/esp32s3/esp32s3_serial.c b/arch/xtensa/src/esp32s3/esp32s3_serial.c index d281de87aa..3b1896590d 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_serial.c +++ b/arch/xtensa/src/esp32s3/esp32s3_serial.c @@ -533,6 +533,7 @@ static void esp32s3_txint(struct uart_dev_s *dev, bool enable) { struct esp32s3_uart_s *priv = dev->priv; uint32_t ints_mask = UART_TXFIFO_EMPTY_INT_ENA_M | UART_TX_DONE_INT_ENA_M; + irqstate_t flags = spin_lock_irqsave(&priv->lock); if (enable) { @@ -550,6 +551,8 @@ static void esp32s3_txint(struct uart_dev_s *dev, bool enable) modifyreg32(UART_INT_ENA_REG(priv->id), ints_mask, 0); } + + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -569,6 +572,7 @@ static void esp32s3_rxint(struct uart_dev_s *dev, bool enable) struct esp32s3_uart_s *priv = dev->priv; uint32_t ints_mask = UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M; + irqstate_t flags = spin_lock_irqsave(&priv->lock); if (enable) { @@ -590,6 +594,8 @@ static void esp32s3_rxint(struct uart_dev_s *dev, bool enable) modifyreg32(UART_INT_ENA_REG(priv->id), ints_mask, 0); } + + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** diff --git a/arch/xtensa/src/esp32s3/esp32s3_smp.h b/arch/xtensa/src/esp32s3/esp32s3_smp.h new file mode 100644 index 0000000000..80a1cef55b --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_smp.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_smp.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H +#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Pre-procesor Definitions + ****************************************************************************/ + +/* An IDLE thread stack size for CPU0 must be defined */ + +#if !defined(CONFIG_IDLETHREAD_STACKSIZE) +# error CONFIG_IDLETHREAD_STACKSIZE is not defined +#elif CONFIG_IDLETHREAD_STACKSIZE < 16 +# error CONFIG_IDLETHREAD_STACKSIZE is to small +#endif + +#define CPU1_IDLETHREAD_STACKSIZE ((CONFIG_IDLETHREAD_STACKSIZE + 15) & ~15) +#define CPU1_IDLETHREAD_STACKWORDS (CPU1_IDLETHREAD_STACKSIZE >> 2) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* This is the CPU1 IDLE stack */ + +extern uint32_t g_cpu1_idlestack[CPU1_IDLETHREAD_STACKWORDS]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_fromcpu[0,1]_interrupt + * + * Description: + * Called to handle the from CPU0/1 interrupts. + * + ****************************************************************************/ + +int esp32s3_fromcpu0_interrupt(int irq, void *context, void *arg); +int esp32s3_fromcpu1_interrupt(int irq, void *context, void *arg); + +#endif /* CONFIG_SMP */ +#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_tim_lowerhalf.c b/arch/xtensa/src/esp32s3/esp32s3_tim_lowerhalf.c index fbaf40d95b..1c2e6521cb 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_tim_lowerhalf.c +++ b/arch/xtensa/src/esp32s3/esp32s3_tim_lowerhalf.c @@ -34,6 +34,7 @@ #include #include +#include #include #include "hardware/esp32s3_soc.h" @@ -62,6 +63,7 @@ struct esp32s3_timer_lowerhalf_s void *arg; /* Argument passed to upper half callback */ bool started; /* True: Timer has been started */ void *upper; /* Pointer to watchdog_upperhalf_s */ + spinlock_t lock; /* Device-specific lock */ }; /**************************************************************************** @@ -250,9 +252,9 @@ static int timer_lh_start(struct timer_lowerhalf_s *lower) if (priv->callback != NULL) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); ret = ESP32S3_TIM_SETISR(priv->tim, timer_lh_handler, priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); if (ret != OK) { @@ -305,9 +307,9 @@ static int timer_lh_stop(struct timer_lowerhalf_s *lower) ESP32S3_TIM_DISABLEINT(priv->tim); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); ret = ESP32S3_TIM_SETISR(priv->tim, NULL, NULL); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); ESP32S3_TIM_STOP(priv->tim); @@ -473,7 +475,7 @@ static void timer_lh_setcallback(struct timer_lowerhalf_s *lower, priv->callback = callback; priv->arg = arg; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); /* There is a user callback and the timer has already been started */ @@ -488,7 +490,7 @@ static void timer_lh_setcallback(struct timer_lowerhalf_s *lower, ret = ESP32S3_TIM_SETISR(priv->tim, NULL, NULL); } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); if (ret != OK) { diff --git a/arch/xtensa/src/esp32s3/esp32s3_wdt_lowerhalf.c b/arch/xtensa/src/esp32s3/esp32s3_wdt_lowerhalf.c index 259a04820e..89d04bd54e 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wdt_lowerhalf.c +++ b/arch/xtensa/src/esp32s3/esp32s3_wdt_lowerhalf.c @@ -24,22 +24,22 @@ #include -#include +#include +#include +#include #include #include -#include -#include -#include +#include #include #include +#include #include #include "xtensa.h" -#include "hardware/esp32s3_soc.h" - #include "esp32s3_wdt.h" #include "esp32s3_wdt_lowerhalf.h" +#include "hardware/esp32s3_soc.h" /**************************************************************************** * Pre-processor Definitions @@ -94,6 +94,7 @@ struct esp32s3_wdt_lowerhalf_s bool started; /* True: Timer has been started */ xcpt_t handler; /* User Handler */ void *upper; /* Pointer to watchdog_upperhalf_s */ + spinlock_t lock; /* Device-specific lock */ }; /**************************************************************************** @@ -236,16 +237,16 @@ static int wdt_lh_start(struct watchdog_lowerhalf_s *lower) /* Set the lower-half handler and enable interrupt */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); ESP32S3_WDT_SETISR(priv->wdt, wdt_handler, priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); ESP32S3_WDT_ENABLEINT(priv->wdt); } - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->lastreset = clock_systime_ticks(); ESP32S3_WDT_START(priv->wdt); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* Lock it again */ @@ -290,9 +291,9 @@ static int wdt_lh_stop(struct watchdog_lowerhalf_s *lower) ESP32S3_WDT_DISABLEINT(priv->wdt); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); ESP32S3_WDT_SETISR(priv->wdt, NULL, NULL); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /* Lock it again */ @@ -333,10 +334,10 @@ static int wdt_lh_keepalive(struct watchdog_lowerhalf_s *lower) /* Feed the dog and updates the lastreset variable */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->lastreset = clock_systime_ticks(); ESP32S3_WDT_FEED(priv->wdt); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* Lock */ @@ -540,7 +541,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower, ESP32S3_WDT_UNLOCK(priv->wdt); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); /* Save the new user handler */ @@ -598,7 +599,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); ESP32S3_WDT_LOCK(priv->wdt); return oldhandler; } diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig b/boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig new file mode 100644 index 0000000000..e2c9d543ca --- /dev/null +++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig @@ -0,0 +1,54 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32s3-devkit" +CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y +CONFIG_ARCH_CHIP="esp32s3" +CONFIG_ARCH_CHIP_ESP32S3=y +CONFIG_ARCH_CHIP_ESP32S3WROOM1=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_ESP32S3_UART0=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SMP=y +CONFIG_SMP_NCPUS=2 +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=8 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2022 +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_TESTING_SMP=y +CONFIG_UART0_SERIAL_CONSOLE=y