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

Sebastian Huber sebastian.huber at embedded-brains.de
Wed Jul 9 07:41:05 UTC 2014


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

[...]

-- 
Sebastian Huber, embedded brains GmbH

Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone   : +49 89 189 47 41-16
Fax     : +49 89 189 47 41-09
E-Mail  : sebastian.huber at embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.


More information about the devel mailing list