[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