Xtensa ESP32: Basically a redesign of the interrupt dispatch logic.
This commit is contained in:
parent
d4ad5f04d3
commit
cdd8dc72a5
@ -390,7 +390,8 @@
|
|||||||
|
|
||||||
#define ESP32_CPUINT_NINTERNAL 6
|
#define ESP32_CPUINT_NINTERNAL 6
|
||||||
|
|
||||||
#define ESP32_CPUINT_MAX 31
|
#define ESP32_NCPUINTS 32
|
||||||
|
#define ESP32_CPUINT_MAX (ESP32_NCPUINTS - 1)
|
||||||
#define EPS32_CPUINT_PERIPHSET 0xdffe773f
|
#define EPS32_CPUINT_PERIPHSET 0xdffe773f
|
||||||
#define EPS32_CPUINT_INTERNALSET 0x200188c0
|
#define EPS32_CPUINT_INTERNALSET 0x200188c0
|
||||||
|
|
||||||
|
@ -126,45 +126,25 @@
|
|||||||
* a consequence of context switching.
|
* a consequence of context switching.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mov a12, sp /* a12 = address of save area */
|
mov a12, sp /* Address of save area */
|
||||||
|
|
||||||
._xtensa_dispatch_level&level&:
|
|
||||||
|
|
||||||
|
#ifdef __XTENSA_CALL0_ABI__
|
||||||
/* Get mask of pending, enabled interrupts at this level into a2. */
|
/* Get mask of pending, enabled interrupts at this level into a2. */
|
||||||
|
|
||||||
rsr a2, INTENABLE
|
rsr a2, INTENABLE
|
||||||
rsr a3, INTERRUPT
|
rsr a3, INTERRUPT
|
||||||
movi a4, \mask
|
movi a4, \mask
|
||||||
and a2, a2, a3
|
and a2, a2, a3
|
||||||
and a2, a2, a4
|
and a2, a2, a4 /* a2 = Set of pending, enabled interrupts for this level */
|
||||||
beqz a2, 5f /* Nothing to do */
|
beqz a2, 3f /* Nothing to do */
|
||||||
|
|
||||||
/* If multiple bits are set then MSB has highest priority. */
|
|
||||||
|
|
||||||
extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */
|
|
||||||
|
|
||||||
/* Check for a timer interrupt.
|
|
||||||
*
|
|
||||||
* REVISIT: XT_TIMER_INTEN will be only one of the configured timers
|
|
||||||
* selected as the system periodic timer (see xtensa_timer.h). There
|
|
||||||
* is no mechanism here to detect other timer interrupts.
|
|
||||||
*/
|
|
||||||
|
|
||||||
movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */
|
|
||||||
wsr a4, INTCLEAR /* Clear sw or edge-triggered interrupt */
|
|
||||||
beq a3, a4, 4f /* If timer interrupt then skip decode */
|
|
||||||
|
|
||||||
/* Call xtensa_int_decode with, passing that address of the register save
|
/* Call xtensa_int_decode with, passing that address of the register save
|
||||||
* area as a parameter (A2).
|
* area as a parameter (A2).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __XTENSA_CALL0_ABI__
|
/* Argument 1: Set of CPU interrupt to dispatch */
|
||||||
mov a2, a12 /* Argument: Top of stack = register save area */
|
mov a3, sp /* Argument 2: Top of stack = register save area */
|
||||||
call0 xtensa_int_decode /* Call xtensa_int_decode */
|
call0 xtensa_int_decode /* Call xtensa_int_decode */
|
||||||
#else
|
|
||||||
mov a6, a12 /* Argument: Top of stack = register save area */
|
|
||||||
call4 xtensa_int_decode /* Call xtensa_int_decode */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* On return from xtensa_int_decode, a2 will contain the address of the new
|
/* On return from xtensa_int_decode, a2 will contain the address of the new
|
||||||
* register save area. Usually this would be the same as the current SP.
|
* register save area. Usually this would be the same as the current SP.
|
||||||
@ -172,7 +152,7 @@
|
|||||||
* register save area. This may or may not reside on a stack.
|
* register save area. This may or may not reside on a stack.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
beq a2, a12, 3f /* If timer interrupt then keep stack */
|
beq a2, sp, 3f /* If no context switch then keep stack */
|
||||||
|
|
||||||
/* Switch stacks */
|
/* Switch stacks */
|
||||||
|
|
||||||
@ -180,53 +160,42 @@
|
|||||||
l32i a2, a12, (4 * REG_A1) /* Retrieve stack ptr and replace */
|
l32i a2, a12, (4 * REG_A1) /* Retrieve stack ptr and replace */
|
||||||
addi sp, a2, -(4 * XCPTCONTEXT_SIZE)
|
addi sp, a2, -(4 * XCPTCONTEXT_SIZE)
|
||||||
|
|
||||||
3:
|
#else
|
||||||
j ._xtensa_dispatch_level&level& /* Check for more interrupts */
|
/* Get mask of pending, enabled interrupts at this level into a2. */
|
||||||
|
|
||||||
4:
|
rsr a6, INTENABLE
|
||||||
|
rsr a2, INTERRUPT
|
||||||
|
movi a3, \mask
|
||||||
|
and a6, a6, a2
|
||||||
|
and a6, a6, a3 /* a6 = Set of pending, enabled interrupts for this level */
|
||||||
|
beqz a6, 3f /* Nothing to do */
|
||||||
|
|
||||||
.ifeq XT_TIMER_INTPRI - \level
|
/* Call xtensa_int_decode with, passing that address of the register save
|
||||||
|
* area as a parameter (A2).
|
||||||
/* Interrupt handler for the NuttX system timer if at this level.
|
|
||||||
* We'll be reading the interrupt state again after this call
|
|
||||||
* so no need to preserve any registers except a7 (pointer to
|
|
||||||
* state save area).
|
|
||||||
*
|
|
||||||
* REVISIT: Here we explicitly assume that the INTERRUPT XT_TIMER_INTEN
|
|
||||||
* corresponds to TIMER0. That is probably that case, but not necessarily
|
|
||||||
* so. xtensa_timer.h should probably select the IRQ number as well.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __XTENSA_CALL0_ABI__
|
/* Argument 1: Set of CPU interrupt to dispatch */
|
||||||
movi a2, XTENSA_IRQ_TIMER0 /* Argument 1: Timer0 IRQ number */
|
mov a7, sp /* Argument 2: Top of stack = register save area */
|
||||||
mov a3, a12 /* Argument 2: Top of stack = register save area */
|
call4 xtensa_int_decode /* Call xtensa_int_decode */
|
||||||
call0 xtensa_irq_dispatch /* Call xtensa_int_decode */
|
|
||||||
#else
|
/* On return from xtensa_int_decode, a2 will contain the address of the new
|
||||||
movi a6, XTENSA_IRQ_TIMER0 /* Argument 1: Timer0 IRQ number */
|
* register save area. Usually this would be the same as the current SP.
|
||||||
mov a7, a12 /* Argument 2: Top of stack = register save area */
|
* But in the event of a context switch, a2 will instead refer to the TCB
|
||||||
call4 xtensa_irq_dispatch /* Call xtensa_int_decode */
|
* register save area. This may or may not reside on a stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
beq a4, sp, 3f /* If no context switch then keep stack */
|
||||||
|
|
||||||
|
/* Switch stacks */
|
||||||
|
|
||||||
|
mov a12, a4 /* Switch to the save area of the new thread */
|
||||||
|
l32i a2, a12, (4 * REG_A1) /* Retrieve stack ptr and replace */
|
||||||
|
addi sp, a2, -(4 * XCPTCONTEXT_SIZE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* On return from xtensa_irq_dispatch, A2 will contain the address of the new
|
|
||||||
* register save area. Usually this would be the same as the current SP.
|
|
||||||
* But in the event of a context switch, A2 will instead refer to the TCB
|
|
||||||
* register save area.
|
|
||||||
*/
|
|
||||||
|
|
||||||
beq a2, a12, 5f /* If timer interrupt then skip table */
|
|
||||||
|
|
||||||
/* Switch stacks */
|
|
||||||
|
|
||||||
mov a12, a2 /* Switch to the save area of the new thread */
|
|
||||||
l32i a2, a12, (4 * REG_A1) /* Retrieve stack ptr and replace */
|
|
||||||
addi sp, a2, -(4 * XCPTCONTEXT_SIZE)
|
|
||||||
.endif
|
|
||||||
|
|
||||||
j ._xtensa_dispatch_level&level& /* Check for more interrupts */
|
|
||||||
|
|
||||||
5:
|
|
||||||
/* done */
|
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
3:
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
@ -147,6 +148,17 @@
|
|||||||
#define ESP32_MAX_PRIORITY 5
|
#define ESP32_MAX_PRIORITY 5
|
||||||
#define ESP32_PRIO_INDEX(p) ((p) - ESP32_MIN_PRIORITY)
|
#define ESP32_PRIO_INDEX(p) ((p) - ESP32_MIN_PRIORITY)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Maps a CPU interrupt to the attached peripheral interrupt */
|
||||||
|
|
||||||
|
uint8_t g_cpu0_intmap[ESP32_NCPUINTS];
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
uint8_t g_cpu1_intmap[ESP32_NCPUINTS];
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -156,13 +168,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
static uint32_t g_intenable[CONFIG_SMP_NCPUS];
|
static uint32_t g_intenable[CONFIG_SMP_NCPUS];
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static uint32_t g_intenable[1];
|
static uint32_t g_intenable[1];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Bitsets for free, unallocated CPU interrupts available to peripheral
|
/* Bitsets for free, unallocated CPU interrupts available to peripheral
|
||||||
@ -170,11 +178,8 @@ static uint32_t g_intenable[1];
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static uint32_t g_cpu0_freeints = EPS32_CPUINT_PERIPHSET;
|
static uint32_t g_cpu0_freeints = EPS32_CPUINT_PERIPHSET;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
static uint32_t g_cpu1_freeints = EPS32_CPUINT_PERIPHSET;
|
static uint32_t g_cpu1_freeints = EPS32_CPUINT_PERIPHSET;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Bitsets for each interrupt priority 1-5 */
|
/* Bitsets for each interrupt priority 1-5 */
|
||||||
@ -311,6 +316,7 @@ int esp32_alloc_cpuint(uint32_t intmask)
|
|||||||
int esp32_cpuint_initialize(void)
|
int esp32_cpuint_initialize(void)
|
||||||
{
|
{
|
||||||
uintptr_t regaddr;
|
uintptr_t regaddr;
|
||||||
|
uint8_t *intmap;
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
int cpu;
|
int cpu;
|
||||||
#endif
|
#endif
|
||||||
@ -345,6 +351,38 @@ int esp32_cpuint_initialize(void)
|
|||||||
putreg32(NO_CPUINT, regaddr);
|
putreg32(NO_CPUINT, regaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize CPU0-to-peripheral mapping table */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
if (cpu != 0)
|
||||||
|
{
|
||||||
|
intmap = g_cpu1_intmap;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
intmap = g_cpu0_intmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indiate that no peripheral interrupts are assigned to CPU interrupts */
|
||||||
|
|
||||||
|
memset(intmap, CPUINT_UNASSIGNED, ESP32_NCPUINTS);
|
||||||
|
|
||||||
|
/* Special case the 6 internal interrupts.
|
||||||
|
*
|
||||||
|
* CPU interrupt bit IRQ number
|
||||||
|
* --------------------------- ---------------------
|
||||||
|
* ESP32_CPUINT_TIMER0 6 XTENSA_IRQ_TIMER0 0
|
||||||
|
* SP32_CPUINT_SOFTWARE0 7 Not yet defined
|
||||||
|
* ESP32_CPUINT_PROFILING 11 Not yet defined
|
||||||
|
* ESP32_CPUINT_TIMER1 15 XTENSA_IRQ_TIMER1 1
|
||||||
|
* ESP32_CPUINT_TIMER2 16 XTENSA_IRQ_TIMER2 2
|
||||||
|
* ESP32_CPUINT_SOFTWARE1 29 Not yet defined
|
||||||
|
*/
|
||||||
|
|
||||||
|
intmap[ESP32_CPUINT_TIMER0] = XTENSA_IRQ_TIMER0;
|
||||||
|
intmap[ESP32_CPUINT_TIMER1] = XTENSA_IRQ_TIMER1;
|
||||||
|
intmap[ESP32_CPUINT_TIMER2] = XTENSA_IRQ_TIMER2;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,6 +562,7 @@ void esp32_free_cpuint(int cpuint)
|
|||||||
void esp32_attach_peripheral(int cpu, int periphid, int cpuint)
|
void esp32_attach_peripheral(int cpu, int periphid, int cpuint)
|
||||||
{
|
{
|
||||||
uintptr_t regaddr;
|
uintptr_t regaddr;
|
||||||
|
uint8_t *intmap;
|
||||||
|
|
||||||
DEBUGASSERT(periphid >= 0 && periphid < ESP32_NPERIPHERALS);
|
DEBUGASSERT(periphid >= 0 && periphid < ESP32_NPERIPHERALS);
|
||||||
DEBUGASSERT(cpuint >= 0 && cpuint <= ESP32_CPUINT_MAX);
|
DEBUGASSERT(cpuint >= 0 && cpuint <= ESP32_CPUINT_MAX);
|
||||||
@ -533,13 +572,18 @@ void esp32_attach_peripheral(int cpu, int periphid, int cpuint)
|
|||||||
if (cpu != 0)
|
if (cpu != 0)
|
||||||
{
|
{
|
||||||
regaddr = DPORT_APP_MAP_REGADDR(periphid);
|
regaddr = DPORT_APP_MAP_REGADDR(periphid);
|
||||||
|
intmap = g_cpu1_intmap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
regaddr = DPORT_PRO_MAP_REGADDR(periphid);
|
regaddr = DPORT_PRO_MAP_REGADDR(periphid);
|
||||||
|
intmap = g_cpu0_intmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUGASSERT(intmap[cpuint] == CPUINT_UNASSIGNED);
|
||||||
|
intmap[cpuint] = periphid + XTENSA_IRQ_FIRSTPERIPH;
|
||||||
|
|
||||||
putreg32(cpuint, regaddr);
|
putreg32(cpuint, regaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,6 +608,7 @@ void esp32_attach_peripheral(int cpu, int periphid, int cpuint)
|
|||||||
void esp32_detach_peripheral(int cpu, int periphid, int cpuint)
|
void esp32_detach_peripheral(int cpu, int periphid, int cpuint)
|
||||||
{
|
{
|
||||||
uintptr_t regaddr;
|
uintptr_t regaddr;
|
||||||
|
uint8_t *intmap;
|
||||||
|
|
||||||
DEBUGASSERT(periphid >= 0 && periphid < ESP32_NPERIPHERALS);
|
DEBUGASSERT(periphid >= 0 && periphid < ESP32_NPERIPHERALS);
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
@ -572,12 +617,17 @@ void esp32_detach_peripheral(int cpu, int periphid, int cpuint)
|
|||||||
if (cpu != 0)
|
if (cpu != 0)
|
||||||
{
|
{
|
||||||
regaddr = DPORT_APP_MAP_REGADDR(periphid);
|
regaddr = DPORT_APP_MAP_REGADDR(periphid);
|
||||||
|
intmap = g_cpu1_intmap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
regaddr = DPORT_PRO_MAP_REGADDR(periphid);
|
regaddr = DPORT_PRO_MAP_REGADDR(periphid);
|
||||||
|
intmap = g_cpu0_intmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUGASSERT(intmap[cpuint] != CPUINT_UNASSIGNED);
|
||||||
|
intmap[cpuint] = CPUINT_UNASSIGNED;
|
||||||
|
|
||||||
putreg32(NO_CPUINT, regaddr);
|
putreg32(NO_CPUINT, regaddr);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,25 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <arch/irq.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define CPUINT_UNASSIGNED 0xff /* No peripheral assigned to this CPU interrupt */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Maps a CPU interrupt to the attached peripheral interrupt */
|
||||||
|
|
||||||
|
extern uint8_t g_cpu0_intmap[ESP32_NCPUINTS];
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
extern uint8_t g_cpu1_intmap[ESP32_NCPUINTS];
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Function Prototypes
|
* Public Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -39,29 +39,32 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
#include <nuttx/sched.h>
|
#include <stdint.h>
|
||||||
#include <arch/chip/irq.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <arch/irq.h>
|
||||||
|
|
||||||
#include "chip/esp32_dport.h"
|
|
||||||
#include "xtensa.h"
|
#include "xtensa.h"
|
||||||
|
#include "esp32_cpuint.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static const uint8_t g_baseirq[3] =
|
/****************************************************************************
|
||||||
{
|
* Name: xtensa_intclear
|
||||||
ESP32_IRQ_SREG0,
|
****************************************************************************/
|
||||||
ESP32_IRQ_SREG1,
|
|
||||||
ESP32_IRQ_SREG2
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t g_nirqs[3] =
|
static inline void xtensa_intclear(uint32_t mask)
|
||||||
{
|
{
|
||||||
ESP32_NIRQS_SREG0,
|
__asm__ __volatile__
|
||||||
ESP32_NIRQS_SREG1,
|
(
|
||||||
ESP32_NIRQS_SREG2
|
"movi a2, 0\n"
|
||||||
};
|
"wsr %0, INTCLEAR\n"
|
||||||
|
: "=r"(mask) : :
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@ -75,80 +78,74 @@ static const uint8_t g_nirqs[3] =
|
|||||||
* handling to the registered interrupt handler via xtensa_irq_dispatch().
|
* handling to the registered interrupt handler via xtensa_irq_dispatch().
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
|
* cpuints - Set of pending interrupts valid for this level
|
||||||
* regs - Saves processor state on the stack
|
* regs - Saves processor state on the stack
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Normally the same vale as regs is returned. But, in the event of an
|
* Normally the same value as regs is returned. But, in the event of an
|
||||||
* interrupt level context switch, the returned value will, instead point
|
* interrupt level context switch, the returned value will, instead point
|
||||||
* to the saved processor state in the TCB of the newly started task.
|
* to the saved processor state in the TCB of the newly started task.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
uint32_t *xtensa_int_decode(uint32_t *regs)
|
uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs)
|
||||||
{
|
{
|
||||||
uintptr_t regaddr;
|
uint8_t *intmap;
|
||||||
uint32_t regval;
|
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
int regndx;
|
|
||||||
int bit;
|
int bit;
|
||||||
int baseirq;
|
|
||||||
int nirqs;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
int cpu;
|
int cpu;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Select PRO or APP interrupt status registers */
|
#ifdef CONFIG_SMP
|
||||||
|
/* Select PRO or APP CPU interrupt mapping table */
|
||||||
|
|
||||||
cpu = up_cpu_index();
|
cpu = up_cpu_index();
|
||||||
if (cpu == 0)
|
if (cpu != 0)
|
||||||
{
|
{
|
||||||
regaddr = DPORT_PRO_INTR_STATUS_0_REG;
|
intmap = g_cpu1_intmap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
regaddr = DPORT_APP_INTR_STATUS_0_REG;
|
intmap = g_cpu0_intmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process each pending interrupt in each of the three interrupt status
|
/* Skip over zero bits, eight at a time */
|
||||||
* registers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (regndx = 0; regndx < 3; regndx++)
|
for (bit = 0, mask = 0xff;
|
||||||
|
bit < ESP32_NCPUINTS && (cpuints & mask) == 0;
|
||||||
|
bit += 8, mask <<= 8);
|
||||||
|
|
||||||
|
/* Process each pending CPU interrupt */
|
||||||
|
|
||||||
|
for (; bit < ESP32_NCPUINTS && cpuints != 0; bit++)
|
||||||
{
|
{
|
||||||
/* Fetch the next register status register */
|
|
||||||
|
|
||||||
regval = getreg32(regaddr);
|
|
||||||
regaddr += sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Set up the search */
|
|
||||||
|
|
||||||
baseirq = g_baseirq[regndx];
|
|
||||||
nirqs = g_nirqs[regndx];
|
|
||||||
|
|
||||||
/* Decode and dispatch each pending bit in the interrupt status
|
|
||||||
* register.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (bit = 0; regval != 0 && bit < nirqs; bit++)
|
|
||||||
{
|
|
||||||
/* Check if this interrupt is pending */
|
|
||||||
|
|
||||||
mask = (1 << bit);
|
mask = (1 << bit);
|
||||||
if ((regval & mask) != 0)
|
if ((cpuints & mask) != 0)
|
||||||
{
|
{
|
||||||
/* Yes.. Dispatch the interrupt. Note that regs may be
|
/* Extract the IRQ number from the mapping table */
|
||||||
* altered in the case of an interrupt level context switch.
|
|
||||||
|
uint8_t irq = intmap[bit];
|
||||||
|
DEBUGASSERT(irq != CPUINT_UNASSIGNED);
|
||||||
|
|
||||||
|
/* Clear software or edge-triggered interrupt */
|
||||||
|
|
||||||
|
xtensa_intclear(mask);
|
||||||
|
|
||||||
|
/* Dispatch the CPU interrupt.
|
||||||
|
*
|
||||||
|
* NOTE that regs may be altered in the case of an interrupt
|
||||||
|
* level context switch.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regs = xtensa_irq_dispatch(baseirq + bit, regs);
|
regs = xtensa_irq_dispatch((int)irq, regs);
|
||||||
|
|
||||||
/* Clear this bit in the sampled status register so that
|
/* Clear the bit in the pending interrupt so that perhaps
|
||||||
* perhaps we can exit this loop sooner.
|
* we can exit the look early.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regval &= ~mask;
|
cpuints &= ~mask;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user