[PATCH 3/3] score: Add SMP support to the cache manager
Daniel Cederman
cederman at gaisler.com
Fri Jul 4 15:12:29 UTC 2014
> This limits the API to the default cpu_set_t. Other routines like
> pthread_setaffinity_np() don't have this limitation.
I looked at pthread_setaffinity_np() and got a bit confused. I see that
it takes both a pointer to a cpu_set_t and the size of the cpu set. It
forwards it to _Scheduler_Set_affinity which requires
__RTEMS_HAVE_SYS_CPUSET_H__ to be defined. If this is defined then
_CPU_set_Handler_initialization checks that the number of cpus is less
than CPU_SETSIZE. In newlib this is defined to 32 and is used to size
the cpu_set_t struct. So why is the size needed for
pthread_setaffinity_np if the number of cpus cannot exceed a hardcoded
constant? I recall that there was a discussion on the list about cpu
sets, but I'm not finding anything searching.
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
On 2014-07-04 08:38, Sebastian Huber wrote:
> On 2014-07-03 11:37, 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. Implementation is shown using both function
>> pointers and function ids together with a switch statement. One needs
>> to be dropped before committing. Any preference?
>> ---
>> c/src/lib/libcpu/shared/src/cache_manager.c | 166
>> +++++++++++++++++++++++++++
>> cpukit/rtems/include/rtems/rtems/cache.h | 84 ++++++++++++++
>> cpukit/score/include/rtems/score/smpimpl.h | 13 +++
>> 3 files changed, 263 insertions(+)
>>
>> diff --git a/c/src/lib/libcpu/shared/src/cache_manager.c
>> b/c/src/lib/libcpu/shared/src/cache_manager.c
>> index 420a013..91e9f72 100644
>> --- a/c/src/lib/libcpu/shared/src/cache_manager.c
>> +++ b/c/src/lib/libcpu/shared/src/cache_manager.c
>> @@ -37,6 +37,172 @@
>>
>> #include <rtems.h>
>> #include "cache_.h"
>> +#include <rtems/score/smplock.h>
>> +#include <rtems/score/smpimpl.h>
>> +
>> +#if defined( RTEMS_SMP )
>> +
>> +typedef void (*cache_manager_func_t)(const void * d_addr, size_t
>> n_bytes);
>
> The *_t namespace is reserved by POSIX. The names don't follow the
> score naming conventions.
>
> http://www.rtems.org/wiki/index.php/Naming_rules
>
>> +
>> +typedef enum {
>> + FLUSH_MULTIPLE_DATA_LINES,
>> + INVALIDATE_MULTIPLE_DATA_LINES,
>> + INVALIDATE_MULTIPLE_INSTRUCTION_LINES,
>> + FLUSH_ENTIRE_DATA,
>> + INVALIDATE_ENTIRE_INSTRUCTION,
>> + INVALIDATE_ENTIRE_DATA
>> +} cache_manager_func_id_t;
>> +
>> +typedef struct {
>> + SMP_lock_Control lock;
>> + cache_manager_func_t func;
>> + cache_manager_func_id_t func_id;
>> + Atomic_Uint count;
>> + const void *addr;
>> + size_t size;
>> +} Cache_Manager_SMP;
>> +
>> +static Cache_Manager_SMP _CM_SMP = {
>> + .lock = SMP_LOCK_INITIALIZER("CacheMgr"),
>> + .count = CPU_ATOMIC_INITIALIZER_UINT(0)
>> +};
>> +
>> +void
>> +_SMP_Cache_manager_ipi_handler(void)
>
> I would rather name this _SMP_Cache_manager_message_handler().
>
>> +{
>> +#ifdef USE_FUNCPTR
>> + _CM_SMP.func( _CM_SMP.addr, _CM_SMP.size );
>> +#else
>> + switch( _CM_SMP.func_id ) {
>> + case FLUSH_MULTIPLE_DATA_LINES:
>> + rtems_cache_flush_multiple_data_lines(
>> + _CM_SMP.addr, _CM_SMP.size );
>> + break;
>> + case INVALIDATE_MULTIPLE_DATA_LINES:
>> + rtems_cache_invalidate_multiple_data_lines(
>> + _CM_SMP.addr, _CM_SMP.size );
>> + break;
>> + case INVALIDATE_MULTIPLE_INSTRUCTION_LINES:
>> + rtems_cache_invalidate_multiple_instruction_lines(
>> + _CM_SMP.addr, _CM_SMP.size );
>> + break;
>> + case FLUSH_ENTIRE_DATA:
>> + rtems_cache_flush_entire_data();
>> + break;
>> + case INVALIDATE_ENTIRE_INSTRUCTION:
>> + rtems_cache_invalidate_entire_instruction();
>> + break;
>> + case INVALIDATE_ENTIRE_DATA:
>> + rtems_cache_invalidate_entire_data();
>> + break;
>> + default:
>> + _Assert( 0 );
>> + break;
>> + }
>> +#endif
>> +
>> + _Atomic_Fetch_sub_uint( &_CM_SMP.count, 1, ATOMIC_ORDER_RELEASE );
>> +}
>> +
>> +static void
>> +_cache_manager_send_ipi_msg( const cpu_set_t *set,
>> cache_manager_func_t func,
>> + cache_manager_func_id_t func_id, const void * addr, size_t size )
>> +{
>> + uint32_t i;
>> + uint32_t set_size = 0;
>> + SMP_lock_Context lock_context;
>> +
>> + _Assert( _System_state_Is_up( _System_state_Get() ) );
>> +
>> + for( i=0; i < _SMP_Get_processor_count(); ++i ) {
>> + set_size += CPU_ISSET(i, set);
>> + }
>> +
>> + _SMP_lock_Acquire( &_CM_SMP.lock, &lock_context );
>
> With this implementation cache routines must not be called from
> interrupt context. This should be mentioned in the documentation.
>
> It is extremely difficult to implement it in a way so that it can be
> used from interrupt context.
>
>> +
>> + _CM_SMP.func = func;
>> + _CM_SMP.func_id = func_id;
>> + _CM_SMP.addr = addr;
>> + _CM_SMP.size = size;
>> + _Atomic_Store_uint( &_CM_SMP.count, set_size, ATOMIC_ORDER_RELEASE );
>> + _Atomic_Fence( ATOMIC_ORDER_RELEASE );
>> +
>> + _SMP_Send_message_cpu_set( set, SMP_MESSAGE_CACHE_MANAGER );
>> +
>> + while(_Atomic_Load_uint( &_CM_SMP.count, ATOMIC_ORDER_ACQUIRE ) !=
>> 0 );
>> +
>> + _SMP_lock_Release( &_CM_SMP.lock, &lock_context );
>> +}
>> +
>> +void
>> +rtems_cache_invalidate_entire_instruction_cpu_set ( const cpu_set_t
>> *set )
>
> This limits the API to the default cpu_set_t. Other routines like
> pthread_setaffinity_np() don't have this limitation.
>
> On other places we don't use "cpu" instead we use "processor" it should
> be consistent in the high level RTEMS APIs.
>
> [...]
>
More information about the devel
mailing list