diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index aa49e001592..ba7da8055af 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -108,8 +108,8 @@ * only a referenced is passed to get the state from the TCB. */ -#define xtensa_savestate(regs) xtensa_copystate(regs, (uint32_t*)g_current_regs) -#define xtensa_restorestate(regs) do { g_current_regs = regs; } while (0) +#define xtensa_savestate(regs) xtensa_copystate(regs, (uint32_t*)CURRENT_REGS) +#define xtensa_restorestate(regs) do { CURRENT_REGS = regs; } while (0) /* Register access macros */ @@ -133,11 +133,27 @@ typedef void (*xtensa_vector_t)(void); ****************************************************************************/ #ifndef __ASSEMBLY__ -/* This holds a references to the current interrupt level register storage - * structure. If is non-NULL only during interrupt processing. +/* g_current_regs[] holds a references to the current interrupt level + * register storage structure. If is non-NULL only during interrupt + * processing. Access to g_current_regs[] must be through the macro + * CURRENT_REGS for portability. */ -extern volatile uint32_t *g_current_regs; +#ifdef CONFIG_SMP +/* For the case of architectures with multiple CPUs, then there must be one + * such value for each processor that can receive an interrupt. + */ + +int up_cpu_index(void); /* See include/nuttx/arch.h */ +extern volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS]; +# define CURRENT_REGS (g_current_regs[up_cpu_index()]) + +#else + +extern volatile uint32_t *g_current_regs[1]; +# define CURRENT_REGS (g_current_regs[0]) + +#endif /* This is the beginning of heap as provided from *_head.S. This is the * first address in DRAM after the loaded program+bss+idle stack. The end @@ -229,7 +245,8 @@ void xtensa_dumpstate(void); /* Common XTENSA functions */ /* IRQs */ -uint32_t *xtensa_doirq(int irq, uint32_t *regs); +uint32_t *xtensa_int_decode(uint32_t *regs); +uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs); /* Software interrupt handler */ diff --git a/arch/xtensa/src/common/xtensa_assert.c b/arch/xtensa/src/common/xtensa_assert.c index 4e7577fb76b..98c5562d924 100644 --- a/arch/xtensa/src/common/xtensa_assert.c +++ b/arch/xtensa/src/common/xtensa_assert.c @@ -76,7 +76,7 @@ static void xtensa_assert(int errorcode) { /* Are we in an interrupt handler or the idle task? */ - if (g_current_regs || this_task()->pid == 0) + if (CURRENT_REGS || this_task()->pid == 0) { (void)up_irq_save(); for (; ; ) diff --git a/arch/xtensa/src/common/xtensa_dumpstate.c b/arch/xtensa/src/common/xtensa_dumpstate.c index ae260f0e6dc..14217d0117b 100644 --- a/arch/xtensa/src/common/xtensa_dumpstate.c +++ b/arch/xtensa/src/common/xtensa_dumpstate.c @@ -95,52 +95,41 @@ static void xtensa_stackdump(uint32_t sp, uint32_t stack_base) static inline void xtensa_registerdump(void) { + uint32_ *regs = CURRENT_REGS; /* Are user registers available from interrupt processing? */ - if (g_current_regs != NULL) + if (regs != NULL) { _alert(" PC: %08lx PS: %08lx\n", - (unsigned long)g_current_regs[REG_PC], - (unsigned long)g_current_regs[REG_PS]); + (unsigned long)regs[REG_PC], (unsigned long)regs[REG_PS]); _alert(" A0: %08lx A1: %08lx A2: %08lx A3: %08lx\n", - (unsigned long)g_current_regs[REG_A0], - (unsigned long)g_current_regs[REG_A1], - (unsigned long)g_current_regs[REG_A2], - (unsigned long)g_current_regs[REG_A3]); + (unsigned long)regs[REG_A0], (unsigned long)regs[REG_A1], + (unsigned long)regs[REG_A2], (unsigned long)regs[REG_A3]); _alert(" A4: %08lx A5: %08lx A6: %08lx A7: %08lx\n", - (unsigned long)g_current_regs[REG_A4], - (unsigned long)g_current_regs[REG_A5], - (unsigned long)g_current_regs[REG_A6], - (unsigned long)g_current_regs[REG_A7]); + (unsigned long)regs[REG_A4], (unsigned long)regs[REG_A5], + (unsigned long)regs[REG_A6], (unsigned long)regs[REG_A7]); _alert(" A8: %08lx A9: %08lx A10: %08lx A11: %08lx\n", - (unsigned long)g_current_regs[REG_A8], - (unsigned long)g_current_regs[REG_A9], - (unsigned long)g_current_regs[REG_A10], - (unsigned long)g_current_regs[REG_A11]); + (unsigned long)regs[REG_A8], (unsigned long)regs[REG_A9], + (unsigned long)regs[REG_A10], (unsigned long)regs[REG_A11]); _alert(" A12: %08lx A13: %08lx A14: %08lx A15: %08lx\n", - (unsigned long)g_current_regs[REG_A12], - (unsigned long)g_current_regs[REG_A13], - (unsigned long)g_current_regs[REG_A14], - (unsigned long)g_current_regs[REG_A15]); + (unsigned long)regs[REG_A12], (unsigned long)regs[REG_A13], + (unsigned long)regs[REG_A14], (unsigned long)regs[REG_A15]); _alert(" SAR: %08lx CAUSE: %08lx VADDR: %08lx\n", - (unsigned long)g_current_regs[REG_SAR], - (unsigned long)g_current_regs[REG_EXCCAUSE], - (unsigned long)g_current_regs[REG_EXCVADDR]); + (unsigned long)regs[REG_SAR], (unsigned long)regs[REG_EXCCAUSE], + (unsigned long)regs[REG_EXCVADDR]); #ifdef XTENSA_HAVE_LOOPS _alert(" LBEG: %08lx LEND: %08lx LCNT: %08lx\n", - (unsigned long)g_current_regs[REG_LBEG], - (unsigned long)g_current_regs[REG_LEND], - (unsigned long)g_current_regs[REG_LCOUNT]); + (unsigned long)regs[REG_LBEG], (unsigned long)regs[REG_LEND], + (unsigned long)regs[REG_LCOUNT]); #endif #ifndef CONFIG_XTENSA_CALL0_ABI _alert(" TMP0: %08lx TMP1: %08lx TMP2: %08lx\n", - (unsigned long)g_current_regs[REG_TMP0], - (unsigned long)g_current_regs[REG_TMP1], - (unsigned long)g_current_regs[REG_TMP2]); + (unsigned long)regs[REG_TMP0], (unsigned long)regs[REG_TMP1], + (unsigned long)regs[REG_TMP2]); #endif #ifdef CONFIG_XTENSA_USE_SWPRI _alert(" VPRI: %08lx\n", - (unsigned long)g_current_regs[REG_VPRI]); + (unsigned long)regs[REG_VPRI]); #endif } } diff --git a/arch/xtensa/src/common/xtensa_initialize.c b/arch/xtensa/src/common/xtensa_initialize.c index 45ee3b42330..2041548b175 100644 --- a/arch/xtensa/src/common/xtensa_initialize.c +++ b/arch/xtensa/src/common/xtensa_initialize.c @@ -113,9 +113,18 @@ static void up_calibratedelay(void) void up_initialize(void) { +#ifdef CONFIG_SMP + int i; + /* Initialize global variables */ - g_current_regs = NULL; + for (i = 0; i < CONFIG_SMP_NCPUS; i++) + { + g_current_regs[i] = NULL; + } +#else + CURRENT_REGS = NULL; +#endif /* Calibrate the timing loop */ diff --git a/arch/xtensa/src/common/xtensa_intdecode.c b/arch/xtensa/src/common/xtensa_intdecode.c index c170732f6ba..484d30f849b 100644 --- a/arch/xtensa/src/common/xtensa_intdecode.c +++ b/arch/xtensa/src/common/xtensa_intdecode.c @@ -46,11 +46,11 @@ ****************************************************************************/ /**************************************************************************** - * Name: xtensa_intdecode + * Name: xtensa_int_decode * * Description: * Determine the peripheral that geneated the interrupt and dispatch - * handling to the registered interrupt handler via irq_dispatch(). + * handling to the registered interrupt handler via xtensa_irq_dispatch(). * * Input Parameters: * regs - Saves processor state on the stack @@ -62,7 +62,7 @@ * ****************************************************************************/ -uint32_t xtensa_intdecode(uint32_t *regs) +uint32_t *xtensa_int_decode(uint32_t *regs) { #warning Missing implementation return regs; diff --git a/arch/xtensa/src/common/xtensa_interruptcontext.c b/arch/xtensa/src/common/xtensa_interruptcontext.c index db03c5c19dc..8cf096f725e 100644 --- a/arch/xtensa/src/common/xtensa_interruptcontext.c +++ b/arch/xtensa/src/common/xtensa_interruptcontext.c @@ -52,11 +52,12 @@ /**************************************************************************** * Name: up_interrupt_context * - * Description: Return true is we are currently executing in - * the interrupt handler context. + * Description: Return true is we are currently executing in + * the interrupt handler context on this CPU. + * ****************************************************************************/ bool up_interrupt_context(void) { - return g_current_regs != NULL; + return CURRENT_REGS != NULL; } diff --git a/arch/xtensa/src/common/xtensa_irqdispatch.c b/arch/xtensa/src/common/xtensa_irqdispatch.c new file mode 100644 index 00000000000..2a3e9920e0b --- /dev/null +++ b/arch/xtensa/src/common/xtensa_irqdispatch.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtena_irqdispatch.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "xtensa.h" + +#include "group/group.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs) +{ + board_autoled_on(LED_INIRQ); +#ifdef CONFIG_SUPPRESS_INTERRUPTS + PANIC(); +#else + /* Nested interrupts are not supported */ + + DEBUGASSERT(CURRENT_REGS == NULL); + + /* Current regs non-zero indicates that we are processing an interrupt; + * CURRENT_REGS is also used to manage interrupt level context switches. + */ + + CURRENT_REGS = regs; + + /* Deliver the IRQ */ + + irq_dispatch(irq, regs); + +#if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV) + /* Check for a context switch. If a context switch occurred, then + * CURRENT_REGS will have a different value than it did on entry. If an + * interrupt level context switch has occurred, then restore the floating + * point state and the establish the correct address environment before + * returning from the interrupt. + */ + + if (regs != CURRENT_REGS) + { +#ifdef CONFIG_ARCH_FPU + /* Restore floating point registers */ + + up_restorefpu((uint32_t *)CURRENT_REGS); +#endif + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(NULL); +#endif + } +#endif + + /* Set CURRENT_REGS to NULL to indicate that we are no longer in an + * interrupt handler. + */ + + regs = (uint32_t *)CURRENT_REGS; + CURRENT_REGS = NULL; +#endif + + board_autoled_off(LED_INIRQ); + return regs; +}