Merge branch 'feature/per_cpu_interrupt_handlers' into 'master'

Per-CPU interrupt handlers and args

Up to now, the interrupt handlers and args were shared between CPUs, that is, if you set an interrupt handler on CPU0, CPU1 would invoke the same interrupt handler on that interrupt. This code gives every CPU its own space for interrupt handlers.

See merge request !192
This commit is contained in:
Jeroen Domburg 2016-11-11 14:50:29 +08:00
commit f5cebd2666
7 changed files with 65 additions and 25 deletions

View file

@ -45,14 +45,9 @@ the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably
*/
static void esp_crosscore_isr(void *arg) {
uint32_t myReasonVal;
#if 0
//A pointer to the correct reason array item is passed to this ISR.
volatile uint32_t *myReason=arg;
#else
//The previous line does not work yet, the interrupt code needs work to understand two separate interrupt and argument
//tables... this is a valid but slightly less optimal replacement.
volatile uint32_t *myReason=&reason[xPortGetCoreID()];
#endif
//Clear the interrupt first.
if (xPortGetCoreID()==0) {
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);

View file

@ -265,12 +265,6 @@
#define INCLUDE_eTaskGetState 1
#define configUSE_QUEUE_SETS 1
#if (!defined XT_INTEXC_HOOKS)
#define configXT_INTEXC_HOOKS 1 /* Exception hooks used by certain tests */
#if configUSE_TRACE_FACILITY_2
#define configASSERT_2 1 /* Specific to Xtensa port */
#endif
#endif
#define configXT_BOARD 1 /* Board mode */
#define configXT_SIMULATOR 0

View file

@ -42,7 +42,8 @@ typedef void (*xt_exc_handler)(XtExcFrame *);
/*
-------------------------------------------------------------------------------
Call this function to set a handler for the specified exception.
Call this function to set a handler for the specified exception. The handler
will be installed on the core that calls this function.
n - Exception number (type)
f - Handler function address, NULL to uninstall handler.
@ -61,7 +62,8 @@ extern xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f);
/*
-------------------------------------------------------------------------------
Call this function to set a handler for the specified interrupt.
Call this function to set a handler for the specified interrupt. The handler
will be installed on the core that calls this function.
n - Interrupt number.
f - Handler function address, NULL to uninstall handler.
@ -73,7 +75,8 @@ extern xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg);
/*
-------------------------------------------------------------------------------
Call this function to enable the specified interrupts.
Call this function to enable the specified interrupts on the core that runs
this code.
mask - Bit mask of interrupts to be enabled.
-------------------------------------------------------------------------------
@ -83,7 +86,8 @@ extern void xt_ints_on(unsigned int mask);
/*
-------------------------------------------------------------------------------
Call this function to disable the specified interrupts.
Call this function to disable the specified interrupts on the core that runs
this code.
mask - Bit mask of interrupts to be disabled.
-------------------------------------------------------------------------------

View file

@ -19,11 +19,6 @@ it would on a single-core system: the other core still will keep on
executing all it's own. Use a mux, queue or semaphore to protect your
structures instead.
- While each core has individual interrupts, the handlers are shared. This
means that when you set a handler for an interrupt, it will get triggered if
the interrupt is triggered on both CPU0 as well as on CPU1. This is something
we may change in future FreeRTOS-esp32 releases.
- This FreeRTOS version has the task local storage backported from the 8.2.x
versions. It, however, has an addition: you can also set a callback when you
set the pointer. This callback will be called by the idle task, with the

View file

@ -30,7 +30,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <xtensa/config/core.h>
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "freertos/portable.h"
#include "rom/ets_sys.h"
@ -39,7 +41,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* Handler table is in xtensa_intr_asm.S */
// Todo: Make multicore - JD
extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM];
extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM*portNUM_PROCESSORS];
/*
@ -66,6 +68,8 @@ xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f)
if( n < 0 || n >= XCHAL_EXCCAUSE_NUM )
return 0; /* invalid exception number */
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
old = _xt_exception_table[n];
if (f) {
@ -89,7 +93,7 @@ typedef struct xt_handler_table_entry {
void * arg;
} xt_handler_table_entry;
extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS];
extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS];
/*
@ -118,6 +122,9 @@ xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg)
if( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL )
return 0; /* priority level too high to safely handle in C */
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
entry = _xt_interrupt_table + n;
old = entry->handler;

View file

@ -30,6 +30,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <xtensa/config/core.h>
#include "xtensa_context.h"
#include "FreeRTOSConfig.h"
#if XCHAL_HAVE_INTERRUPTS
@ -59,6 +60,15 @@ _xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */
Table of C-callable interrupt handlers for each interrupt. Note that not all
slots can be filled, because interrupts at level > EXCM_LEVEL will not be
dispatched to a C handler by default.
Stored as:
int 0 cpu 0
int 0 cpu 1
...
int 0 cpu n
int 1 cpu 0
int 1 cpu 1
etc
-------------------------------------------------------------------------------
*/
@ -69,7 +79,7 @@ _xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */
_xt_interrupt_table:
.set i, 0
.rept XCHAL_NUM_INTERRUPTS
.rept XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS
.word xt_unhandled_interrupt /* handler address */
.word i /* handler arg (default: intnum) */
.set i, i+1
@ -85,6 +95,15 @@ _xt_interrupt_table:
Table of C-callable exception handlers for each exception. Note that not all
slots will be active, because some exceptions (e.g. coprocessor exceptions)
are always handled by the OS and cannot be hooked by user handlers.
Stored as:
exc 0 cpu 0
exc 0 cpu 1
...
exc 0 cpu n
exc 1 cpu 0
exc 1 cpu 1
etc
-------------------------------------------------------------------------------
*/
@ -93,7 +112,7 @@ _xt_interrupt_table:
.align 4
_xt_exception_table:
.rept XCHAL_EXCCAUSE_NUM
.rept XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS
.word xt_unhandled_exception /* handler address */
.endr

View file

@ -113,6 +113,27 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define XIE_ARG 4
#define XIE_SIZE 8
/*
Macro get_percpu_entry_for - convert a per-core ID into a multicore entry.
Basically does reg=reg*portNUM_PROCESSORS+current_core_id
Multiple versions here to optimize for specific portNUM_PROCESSORS values.
*/
.macro get_percpu_entry_for reg scratch
#if (portNUM_PROCESSORS == 1)
/* No need to do anything */
#elif (portNUM_PROCESSORS == 2)
/* Optimized 2-core code. */
getcoreid \scratch
addx2 \reg,\reg,\scratch
#else
/* Generalized n-core code. Untested! */
movi \scratch,portNUM_PROCESSORS
mull \scratch,\reg,\scratch
getcoreid \reg
add \reg,\scratch,\reg
#endif
.endm
/*
--------------------------------------------------------------------------------
Macro extract_msb - return the input with only the highest bit set.
@ -229,6 +250,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */
get_percpu_entry_for a3, a12
movi a4, _xt_interrupt_table
addx8 a3, a3, a4 /* a3 = address of interrupt table entry */
l32i a4, a3, XIE_HANDLER /* a4 = handler address */
@ -395,6 +417,9 @@ panic_print_hex_ok:
with index 0 containing the entry for user exceptions.
Initialized with all 0s, meaning no handler is installed at each level.
See comment in xtensa_rtos.h for more details.
*WARNING* This array is for all CPUs, that is, installing a hook for
one CPU will install it for all others as well!
--------------------------------------------------------------------------------
*/
@ -688,6 +713,7 @@ _xt_user_exc:
rsr a2, EXCCAUSE /* recover exc cause */
movi a3, _xt_exception_table
get_percpu_entry_for a3, a4
addx4 a4, a2, a3 /* a4 = address of exception table entry */
l32i a4, a4, 0 /* a4 = handler address */
#ifdef __XTENSA_CALL0_ABI__