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