summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/ChangeLog22
-rw-r--r--cpukit/aclocal/check-smp.m419
-rw-r--r--cpukit/aclocal/enable-smp.m418
-rw-r--r--cpukit/configure.ac7
-rw-r--r--cpukit/sapi/include/confdefs.h70
-rw-r--r--cpukit/sapi/src/exinit.c18
-rw-r--r--cpukit/score/Makefile.am7
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h18
-rw-r--r--cpukit/score/cpu/sparc/cpu_asm.S545
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h31
-rw-r--r--cpukit/score/include/rtems/bspsmp.h233
-rw-r--r--cpukit/score/include/rtems/score/basedefs.h13
-rw-r--r--cpukit/score/include/rtems/score/context.h17
-rw-r--r--cpukit/score/include/rtems/score/percpu.h131
-rw-r--r--cpukit/score/include/rtems/score/smplock.h95
-rw-r--r--cpukit/score/preinstall.am8
-rw-r--r--cpukit/score/src/percpu.c49
-rw-r--r--cpukit/score/src/smp.c153
-rw-r--r--cpukit/score/src/smplock.c49
-rw-r--r--cpukit/score/src/thread.c46
-rw-r--r--cpukit/score/src/threadcreateidle.c44
21 files changed, 995 insertions, 598 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog
index df9b122955..eee80b12c9 100644
--- a/cpukit/ChangeLog
+++ b/cpukit/ChangeLog
@@ -1,5 +1,27 @@
2011-03-16 Jennifer Averett <jennifer.averett@OARcorp.com>
+ PR 1729/cpukit
+ * configure.ac, sapi/include/confdefs.h, sapi/src/exinit.c,
+ score/Makefile.am, score/preinstall.am,
+ score/cpu/i386/rtems/score/cpu.h, score/cpu/sparc/cpu_asm.S,
+ score/cpu/sparc/rtems/score/cpu.h,
+ score/include/rtems/score/basedefs.h,
+ score/include/rtems/score/context.h,
+ score/include/rtems/score/percpu.h, score/src/percpu.c,
+ score/src/thread.c, score/src/threadcreateidle.c: Add next step in
+ SMP support. This adds an allocated array of the Per_CPU structures
+ to support multiple cpus vs a single instance of the structure which
+ is still used if SMP support is disabled. Configuration support is
+ also added to explicitly enable or disable SMP. But SMP can only be
+ enabled for the CPUs which will support it initially -- SPARC and
+ i386. With the stub BSP support, a BSP can be run as a single core
+ SMP system from an RTEMS data structure standpoint.
+ * aclocal/check-smp.m4, aclocal/enable-smp.m4,
+ score/include/rtems/bspsmp.h, score/include/rtems/score/smplock.h,
+ score/src/smp.c, score/src/smplock.c: New files.
+
+2011-03-16 Jennifer Averett <jennifer.averett@OARcorp.com>
+
PR 1743/cpu
* sapi/include/confdefs.h, score/Makefile.am, score/preinstall.am: Add
Simple Priority Scheduler as complement to existing Deterministic
diff --git a/cpukit/aclocal/check-smp.m4 b/cpukit/aclocal/check-smp.m4
new file mode 100644
index 0000000000..294f5c9d2c
--- /dev/null
+++ b/cpukit/aclocal/check-smp.m4
@@ -0,0 +1,19 @@
+dnl $Id$
+dnl
+AC_DEFUN([RTEMS_CHECK_SMP],
+[dnl
+AC_REQUIRE([RTEMS_ENABLE_SMP])dnl
+
+AC_CACHE_CHECK([whether CPU supports libposix],
+ rtems_cv_HAS_SMP,
+ [dnl
+ case "$RTEMS_CPU" in
+ *)
+ if test "${RTEMS_HAS_SMP}" = "yes"; then
+ rtems_cv_HAS_SMP="yes";
+ else
+ rtems_cv_HAS_SMP="disabled";
+ fi
+ ;;
+ esac])
+])
diff --git a/cpukit/aclocal/enable-smp.m4 b/cpukit/aclocal/enable-smp.m4
new file mode 100644
index 0000000000..84561f8bbd
--- /dev/null
+++ b/cpukit/aclocal/enable-smp.m4
@@ -0,0 +1,18 @@
+dnl $Id$
+
+AC_DEFUN([RTEMS_ENABLE_SMP],
+[
+## AC_BEFORE([$0], [RTEMS_CHECK_SMP])dnl
+
+AC_ARG_ENABLE(smp,
+[AS_HELP_STRING([--enable-smp],[enable smp interface])],
+[case "${enableval}" in
+ yes) case "${RTEMS_CPU}" in
+ sparc|i386) RTEMS_HAS_SMP=yes ;;
+ *) RTEMS_HAS_SMP=no ;;
+ esac
+ ;;
+ no) RTEMS_HAS_SMP=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for enable-smp option) ;;
+esac],[RTEMS_HAS_SMP=no])
+])
diff --git a/cpukit/configure.ac b/cpukit/configure.ac
index a1cc748264..4a771add3d 100644
--- a/cpukit/configure.ac
+++ b/cpukit/configure.ac
@@ -138,6 +138,7 @@ AC_CHECK_HEADER([signal.h],[
RTEMS_CHECK_MULTIPROCESSING
RTEMS_CHECK_POSIX_API
RTEMS_CHECK_NETWORKING
+RTEMS_CHECK_SMP
rtems_major=`echo _RTEMS_VERSION | sed "s/\..*//"`
rtems_minor=`echo _RTEMS_VERSION | sed "s/[[0-9]][[0-9]]*\.//;s/\..*//"`
@@ -169,6 +170,11 @@ RTEMS_CPUOPT([RTEMS_POSIX_API],
[1],
[if posix api is supported])
+RTEMS_CPUOPT([RTEMS_SMP],
+ [test x"$RTEMS_HAS_SMP" = xyes],
+ [1],
+ [if SMP is enabled])
+
RTEMS_CPUOPT([RTEMS_NETWORKING],
[test x"$rtems_cv_HAS_NETWORKING" = xyes],
[1],
@@ -290,6 +296,7 @@ AM_CONDITIONAL(LIBRPC,[test x"$rtems_cv_HAS_NETWORKING" = x"yes"])
AM_CONDITIONAL(NEWLIB,test x"$RTEMS_USE_NEWLIB" = x"yes")
AM_CONDITIONAL(HAS_MP,test x"$enable_multiprocessing" = x"yes" )
+AM_CONDITIONAL(HAS_SMP,[test "$RTEMS_HAS_SMP" = "yes"])
AM_CONDITIONAL(HAS_PTHREADS,test x"$rtems_cv_HAS_POSIX_API" = x"yes")
AM_CONDITIONAL(LIBNETWORKING,test x"$rtems_cv_HAS_NETWORKING" = x"yes")
diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index d194fed1bc..ad81403430 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -174,6 +174,21 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
extern int rtems_telnetd_maximum_ptys;
#endif
+#if defined(RTEMS_SMP)
+ /*
+ * If configured for SMP, then we need to know the maximum CPU cores.
+ */
+ #if !defined(CONFIGURE_SMP_APPLICATION)
+ #if !defined(CONFIGURE_SMP_MAXIMUM_PROCESSORS)
+ #define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
+ #endif
+ #else
+ #if !defined(CONFIGURE_SMP_MAXIMUM_PROCESSORS)
+ #error "CONFIGURE_SMP_MAXIMUM_PROCESSORS not specified for SMP Application"
+ #endif
+ #endif
+#endif
+
/*
* Filesystems and Mount Table Configuration.
*
@@ -1805,12 +1820,25 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
_Configure_Object_RAM(1, sizeof(API_Mutex_Control))
/**
- * This defines the amount of memory reserved for the IDLE task
- * control structures and stack.
+ * This defines the formula used to compute the amount of memory
+ * reserved for IDLE task control structures and stacks.
+ */
+#define CONFIGURE_IDLE_TASKS(_count) \
+ (CONFIGURE_MEMORY_FOR_TASKS(_count, 0) + \
+ _count * _Configure_From_workspace( \
+ (CONFIGURE_IDLE_TASK_STACK_SIZE - CONFIGURE_MINIMUM_TASK_STACK_SIZE)))
+
+/**
+ * This calculates the amount of memory reserved for the IDLE tasks.
+ * In an SMP system, each CPU core has its own idle task.
*/
-#define CONFIGURE_MEMORY_FOR_IDLE_TASK \
- (CONFIGURE_MEMORY_FOR_TASKS(1, 0) + \
- (CONFIGURE_IDLE_TASK_STACK_SIZE - CONFIGURE_MINIMUM_TASK_STACK_SIZE))
+#if defined(RTEMS_SMP)
+ #define CONFIGURE_MEMORY_FOR_IDLE_TASK \
+ CONFIGURE_IDLE_TASKS(CONFIGURE_SMP_MAXIMUM_PROCESSORS)
+#else
+ #define CONFIGURE_MEMORY_FOR_IDLE_TASK \
+ CONFIGURE_IDLE_TASKS(1)
+#endif
/**
* This macro accounts for general RTEMS system overhead.
@@ -1898,6 +1926,15 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
CONFIGURE_MEMORY_FOR_USER_EXTENSIONS(CONFIGURE_MAXIMUM_USER_EXTENSIONS) \
)
+#if defined(RTEMS_SMP)
+ #define CONFIGURE_MEMORY_FOR_SMP \
+ (CONFIGURE_SMP_MAXIMUM_PROCESSORS * \
+ _Configure_From_workspace( CONFIGURE_INTERRUPT_STACK_SIZE ) \
+ )
+#else
+ #define CONFIGURE_MEMORY_FOR_SMP 0
+#endif
+
#if defined(CONFIGURE_CONFDEFS_DEBUG) && defined(CONFIGURE_INIT)
/**
* This is a debug mechanism, so if you need to, the executable will
@@ -2012,10 +2049,11 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
CONFIGURE_MEMORY_FOR_CLASSIC + \
CONFIGURE_MEMORY_FOR_POSIX + \
(CONFIGURE_MAXIMUM_POSIX_THREADS * CONFIGURE_MINIMUM_TASK_STACK_SIZE ) + \
- (CONFIGURE_MAXIMUM_GOROUTINES * CONFIGURE_MINIMUM_TASK_STACK_SIZE ) + \
+ (CONFIGURE_MAXIMUM_GOROUTINES * CONFIGURE_MINIMUM_TASK_STACK_SIZE) + \
CONFIGURE_INITIALIZATION_THREADS_STACKS + \
CONFIGURE_MEMORY_FOR_STATIC_EXTENSIONS + \
CONFIGURE_MEMORY_FOR_MP + \
+ CONFIGURE_MEMORY_FOR_SMP + \
CONFIGURE_MESSAGE_BUFFER_MEMORY + \
(CONFIGURE_MEMORY_OVERHEAD * 1024) + \
(CONFIGURE_EXTRA_TASK_STACKS) + (CONFIGURE_ADA_TASKS_STACK) \
@@ -2117,6 +2155,26 @@ rtems_fs_init_functions_t rtems_fs_init_helper =
#endif /* CONFIGURE_HAS_OWN_CONFIGURATION_TABLE */
+#if defined(RTEMS_SMP)
+ /**
+ * Instantiate the variable which specifies the number of CPUs
+ * in an SMP configuration.
+ */
+ #if defined(CONFIGURE_INIT)
+ uint32_t rtems_smp_maximum_processors = CONFIGURE_SMP_MAXIMUM_PROCESSORS;
+ #else
+ extern uint32_t rtems_smp_maximum_processors;
+ #endif
+ /*
+ * Instantiate the Per CPU information based upon the user configuration.
+ */
+ #if defined(CONFIGURE_INIT)
+ Per_CPU_Control _Per_CPU_Information[CONFIGURE_SMP_MAXIMUM_PROCESSORS];
+ Per_CPU_Control *_Per_CPU_Information_p[CONFIGURE_SMP_MAXIMUM_PROCESSORS];
+ #endif
+
+#endif
+
/*
* If the user has configured a set of Classic API Initialization Tasks,
* then we need to install the code that runs that loop.
diff --git a/cpukit/sapi/src/exinit.c b/cpukit/sapi/src/exinit.c
index 2cbddfa1da..a431669641 100644
--- a/cpukit/sapi/src/exinit.c
+++ b/cpukit/sapi/src/exinit.c
@@ -1,7 +1,7 @@
/*
* Initialization Manager
*
- * COPYRIGHT (c) 1989-2008.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -57,6 +57,11 @@
#include <rtems/posix/posixapi.h>
#endif
+#if defined(RTEMS_SMP)
+ #include <rtems/bspsmp.h>
+ #include <rtems/score/percpu.h>
+#endif
+
Objects_Information *_Internal_Objects[ OBJECTS_INTERNAL_CLASSES_LAST + 1 ];
void rtems_initialize_data_structures(void)
@@ -114,6 +119,10 @@ void rtems_initialize_data_structures(void)
*/
_Workspace_Handler_initialization();
+ #if defined(RTEMS_SMP)
+ _SMP_Handler_initialize();
+ #endif
+
_User_extensions_Handler_initialization();
_ISR_Handler_initialization();
@@ -150,6 +159,13 @@ void rtems_initialize_data_structures(void)
_POSIX_API_Initialize();
#endif
+ /*
+ * Discover and initialize the secondary cores in an SMP system.
+ */
+ #if defined(RTEMS_SMP)
+ _SMP_Processor_count = bsp_smp_initialize( rtems_smp_maximum_processors );
+ #endif
+
_System_state_Set( SYSTEM_STATE_BEFORE_MULTITASKING );
/*
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index bdd8e510d9..9d3d97f593 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -12,7 +12,7 @@ SUBDIRS = cpu
include_rtemsdir = $(includedir)/rtems
include_rtems_HEADERS = include/rtems/debug.h include/rtems/system.h \
- include/rtems/seterr.h
+ include/rtems/seterr.h include/rtems/bspsmp.h
include_rtems_scoredir = $(includedir)/rtems/score
@@ -35,7 +35,8 @@ include_rtems_score_HEADERS = include/rtems/score/address.h \
include/rtems/score/timestamp64.h include/rtems/score/tod.h \
include/rtems/score/tqdata.h include/rtems/score/userext.h \
include/rtems/score/watchdog.h include/rtems/score/wkspace.h \
- include/rtems/score/cpuopts.h include/rtems/score/basedefs.h
+ include/rtems/score/cpuopts.h include/rtems/score/basedefs.h \
+ include/rtems/score/smplock.h
if HAS_PTHREADS
include_rtems_score_HEADERS += include/rtems/score/corespinlock.h \
@@ -88,6 +89,8 @@ if HAS_MP
libscore_a_SOURCES += src/mpci.c src/objectmp.c src/threadmp.c
endif
+libscore_a_SOURCES += src/smp.c src/smplock.c
+
## CORE_APIMUTEX_C_FILES
libscore_a_SOURCES += src/apimutex.c src/apimutexallocate.c \
src/apimutexlock.c src/apimutexunlock.c
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index e793b3372c..0e47c285bb 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -6,7 +6,7 @@
* This include file contains information pertaining to the Intel
* i386 processor.
*
- * COPYRIGHT (c) 1989-2008.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -270,8 +270,6 @@ typedef enum {
/* variables */
SCORE_EXTERN Context_Control_fp _CPU_Null_fp_context;
-SCORE_EXTERN void *_CPU_Interrupt_stack_low;
-SCORE_EXTERN void *_CPU_Interrupt_stack_high;
#endif /* ASM */
@@ -437,6 +435,20 @@ uint32_t _CPU_ISR_Get_level( void );
#define _CPU_Context_Restart_self( _the_context ) \
_CPU_Context_restore( (_the_context) );
+#if defined(RTEMS_SMP)
+ #define _CPU_Context_switch_to_first_task_smp( _the_context ) \
+ _CPU_Context_restore( (_the_context) );
+
+ /* address space 1 is uncacheable */
+ #define SMP_CPU_SWAP( _address, _value, _previous ) \
+ do { \
+ asm volatile("lock; xchgl %0, %1" : \
+ "+m" (*_address), "=a" (_previous) : \
+ "1" (_value) : \
+ "cc"); \
+ } while (0)
+#endif
+
#define _CPU_Context_Fp_start( _base, _offset ) \
( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index 363ce80ad9..fb9835d16a 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -4,7 +4,7 @@
* in an specific CPU port of RTEMS. These algorithms must be implemented
* in assembly language.
*
- * COPYRIGHT (c) 1989-2010.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -319,7 +319,6 @@ done_flushing:
*
* NOTE: It is unnecessary to reload some registers.
*/
-
.align 4
PUBLIC(_CPU_Context_restore)
SYM(_CPU_Context_restore):
@@ -327,532 +326,32 @@ SYM(_CPU_Context_restore):
rd %psr, %o2
ba SYM(_CPU_Context_restore_heir)
mov %i0, %o1 ! in the delay slot
+ .align 4
+#if defined(RTEMS_SMP)
/*
- * void _ISR_Handler()
- *
- * This routine provides the RTEMS interrupt management.
- *
- * We enter this handler from the 4 instructions in the trap table with
- * the following registers assumed to be set as shown:
- *
- * l0 = PSR
- * l1 = PC
- * l2 = nPC
- * l3 = trap type
+ * void _CPU_Context_switch_to_first_task_smp(
+ * Context_Control *new_context
+ * )
*
- * NOTE: By an executive defined convention, trap type is between 0 and 255 if
- * it is an asynchonous trap and 256 and 511 if it is synchronous.
+ * This routine is only used to switch to the first task on a
+ * secondary core in an SMP configuration. We do not need to
+ * flush all the windows and, in fact, this can be dangerous
+ * as they may or may not be initialized properly. So we just
+ * reinitialize the PSR and WIM.
*/
+ PUBLIC(_CPU_Context_switch_to_first_task_smp)
+SYM(_CPU_Context_switch_to_first_task_smp):
+ save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
- .align 4
- PUBLIC(_ISR_Handler)
-SYM(_ISR_Handler):
- /*
- * Fix the return address for synchronous traps.
- */
-
- andcc %l3, SPARC_SYNCHRONOUS_TRAP_BIT_MASK, %g0
- ! Is this a synchronous trap?
- be,a win_ovflow ! No, then skip the adjustment
- nop ! DELAY
- mov %l1, %l6 ! save trapped pc for debug info
- mov %l2, %l1 ! do not return to the instruction
- add %l2, 4, %l2 ! indicated
-
-win_ovflow:
- /*
- * Save the globals this block uses.
- *
- * These registers are not restored from the locals. Their contents
- * are saved directly from the locals into the ISF below.
- */
-
- mov %g4, %l4 ! save the globals this block uses
- mov %g5, %l5
-
- /*
- * When at a "window overflow" trap, (wim == (1 << cwp)).
- * If we get here like that, then process a window overflow.
- */
-
- rd %wim, %g4
- srl %g4, %l0, %g5 ! g5 = win >> cwp ; shift count and CWP
- ! are LS 5 bits ; how convenient :)
- cmp %g5, 1 ! Is this an invalid window?
- bne dont_do_the_window ! No, then skip all this stuff
- ! we are using the delay slot
-
- /*
- * The following is same as a 1 position right rotate of WIM
- */
-
- srl %g4, 1, %g5 ! g5 = WIM >> 1
- sll %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4
- ! g4 = WIM << (Number Windows - 1)
- or %g4, %g5, %g4 ! g4 = (WIM >> 1) |
- ! (WIM << (Number Windows - 1))
-
- /*
- * At this point:
- *
- * g4 = the new WIM
- * g5 is free
- */
-
- /*
- * Since we are tinkering with the register windows, we need to
- * make sure that all the required information is in global registers.
- */
-
- save ! Save into the window
- wr %g4, 0, %wim ! WIM = new WIM
- nop ! delay slots
- nop
- nop
-
- /*
- * Now save the window just as if we overflowed to it.
- */
-
- std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
- std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
- std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
- std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
-
- std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
- std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
- std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
- std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
-
- restore
- nop
-
-dont_do_the_window:
- /*
- * Global registers %g4 and %g5 are saved directly from %l4 and
- * %l5 directly into the ISF below.
- */
-
-save_isf:
-
- /*
- * Save the state of the interrupted task -- especially the global
- * registers -- in the Interrupt Stack Frame. Note that the ISF
- * includes a regular minimum stack frame which will be used if
- * needed by register window overflow and underflow handlers.
- *
- * REGISTERS SAME AS AT _ISR_Handler
- */
-
- sub %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
- ! make space for ISF
-
- std %l0, [%sp + ISF_PSR_OFFSET] ! save psr, PC
- st %l2, [%sp + ISF_NPC_OFFSET] ! save nPC
- st %g1, [%sp + ISF_G1_OFFSET] ! save g1
- std %g2, [%sp + ISF_G2_OFFSET] ! save g2, g3
- std %l4, [%sp + ISF_G4_OFFSET] ! save g4, g5 -- see above
- std %g6, [%sp + ISF_G6_OFFSET] ! save g6, g7
-
- std %i0, [%sp + ISF_I0_OFFSET] ! save i0, i1
- std %i2, [%sp + ISF_I2_OFFSET] ! save i2, i3
- std %i4, [%sp + ISF_I4_OFFSET] ! save i4, i5
- std %i6, [%sp + ISF_I6_FP_OFFSET] ! save i6/fp, i7
-
- rd %y, %g1
- st %g1, [%sp + ISF_Y_OFFSET] ! save y
- st %l6, [%sp + ISF_TPC_OFFSET] ! save real trapped pc
-
- mov %sp, %o1 ! 2nd arg to ISR Handler
-
- /*
- * Increment ISR nest level and Thread dispatch disable level.
- *
- * Register usage for this section:
- *
- * l4 = _Thread_Dispatch_disable_level pointer
- * l5 = per cpu info pointer
- * l6 = _Thread_Dispatch_disable_level value
- * l7 = _ISR_Nest_level value
- *
- * NOTE: It is assumed that l4 - l7 will be preserved until the ISR
- * nest and thread dispatch disable levels are unnested.
- */
-
- sethi %hi(SYM(_Thread_Dispatch_disable_level)), %l4
- ld [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))], %l6
-
- sethi %hi(_Per_CPU_Information), %l5
- add %l5, %lo(_Per_CPU_Information), %l5
-
- ld [%l5 + PER_CPU_ISR_NEST_LEVEL], %l7
-
- add %l6, 1, %l6
- st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
-
- add %l7, 1, %l7
- st %l7, [%l5 + PER_CPU_ISR_NEST_LEVEL]
-
- /*
- * If ISR nest level was zero (now 1), then switch stack.
- */
-
- mov %sp, %fp
- subcc %l7, 1, %l7 ! outermost interrupt handler?
- bnz dont_switch_stacks ! No, then do not switch stacks
-
- nop
- ld [%l5 + PER_CPU_INTERRUPT_STACK_HIGH], %sp
-
-dont_switch_stacks:
- /*
- * Make sure we have a place on the stack for the window overflow
- * trap handler to write into. At this point it is safe to
- * enable traps again.
- */
-
- sub %sp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
-
- /*
- * Check if we have an external interrupt (trap 0x11 - 0x1f). If so,
- * set the PIL in the %psr to mask off interrupts with lower priority.
- * The original %psr in %l0 is not modified since it will be restored
- * when the interrupt handler returns.
- */
-
- mov %l0, %g5
- and %l3, 0x0ff, %g4
-
-/* This is a fix for ERC32 with FPU rev.B or rev.C */
-
-#if defined(FPU_REVB)
-
-
- subcc %g4, 0x08, %g0
- be fpu_revb
- subcc %g4, 0x11, %g0
- bl dont_fix_pil
- subcc %g4, 0x1f, %g0
- bg dont_fix_pil
- sll %g4, 8, %g4
- and %g4, SPARC_PSR_PIL_MASK, %g4
- andn %l0, SPARC_PSR_PIL_MASK, %g5
- or %g4, %g5, %g5
- srl %l0, 12, %g4
- andcc %g4, 1, %g0
- be dont_fix_pil
- nop
- ba,a enable_irq
-
-
-fpu_revb:
- srl %l0, 12, %g4 ! check if EF is set in %psr
- andcc %g4, 1, %g0
- be dont_fix_pil ! if FPU disabled than continue as normal
- and %l3, 0xff, %g4
- subcc %g4, 0x08, %g0
- bne enable_irq ! if not a FPU exception then do two fmovs
- set __sparc_fq, %g4
- st %fsr, [%g4] ! if FQ is not empty and FQ[1] = fmovs
- ld [%g4], %g4 ! than this is bug 3.14
- srl %g4, 13, %g4
- andcc %g4, 1, %g0
- be dont_fix_pil
- set __sparc_fq, %g4
- std %fq, [%g4]
- ld [%g4+4], %g4
- set 0x81a00020, %g5
- subcc %g4, %g5, %g0
- bne,a dont_fix_pil2
- wr %l0, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
- ba,a simple_return
-
-enable_irq:
- or %g5, SPARC_PSR_PIL_MASK, %g4
- wr %g4, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
- nop; nop; nop
- fmovs %f0, %f0
- ba dont_fix_pil
- fmovs %f0, %f0
-
- .data
- .global __sparc_fq
- .align 8
-__sparc_fq:
- .word 0,0
-
- .text
-/* end of ERC32 FPU rev.B/C fix */
-
-#else
-
- subcc %g4, 0x11, %g0
- bl dont_fix_pil
- subcc %g4, 0x1f, %g0
- bg dont_fix_pil
- sll %g4, 8, %g4
- and %g4, SPARC_PSR_PIL_MASK, %g4
- andn %l0, SPARC_PSR_PIL_MASK, %g5
- ba pil_fixed
- or %g4, %g5, %g5
+ mov %psr, %g1 ! Initialize WIM
+ add %g1, 1, %g2
+ and %g2, 0x7, %g2
+ set 1, %g3
+ sll %g3, %g2, %g3
+ mov %g3, %wim
+ ba done_flushing
+ mov %i0, %o1 ! in the delay slot
#endif
-dont_fix_pil:
- or %g5, SPARC_PSR_PIL_MASK, %g5
-pil_fixed:
- wr %g5, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
-dont_fix_pil2:
-
- /*
- * Vector to user's handler.
- *
- * NOTE: TBR may no longer have vector number in it since
- * we just enabled traps. It is definitely in l3.
- */
-
- sethi %hi(SYM(_ISR_Vector_table)), %g4
- ld [%g4+%lo(SYM(_ISR_Vector_table))], %g4
- and %l3, 0xFF, %g5 ! remove synchronous trap indicator
- sll %g5, 2, %g5 ! g5 = offset into table
- ld [%g4 + %g5], %g4 ! g4 = _ISR_Vector_table[ vector ]
-
-
- ! o1 = 2nd arg = address of the ISF
- ! WAS LOADED WHEN ISF WAS SAVED!!!
- mov %l3, %o0 ! o0 = 1st arg = vector number
- call %g4, 0
- nop ! delay slot
-
- /*
- * Redisable traps so we can finish up the interrupt processing.
- * This is a VERY conservative place to do this.
- *
- * NOTE: %l0 has the PSR which was in place when we took the trap.
- */
-
- mov %l0, %psr ! **** DISABLE TRAPS ****
- nop; nop; nop
-
- /*
- * Decrement ISR nest level and Thread dispatch disable level.
- *
- * Register usage for this section:
- *
- * l4 = _Thread_Dispatch_disable_level pointer
- * l5 = _ISR_Nest_level pointer
- * l6 = _Thread_Dispatch_disable_level value
- * l7 = _ISR_Nest_level value
- */
-
- sub %l6, 1, %l6
- st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
-
- st %l7, [%l5 + PER_CPU_ISR_NEST_LEVEL]
-
- /*
- * If dispatching is disabled (includes nested interrupt case),
- * then do a "simple" exit.
- */
-
- orcc %l6, %g0, %g0 ! Is dispatching disabled?
- bnz simple_return ! Yes, then do a "simple" exit
- ! NOTE: Use the delay slot
- sethi %hi(SYM(_CPU_ISR_Dispatch_disable)), %l6
-
- ! Are we dispatching from a previous ISR in the interrupted thread?
- ld [%l6 + %lo(SYM(_CPU_ISR_Dispatch_disable))], %l7
- orcc %l7, %g0, %g0 ! Is this thread already doing an ISR?
- bnz simple_return ! Yes, then do a "simple" exit
- nop
-
-
- /*
- * If a context switch is necessary, then do fudge stack to
- * return to the interrupt dispatcher.
- */
-
- ldub [%l5 + PER_CPU_DISPATCH_NEEDED], %l5
-
- orcc %l5, %g0, %g0 ! Is thread switch necessary?
- bz simple_return ! no, then do a simple return
- nop
-
- /*
- * Invoke interrupt dispatcher.
- */
-
- PUBLIC(_ISR_Dispatch)
-SYM(_ISR_Dispatch):
- ! Set ISR dispatch nesting prevention flag
- mov 1,%l6
- sethi %hi(SYM(_CPU_ISR_Dispatch_disable)), %l5
- st %l6,[%l5 + %lo(SYM(_CPU_ISR_Dispatch_disable))]
-
- /*
- * The following subtract should get us back on the interrupted
- * tasks stack and add enough room to invoke the dispatcher.
- * When we enable traps, we are mostly back in the context
- * of the task and subsequent interrupts can operate normally.
- */
-
- sub %fp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
-
- or %l0, SPARC_PSR_ET_MASK, %l7 ! l7 = PSR with ET=1
- mov %l7, %psr ! **** ENABLE TRAPS ****
- nop
- nop
- nop
-isr_dispatch:
- call SYM(_Thread_Dispatch), 0
- nop
-
- /*
- * We invoked _Thread_Dispatch in a state similar to the interrupted
- * task. In order to safely be able to tinker with the register
- * windows and get the task back to its pre-interrupt state,
- * we need to disable interrupts disabled so we can safely tinker
- * with the register windowing. In particular, the CWP in the PSR
- * is fragile during this period. (See PR578.)
- */
- mov 2,%g1 ! syscall (disable interrupts)
- ta 0 ! syscall (disable interrupts)
-
- /*
- * While we had ISR dispatching disabled in this thread,
- * did we miss anything. If so, then we need to do another
- * _Thread_Dispatch before leaving this ISR Dispatch context.
- */
-
- sethi %hi(_Per_CPU_Information), %l5
- add %l5, %lo(_Per_CPU_Information), %l5
-
- ldub [%l5 + PER_CPU_DISPATCH_NEEDED], %l7
-
- orcc %l7, %g0, %g0 ! Is thread switch necesary?
- bz allow_nest_again ! No, then clear out and return
- nop
-
- ! Yes, then invoke the dispatcher
-dispatchAgain:
- mov 3,%g1 ! syscall (enable interrupts)
- ta 0 ! syscall (enable interrupts)
- ba isr_dispatch
- nop
-
-allow_nest_again:
-
- ! Zero out ISR stack nesting prevention flag
- sethi %hi(SYM(_CPU_ISR_Dispatch_disable)), %l5
- st %g0,[%l5 + %lo(SYM(_CPU_ISR_Dispatch_disable))]
-
- /*
- * The CWP in place at this point may be different from
- * that which was in effect at the beginning of the ISR if we
- * have been context switched between the beginning of this invocation
- * of _ISR_Handler and this point. Thus the CWP and WIM should
- * not be changed back to their values at ISR entry time. Any
- * changes to the PSR must preserve the CWP.
- */
-
-simple_return:
- ld [%fp + ISF_Y_OFFSET], %l5 ! restore y
- wr %l5, 0, %y
-
- ldd [%fp + ISF_PSR_OFFSET], %l0 ! restore psr, PC
- ld [%fp + ISF_NPC_OFFSET], %l2 ! restore nPC
- rd %psr, %l3
- and %l3, SPARC_PSR_CWP_MASK, %l3 ! want "current" CWP
- andn %l0, SPARC_PSR_CWP_MASK, %l0 ! want rest from task
- or %l3, %l0, %l0 ! install it later...
- andn %l0, SPARC_PSR_ET_MASK, %l0
-
- /*
- * Restore tasks global and out registers
- */
-
- mov %fp, %g1
-
- ! g1 is restored later
- ldd [%fp + ISF_G2_OFFSET], %g2 ! restore g2, g3
- ldd [%fp + ISF_G4_OFFSET], %g4 ! restore g4, g5
- ldd [%fp + ISF_G6_OFFSET], %g6 ! restore g6, g7
-
- ldd [%fp + ISF_I0_OFFSET], %i0 ! restore i0, i1
- ldd [%fp + ISF_I2_OFFSET], %i2 ! restore i2, i3
- ldd [%fp + ISF_I4_OFFSET], %i4 ! restore i4, i5
- ldd [%fp + ISF_I6_FP_OFFSET], %i6 ! restore i6/fp, i7
-
- /*
- * Registers:
- *
- * ALL global registers EXCEPT G1 and the input registers have
- * already been restored and thuse off limits.
- *
- * The following is the contents of the local registers:
- *
- * l0 = original psr
- * l1 = return address (i.e. PC)
- * l2 = nPC
- * l3 = CWP
- */
-
- /*
- * if (CWP + 1) is an invalid window then we need to reload it.
- *
- * WARNING: Traps should now be disabled
- */
-
- mov %l0, %psr ! **** DISABLE TRAPS ****
- nop
- nop
- nop
- rd %wim, %l4
- add %l0, 1, %l6 ! l6 = cwp + 1
- and %l6, SPARC_PSR_CWP_MASK, %l6 ! do the modulo on it
- srl %l4, %l6, %l5 ! l5 = win >> cwp + 1 ; shift count
- ! and CWP are conveniently LS 5 bits
- cmp %l5, 1 ! Is tasks window invalid?
- bne good_task_window
-
- /*
- * The following code is the same as a 1 position left rotate of WIM.
- */
-
- sll %l4, 1, %l5 ! l5 = WIM << 1
- srl %l4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
- ! l4 = WIM >> (Number Windows - 1)
- or %l4, %l5, %l4 ! l4 = (WIM << 1) |
- ! (WIM >> (Number Windows - 1))
-
- /*
- * Now restore the window just as if we underflowed to it.
- */
-
- wr %l4, 0, %wim ! WIM = new WIM
- nop ! must delay after writing WIM
- nop
- nop
- restore ! now into the tasks window
-
- ldd [%g1 + CPU_STACK_FRAME_L0_OFFSET], %l0
- ldd [%g1 + CPU_STACK_FRAME_L2_OFFSET], %l2
- ldd [%g1 + CPU_STACK_FRAME_L4_OFFSET], %l4
- ldd [%g1 + CPU_STACK_FRAME_L6_OFFSET], %l6
- ldd [%g1 + CPU_STACK_FRAME_I0_OFFSET], %i0
- ldd [%g1 + CPU_STACK_FRAME_I2_OFFSET], %i2
- ldd [%g1 + CPU_STACK_FRAME_I4_OFFSET], %i4
- ldd [%g1 + CPU_STACK_FRAME_I6_FP_OFFSET], %i6
- ! reload of sp clobbers ISF
- save ! Back to ISR dispatch window
-
-good_task_window:
-
- mov %l0, %psr ! **** DISABLE TRAPS ****
- nop; nop; nop
- ! and restore condition codes.
- ld [%g1 + ISF_G1_OFFSET], %g1 ! restore g1
- jmp %l1 ! transfer control and
- rett %l2 ! go back to tasks window
-
/* end of file */
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index ddc5badfe5..330f56c6a3 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -6,7 +6,7 @@
* This include file contains information pertaining to the port of
* the executive to the SPARC processor.
*
- * COPYRIGHT (c) 1989-2006.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -927,6 +927,35 @@ void _CPU_Context_restore(
Context_Control *new_context
) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
+#if defined(RTEMS_SMP)
+ /*
+ * _CPU_Context_switch_to_first_task_smp
+ *
+ * This routine is only used to switch to the first task on a
+ * secondary core in an SMP configuration. We do not need to
+ * flush all the windows and, in fact, this can be dangerous
+ * as they may or may not be initialized properly.
+ */
+ void _CPU_Context_switch_to_first_task_smp(
+ Context_Control *new_context
+ );
+
+ /* address space 1 is uncacheable */
+ #define SMP_CPU_SWAP( _address, _value, _previous ) \
+ do { \
+ register unsigned int _val = _value; \
+ asm volatile( \
+ "swapa [%2] %3, %0" : \
+ "=r" (_val) : \
+ "0" (_val), \
+ "r" (_address), \
+ "i" (1) \
+ ); \
+ _previous = _val; \
+ } while (0)
+
+#endif
+
/*
* _CPU_Context_save_fp
*
diff --git a/cpukit/score/include/rtems/bspsmp.h b/cpukit/score/include/rtems/bspsmp.h
new file mode 100644
index 0000000000..26da0a7614
--- /dev/null
+++ b/cpukit/score/include/rtems/bspsmp.h
@@ -0,0 +1,233 @@
+/**
+ * @file rtems/bspsmp.h
+ *
+ * This include file defines the interface between RTEMS and an
+ * SMP aware BSP. These methods will only be used when RTEMS
+ * is configured with SMP support enabled.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_BSPSMP_H
+#define _RTEMS_BSPSMP_H
+
+#if defined (RTEMS_SMP)
+#include <rtems/score/percpu.h>
+
+/**
+ * @defgroup RTEMS BSP SMP Interface
+ *
+ * This defines the interface between RTEMS and the BSP for
+ * SMP support. The interface uses the term primary
+ * to refer to the "boot" processor and secondary to refer
+ * to the "application" processors. Different architectures
+ * use different terminology.
+ *
+ * It is assumed that when the processor is reset and thus
+ * when RTEMS is initialized, that the primary processor is
+ * the only one executing. The others are assumed to be in
+ * a quiescent or reset state awaiting a command to come online.
+ */
+
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This defines the bit which indicates the interprocessor interrupt
+ * has been requested so that RTEMS will reschedule on this CPU
+ * because the currently executing thread needs to be switched out.
+ */
+#define RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY 0x01
+
+/**
+ * This defines the bit which indicates the interprocessor interrupt
+ * has been requested so that RTEMS will reschedule on this CPU
+ * because the currently executing thread has been sent a signal.
+ */
+#define RTEMS_BSP_SMP_SIGNAL_TO_SELF 0x02
+
+/**
+ * This defines the bit which indicates the interprocessor interrupt
+ * has been requested so that this CPU will be shutdown. This is done
+ * as part of rtems_executive_shutdown().
+ */
+#define RTEMS_BSP_SMP_SHUTDOWN 0x04
+
+/**
+ * This defines the bit which indicates the interprocessor interrupt
+ * has been requested that the receiving CPU needs to perform a context
+ * switch to the first task.
+ */
+#define RTEMS_BSP_SMP_FIRST_TASK 0x08
+
+#ifndef ASM
+/**
+ * @brief Number of CPUs in SMP System
+ *
+ * This variable is set during the SMP initialization sequence to
+ * indicate the number of CPUs in this system.
+ */
+SCORE_EXTERN uint32_t _SMP_Processor_count;
+
+/**
+ * @brief Maximum Number of CPUs in SMP System
+ *
+ * This variable is set during the SMP initialization sequence to
+ * indicate the Maximum number of CPUs in this system.
+ */
+extern uint32_t rtems_smp_maximum_processors;
+
+/**
+ * @brief Initialize Secondary CPUs
+ *
+ * This method is invoked by RTEMS during initialization to bring the
+ * secondary CPUs out of reset.
+ *
+ * @param [in] maximum is the maximum number of CPU cores that RTEMS
+ * can handle
+ *
+ * @return This method returns the number of cores available in the
+ * system.
+ */
+int bsp_smp_initialize(
+ int maximum
+);
+
+/**
+ * @brief Obtain Current CPU Index
+ *
+ * This method is invoked by RTEMS when it needs to know the index
+ * of the CPU it is executing on.
+ *
+ * @return This method returns the current CPU index.
+ */
+int bsp_smp_processor_id(void) RTEMS_COMPILER_PURE_ATTRIBUTE;
+
+/**
+ * @brief Make Request of Another CPU
+ *
+ * This method is invoked by RTEMS when it needs to make a request
+ * of another CPU. It should be implemented using some type of
+ * interprocessor interrupt.
+ *
+ * @param [in] cpu is the target CPU for this request.
+ * @param [in] message is message to send
+ */
+void bsp_smp_send_message(
+ int cpu,
+ uint32_t message
+);
+
+/**
+ * @brief Make Request of Others CPUs
+ *
+ * This method is invoked by RTEMS when it needs to make a request
+ * of the other CPUs. It should be implemented using some type of
+ * interprocessor interrupt. CPUs not including the originating
+ * CPU should receive the message.
+ *
+ * @param [in] message is message to send
+ */
+void bsp_smp_broadcast_message(
+ uint32_t message
+);
+
+/**
+ * @brief Generate a Interprocessor Broadcast Interrupt
+ *
+ * This method is invoked when RTEMS wants to let all of the other
+ * CPUs know that it has sent them message. CPUs not including
+ * the originating CPU should receive the interrupt.
+
+ *
+ * @note On CPUs without the capability to generate a broadcast
+ * to all other CPUs interrupt, this can be implemented by
+ * a loop of sending interrupts to specific CPUs.
+ */
+void bsp_smp_broadcast_interrupt(void);
+
+/**
+ * @brief Generate a Interprocessor Interrupt
+ *
+ * This method is invoked by RTEMS to let @a cpu know that it
+ * has sent it a message.
+ *
+ * @param [in] cpu is the recipient CPU
+ */
+void bsp_smp_interrupt_cpu(
+ int cpu
+);
+
+/**
+ * @brief Obtain CPU Core Number
+ *
+ * This method is invoked by RTEMS when it needs to know which core
+ * number it is executing on. This is used when it needs to perform
+ * some action or bookkeeping and needs to distinguish itself from
+ * the other cores. For example, it may need to realize it needs to
+ * preempt a thread on another node.
+ *
+ * @return This method returns the Id of the current CPU core.
+ */
+int bsp_smp_processor_id( void );
+
+/**
+ * This method is invoked by @ref rtems_smp_secondary_cpu_initialize
+ * to allow the BSP to perform some intialization. The @a cpu
+ * parameter indicates the secondary CPU that the code is executing on
+ * and is currently being initialized.
+ *
+ * @note This is called by @ref rtems_smp_secondary_cpu_initialize.
+ */
+void bsp_smp_secondary_cpu_initialize(int cpu);
+
+/**
+ * This method is the C entry point which secondary CPUs should
+ * arrange to call. It performs OS initialization for the secondary
+ * CPU and coordinates bring it to a useful state.
+ *
+ * @note This is provided by RTEMS.
+ */
+void rtems_smp_secondary_cpu_initialize(void);
+
+/**
+ * This method is invoked by the BSP to initialize the per CPU structure
+ * for the specified @a cpu while it is bringing the secondary CPUs
+ * out of their reset state and into a useful state.
+ *
+ * @param [in] cpu indicates the CPU whose per cpu structure is to
+ * be initialized.
+ */
+void rtems_smp_initialize_per_cpu(int cpu);
+
+/**
+ * This is the method called by the BSP's interrupt handler
+ * to process the incoming interprocessor request.
+ */
+void rtems_smp_process_interrupt(void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#else
+ #define bsp_smp_processor_id() 0
+#endif
+
+#endif
+
+/* end of include file */
diff --git a/cpukit/score/include/rtems/score/basedefs.h b/cpukit/score/include/rtems/score/basedefs.h
index 6bb03459e6..b956806313 100644
--- a/cpukit/score/include/rtems/score/basedefs.h
+++ b/cpukit/score/include/rtems/score/basedefs.h
@@ -136,6 +136,19 @@
#endif
/**
+ * The following defines a compiler specific attribute which informs
+ * the compiler that the method has no effect except the return value
+ * and that the return value depends only on parameters and/or global
+ * variables.
+ */
+#ifdef __GNUC__
+ #define RTEMS_COMPILER_PURE_ATTRIBUTE \
+ __attribute__ ((pure))
+#else
+ #define RTEMS_COMPILER_PURE_ATTRIBUTE
+#endif
+
+/**
* Instructs the compiler to issue a warning whenever a variable or function
* with this attribute will be used.
*/
diff --git a/cpukit/score/include/rtems/score/context.h b/cpukit/score/include/rtems/score/context.h
index cdef1d3fa5..34baf32669 100644
--- a/cpukit/score/include/rtems/score/context.h
+++ b/cpukit/score/include/rtems/score/context.h
@@ -101,6 +101,23 @@ extern "C" {
#define _Context_Restart_self( _the_context ) \
_CPU_Context_Restart_self( _the_context )
+#if defined(RTEMS_SMP)
+/*
+ * @brief Switch to First Task on Secondary Core
+ *
+ * This routine is only used to switch to the first task on a
+ * secondary core in an SMP configuration. Since the switch
+ * to the first task is done from an interrupt handler, this
+ * may be different from simply restarting the currently running
+ * task.
+ *
+ * @param[in] _the_context is the context of the first thread to
+ * run on this core
+ */
+#define _Context_Switch_to_first_task_smp( _the_context ) \
+ _CPU_Context_switch_to_first_task_smp( _the_context )
+#endif
+
/**
* @brief Return Starting Address of Floating Point Context
*
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 2778573481..0c48b50570 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -6,14 +6,14 @@
*/
/*
- * COPYRIGHT (c) 1989-2010.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
- * $Id$
+ * $Id$
*/
#ifndef _RTEMS_PERCPU_H
@@ -23,6 +23,11 @@
#ifdef ASM
#include <rtems/asm.h>
+#else
+ #if defined(RTEMS_SMP)
+ #include <rtems/score/smplock.h>
+ #endif
+ #include <rtems/bspsmp.h>
#endif
/**
@@ -41,11 +46,35 @@ extern "C" {
#endif
#ifndef ASM
-
-/**
- * This forward defines the Thread Control Block structure.
- */
+#ifndef __THREAD_CONTROL_DEFINED__
+#define __THREAD_CONTROL_DEFINED__
typedef struct Thread_Control_struct Thread_Control;
+#endif
+
+#if (CPU_ALLOCATE_INTERRUPT_STACK == FALSE) && defined(RTEMS_SMP)
+ #error "RTEMS must allocate per CPU interrupt stack for SMP"
+#endif
+
+typedef enum {
+
+ /**
+ * This defines the constant used to indicate that the cpu code is in
+ * its initial powered up start.
+ */
+ RTEMS_BSP_SMP_CPU_INITIAL_STATE = 1,
+
+ /**
+ * This defines the constant used to indicate that the cpu code has
+ * completed basic initialization and awaits further commands.
+ */
+ RTEMS_BSP_SMP_CPU_INITIALIZED = 2,
+
+ /**
+ * This defines the constant used to indicate that the cpu code has
+ * shut itself down.
+ */
+ RTEMS_BSP_SMP_CPU_SHUTDOWN = 3
+} bsp_smp_cpu_state;
/**
* @brief Per CPU Core Structure
@@ -53,6 +82,22 @@ typedef struct Thread_Control_struct Thread_Control;
* This structure is used to hold per core state information.
*/
typedef struct {
+ #if defined(RTEMS_SMP)
+ /** This element is used to lock this structure */
+ SMP_lock_Control lock;
+
+ /** This indicates that the CPU is online. */
+ uint32_t state;
+
+ /**
+ * This is the request for the interrupt.
+ *
+ * @note This may become a chain protected by atomic instructions.
+ */
+ uint32_t message;
+
+ #endif
+
#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
(CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
/**
@@ -69,7 +114,6 @@ typedef struct {
#endif
/**
- *
* This contains the current interrupt nesting level on this
* CPU.
*/
@@ -91,6 +135,14 @@ typedef struct {
#endif
#ifdef ASM
+#if defined(RTEMS_SMP)
+ #define PER_CPU_LOCK 0
+ #define PER_CPU_STATE (1 * __RTEMS_SIZEOF_VOID_P__)
+ #define PER_CPU_MESSAGE (2 * __RTEMS_SIZEOF_VOID_P__)
+ #define PER_CPU_END_SMP (3 * __RTEMS_SIZEOF_VOID_P__)
+#else
+ #define PER_CPU_END_SMP 0
+#endif
#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
(CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
@@ -98,14 +150,13 @@ typedef struct {
* If this CPU target lets RTEMS allocates the interrupt stack, then
* we need to have places in the per cpu table to hold them.
*/
- #define PER_CPU_INTERRUPT_STACK_LOW 0
- #define PER_CPU_INTERRUPT_STACK_HIGH (1 * __RTEMS_SIZEOF_VOID_P__)
- #define PER_CPU_END_STACK (2 * __RTEMS_SIZEOF_VOID_P__)
+ #define PER_CPU_INTERRUPT_STACK_LOW PER_CPU_END_SMP
+ #define PER_CPU_INTERRUPT_STACK_HIGH \
+ PER_CPU_INTERRUPT_STACK_LOW + (1 * __RTEMS_SIZEOF_VOID_P__)
+ #define PER_CPU_END_STACK \
+ PER_CPU_INTERRUPT_STACK_HIGH + (1 * __RTEMS_SIZEOF_VOID_P__)
#else
- /*
- * Otherwise, there are no interrupt stack addresses in the per CPU table.
- */
- #define PER_CPU_END_STACK 0
+ #define PER_CPU_END_STACK PER_CPU_END_SMP
#endif
/*
@@ -147,20 +198,52 @@ typedef struct {
*
* This is an array of per CPU core information.
*/
-extern Per_CPU_Control _Per_CPU_Information;
+extern Per_CPU_Control _Per_CPU_Information[];
+
+#if defined(RTEMS_SMP)
+/**
+ * @brief Set of Pointers to Per CPU Core Information
+ *
+ * This is an array of pointers to each CPU's per CPU data structure.
+ * It should be simpler to retrieve this pointer in assembly language
+ * that to calculate the array offset.
+ */
+extern Per_CPU_Control *_Per_CPU_Information_p[];
+
+/**
+ * @brief Initialize SMP Handler
+ *
+ * This method initialize the SMP Handler.
+ */
+void _SMP_Handler_initialize(void);
+
+/**
+ * @brief Allocate and Initialize Per CPU Structures
+ *
+ * This method allocates and initialize the per CPU structure.
+ */
+void _Per_CPU_Initialize(void);
+
+#endif
/*
- * On an SMP system, these macros dereference the CPU core number.
- * But on a non-SMP system, these macros are simple references.
+ * On a non SMP system, the bsp_smp_processor_id is defined to 0.
* Thus when built for non-SMP, there should be no performance penalty.
*/
-#define _Thread_Heir _Per_CPU_Information.heir
-#define _Thread_Executing _Per_CPU_Information.executing
-#define _Thread_Idle _Per_CPU_Information.idle
-#define _ISR_Nest_level _Per_CPU_Information.isr_nest_level
-#define _CPU_Interrupt_stack_low _Per_CPU_Information.interrupt_stack_low
-#define _CPU_Interrupt_stack_high _Per_CPU_Information.interrupt_stack_high
-#define _Thread_Dispatch_necessary _Per_CPU_Information.dispatch_necessary
+#define _Thread_Heir \
+ _Per_CPU_Information[bsp_smp_processor_id()].heir
+#define _Thread_Executing \
+ _Per_CPU_Information[bsp_smp_processor_id()].executing
+#define _Thread_Idle \
+ _Per_CPU_Information[bsp_smp_processor_id()].idle
+#define _ISR_Nest_level \
+ _Per_CPU_Information[bsp_smp_processor_id()].isr_nest_level
+#define _CPU_Interrupt_stack_low \
+ _Per_CPU_Information[bsp_smp_processor_id()].interrupt_stack_low
+#define _CPU_Interrupt_stack_high \
+ _Per_CPU_Information[bsp_smp_processor_id()].interrupt_stack_high
+#define _Thread_Dispatch_necessary \
+ _Per_CPU_Information[bsp_smp_processor_id()].dispatch_necessary
#endif /* ASM */
diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h
new file mode 100644
index 0000000000..a20d9260a4
--- /dev/null
+++ b/cpukit/score/include/rtems/score/smplock.h
@@ -0,0 +1,95 @@
+/**
+ * @file rtems/score/smplock.h
+ *
+ * This include file defines the interface for atomic locks
+ * which can be used in multiprocessor configurations.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_LOCK_H
+#define _RTEMS_LOCK_H
+
+#include <rtems/score/isr.h>
+
+/**
+ * @defgroup RTEMS Lock Interface
+ *
+ */
+
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This type is used to lock elements for atomic access.
+ *
+ * @note This type may move to RTEMS.
+ */
+typedef volatile uint32_t SMP_lock_Control;
+
+/**
+ * @brief Initialize a Lock
+ *
+ * This method is used to initialize the lock at @a lock.
+ *
+ * @param [in] lock is the address of the lock to obtain.
+ *
+ * @note This lock may be "too low" here. It may need to move
+ * out of the BSP area.
+ */
+void _SMP_lock_Spinlock_Initialize(
+ SMP_lock_Control *lock
+);
+
+/**
+ * @brief Obtain a Lock
+ *
+ * This method is used to obtain the lock at @a lock.
+ *
+ * @param [in] lock is the address of the lock to obtain.
+ *
+ * @return This method returns with processor interrupts disabled.
+ * The previous level is returned.
+ *
+ * @note This lock may be "too low" here. It may need to move
+ * out of the BSP area.
+ */
+ISR_Level _SMP_lock_Spinlock_Obtain(
+ SMP_lock_Control *lock
+);
+
+/**
+ * @brief Release a Lock
+ *
+ * This method is used to release the lock at @a lock.
+ *
+ * @param [in] lock is the address of the lock to obtain.
+ *
+ * @note This lock may be "too low" here. It may need to move
+ * out of the BSP area.
+ */
+void _SMP_lock_Spinlock_Release(
+ SMP_lock_Control *lock,
+ ISR_Level level
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif
+/* end of include file */
diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am
index e188eb7fe1..6979313a19 100644
--- a/cpukit/score/preinstall.am
+++ b/cpukit/score/preinstall.am
@@ -30,6 +30,10 @@ $(PROJECT_INCLUDE)/rtems/seterr.h: include/rtems/seterr.h $(PROJECT_INCLUDE)/rte
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/seterr.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/seterr.h
+$(PROJECT_INCLUDE)/rtems/bspsmp.h: include/rtems/bspsmp.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bspsmp.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bspsmp.h
+
$(PROJECT_INCLUDE)/rtems/score/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/score
@: > $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
@@ -187,6 +191,10 @@ $(PROJECT_INCLUDE)/rtems/score/basedefs.h: include/rtems/score/basedefs.h $(PROJ
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/basedefs.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/basedefs.h
+$(PROJECT_INCLUDE)/rtems/score/smplock.h: include/rtems/score/smplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smplock.h
+
if HAS_PTHREADS
$(PROJECT_INCLUDE)/rtems/score/corespinlock.h: include/rtems/score/corespinlock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/corespinlock.h
diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c
index 4c719af6db..2d429b4db9 100644
--- a/cpukit/score/src/percpu.c
+++ b/cpukit/score/src/percpu.c
@@ -1,5 +1,5 @@
/*
- * COPYRIGHT (c) 1989-2010.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -19,11 +19,46 @@
#include <rtems/score/wkspace.h>
#include <rtems/score/wkspace.h>
#include <rtems/config.h>
+#include <rtems/bspsmp.h>
#include <string.h>
-/*
- * On single core systems, we can efficiently directly access a single
- * statically allocated per cpu structure. And the fields are initialized
- * as individual elements just like it has always been done.
- */
-Per_CPU_Control _Per_CPU_Information;
+#if defined(RTEMS_SMP)
+ void _SMP_Handler_initialize(void)
+ {
+ int cpu;
+ size_t size;
+ uintptr_t ptr;
+
+ /*
+ * Initialize per CPU structures.
+ */
+ size = (_SMP_Processor_count) * sizeof(Per_CPU_Control);
+ memset( _Per_CPU_Information, '\0', size );
+
+ /*
+ * Initialize per cpu pointer table
+ */
+ size = Configuration.interrupt_stack_size;
+ _Per_CPU_Information_p[0] = &_Per_CPU_Information[0];
+ for (cpu=1 ; cpu < _SMP_Processor_count ; cpu++ ) {
+ Per_CPU_Control *p = &_Per_CPU_Information[cpu];
+
+ _Per_CPU_Information_p[cpu] = p;
+
+ p->interrupt_stack_low = _Workspace_Allocate_or_fatal_error( size );
+
+ ptr = (uintptr_t) _Addresses_Add_offset( p->interrupt_stack_low, size );
+ ptr &= ~CPU_STACK_ALIGNMENT;
+ p->interrupt_stack_high = (void *)ptr;
+ p->state = RTEMS_BSP_SMP_CPU_INITIAL_STATE;
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ }
+ }
+#else
+ /*
+ * On single core systems, we can efficiently directly access a single
+ * statically allocated per cpu structure. And the fields are initialized
+ * as individual elements just like it has always been done.
+ */
+ Per_CPU_Control _Per_CPU_Information[1];
+#endif
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
new file mode 100644
index 0000000000..4a0c13947f
--- /dev/null
+++ b/cpukit/score/src/smp.c
@@ -0,0 +1,153 @@
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/system.h>
+#include <rtems/bspsmp.h>
+#include <rtems/score/thread.h>
+
+#if defined(RTEMS_SMP)
+#define SMP_DEBUG
+
+#if defined(SMP_DEBUG)
+ #include <rtems/bspIo.h>
+#endif
+
+void rtems_smp_run_first_task(int cpu)
+{
+ Thread_Control *heir;
+
+ /*
+ * This CPU has an heir thread so we need to dispatch it.
+ */
+ heir = _Thread_Heir;
+
+ /*
+ * This is definitely a hack until we have SMP scheduling. Since there
+ * is only one executing and heir right now, we have to fake this out.
+ */
+ _Thread_Dispatch_disable_level = 1;
+ _Thread_Executing = heir;
+ _CPU_Context_switch_to_first_task_smp( &heir->Registers );
+}
+
+void rtems_smp_secondary_cpu_initialize(void)
+{
+ int cpu;
+
+ cpu = bsp_smp_processor_id();
+
+ bsp_smp_secondary_cpu_initialize(cpu);
+
+ #if defined(SMP_DEBUG)
+ printk( "Made it to %d -- ", cpu );
+ #endif
+
+ /*
+ * Inform the primary CPU that this secondary CPU is initialized
+ * and ready to dispatch to the first thread it is supposed to
+ * execute when the primary CPU is ready.
+ */
+ _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED;
+
+ /*
+ * HACK: Should not have to enable interrupts in real system here.
+ * It should happen as part of switching to the first task.
+ */
+
+ _Per_CPU_Information[cpu].isr_nest_level = 1;
+ _ISR_Set_level( 0 );
+ while(1) ;
+}
+
+void rtems_smp_process_interrupt(void)
+{
+ int cpu;
+ uint32_t message;
+ ISR_Level level;
+
+ cpu = bsp_smp_processor_id();
+
+ level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
+ message = _Per_CPU_Information[cpu].message;
+ _Per_CPU_Information[cpu].message &= ~message;
+ _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
+
+ #if defined(SMP_DEBUG)
+ {
+ void *sp = __builtin_frame_address(0);
+ if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) )
+ printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", cpu, message, sp );
+ printk( "Dispatch level %d\n", _Thread_Dispatch_disable_level );
+ }
+ #endif
+
+ if ( message & RTEMS_BSP_SMP_FIRST_TASK ) {
+ _Per_CPU_Information[cpu].isr_nest_level = 0;
+ _Per_CPU_Information[cpu].message = 0;
+ _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED;
+ rtems_smp_run_first_task(cpu);
+ /* does not return */
+ }
+
+ if ( message & RTEMS_BSP_SMP_SHUTDOWN ) {
+ ISR_Level level;
+ _Thread_Dispatch_disable_level = 0;
+ _Per_CPU_Information[cpu].isr_nest_level = 0;
+ _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_SHUTDOWN;
+ _ISR_Disable( level );
+ while(1)
+ ;
+ /* does not continue past here */
+ }
+
+ if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ) {
+ printk( "switch needed\n" );
+ _Per_CPU_Information[cpu].dispatch_necessary = true;
+ }
+}
+
+void rtems_smp_send_message(
+ int cpu,
+ uint32_t message
+)
+{
+ ISR_Level level;
+
+ level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
+ _Per_CPU_Information[cpu].message |= message;
+ _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
+ bsp_smp_interrupt_cpu( cpu );
+}
+
+void rtems_smp_broadcast_message(
+ uint32_t message
+)
+{
+ int dest_cpu;
+ int cpu;
+ ISR_Level level;
+
+ cpu = bsp_smp_processor_id();
+
+ for ( dest_cpu=0 ; dest_cpu < _SMP_Processor_count; dest_cpu++ ) {
+ if ( cpu == dest_cpu )
+ continue;
+ level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
+ _Per_CPU_Information[dest_cpu].message |= message;
+ _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
+ }
+ bsp_smp_broadcast_interrupt();
+}
+#endif
diff --git a/cpukit/score/src/smplock.c b/cpukit/score/src/smplock.c
new file mode 100644
index 0000000000..1dd691835b
--- /dev/null
+++ b/cpukit/score/src/smplock.c
@@ -0,0 +1,49 @@
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/system.h>
+#include <rtems/score/smplock.h>
+
+void _SMP_lock_Spinlock_Initialize(
+ SMP_lock_Control *lock
+)
+{
+ *lock = 0;
+}
+
+ISR_Level _SMP_lock_Spinlock_Obtain(
+ SMP_lock_Control *lock
+)
+{
+ ISR_Level level;
+ uint32_t value = 1;
+ uint32_t previous;
+
+ /* Note: Disable provides an implicit memory barrier. */
+ _ISR_Disable( level );
+ do {
+ SMP_CPU_SWAP( lock, value, previous );
+ } while (previous == 1);
+ return level;
+}
+
+void _SMP_lock_Spinlock_Release(
+ SMP_lock_Control *lock,
+ ISR_Level level
+)
+{
+ *lock = 0;
+ _ISR_Enable( level );
+}
diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c
index 6284e4b3e3..7a0eb38502 100644
--- a/cpukit/score/src/thread.c
+++ b/cpukit/score/src/thread.c
@@ -2,7 +2,7 @@
* Thread Handler
*
*
- * COPYRIGHT (c) 1989-2008.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -33,8 +33,11 @@
#include <rtems/score/wkspace.h>
#include <rtems/config.h>
-/*PAGE
- *
+#if defined(RTEMS_SMP)
+ #include <rtems/bspsmp.h>
+#endif
+
+/*
* _Thread_Handler_initialization
*
* This routine initializes all thread manager related data structures.
@@ -48,6 +51,7 @@ void _Thread_Handler_initialization(void)
{
uint32_t ticks_per_timeslice;
uint32_t maximum_extensions;
+ uint32_t maximum_internal_threads;
#if defined(RTEMS_MULTIPROCESSING)
uint32_t maximum_proxies;
#endif
@@ -80,32 +84,40 @@ void _Thread_Handler_initialization(void)
_Thread_Ticks_per_timeslice = ticks_per_timeslice;
-#if defined(RTEMS_MULTIPROCESSING)
- _Thread_MP_Handler_initialization( maximum_proxies );
-#endif
+ #if defined(RTEMS_MULTIPROCESSING)
+ _Thread_MP_Handler_initialization( maximum_proxies );
+ #endif
/*
- * Initialize this class of objects.
+ * Initialize the internal class of threads. We need an IDLE thread
+ * per CPU in an SMP system. In addition, if this is a loosely
+ * coupled multiprocessing system, account for the MPCI Server Thread.
*/
+ #if defined(RTEMS_SMP)
+ maximum_internal_threads = rtems_smp_maximum_processors;
+ #else
+ maximum_internal_threads = 1;
+ #endif
+
+ #if defined(RTEMS_MULTIPROCESSING)
+ if ( _System_state_Is_multiprocessing )
+ maximum_internal_threads += 1;
+ #endif
_Objects_Initialize_information(
&_Thread_Internal_information,
OBJECTS_INTERNAL_API,
OBJECTS_INTERNAL_THREADS,
-#if defined(RTEMS_MULTIPROCESSING)
- ( _System_state_Is_multiprocessing ) ? 2 : 1,
-#else
- 1,
-#endif
+ maximum_internal_threads,
sizeof( Thread_Control ),
/* size of this object's control block */
false, /* true if names for this object are strings */
8 /* maximum length of each object's name */
-#if defined(RTEMS_MULTIPROCESSING)
- ,
- false, /* true if this is a global object class */
- NULL /* Proxy extraction support callout */
-#endif
+ #if defined(RTEMS_MULTIPROCESSING)
+ ,
+ false, /* true if this is a global object class */
+ NULL /* Proxy extraction support callout */
+ #endif
);
}
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index bea6a23b89..6a4bf65e9c 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -2,7 +2,7 @@
* Thread Handler
*
*
- * COPYRIGHT (c) 1989-2008.
+ * COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -30,24 +30,24 @@
#include <rtems/score/userext.h>
#include <rtems/score/wkspace.h>
#include <rtems/config.h>
+#include <rtems/bspsmp.h>
-/*PAGE
- *
- * _Thread_Create_idle
- */
-
-void _Thread_Create_idle( void )
+static inline void _Thread_Create_idle_helper(
+ uint32_t name_u32,
+ int cpu
+)
{
- Objects_Name name;
+ Objects_Name name;
+ Thread_Control *idle;
- name.name_u32 = _Objects_Build_name( 'I', 'D', 'L', 'E' );
+ name.name_u32 = name_u32;
/*
* The entire workspace is zeroed during its initialization. Thus, all
* fields not explicitly assigned were explicitly zeroed by
* _Workspace_Initialization.
*/
- _Thread_Idle = _Thread_Internal_allocate();
+ idle = _Thread_Internal_allocate();
/*
* This is only called during initialization and we better be sure
@@ -58,7 +58,7 @@ void _Thread_Create_idle( void )
_Thread_Initialize(
&_Thread_Internal_information,
- _Thread_Idle,
+ idle,
NULL, /* allocate the stack */
_Stack_Ensure_minimum( Configuration.idle_task_stack_size ),
CPU_IDLE_TASK_IS_FP,
@@ -76,15 +76,31 @@ void _Thread_Create_idle( void )
* WARNING!!! This is necessary to "kick" start the system and
* MUST be done before _Thread_Start is invoked.
*/
- _Thread_Heir =
- _Thread_Executing = _Thread_Idle;
+ _Per_CPU_Information[ cpu ].idle =
+ _Per_CPU_Information[ cpu ].heir =
+ _Per_CPU_Information[ cpu ].executing = idle;
_Thread_Start(
- _Thread_Idle,
+ idle,
THREAD_START_NUMERIC,
Configuration.idle_task,
NULL,
0
);
+}
+
+void _Thread_Create_idle( void )
+{
+ #if defined(RTEMS_SMP)
+ int cpu;
+ for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) {
+ _Thread_Create_idle_helper(
+ _Objects_Build_name( 'I', 'D', 'L', 'E' ),
+ cpu
+ );
+ }
+ #else
+ _Thread_Create_idle_helper(_Objects_Build_name( 'I', 'D', 'L', 'E' ), 0);
+ #endif
}