You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/03/05 05:33:50 UTC

[incubator-nuttx] 01/02: arch: xtensa: Fix SMP related logic

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch pr436
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit ec285f81910024dddd12e2f145314fa1309c4956
Author: Masayuki Ishikawa <ma...@gmail.com>
AuthorDate: Thu Mar 5 13:18:55 2020 +0900

    arch: xtensa: Fix SMP related logic
    
    NOTE: Applied the same logic as in other SMP architectures
    
    Signed-off-by: Masayuki Ishikawa <Ma...@jp.sony.com>
---
 arch/xtensa/Kconfig                              |  1 +
 arch/xtensa/src/common/xtensa_cpupause.c         | 45 +++++++++--------
 arch/xtensa/src/common/xtensa_schedsigaction.c   |  6 +--
 arch/xtensa/src/esp32/esp32_intercpu_interrupt.c | 63 ++----------------------
 4 files changed, 33 insertions(+), 82 deletions(-)

diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index e073ff6..1bedd53 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -15,6 +15,7 @@ config ARCH_CHIP_ESP32
 	select XTENSA_HAVE_INTERRUPTS
 	select ARCH_HAVE_MULTICPU
 	select ARCH_TOOLCHAIN_GNU
+	select ARCH_GLOBAL_IRQDISABLE
 	---help---
 		The ESP32 is a dual-core system from Expressif with two Harvard
 		architecture Xtensa LX6 CPUs. All embedded memory, external memory
diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c
index 59de3cc..a19aae3 100644
--- a/arch/xtensa/src/common/xtensa_cpupause.c
+++ b/arch/xtensa/src/common/xtensa_cpupause.c
@@ -111,57 +111,50 @@ bool up_cpu_pausereq(int cpu)
 
 int up_cpu_paused(int cpu)
 {
-  FAR struct tcb_s *otcb = this_task();
-  FAR struct tcb_s *ntcb;
+  FAR struct tcb_s *tcb = this_task();
 
   /* Update scheduler parameters */
 
-  sched_suspend_scheduler(otcb);
+  sched_suspend_scheduler(tcb);
 
 #ifdef CONFIG_SCHED_INSTRUMENTATION
   /* Notify that we are paused */
 
-  sched_note_cpu_paused(otcb);
+  sched_note_cpu_paused(tcb);
 #endif
 
   /* Copy the CURRENT_REGS into the OLD TCB (otcb).  The co-processor state
    * will be saved as part of the return from xtensa_irq_dispatch().
    */
 
-  xtensa_savestate(otcb->xcp.regs);
+  xtensa_savestate(tcb->xcp.regs);
 
   /* Wait for the spinlock to be released */
 
   spin_unlock(&g_cpu_paused[cpu]);
   spin_lock(&g_cpu_wait[cpu]);
 
-  /* Upon return, we will restore the exception context of the new TCB
-   * (ntcb) at the head of the ready-to-run task list.
+  /* Restore the exception context of the tcb at the (new) head of the
+   * assigned task list.
    */
 
-  ntcb = this_task();
+  tcb = this_task();
 
 #ifdef CONFIG_SCHED_INSTRUMENTATION
   /* Notify that we have resumed */
 
-  sched_note_cpu_resumed(ntcb);
+  sched_note_cpu_resumed(tcb);
 #endif
 
   /* Reset scheduler parameters */
 
-  sched_resume_scheduler(ntcb);
+  sched_resume_scheduler(tcb);
 
-  /* Did the task at the head of the list change? */
-
-  if (otcb != ntcb)
-    {
-      /* Set CURRENT_REGS to the context save are of the new TCB to start.
-       * This will inform the return-from-interrupt logic that a context
-       * switch must be performed.
-       */
+  /* Then switch contexts.  Any necessary address environment changes
+   * will be made when the interrupt returns.
+   */
 
-      xtensa_restorestate(ntcb->xcp.regs);
-    }
+  xtensa_restorestate(tcb->xcp.regs);
 
   spin_unlock(&g_cpu_wait[cpu]);
   return OK;
@@ -190,7 +183,17 @@ int up_cpu_paused(int cpu)
 
 void xtensa_pause_handler(void)
 {
-  up_cpu_paused(up_cpu_index());
+  int cpu = up_cpu_index();
+
+  /* Check for false alarms.  Such false could occur as a consequence of
+   * some deadlock breaking logic that might have already serviced the SG2
+   * interrupt by calling up_cpu_paused.
+   */
+
+  if (spin_islocked(&g_cpu_paused[cpu]))
+    {
+      up_cpu_paused(cpu);
+    }
 }
 
 /****************************************************************************
diff --git a/arch/xtensa/src/common/xtensa_schedsigaction.c b/arch/xtensa/src/common/xtensa_schedsigaction.c
index 693e555..e989d4f 100644
--- a/arch/xtensa/src/common/xtensa_schedsigaction.c
+++ b/arch/xtensa/src/common/xtensa_schedsigaction.c
@@ -284,11 +284,11 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
                    * disabled
                    */
 
-                  CURRENT_REGS[REG_PC] = (uint32_t)_xtensa_sig_trampoline;
+                  tcb->xcp.regs[REG_PC] = (uint32_t)_xtensa_sig_trampoline;
 #ifdef __XTENSA_CALL0_ABI__
-                  CURRENT_REGS[REG_PS] = (uint32_t)(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
+                  tcb->xcp.regs[REG_PS] = (uint32_t)(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
 #else
-                  CURRENT_REGS[REG_PS] = (uint32_t)(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE);
+                  tcb->xcp.regs[REG_PS] = (uint32_t)(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE);
 #endif
                 }
               else
diff --git a/arch/xtensa/src/esp32/esp32_intercpu_interrupt.c b/arch/xtensa/src/esp32/esp32_intercpu_interrupt.c
index eade8e5..42eba07 100644
--- a/arch/xtensa/src/esp32/esp32_intercpu_interrupt.c
+++ b/arch/xtensa/src/esp32/esp32_intercpu_interrupt.c
@@ -53,21 +53,6 @@
 #ifdef CONFIG_SMP
 
 /****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* Single parameter passed with the inter-CPU interrupt */
-
-static volatile uint8_t g_intcode[CONFIG_SMP_NCPUS] SP_SECTION;
-
-/* Spinlock protects parameter array */
-
-static volatile spinlock_t g_intercpu_spin[CONFIG_SMP_NCPUS] SP_SECTION =
-{
-  SP_UNLOCKED, SP_UNLOCKED
-};
-
-/****************************************************************************
  * Private Function
  ****************************************************************************/
 
@@ -82,10 +67,9 @@ static volatile spinlock_t g_intercpu_spin[CONFIG_SMP_NCPUS] SP_SECTION =
 static int esp32_fromcpu_interrupt(int fromcpu)
 {
   uintptr_t regaddr;
-  int intcode;
-  int tocpu;
 
   DEBUGASSERT((unsigned)fromcpu < CONFIG_SMP_NCPUS);
+  DEBUGASSERT(fromcpu != up_cpu_index());
 
   /* Clear the interrupt from the other CPU */
 
@@ -93,29 +77,9 @@ static int esp32_fromcpu_interrupt(int fromcpu)
                              DPORT_CPU_INTR_FROM_CPU_1_REG;
   putreg32(0, regaddr);
 
-  /* Get the inter-CPU interrupt code */
-
-  tocpu            = up_cpu_index();
-  intcode          = g_intcode[tocpu];
-  g_intcode[tocpu] = CPU_INTCODE_NONE;
+  /* Call pause handler */
 
-  spin_unlock(&g_intercpu_spin[tocpu]);
-
-  /* Dispatch the inter-CPU interrupt based on the intcode value */
-
-  switch (intcode)
-    {
-      case CPU_INTCODE_NONE:
-        break;
-
-      case CPU_INTCODE_PAUSE:
-        xtensa_pause_handler();
-        break;
-
-      default:
-        DEBUGPANIC();
-        break;
-    }
+  xtensa_pause_handler();
 
   return OK;
 }
@@ -157,28 +121,11 @@ int xtensa_intercpu_interrupt(int tocpu, int intcode)
   DEBUGASSERT((unsigned)tocpu < CONFIG_SMP_NCPUS &&
               (unsigned)intcode <= UINT8_MAX);
 
-  /* Make sure that each inter-cpu event is atomic.  The spinlock should
-   * only be locked if we just completed sending an interrupt to this
-   * CPU but the other CPU has not yet processed it.
-   */
-
-  spin_lock(&g_intercpu_spin[tocpu]);
-
-  /* Save the passed parameter.  The previous interrupt code should be
-   * CPU_INTCODE_NONE or we have overrun the other CPU.
-   */
-
-  DEBUGASSERT(g_intcode[tocpu] == CPU_INTCODE_NONE);
-  g_intcode[tocpu] = intcode;
-
-  /* Interrupt the other CPU (tocpu) form this CPU.  NOTE: that this logic
-   * fails in numerous ways if fromcpu == tocpu (for example because non-
-   * reentrant spinlocks are used).
-   */
-
   fromcpu = up_cpu_index();
   DEBUGASSERT(fromcpu != tocpu);
 
+  /* Generate an Inter-Processor Interrupt */
+
   if (fromcpu == 0)
     {
       putreg32(DPORT_CPU_INTR_FROM_CPU_0, DPORT_CPU_INTR_FROM_CPU_0_REG);