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 * 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 * Public Functions
@ -98,7 +99,8 @@ int arm_pause_handler(int irq, FAR void *context)
/* Wait for the spinlock to be released */ /* 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 /* Restore the exception context of the tcb at the (new) head of the
* assigned task list. * assigned task list.
@ -115,7 +117,7 @@ int arm_pause_handler(int irq, FAR void *context)
*/ */
up_restorestate(tcb->xcp.regs); up_restorestate(tcb->xcp.regs);
spin_unlock(&g_pause_spinlock[cpu]); spin_unlock(&g_cpu_wait[cpu]);
return OK; return OK;
} }
@ -141,18 +143,48 @@ int arm_pause_handler(int irq, FAR void *context)
int up_cpu_pause(int cpu) int up_cpu_pause(int cpu)
{ {
int ret;
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
/* Take the spinlock. The spinlock will cause the SGI2 handler to block /* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
* on 'cpu'. * 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])); DEBUGASSERT(!spin_islocked(&g_cpu_wait[cpu]) &&
spin_lock(&g_pause_spinlock[cpu]); !spin_islocked(&g_cpu_paused[cpu]));
spin_lock(&g_cpu_wait[cpu]);
spin_lock(&g_cpu_paused[cpu]);
/* Execute SGI2 */ /* 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. * established thread.
*/ */
DEBUGASSERT(spin_islocked(&g_pause_spinlock[cpu])); DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
spin_unlock(&g_pause_spinlock[cpu]); !spin_islocked(&g_cpu_paused[cpu]));
spin_unlock(&g_cpu_wait[cpu]);
return OK; 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 * 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 * value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
* 0 is already active) * 0 is already active)
* idletask - The entry point to the IDLE task.
* *
* Returned Value: * Returned Value:
* Zero on success; a negated errno value on failure. * 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()); 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); DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
#if CONFIG_SMP #ifdef CONFIG_SMP
regval = GIC_ICDSGIR_INTID(sgi) | GIC_ICDSGIR_CPUTARGET(cpuset) | regval = GIC_ICDSGIR_INTID(sgi) | GIC_ICDSGIR_CPUTARGET(cpuset) |
GIC_ICDSGIR_TGTFILTER_LIST; GIC_ICDSGIR_TGTFILTER_LIST;
#else #else

View File

@ -70,7 +70,7 @@ ifeq ($(CONFIG_SPINLOCK),y)
endif endif
ifeq ($(CONFIG_SMP),y) ifeq ($(CONFIG_SMP),y)
CSRCS += up_smpsignal.c CSRCS += up_smpsignal.c up_smphook.c
HOSTSRCS += up_simsmp.c HOSTSRCS += up_simsmp.c
endif endif
@ -181,7 +181,7 @@ endif
endif endif
ifeq ($(CONFIG_SMP),y) ifeq ($(CONFIG_SMP),y)
REQUIREDOBJS += up_smpsignal$(OBJEXT) REQUIREDOBJS += up_smpsignal$(OBJEXT) up_smphook$(OBJEXT)
endif endif
# Determine which NuttX libraries will need to be linked in # 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); FAR volatile unsigned char *paused);
#endif #endif
/* up_smphook.c ***********************************************************/
#ifdef CONFIG_SMP
void sim_smp_hook(void);
#endif
/* up_tickless.c **********************************************************/ /* up_tickless.c **********************************************************/
#ifdef CONFIG_SCHED_TICKLESS #ifdef CONFIG_SCHED_TICKLESS

View File

@ -70,7 +70,6 @@ struct sim_cpuinfo_s
{ {
int cpu; /* CPU number */ int cpu; /* CPU number */
pthread_mutex_t mutex; /* For synchronization */ 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 os_start(void) __attribute__ ((noreturn));
void sim_cpu_pause(int cpu, volatile spinlock_t *wait, void sim_cpu_pause(int cpu, volatile spinlock_t *wait,
volatile unsigned char *paused); volatile unsigned char *paused);
void sim_smp_hook(void);
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
@ -191,9 +191,12 @@ static void *sim_idle_trampoline(void *arg)
(void)pthread_mutex_unlock(&cpuinfo->mutex); (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 */ /* 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 * 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 * value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
* 0 is already active) * 0 is already active)
* idletask - The entry point to the IDLE task.
* *
* Returned Value: * Returned Value:
* Zero on success; a negated errno value on failure. * 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; struct sim_cpuinfo_s cpuinfo;
int ret; int ret;
@ -376,7 +378,6 @@ int up_cpu_start(int cpu, main_t idletask)
/* Initialize the CPU info */ /* Initialize the CPU info */
cpuinfo.cpu = cpu; cpuinfo.cpu = cpu;
cpuinfo.idletask = idletask;
ret = pthread_mutex_init(&cpuinfo.mutex, NULL); ret = pthread_mutex_init(&cpuinfo.mutex, NULL);
if (ret != 0) if (ret != 0)
{ {