Index: cpukit/score/include/rtems/score/percpu.h =================================================================== RCS file: /usr1/CVS/rtems/cpukit/score/include/rtems/score/percpu.h,v retrieving revision 1.5 diff -u -r1.5 percpu.h --- cpukit/score/include/rtems/score/percpu.h 16 Mar 2011 20:05:06 -0000 1.5 +++ cpukit/score/include/rtems/score/percpu.h 10 May 2011 13:46:31 -0000 @@ -84,18 +84,17 @@ 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) || \ Index: cpukit/score/include/rtems/score/smplock.h =================================================================== RCS file: /usr1/CVS/rtems/cpukit/score/include/rtems/score/smplock.h,v retrieving revision 1.1 diff -u -r1.1 smplock.h --- cpukit/score/include/rtems/score/smplock.h 16 Mar 2011 20:05:06 -0000 1.1 +++ cpukit/score/include/rtems/score/smplock.h 10 May 2011 13:46:31 -0000 @@ -34,10 +34,23 @@ /** * 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 volatile uint32_t SMP_lock_Control; +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 struct { + uint32_t count; + int cpu_id; +} SMP_lock_spinlock_nested_Control; /** * @brief Initialize a Lock @@ -45,12 +58,9 @@ * 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 @@ * * @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 @@ * 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. * - * @note This lock may be "too low" here. It may need to move - * out of the BSP area. + * @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. + * + * @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 Index: cpukit/score/src/smp.c =================================================================== RCS file: /usr1/CVS/rtems/cpukit/score/src/smp.c,v retrieving revision 1.3 diff -u -r1.3 smp.c --- cpukit/score/src/smp.c 27 Apr 2011 17:18:59 -0000 1.3 +++ cpukit/score/src/smp.c 10 May 2011 13:46:31 -0000 @@ -80,10 +80,10 @@ 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 @@ { 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 @@ 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(); } Index: cpukit/score/src/smplock.c =================================================================== RCS file: /usr1/CVS/rtems/cpukit/score/src/smplock.c,v retrieving revision 1.1 diff -u -r1.1 smplock.c --- cpukit/score/src/smplock.c 16 Mar 2011 20:05:06 -0000 1.1 +++ cpukit/score/src/smplock.c 10 May 2011 13:46:31 -0000 @@ -15,35 +15,93 @@ #include #include +#include -void _SMP_lock_Spinlock_Initialize( - SMP_lock_Control *lock +#if defined (RTEMS_DEBUG) + #include +#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 ); }