From 3147dfc7d5fe2cad80afa016db691f2eff697852 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 10 Feb 2016 13:49:27 -0600 Subject: [PATCH] SMP: Add some tentative initialization logic --- include/nuttx/arch.h | 29 +++++++ include/sys/types.h | 2 +- sched/init/Make.defs | 4 + sched/init/init.h | 36 +++++---- sched/init/os_bringup.c | 16 ---- sched/init/os_smpstart.c | 156 +++++++++++++++++++++++++++++++++++++ sched/init/os_start.c | 10 ++- sched/semaphore/spinlock.c | 4 +- 8 files changed, 224 insertions(+), 33 deletions(-) create mode 100644 sched/init/os_smpstart.c diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index bbca284eab..580ba4bd5e 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1682,6 +1682,35 @@ int up_cpundx(void); # define up_cpundx() (0) #endif +/**************************************************************************** + * Name: up_cpustart + * + * Description: + * In an SMP configution, only one CPU is initially active (CPU 0). System + * initialization occurs on that single thread. At the completion of the + * initialization of the OS, just before beginning normal multitasking, + * the additional CPUs would be started by calling this function. + * + * Each CPU is provided the entry point to is IDLE task when started. The + * OS initialization logic calls this function repeatedly until each CPU + * has been started. + * + * Input Parameters: + * 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: + * An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + ****************************************************************************/ + +#ifdef CONFIG_SMP +int up_cpustart(int cpu, main_t idletask); +#endif + /**************************************************************************** * Name: up_romgetc * diff --git a/include/sys/types.h b/include/sys/types.h index 298414c408..cc6672d2c0 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -262,7 +262,7 @@ typedef FAR char *caddr_t; /* Task entry point */ -typedef CODE int (*main_t)(int argc, char *argv[]); +typedef CODE int (*main_t)(int argc, FAR char *argv[]); #endif /* __ASSEMBLY__ */ diff --git a/sched/init/Make.defs b/sched/init/Make.defs index eae5e2fa87..46c0718c8e 100644 --- a/sched/init/Make.defs +++ b/sched/init/Make.defs @@ -35,6 +35,10 @@ CSRCS += os_start.c os_bringup.c +ifeq ($(CONFIG_SMP),y) +CSRCS += os_smpstart.c +endif + # Include init build support DEPPATH += --dep-path init diff --git a/sched/init/init.h b/sched/init/init.h index 8d60a71694..d87b0341f3 100644 --- a/sched/init/init.h +++ b/sched/init/init.h @@ -1,7 +1,7 @@ /**************************************************************************** * sched/init/init.h * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -42,21 +42,10 @@ #include -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Public Type Definitions - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Public Function Prototypes ****************************************************************************/ + /**************************************************************************** * Name: os_start * @@ -75,6 +64,27 @@ void os_start(void); +/**************************************************************************** + * Name: os_smpstart + * + * Description: + * In an SMP configution, only one CPU is initially active (CPU 0). System + * initialization occurs on that single thread. At the completion of the + * initialization of the OS, just before beginning normal multitasking, + * the additional CPUs would be started by calling this function. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero on success; a negater errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SMP +int os_smpstart(void); +#endif + /**************************************************************************** * Name: os_bringup * diff --git a/sched/init/os_bringup.c b/sched/init/os_bringup.c index 405b93d0a9..1652a36b7f 100644 --- a/sched/init/os_bringup.c +++ b/sched/init/os_bringup.c @@ -124,22 +124,6 @@ # undef CONFIG_LIB_USRWORK #endif -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ diff --git a/sched/init/os_smpstart.c b/sched/init/os_smpstart.c new file mode 100644 index 0000000000..0bd33ffb8e --- /dev/null +++ b/sched/init/os_smpstart.c @@ -0,0 +1,156 @@ +/**************************************************************************** + * sched/init/os_smpstart.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +# include "init/init.h" + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: os_idletask + * + * Description: + * This is the common IDLE task for CPUs 1 through (CONFIG_SMP_NCPUS-1). + * It is equivalent to the CPU 0 IDLE logic in os_start.c + * + * Input Parameters: + * Standard task arguments. + * + * Returned Value: + * This function does not return. + * + ****************************************************************************/ + +int os_idletask(int argc, FAR char *argv[]) +{ + sdbg("CPU%d: Beginning Idle Loop\n"); + for (; ; ) + { + /* Perform garbage collection (if it is not being done by the worker + * thread). This cleans-up memory de-allocations that were queued + * because they could not be freed in that execution context (for + * example, if the memory was freed from an interrupt handler). + */ + +#ifndef CONFIG_SCHED_WORKQUEUE + /* We must have exclusive access to the memory manager to do this + * BUT the idle task cannot wait on a semaphore. So we only do + * the cleanup now if we can get the semaphore -- this should be + * possible because if the IDLE thread is running, no other task is! + * + * WARNING: This logic could have undesirable side-effects if priority + * inheritance is enabled. Imaginee the possible issues if the + * priority of the IDLE thread were to get boosted! Moral: If you + * use priority inheritance, then you should also enable the work + * queue so that is done in a safer context. + */ + + if (kmm_trysemaphore() == 0) + { + sched_garbagecollection(); + kmm_givesemaphore(); + } +#endif + + /* Perform any processor-specific idle state operations */ + + up_idle(); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: os_smpstart + * + * Description: + * In an SMP configution, only one CPU is initially active (CPU 0). System + * initialization occurs on that single thread. At the completion of the + * initialization of the OS, just before beginning normal multitasking, + * the additional CPUs would be started by calling this function. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero on success; a negater errno value on failure. + * + ****************************************************************************/ + +int os_smpstart(void) +{ + int ret; + int i; + + for (i = 1; i < CONFIG_SMP_NCPUS; i++) + { + ret = up_cpustart(i, os_idletask); +#ifdef CONFIG_DEBUG + if (ret < 0) + { + sdbg("ERROR: Failed to start CPU%d: %d\n", i, ret); + return ret; + } +#else + UNUSED(ret); +#endif + } + + return OK; +} + +#endif /* CONFIG_SMP */ diff --git a/sched/init/os_start.c b/sched/init/os_start.c index f64a33bae9..a9696c8943 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -588,6 +588,14 @@ void os_start(void) g_idletcb.cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT; #endif +#ifdef CONFIG_SMP + /* Start all CPUs *********************************************************/ + + DEBUGASSERT(this_cpu() == 0); + DEBUGVERIFY(os_smpstart()); + +#endif /* CONFIG_SMP */ + /* Bring Up the System ****************************************************/ /* The OS is fully initialized and we are beginning multi-tasking */ @@ -600,7 +608,7 @@ void os_start(void) /* The IDLE Loop **********************************************************/ /* When control is return to this point, the system is idle. */ - sdbg("Beginning Idle Loop\n"); + sdbg("CPU0: Beginning Idle Loop\n"); for (; ; ) { /* Perform garbage collection (if it is not being done by the worker diff --git a/sched/semaphore/spinlock.c b/sched/semaphore/spinlock.c index 20bb3d048a..ef6dd021a4 100644 --- a/sched/semaphore/spinlock.c +++ b/sched/semaphore/spinlock.c @@ -234,7 +234,7 @@ void spinunlock(FAR struct spinlock_s *lock) lock->sp_count = 0; lock->sp_cpu = IMPOSSIBLE_CPU; - lock->sp_lock = SP_UNLOCKED; + lock->sp_lock = SP_UNLOCKED; } else { @@ -248,7 +248,7 @@ void spinunlock(FAR struct spinlock_s *lock) /* Just mark the spinlock unlocked */ DEBUGASSERT(lock != NULL && lock->sp-lock = SP_LOCKED); - lock->sp_lock = SP_UNLOCKED; + lock->sp_lock = SP_UNLOCKED; #endif /* CONFIG_SMP */ }