summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-05-28 10:54:46 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-05-31 15:20:32 +0200
commite358088fc25fb3f62b30ae6a187f3e374f6a5ed7 (patch)
tree554337534e7212617c1523be0453c604ad120916 /cpukit/score/cpu
parentscore: Mark as no return (diff)
downloadrtems-e358088fc25fb3f62b30ae6a187f3e374f6a5ed7.tar.bz2
smp: New SMP lock API
Move the SMP lock implementation to the CPU port. An optimal SMP lock implementation is highly architecture dependent. For example the memory models may be fundamentally different. The new SMP lock API has a flaw. It does not provide the ability to use a local context for acquire and release pairs. Such a context is necessary to implement for example the Mellor-Crummey and Scott (MCS) locks. The SMP lock is currently used in _Thread_Disable_dispatch() and _Thread_Enable_dispatch() and makes them to a giant lock acquire and release. Since these functions do not pass state information via a local context there is currently no use case for such a feature.
Diffstat (limited to 'cpukit/score/cpu')
-rw-r--r--cpukit/score/cpu/i386/Makefile.am1
-rw-r--r--cpukit/score/cpu/i386/preinstall.am4
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h9
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpusmplock.h100
-rw-r--r--cpukit/score/cpu/no_cpu/Makefile.am1
-rw-r--r--cpukit/score/cpu/no_cpu/preinstall.am4
-rw-r--r--cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h114
-rw-r--r--cpukit/score/cpu/sparc/Makefile.am1
-rw-r--r--cpukit/score/cpu/sparc/preinstall.am4
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h18
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpusmplock.h105
11 files changed, 334 insertions, 27 deletions
diff --git a/cpukit/score/cpu/i386/Makefile.am b/cpukit/score/cpu/i386/Makefile.am
index d25002d390..e35a81c333 100644
--- a/cpukit/score/cpu/i386/Makefile.am
+++ b/cpukit/score/cpu/i386/Makefile.am
@@ -11,6 +11,7 @@ include_rtems_score_HEADERS += rtems/score/interrupts.h
include_rtems_score_HEADERS += rtems/score/registers.h
include_rtems_score_HEADERS += rtems/score/idtr.h
include_rtems_score_HEADERS += rtems/score/cpuatomic.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
noinst_LIBRARIES = libscorecpu.a
libscorecpu_a_SOURCES = cpu.c cpu_asm.S
diff --git a/cpukit/score/cpu/i386/preinstall.am b/cpukit/score/cpu/i386/preinstall.am
index 060176be04..f9faf87157 100644
--- a/cpukit/score/cpu/i386/preinstall.am
+++ b/cpukit/score/cpu/i386/preinstall.am
@@ -55,3 +55,7 @@ $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_IN
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index c262e3cf45..3f7a331c3f 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -455,15 +455,6 @@ uint32_t _CPU_ISR_Get_level( void );
#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)
-
static inline void _CPU_Processor_event_broadcast( void )
{
__asm__ volatile ( "" : : : "memory" );
diff --git a/cpukit/score/cpu/i386/rtems/score/cpusmplock.h b/cpukit/score/cpu/i386/rtems/score/cpusmplock.h
new file mode 100644
index 0000000000..6fadfef419
--- /dev/null
+++ b/cpukit/score/cpu/i386/rtems/score/cpusmplock.h
@@ -0,0 +1,100 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockI386
+ *
+ * @brief i386 SMP Lock Implementation
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_I386_SMPLOCK_H
+#define _RTEMS_SCORE_I386_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockI386 i386 SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * The implementation is Test and Swap.
+ *
+ * @{
+ */
+
+typedef struct {
+ uint32_t locked;
+} CPU_SMP_lock_Control;
+
+#define CPU_SMP_LOCK_INITIALIZER { 0 }
+
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+ lock->locked = 0;
+}
+
+static inline uint32_t _I386_Atomic_swap(
+ volatile uint32_t *address,
+ uint32_t value
+)
+{
+ uint32_t previous;
+
+ asm volatile(
+ "lock; xchgl %0, %1"
+ : "+m" (*address), "=a" (previous)
+ : "1" (value)
+ : "cc"
+ );
+
+ return previous;
+}
+
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+ do {
+ while ( lock->locked ) {
+ /* Do nothing */
+ }
+ } while ( _I386_Atomic_swap( &lock->locked, 1 ) );
+}
+
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ lock->locked = 0;
+}
+
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+ do { \
+ _CPU_ISR_Disable( isr_cookie ); \
+ _CPU_SMP_lock_Acquire( lock ); \
+ } while (0)
+
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+ do { \
+ _CPU_SMP_lock_Release( lock ); \
+ _CPU_ISR_Enable( isr_cookie ); \
+ } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_I386_SMPLOCK_H */
diff --git a/cpukit/score/cpu/no_cpu/Makefile.am b/cpukit/score/cpu/no_cpu/Makefile.am
index 820579cd42..24517431e7 100644
--- a/cpukit/score/cpu/no_cpu/Makefile.am
+++ b/cpukit/score/cpu/no_cpu/Makefile.am
@@ -8,6 +8,7 @@ include_rtems_score_HEADERS = rtems/score/cpu.h
include_rtems_score_HEADERS += rtems/score/no_cpu.h
include_rtems_score_HEADERS += rtems/score/cpu_asm.h
include_rtems_score_HEADERS += rtems/score/types.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
noinst_LIBRARIES = libscorecpu.a
libscorecpu_a_SOURCES = cpu.c cpu_asm.c
diff --git a/cpukit/score/cpu/no_cpu/preinstall.am b/cpukit/score/cpu/no_cpu/preinstall.am
index a56caeafd8..a46f8b0bfd 100644
--- a/cpukit/score/cpu/no_cpu/preinstall.am
+++ b/cpukit/score/cpu/no_cpu/preinstall.am
@@ -43,3 +43,7 @@ $(PROJECT_INCLUDE)/rtems/score/types.h: rtems/score/types.h $(PROJECT_INCLUDE)/r
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/types.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/types.h
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h b/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h
new file mode 100644
index 0000000000..387bbb47c1
--- /dev/null
+++ b/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h
@@ -0,0 +1,114 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockCPU
+ *
+ * @brief CPU SMP Lock Implementation
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_NO_CPU_SMPLOCK_H
+#define _RTEMS_SCORE_NO_CPU_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockCPU CPU SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * This example will implement a ticket lock.
+ *
+ * @{
+ */
+
+/**
+ * @brief CPU SMP lock control.
+ */
+typedef struct {
+ unsigned int next_ticket;
+ unsigned int now_serving;
+} CPU_SMP_lock_Control;
+
+/**
+ * @brief CPU SMP lock control initializer for static initialization.
+ */
+#define CPU_SMP_LOCK_INITIALIZER { 0, 0 }
+
+/**
+ * @brief Initializes a CPU SMP lock control.
+ *
+ * @param[out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+ lock->next_ticket = 0;
+ lock->now_serving = 0;
+}
+
+/**
+ * @brief Acquires a CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+ unsigned int my_ticket = _Atomic_Fetch_and_increment( &lock->next_ticket );
+
+ while ( _Atomic_Load_and_acquire( &lock->now_serving ) != my_ticket ) {
+ _Wait_some_time();
+ }
+}
+
+/**
+ * @brief Releases a CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+ _Atomic_Store_and_release( &lock->now_serving, lock->now_serving + 1 );
+}
+
+/**
+ * @brief Disables interrupts and acquires the CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ * @param[out] isr_cookie The ISR cookie.
+ */
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+ do { \
+ _CPU_ISR_Disable( isr_cookie ); \
+ _CPU_SMP_lock_Acquire( lock ); \
+ } while (0)
+
+/**
+ * @brief Releases the CPU SMP lock and enables interrupts.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ * @param[in] isr_cookie The ISR cookie.
+ */
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+ do { \
+ _CPU_SMP_lock_Release( lock ); \
+ _CPU_ISR_Enable( isr_cookie ); \
+ } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_NO_CPU_SMPLOCK_H */
diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am
index 4bb09c6b56..3065f3ce18 100644
--- a/cpukit/score/cpu/sparc/Makefile.am
+++ b/cpukit/score/cpu/sparc/Makefile.am
@@ -8,6 +8,7 @@ include_rtems_score_HEADERS = rtems/score/sparc.h
include_rtems_score_HEADERS += rtems/score/cpu.h
include_rtems_score_HEADERS += rtems/score/types.h
include_rtems_score_HEADERS += rtems/score/cpuatomic.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
noinst_LIBRARIES = libscorecpu.a
libscorecpu_a_SOURCES = cpu.c cpu_asm.S
diff --git a/cpukit/score/cpu/sparc/preinstall.am b/cpukit/score/cpu/sparc/preinstall.am
index a2bb01bfd2..e497b48f7f 100644
--- a/cpukit/score/cpu/sparc/preinstall.am
+++ b/cpukit/score/cpu/sparc/preinstall.am
@@ -43,3 +43,7 @@ $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_IN
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 9654c294f5..defc01a779 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -1186,24 +1186,6 @@ void _CPU_Context_restore(
Context_Control *new_context
);
- /**
- * Macro to access memory and bypass the cache.
- *
- * NOTE: 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)
-
static inline void _CPU_Processor_event_broadcast( void )
{
__asm__ volatile ( "" : : : "memory" );
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h b/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h
new file mode 100644
index 0000000000..1158040dc5
--- /dev/null
+++ b/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h
@@ -0,0 +1,105 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockSPARC
+ *
+ * @brief SPARC SMP Lock Implementation
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_SPARC_SMPLOCK_H
+#define _RTEMS_SCORE_SPARC_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockSPARC SPARC SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * The implementation is Test and Swap.
+ *
+ * @{
+ */
+
+typedef struct {
+ uint32_t locked;
+} CPU_SMP_lock_Control;
+
+#define CPU_SMP_LOCK_INITIALIZER { 0 }
+
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+ lock->locked = 0;
+}
+
+/*
+ * Function to access memory and bypass the cache.
+ *
+ * NOTE: address space 1 is uncacheable
+ *
+ * FIXME: This implementation uses specific Leon features.
+ */
+static inline uint32_t _SPARC_Atomic_swap(
+ volatile uint32_t *address,
+ uint32_t value
+)
+{
+ asm volatile (
+ "swapa [%2] %3, %0"
+ : "=r" (value)
+ : "0" (value), "r" (address), "i" (1)
+ : "memory"
+ );
+
+ return value;
+}
+
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+ do {
+ while ( lock->locked ) {
+ /* Do nothing */
+ }
+ } while ( _SPARC_Atomic_swap( &lock->locked, 1 ) );
+}
+
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ lock->locked = 0;
+}
+
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+ do { \
+ _CPU_ISR_Disable( isr_cookie ); \
+ _CPU_SMP_lock_Acquire( lock ); \
+ } while (0)
+
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+ do { \
+ _CPU_SMP_lock_Release( lock ); \
+ _CPU_ISR_Enable( isr_cookie ); \
+ } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_SPARC_SMPLOCK_H */