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
ceder...@gaisler.com
www.Aeroflex.com/Gaisler
_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to