[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