summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
authorJennifer Averett <Jennifer.Averett@OARcorp.com>2011-05-20 12:36:01 +0000
committerJennifer Averett <Jennifer.Averett@OARcorp.com>2011-05-20 12:36:01 +0000
commita8d7e2ab16f6c4a1a6e4f90010651b016ac6f7c1 (patch)
tree4123cb2913b2db3224b9c75ab8f9a49c60ea498c /cpukit
parent2011-05-20 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff)
downloadrtems-a8d7e2ab16f6c4a1a6e4f90010651b016ac6f7c1.tar.bz2
2011-05-20 Jennifer Averett <Jennifer.Averett@OARcorp.com>
PR 1787/cpukit * score/include/rtems/score/percpu.h, score/include/rtems/score/smplock.h, score/src/smp.c, score/src/smplock.c: Add nesting support to smp spinlock.
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/ChangeLog7
-rw-r--r--cpukit/score/include/rtems/score/percpu.h7
-rw-r--r--cpukit/score/include/rtems/score/smplock.h85
-rw-r--r--cpukit/score/src/smp.c12
-rw-r--r--cpukit/score/src/smplock.c86
5 files changed, 155 insertions, 42 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog
index 0a67a307c7..db98580c86 100644
--- a/cpukit/ChangeLog
+++ b/cpukit/ChangeLog
@@ -1,3 +1,10 @@
+2011-05-20 Jennifer Averett <Jennifer.Averett@OARcorp.com>
+
+ PR 1787/cpukit
+ * score/include/rtems/score/percpu.h,
+ score/include/rtems/score/smplock.h, score/src/smp.c,
+ score/src/smplock.c: Add nesting support to smp spinlock.
+
2011-05-19 Ralf Corsépius <ralf.corsepius@rtems.org>
* posix/Makefile.am: Remove posixtime.h.
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 9224ad0d2e..1ba5b3d6d2 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -92,18 +92,17 @@ typedef enum {
typedef struct {
#if defined(RTEMS_SMP)
/** This element is used to lock this structure */
- SMP_lock_Control lock;
+ SMP_lock_spinlock_simple_Control lock;
/** This indicates that the CPU is online. */
- uint32_t state;
+ uint32_t state;
/**
* This is the request for the interrupt.
*
* @note This may become a chain protected by atomic instructions.
*/
- uint32_t message;
-
+ uint32_t message;
#endif
#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h
index a20d9260a4..279df6ecd8 100644
--- a/cpukit/score/include/rtems/score/smplock.h
+++ b/cpukit/score/include/rtems/score/smplock.h
@@ -34,10 +34,23 @@ extern "C" {
/**
* This type is used to lock elements for atomic access.
- *
- * @note This type may move to RTEMS.
+ * This spinlock is a simple non-nesting spinlock, and
+ * may be used for short non-nesting accesses.
+ */
+typedef uint32_t SMP_lock_spinlock_simple_Control;
+
+/**
+ * This type is used to lock elements for atomic access.
+ * This spinlock supports nesting, but is slightly more
+ * complicated to use. Please see the descriptions of
+ * obtain and release prior to using in order to understand
+ * the callers responsibilty of managing short interupt disable
+ * times.
*/
-typedef volatile uint32_t SMP_lock_Control;
+typedef struct {
+ uint32_t count;
+ int cpu_id;
+} SMP_lock_spinlock_nested_Control;
/**
* @brief Initialize a Lock
@@ -45,12 +58,9 @@ typedef volatile uint32_t SMP_lock_Control;
* 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
+void _SMP_lock_spinlock_simple_Initialize(
+ SMP_lock_spinlock_simple_Control *lock
);
/**
@@ -62,12 +72,9 @@ void _SMP_lock_Spinlock_Initialize(
*
* @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
+ISR_Level _SMP_lock_spinlock_simple_Obtain(
+ SMP_lock_spinlock_simple_Control *lock
);
/**
@@ -76,13 +83,55 @@ ISR_Level _SMP_lock_Spinlock_Obtain(
* This method is used to release the lock at @a lock.
*
* @param [in] lock is the address of the lock to obtain.
+ */
+void _SMP_lock_spinlock_simple_Release(
+ SMP_lock_spinlock_simple_Control *lock,
+ ISR_Level level
+);
+
+/**
+ * @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.
+ */
+void _SMP_lock_spinlock_nested_Initialize(
+ SMP_lock_spinlock_nested_Control *lock
+);
+
+/**
+ * @brief Obtain a Lock
+ *
+ * This method is used to obtain the lock at @a lock. ISR's are
+ * disabled when this routine returns and it is the callers responsibility
+ * to either:
+ * 1) Do something very short and then call
+ * _SMP_lock_spinlock_nested_Release or
+ * 2) Do something very sort, call isr enable, then when ready
+ * call isr_disable and _SMP_lock_spinlock_nested_Release
+ *
+ * @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.
+ * @return This method returns with processor interrupts disabled.
+ * The previous level is returned.
+ */
+ISR_Level _SMP_lock_spinlock_nested_Obtain(
+ SMP_lock_spinlock_nested_Control *lock
+);
+
+/**
+ * @brief Release a Lock
+ *
+ * This method is used to release the lock at @a lock. Note:
+ * ISR's are reenabled by this method and are expected to be
+ * disabled upon entry to the method.
+ *
+ * @param [in] lock is the address of the lock to obtain.
*/
-void _SMP_lock_Spinlock_Release(
- SMP_lock_Control *lock,
- ISR_Level level
+void _SMP_lock_spinlock_nested_Release(
+ SMP_lock_spinlock_nested_Control *lock,
+ ISR_Level level
);
#ifdef __cplusplus
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
index 068285c114..9714add5ea 100644
--- a/cpukit/score/src/smp.c
+++ b/cpukit/score/src/smp.c
@@ -80,10 +80,10 @@ void rtems_smp_process_interrupt(void)
cpu = bsp_smp_processor_id();
- level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
+ level = _SMP_lock_spinlock_simple_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 );
+ _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
#if defined(SMP_DEBUG)
{
@@ -126,9 +126,9 @@ void rtems_smp_send_message(
{
ISR_Level level;
- level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
+ level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
_Per_CPU_Information[cpu].message |= message;
- _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
+ _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
bsp_smp_interrupt_cpu( cpu );
}
@@ -145,9 +145,9 @@ void rtems_smp_broadcast_message(
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 );
+ level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
_Per_CPU_Information[dest_cpu].message |= message;
- _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
+ _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
}
bsp_smp_broadcast_interrupt();
}
diff --git a/cpukit/score/src/smplock.c b/cpukit/score/src/smplock.c
index 1dd691835b..91589b5c54 100644
--- a/cpukit/score/src/smplock.c
+++ b/cpukit/score/src/smplock.c
@@ -15,35 +15,93 @@
#include <rtems/system.h>
#include <rtems/score/smplock.h>
+#include <rtems/score/smp.h>
-void _SMP_lock_Spinlock_Initialize(
- SMP_lock_Control *lock
+#if defined (RTEMS_DEBUG)
+ #include <rtems/bspIo.h>
+#endif
+
+void _SMP_lock_spinlock_simple_Initialize(
+ SMP_lock_spinlock_simple_Control *lock
)
{
*lock = 0;
}
-ISR_Level _SMP_lock_Spinlock_Obtain(
- SMP_lock_Control *lock
+ISR_Level _SMP_lock_spinlock_simple_Obtain(
+ SMP_lock_spinlock_simple_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_simple_Release(
+ SMP_lock_spinlock_simple_Control *lock,
+ ISR_Level level
+)
+{
+ *lock = 0;
+ _ISR_Enable( level );
+}
+
+void _SMP_lock_spinlock_nested_Initialize(
+ SMP_lock_spinlock_nested_Control *lock
+)
+{
+ lock->count = 0;
+ lock->cpu_id = 0;
+}
+
+ISR_Level _SMP_lock_spinlock_nested_Obtain(
+ SMP_lock_spinlock_nested_Control *lock
)
{
- ISR_Level level;
+ ISR_Level level = 0;
uint32_t value = 1;
uint32_t previous;
+ int cpu_id;
/* Note: Disable provides an implicit memory barrier. */
- _ISR_Disable( level );
- do {
- SMP_CPU_SWAP( lock, value, previous );
- } while (previous == 1);
+ _ISR_Disable( level );
+
+ cpu_id = bsp_smp_processor_id();
+
+ /* Deal with nested calls from one cpu */
+ if ( (lock->count > 0) && (cpu_id == lock->cpu_id) ) {
+ lock->count++;
+ return level;
+ }
+
+ do {
+ SMP_CPU_SWAP( lock, value, previous );
+ } while (previous == 1);
+
+ lock->count++;
+ lock->cpu_id = cpu_id;
+
return level;
}
-void _SMP_lock_Spinlock_Release(
- SMP_lock_Control *lock,
- ISR_Level level
+void _SMP_lock_spinlock_nested_Release(
+ SMP_lock_spinlock_nested_Control *lock,
+ ISR_Level level
)
{
- *lock = 0;
- _ISR_Enable( level );
+#if defined(RTEMS_DEBUG)
+ if ( lock->count == 0 )
+ printk ("Releasing spinlock when count is already zero?!?!\n");
+#endif
+ lock->count--;
+
+ _ISR_Enable( level );
}