Просмотр исходного кода

Per-CPU interrupt handlers and args

Jeroen Domburg 9 лет назад
Родитель
Сommit
86d8f63005

+ 1 - 6
components/esp32/crosscore_int.c

@@ -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);

+ 0 - 6
components/freertos/include/freertos/FreeRTOSConfig.h

@@ -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

+ 0 - 5
components/freertos/readme_smp.txt

@@ -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 

+ 9 - 2
components/freertos/xtensa_intr.c

@@ -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;
 

+ 21 - 2
components/freertos/xtensa_intr_asm.S

@@ -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
 

+ 26 - 0
components/freertos/xtensa_vectors.S

@@ -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 for multiple 
+*/
+    .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__