diff options
author | Jennifer Averett <Jennifer.Averett@OARcorp.com> | 2011-05-20 12:36:01 +0000 |
---|---|---|
committer | Jennifer Averett <Jennifer.Averett@OARcorp.com> | 2011-05-20 12:36:01 +0000 |
commit | a8d7e2ab16f6c4a1a6e4f90010651b016ac6f7c1 (patch) | |
tree | 4123cb2913b2db3224b9c75ab8f9a49c60ea498c /cpukit | |
parent | 2011-05-20 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff) | |
download | rtems-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/ChangeLog | 7 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/percpu.h | 7 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/smplock.h | 85 | ||||
-rw-r--r-- | cpukit/score/src/smp.c | 12 | ||||
-rw-r--r-- | cpukit/score/src/smplock.c | 86 |
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 ); } |