[PATCH-V2 3/7] score: Add SMP support to the cache manager

Daniel Cederman cederman at gaisler.com
Fri Jul 11 07:16:19 UTC 2014


I'm currently working on adding tests. Thank you for your other comments!

On 2014-07-09 09:41, Sebastian Huber wrote:
> The new cache manager functions should have tests, see also
>
> http://git.rtems.org/rtems/tree/testsuites/sptests/spcache01/init.c
>
> On 2014-07-09 09:02, Daniel Cederman wrote:
>> Adds functions that allows the user to specify which cores that should
>> perform the cache operation. SMP messages are sent to all the specified
>> cores and the caller waits until all cores have acknowledged that they
>> have flushed their cache. If CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING is
>> defined the instruction cache invalidation function will perform the
>> operation on all cores using the previous method.
>> ---
>>   c/src/lib/libbsp/sparc/leon3/include/cache_.h |    2 +
>>   c/src/lib/libcpu/shared/src/cache_manager.c   |  200
>> ++++++++++++++++++++++++-
>>   cpukit/rtems/include/rtems/rtems/cache.h      |   88 +++++++++++
>>   cpukit/score/include/rtems/score/smpimpl.h    |   13 ++
>>   4 files changed, 297 insertions(+), 6 deletions(-)
>>
>> diff --git a/c/src/lib/libbsp/sparc/leon3/include/cache_.h
>> b/c/src/lib/libbsp/sparc/leon3/include/cache_.h
>> index 70c1e2c..63790c1 100644
>> --- a/c/src/lib/libbsp/sparc/leon3/include/cache_.h
>> +++ b/c/src/lib/libbsp/sparc/leon3/include/cache_.h
>> @@ -26,6 +26,8 @@ extern "C" {
>>
>>   #define CPU_CACHE_SUPPORT_PROVIDES_CACHE_SIZE_FUNCTIONS
>>
>> +#define CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING
>> +
>>   #define CPU_INSTRUCTION_CACHE_ALIGNMENT 64
>>
>>   #define CPU_DATA_CACHE_ALIGNMENT 64
>> diff --git a/c/src/lib/libcpu/shared/src/cache_manager.c
>> b/c/src/lib/libcpu/shared/src/cache_manager.c
>> index 420a013..da57c12 100644
>> --- a/c/src/lib/libcpu/shared/src/cache_manager.c
>> +++ b/c/src/lib/libcpu/shared/src/cache_manager.c
>
> This file should follow the coding and naming conventions:
>
> http://www.rtems.org/wiki/index.php/Coding_Conventions
>
>> @@ -37,6 +37,156 @@
>>
>>   #include <rtems.h>
>>   #include "cache_.h"
>> +#include <rtems/score/smpimpl.h>
>> +#include <rtems/score/sysstate.h>
>> +#include <rtems/score/threaddispatch.h>
>> +
>> +#if defined( RTEMS_SMP )
>> +
>> +typedef void (*Cache_manager_Function_ptr)(const void *d_addr, size_t
>> n_bytes);
>> +
>> +typedef struct {
>> +  Atomic_Flag lock;
>> +  Cache_manager_Function_ptr func;
>> +  Atomic_Uint count;
>> +  const void *addr;
>> +  size_t size;
>> +} Cache_manager_SMP_control;
>> +
>> +static Cache_manager_SMP_control _CM_SMP = {
>> +  .lock = ATOMIC_INITIALIZER_FLAG,
>> +  .count = ATOMIC_INITIALIZER_UINT(0)
>> +};
>> +
>> +void
>> +_SMP_Cache_manager_message_handler(void)
>> +{
>> +  _CM_SMP.func( _CM_SMP.addr, _CM_SMP.size );
>> +  _Atomic_Fetch_add_uint( &_CM_SMP.count, 1, ATOMIC_ORDER_RELEASE );
>> +}
>> +
>> +#if defined(CPU_DATA_CACHE_ALIGNMENT) || \
>> +    (defined(CPU_INSTRUCTION_CACHE_ALIGNMENT) && \
>> +    defined(CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING))
>> +
>> +static void
>> +_cache_manager_process_cache_messages( void )
>> +{
>> +  unsigned long message;
>> +  Per_CPU_Control *cpu_self = _Per_CPU_Get();
>> +
>> +  message = _Atomic_Load_ulong( &cpu_self->message,
>> ATOMIC_ORDER_RELAXED );
>> +
>> +  if ( message & SMP_MESSAGE_CACHE_MANAGER) {
>> +    if ( _Atomic_Compare_exchange_ulong( &cpu_self->message, &message,
>> +        message & ~SMP_MESSAGE_CACHE_MANAGER, ATOMIC_ORDER_RELAXED,
>> +        ATOMIC_ORDER_RELAXED ) ) {
>> +      _SMP_Cache_manager_message_handler();
>> +    }
>> +  }
>> +}
>> +
>> +static void
>> +_cache_manager_send_smp_msg(
>> +    const size_t setsize,
>> +    const cpu_set_t *set,
>> +    Cache_manager_Function_ptr func,
>> +    const void * addr,
>> +    size_t size
>> +  )
>> +{
>> +  uint32_t cpu_count = 0;
>> +
>> +  if ( ! _System_state_Is_up( _System_state_Get() ) ) {
>> +    func( addr, size );
>> +    return;
>> +  }
>> +
>> +  if ( set == NULL )
>> +    cpu_count = _SMP_Get_processor_count();
>> +  else
>> +    cpu_count = CPU_COUNT_S( setsize, set );
>> +
>> +  _Thread_Disable_dispatch();
>
> This will not work since _Thread_Disable_dispatch() obtains the Giant
> lock. Other processors acquiring the Giant lock will do this with
> interrupts disabled, thus you cannot make progress ...
>
>> +
>> +  while ( _Atomic_Flag_test_and_set( &_CM_SMP.lock,
>> ATOMIC_ORDER_ACQUIRE ) )
>> +    _cache_manager_process_cache_messages();
>> +
>> +  _CM_SMP.func = func;
>> +  _CM_SMP.addr = addr;
>> +  _CM_SMP.size = size;
>> +  _Atomic_Store_uint( &_CM_SMP.count, 0, ATOMIC_ORDER_RELEASE );
>> +  _Atomic_Fence( ATOMIC_ORDER_RELEASE );
>> +
>> +  if ( set == NULL ) {
>> +    _SMP_Send_message_broadcast( SMP_MESSAGE_CACHE_MANAGER );
>> +    _SMP_Cache_manager_message_handler();
>> +  } else {
>> +    _SMP_Send_message_multicast( setsize, set,
>> SMP_MESSAGE_CACHE_MANAGER );
>> +    _cache_manager_process_cache_messages();
>> +  }
>> +
>> +  while ( _Atomic_Load_uint( &_CM_SMP.count, ATOMIC_ORDER_ACQUIRE )
>> +      != cpu_count );
>
> ... here.
>
>> +
>> +  _Atomic_Flag_clear( &_CM_SMP.lock, ATOMIC_ORDER_RELEASE );
>> +
>> +  _Thread_Enable_dispatch();
>> +}
>> +#endif
>> +
>> +void
>> +rtems_cache_flush_multiple_data_lines_processor_set(
>> +  const void *addr,
>> +  size_t size,
>> +  const size_t setsize,
>> +  const cpu_set_t *set
>> +)
>> +{
>> +#if defined(CPU_DATA_CACHE_ALIGNMENT)
>> +  _cache_manager_send_smp_msg( setsize, set,
>> +      rtems_cache_flush_multiple_data_lines, addr, size );
>> +#endif
>> +}
>> +
>> +void
>> +rtems_cache_invalidate_multiple_data_lines_processor_set(
>> +  const void *addr,
>> +  size_t size,
>> +  const size_t setsize,
>> +  const cpu_set_t *set
>> +)
>> +{
>> +#if defined(CPU_DATA_CACHE_ALIGNMENT)
>> +  _cache_manager_send_smp_msg( setsize, set,
>> +      rtems_cache_invalidate_multiple_data_lines, addr, size );
>> +#endif
>> +}
>> +
>> +void
>> +rtems_cache_flush_entire_data_processor_set(
>> +  const size_t setsize,
>> +  const cpu_set_t *set
>> +)
>> +{
>> +#if defined(CPU_DATA_CACHE_ALIGNMENT)
>> +  _cache_manager_send_smp_msg( setsize, set,
>> +      (Cache_manager_Function_ptr)rtems_cache_flush_entire_data, 0, 0 );
>> +#endif
>> +}
>> +
>> +void
>> +rtems_cache_invalidate_entire_data_processor_set(
>> +  const size_t setsize,
>> +  const cpu_set_t *set
>> +)
>> +{
>> +#if defined(CPU_DATA_CACHE_ALIGNMENT)
>> +  _cache_manager_send_smp_msg( setsize, set,
>> +      (Cache_manager_Function_ptr)rtems_cache_invalidate_entire_data,
>> 0, 0 );
>> +#endif
>> +}
>> +#endif
>>
>>   /*
>>    * THESE FUNCTIONS ONLY HAVE BODIES IF WE HAVE A DATA CACHE
>> @@ -219,18 +369,21 @@ rtems_cache_disable_data( void )
>>    * THESE FUNCTIONS ONLY HAVE BODIES IF WE HAVE AN INSTRUCTION CACHE
>>    */
>>
>> +
>> +
>>   /*
>>    * This function is responsible for performing an instruction cache
>>    * invalidate. It must determine how many cache lines need to be
>> invalidated
>>    * and then perform the invalidations.
>>    */
>> -void
>> -rtems_cache_invalidate_multiple_instruction_lines( const void *
>> i_addr, size_t n_bytes )
>> +
>> +#if !defined(CPU_CACHE_SUPPORT_PROVIDES_RANGE_FUNCTIONS)
>> +static void
>> +_invalidate_multiple_instruction_lines_no_range_functions(
>> +  const void * i_addr,
>> +  size_t n_bytes
>> +)
>>   {
>> -#if defined(CPU_INSTRUCTION_CACHE_ALIGNMENT)
>> -#if defined(CPU_CACHE_SUPPORT_PROVIDES_RANGE_FUNCTIONS)
>> -  _CPU_cache_invalidate_instruction_range( i_addr, n_bytes );
>> -#else
>>     const void * final_address;
>>
>>    /*
>> @@ -249,6 +402,35 @@
>> rtems_cache_invalidate_multiple_instruction_lines( const void *
>> i_addr, size_t n
>>       _CPU_cache_invalidate_1_instruction_line( i_addr );
>>       i_addr = (void *)((size_t)i_addr +
>> CPU_INSTRUCTION_CACHE_ALIGNMENT);
>>     }
>> +}
>> +#endif
>> +
>> +void
>> +rtems_cache_invalidate_multiple_instruction_lines(
>> +  const void * i_addr,
>> +  size_t n_bytes
>> +)
>> +{
>> +#if defined(CPU_INSTRUCTION_CACHE_ALIGNMENT)
>> +#if defined(CPU_CACHE_SUPPORT_PROVIDES_RANGE_FUNCTIONS)
>> +
>> +#if defined(RTEMS_SMP) &&
>> defined(CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING)
>> +  _cache_manager_send_smp_msg( 0, 0,
>> _CPU_cache_invalidate_instruction_range,
>> +      i_addr, n_bytes );
>> +#else
>> +  _CPU_cache_invalidate_instruction_range( i_addr, n_bytes );
>> +#endif
>> +
>> +#else
>> +
>> +#if defined(RTEMS_SMP) &&
>> defined(CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING)
>> +  _cache_manager_send_smp_msg( 0, 0,
>> +      _invalidate_multiple_instruction_lines_no_range_functions, i_addr,
>> +      n_bytes );
>> +#else
>> +  _invalidate_multiple_instruction_lines_no_range_functions( i_addr,
>> n_bytes );
>> +#endif
>> +
>>   #endif
>>   #endif
>>   }
>> @@ -266,8 +448,14 @@ rtems_cache_invalidate_entire_instruction( void )
>>     * Call the CPU-specific routine
>>     */
>>
>> +#if defined(RTEMS_SMP) &&
>> defined(CPU_CACHE_NO_INSTRUCTION_CACHE_SNOOPING)
>> +  _cache_manager_send_smp_msg( 0, 0,
>> +
>> (Cache_manager_Function_ptr)_CPU_cache_invalidate_entire_instruction,
>> +      0, 0 );
>> +#else
>>    _CPU_cache_invalidate_entire_instruction();
>>   #endif
>> +#endif
>>   }
>>
>>
>> diff --git a/cpukit/rtems/include/rtems/rtems/cache.h
>> b/cpukit/rtems/include/rtems/rtems/cache.h
>> index 05f6612..721d694 100644
>> --- a/cpukit/rtems/include/rtems/rtems/cache.h
>> +++ b/cpukit/rtems/include/rtems/rtems/cache.h
>> @@ -113,6 +113,9 @@ void rtems_cache_invalidate_multiple_data_lines(
>>    *
>>    * The cache lines covering the area are marked as invalid.  A later
>>    * instruction fetch from the area will result in a load from memory.
>> + * In SMP mode, on processors without instruction cache snooping, this
>> + * operation will invalidate the instruction cache lines on all
>> processors.
>> + * It should not be called from interrupt context in such case.
>>    *
>>    * @param[in] addr The start address of the area to invalidate.
>>    * @param[in] size The size in bytes of the area to invalidate.
>> @@ -188,6 +191,91 @@ void rtems_cache_disable_instruction( void );
>>    */
>>   void *rtems_cache_aligned_malloc ( size_t nbytes );
>>
>> +#if defined( RTEMS_SMP )
>> +
>> +/**
>> + * @brief Handles cache invalidation/flush requests from a remote
>> processor
>> + *
>> + */
>> +void _SMP_Cache_manager_message_handler( void );
>
> This function declaration should move to <rtems/score/smpimpl.h>.
>
>> +
>> +/**
>> + * @brief Flushes multiple data cache lines for a set of processors
>> + *
>> + * Dirty cache lines covering the area are transfered to memory.
>
> transferred
>
> [...]
>

-- 
Daniel Cederman
Software Engineer
Aeroflex Gaisler AB
Aeroflex Microelectronic Solutions – HiRel
Kungsgatan 12
SE-411 19 Gothenburg, Sweden
Phone: +46 31 7758665
cederman at gaisler.com
www.Aeroflex.com/Gaisler


More information about the devel mailing list