Xtensa: Add some data structures needed for SMP support.
This commit is contained in:
parent
67c98baaea
commit
bd6633dd84
@ -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 */
|
||||
|
||||
|
@ -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 (; ; )
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
116
arch/xtensa/src/common/xtensa_irqdispatch.c
Normal file
116
arch/xtensa/src/common/xtensa_irqdispatch.c
Normal file
@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/common/xtena_irqdispatch.c
|
||||
*
|
||||
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user