Conform to revised SMP interfaces. Improve i.MX6 SMP startup handshake.

This commit is contained in:
Gregory Nutt 2016-03-12 15:22:45 -06:00
parent 8ad1188fe5
commit 6288e381ee
6 changed files with 61 additions and 21 deletions

View File

@ -55,7 +55,8 @@
* Private Data
****************************************************************************/
static spinlock_t g_pause_spinlock[CONFIG_SMP_NCPUS];
static spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
static spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
/****************************************************************************
* Public Functions
@ -98,7 +99,8 @@ int arm_pause_handler(int irq, FAR void *context)
/* Wait for the spinlock to be released */
spin_lock(&g_pause_spinlock[cpu]);
spin_unlock(&g_cpu_paused[cpu]);
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
@ -115,7 +117,7 @@ int arm_pause_handler(int irq, FAR void *context)
*/
up_restorestate(tcb->xcp.regs);
spin_unlock(&g_pause_spinlock[cpu]);
spin_unlock(&g_cpu_wait[cpu]);
return OK;
}
@ -141,18 +143,48 @@ int arm_pause_handler(int irq, FAR void *context)
int up_cpu_pause(int cpu)
{
int ret;
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
/* Take the spinlock. The spinlock will cause the SGI2 handler to block
* on 'cpu'.
/* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
* handler from returning until up_cpu_resume() is called; g_cpu_paused
* is a handshake that will prefent this function from returning until
* the CPU is actually paused.
*/
DEBUGASSERT(!spin_islocked(&g_pause_spinlock[cpu]));
spin_lock(&g_pause_spinlock[cpu]);
DEBUGASSERT(!spin_islocked(&g_cpu_wait[cpu]) &&
!spin_islocked(&g_cpu_paused[cpu]));
spin_lock(&g_cpu_wait[cpu]);
spin_lock(&g_cpu_paused[cpu]);
/* Execute SGI2 */
return arm_cpu_sgi(GIC_IRQ_SGI2, (1 << cpu));
ret = arm_cpu_sgi(GIC_IRQ_SGI2, (1 << cpu));
if (ret < 0)
{
/* What happened? Unlock the g_cpu_wait spinlock */
spin_unlock(&g_cpu_wait[cpu]);
}
else
{
/* Wait for the other CPU to unlock g_cpu_paused meaning that
* it is fully paused and ready for up_cpu_resume();
*/
spin_lock(&g_cpu_paused[cpu]);
}
spin_unlock(&g_cpu_paused[cpu]);
/* On successful return g_cpu_wait will be locked, the other CPU will be
* spinninf on g_cpu_wait and will not continue until g_cpu_resume() is
* called. g_cpu_paused will be unlocked in any case.
*/
return ret;
}
/****************************************************************************
@ -183,8 +215,10 @@ int up_cpu_resume(int cpu)
* established thread.
*/
DEBUGASSERT(spin_islocked(&g_pause_spinlock[cpu]));
spin_unlock(&g_pause_spinlock[cpu]);
DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
!spin_islocked(&g_cpu_paused[cpu]));
spin_unlock(&g_cpu_wait[cpu]);
return OK;
}

View File

@ -108,14 +108,13 @@ int arm_start_handler(int irq, FAR void *context)
* cpu - The index of the CPU being started. This will be a numeric
* value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
* 0 is already active)
* idletask - The entry point to the IDLE task.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
int up_cpu_start(int cpu, main_t idletask)
int up_cpu_start(int cpu)
{
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());

View File

@ -426,7 +426,7 @@ int arm_cpu_sgi(int sgi, unsigned int cpuset)
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
#if CONFIG_SMP
#ifdef CONFIG_SMP
regval = GIC_ICDSGIR_INTID(sgi) | GIC_ICDSGIR_CPUTARGET(cpuset) |
GIC_ICDSGIR_TGTFILTER_LIST;
#else

View File

@ -70,7 +70,7 @@ ifeq ($(CONFIG_SPINLOCK),y)
endif
ifeq ($(CONFIG_SMP),y)
CSRCS += up_smpsignal.c
CSRCS += up_smpsignal.c up_smphook.c
HOSTSRCS += up_simsmp.c
endif
@ -181,7 +181,7 @@ endif
endif
ifeq ($(CONFIG_SMP),y)
REQUIREDOBJS += up_smpsignal$(OBJEXT)
REQUIREDOBJS += up_smpsignal$(OBJEXT) up_smphook$(OBJEXT)
endif
# Determine which NuttX libraries will need to be linked in

View File

@ -228,6 +228,12 @@ void sim_cpu_pause(int cpu, FAR volatile spinlock_t *wait,
FAR volatile unsigned char *paused);
#endif
/* up_smphook.c ***********************************************************/
#ifdef CONFIG_SMP
void sim_smp_hook(void);
#endif
/* up_tickless.c **********************************************************/
#ifdef CONFIG_SCHED_TICKLESS

View File

@ -70,7 +70,6 @@ struct sim_cpuinfo_s
{
int cpu; /* CPU number */
pthread_mutex_t mutex; /* For synchronization */
main_t idletask; /* IDLE task entry point */
};
/****************************************************************************
@ -89,6 +88,7 @@ static volatile spinlock_t g_sim_cpuwait[CONFIG_SMP_NCPUS];
void os_start(void) __attribute__ ((noreturn));
void sim_cpu_pause(int cpu, volatile spinlock_t *wait,
volatile unsigned char *paused);
void sim_smp_hook(void);
/****************************************************************************
* Private Functions
@ -191,9 +191,12 @@ static void *sim_idle_trampoline(void *arg)
(void)pthread_mutex_unlock(&cpuinfo->mutex);
/* Give control to the IDLE task */
/* Give control to the IDLE task via the nasty little sim_smp_hook().
* sim_smp_hook() is logically a part of this function but needs to be
* inserted in the path because in needs to access NuttX domain definitions.
*/
(void)cpuinfo->idletask(0, (char **)0);
sim_smp_hook();
/* The IDLE task will not return. This is just to keep the compiler happy */
@ -361,14 +364,13 @@ int up_cpu_index(void)
* cpu - The index of the CPU being started. This will be a numeric
* value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
* 0 is already active)
* idletask - The entry point to the IDLE task.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
int up_cpu_start(int cpu, main_t idletask)
int up_cpu_start(int cpu)
{
struct sim_cpuinfo_s cpuinfo;
int ret;
@ -376,7 +378,6 @@ int up_cpu_start(int cpu, main_t idletask)
/* Initialize the CPU info */
cpuinfo.cpu = cpu;
cpuinfo.idletask = idletask;
ret = pthread_mutex_init(&cpuinfo.mutex, NULL);
if (ret != 0)
{