Skip to content

Commit

Permalink
os/arch/arm/src/amebasmart,armv7-a: Update CPU gating mechanism for SMP
Browse files Browse the repository at this point in the history
- A deadlock was observed when the cpuA which undergo flash operation is trying to gate the other cpuB, but the cpuB is in critical zone (ie. interrupt disabled state), due to waiting for cpuA to pause itself
- This commit fix the deadlock issue by letting cpuA to check and handle any pending pause request at first, so that cpuB can continue it's workflow and exit from critical zone, thus it can handle the gating request from cpuA
  • Loading branch information
edwakuwaku committed Apr 29, 2024
1 parent c5830d4 commit e9c25c6
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 43 deletions.
41 changes: 30 additions & 11 deletions os/arch/arm/src/amebasmart/amebasmart_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#endif

#ifdef CONFIG_PLATFORM_TIZENRT_OS
#ifdef CONFIG_CPU_GATING
extern volatile uint32_t ulFlashPG_Flag;
#endif
extern void __cpu1_start(void);
#else
extern void _boot(void);
Expand Down Expand Up @@ -71,31 +73,48 @@ void rtk_core1_power_off(void)
HAL_WRITE32(SYSTEM_CTRL_BASE_HP, REG_HSYS_HP_PWC, val);
}

void vPortGateOtherCore(void)
bool vPortGateOtherCore(void)
{
#if ( defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1 )
ulFlashPG_Flag = 1;
ARM_DSB();
ARM_ISB();

BaseType_t ulCoreID = up_cpu_index();
ulCoreID = (ulCoreID + 1) % CONFIG_SMP_NCPUS;
CA32_TypeDef *ca32 = CA32_BASE;
/* ulFlashPG_Flag should be checked here, it should only exists under 3 states:
0: No flash operation / Just completed a flash operation
1: A gating request has been sent out to another core, further checking shall be done at the while condition below
2: The target core is already in gating state, proceed for flash operation
*/
if (!ulFlashPG_Flag) {
ulFlashPG_Flag = 1;
ARM_DSB();

#ifndef CONFIG_PLATFORM_TIZENRT_OS
arm_gic_raise_softirq(ulCoreID, IPI_FLASHPG_IRQ);
arm_gic_raise_softirq(ulCoreID, IPI_FLASHPG_IRQ);
#else
arm_cpu_sgi(GIC_IRQ_SGI3, (1 << ulCoreID));
arm_cpu_sgi(GIC_IRQ_SGI3, (1 << ulCoreID));
#endif

CA32_TypeDef *ca32 = CA32_BASE;
while (CA32_GET_STANDBYWFE(ca32->CA32_C0_CPU_STATUS) != BIT(ulCoreID));
}
/* We already initiated a gating request previously, skip sending duplicated request */
/* Before gating the other CPU, we have to check for pending pause request, as the target core
* might have entered spinlock to wait for current core to pause itself. And currently
* we are in a interrupt disabled status here, thus we should exit and handle
* pause request first, before we proceed to gate another cpu for executing
* flash operation
*/
while ((ulFlashPG_Flag == 1) || CA32_GET_STANDBYWFE(ca32->CA32_C0_CPU_STATUS) != BIT(ulCoreID)) {
/* If there is a pause request, we should handle it first */
if (up_cpu_pausereq(up_cpu_index())) {
return false;
}
}
return true;
#endif
}

void vPortWakeOtherCore(void)
{
ulFlashPG_Flag = 0;
ARM_DSB();
ARM_ISB();
__asm__ __volatile__ ("sev" : : : "memory");
}

Expand Down
36 changes: 7 additions & 29 deletions os/arch/arm/src/armv7-a/arm_cpuflash.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,10 @@
#include "sched/sched.h"
#include "section_config.h"
#include "sheipa.h"
#include "barriers.h"

#ifdef CONFIG_SMP
#ifdef CONFIG_CPU_GATING
volatile uint32_t ulFlashPG_Flag = 0;
/****************************************************************************
* Private Functions
****************************************************************************/
#define portCPU_IRQ_DISABLE() \
__asm volatile ( "CPSID i" ::: "memory" ); \
__asm volatile ( "DSB" ); \
__asm volatile ( "ISB" );
/****************************************************************************
* Public Functions
****************************************************************************/
uint32_t ulPortInterruptLock(void)
{
uint32_t key;

__asm volatile ( "mrs %0, cpsr \n": "=r" (key) :: "memory");
portCPU_IRQ_DISABLE();

return key;
}
/*-----------------------------------------------------------*/

void ulPortInterruptUnLock(uint32_t key)
{
__asm volatile ( "msr cpsr_c, %0 \n" :: "r" (key) : "memory");
}

/****************************************************************************
* Name: arm_flash_handler
*
Expand All @@ -85,11 +60,14 @@ void ulPortInterruptUnLock(uint32_t key)
SRAMDRAM_ONLY_TEXT_SECTION
int arm_flash_handler(int irq, void *context, void *arg)
{
uint32_t PrevIrqStatus = ulPortInterruptLock();
uint32_t PrevIrqStatus = irqsave();
ulFlashPG_Flag++;
ARM_DSB();
ARM_ISB();
while(ulFlashPG_Flag) {
__asm__ __volatile__ ("wfe" : : : "memory");
}
ulPortInterruptUnLock(PrevIrqStatus);
irqrestore(PrevIrqStatus);

return OK;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include "ameba_soc.h"

uint32_t PrevIrqStatus;
#ifdef CONFIG_CPU_GATING
extern volatile uint32_t ulFlashPG_Flag;
#endif

void FLASH_WaitBusy_InUserMode(u32 WaitType);
void FLASH_TxCmd_InUserMode(u8 cmd, u8 DataPhaseLen, u8 *pData);
Expand Down Expand Up @@ -79,14 +82,20 @@ ALIGNMTO(CACHE_LINE_SIZE) u8 Flash_Sync_Flag[CACHE_LINE_ALIGMENT(64)];
SRAMDRAM_ONLY_TEXT_SECTION
void FLASH_Write_Lock(void)
{
retry_gating:
/* disable irq */
PrevIrqStatus = save_and_cli();
/* We do not need to acquire lock for this core, as the other core will enter gating */
PrevIrqStatus = irqsave();

/* Add This Code For XIP when ca32 Program Flah */
#if (defined(ARM_CORE_CA32) && defined(CONFIG_XIP_FLASH))
#if (defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1)
/*1. Close Core1 to avoid Core1 XIP */
vPortGateOtherCore();
if (!vPortGateOtherCore()) {
/* Restore irq here due to pending pause request */
irqrestore(PrevIrqStatus);
goto retry_gating;
}
#endif
#if FLASH_GATE_USE_CKE
/*2. Disable KM4 clock */
Expand Down Expand Up @@ -137,7 +146,7 @@ void FLASH_Write_Unlock(void)
#endif

/* restore irq */
restore_flags(PrevIrqStatus);
irqrestore(PrevIrqStatus);
}

/**
Expand Down Expand Up @@ -399,6 +408,13 @@ SRAMDRAM_ONLY_TEXT_SECTION
void FLASH_UserMode_Enter(void)
{
SPIC_TypeDef *spi_flash = SPIC;
#ifdef CONFIG_CPU_GATING
long ulCoreID = up_cpu_index();
ulCoreID = (ulCoreID + 1) % CONFIG_SMP_NCPUS;
CA32_TypeDef *ca32 = CA32_BASE;

while ((ulFlashPG_Flag != 2) || CA32_GET_STANDBYWFE(ca32->CA32_C0_CPU_STATUS) != BIT(ulCoreID));
#endif
spi_flash->CTRLR0 |= BIT_USER_MODE;

/* user mode is entered after auto cmd is done, which means if SPIC BUSY=1, HW will not write Ctrl0 */
Expand Down

0 comments on commit e9c25c6

Please sign in to comment.