[rtems commit] sparc: Rework CPU counter support

Sebastian Huber sebh at rtems.org
Tue Jun 21 13:55:04 UTC 2016


Module:    rtems
Branch:    master
Commit:    9460333e9910471eda010423dcb493f758d997d4
Changeset: http://git.rtems.org/rtems/commit/?id=9460333e9910471eda010423dcb493f758d997d4

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Jun 20 10:08:39 2016 +0200

sparc: Rework CPU counter support

Rework CPU counter support to enable use of the GR740 up-counter via
%asr22 and %asr23.

---

 c/src/lib/libbsp/sparc/erc32/clock/ckinit.c       | 25 +++---
 c/src/lib/libbsp/sparc/leon2/clock/ckinit.c       |  6 ++
 c/src/lib/libbsp/sparc/leon3/include/leon.h       | 47 ++++++++++-
 c/src/lib/libbsp/sparc/leon3/startup/bspstart.c   |  2 -
 c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c | 95 +++++++++++------------
 c/src/lib/libbsp/sparc/shared/irq_asm.S           | 16 ++--
 cpukit/score/cpu/sparc/Makefile.am                |  1 +
 cpukit/score/cpu/sparc/rtems/score/cpu.h          | 49 +++++++-----
 cpukit/score/cpu/sparc/sparc-counter-asm.S        | 34 ++++++++
 cpukit/score/cpu/sparc/sparc-counter.c            | 30 +++++--
 10 files changed, 208 insertions(+), 97 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
index d78fb0e..cb5cee8 100644
--- a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
+++ b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
@@ -83,14 +83,14 @@ static void erc32_tc_tick( void )
   );
 }
 
-static CPU_Counter_ticks erc32_counter_difference(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
+static void erc32_counter_initialize( uint32_t frequency )
 {
-  CPU_Counter_ticks period = rtems_configuration_get_microseconds_per_tick();
-
-  return (first + period - second) % period;
+  _SPARC_Counter_initialize(
+    _SPARC_Counter_read_address,
+    _SPARC_Counter_difference_clock_period,
+    &ERC32_MEC.Real_Time_Clock_Counter
+  );
+  rtems_counter_initialize_converter( frequency );
 }
 
 #define Clock_driver_support_initialize_hardware() \
@@ -117,11 +117,7 @@ static CPU_Counter_ticks erc32_counter_difference(
         rtems_configuration_get_microseconds_per_tick(), \
         erc32_tc_get_timecount \
     ); \
-    _SPARC_Counter_initialize( \
-      &ERC32_MEC.Real_Time_Clock_Counter, \
-      erc32_counter_difference \
-    ); \
-    rtems_counter_initialize_converter( frequency ); \
+    erc32_counter_initialize( frequency ); \
   } while (0)
 
 #define Clock_driver_timecounter_tick() erc32_tc_tick()
@@ -137,3 +133,8 @@ static CPU_Counter_ticks erc32_counter_difference(
 
 #include "../../../shared/clockdrv_shell.h"
 
+SPARC_Counter _SPARC_Counter = {
+  .counter_read = _SPARC_Counter_read_address,
+  .counter_difference = _SPARC_Counter_difference_one,
+  .counter_address = (uint32_t *) &_SPARC_Counter
+};
diff --git a/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c b/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c
index 6c2cf98..f21bd18 100644
--- a/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c
+++ b/c/src/lib/libbsp/sparc/leon2/clock/ckinit.c
@@ -105,3 +105,9 @@ extern int CLOCK_SPEED;
 #define Clock_driver_timecounter_tick() leon2_tc_tick()
 
 #include "../../../shared/clockdrv_shell.h"
+
+SPARC_Counter _SPARC_Counter = {
+  .counter_read = _SPARC_Counter_read_address,
+  .counter_difference = _SPARC_Counter_difference_one,
+  .counter_address = (uint32_t *) &_SPARC_Counter
+};
diff --git a/c/src/lib/libbsp/sparc/leon3/include/leon.h b/c/src/lib/libbsp/sparc/leon3/include/leon.h
index ba0673f..b751163 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/leon.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/leon.h
@@ -387,8 +387,6 @@ extern int leon3_timer_core_index;
  */
 extern unsigned int leon3_timer_prescaler;
 
-void leon3_cpu_counter_initialize(void);
-
 /* GRLIB extended IRQ controller register */
 void leon3_ext_irq_init(void);
 
@@ -457,6 +455,51 @@ static inline bool leon3_irqmp_has_timestamp(
   return (irqmp_ts->control >> 27) > 0;
 }
 
+static inline uint32_t leon3_up_counter_low(void)
+{
+  uint32_t asr23;
+
+  __asm__ volatile (
+    "mov %%asr23, %0"
+    : "=&r" (asr23)
+  );
+
+  return asr23;
+}
+
+static inline uint32_t leon3_up_counter_high(void)
+{
+  uint32_t asr22;
+
+  __asm__ volatile (
+    "mov %%asr22, %0"
+    : "=&r" (asr22)
+  );
+
+  return asr22;
+}
+
+static inline void leon3_up_counter_enable(void)
+{
+  __asm__ volatile (
+    "mov %g0, %asr23"
+  );
+}
+
+static inline bool leon3_up_counter_is_available(void)
+{
+  return leon3_up_counter_low() != leon3_up_counter_low();
+}
+
+static inline uint32_t leon3_up_counter_frequency(void)
+{
+  /*
+   * For simplicity, assume that the interrupt controller uses the processor
+   * clock.  This is at least true on the GR740.
+   */
+  return ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev);
+}
+
 #endif /* !ASM */
 
 #ifdef __cplusplus
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c b/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
index 35fe233..80c2bc0 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/bspstart.c
@@ -58,8 +58,6 @@ static inline int set_snooping(void)
 void bsp_start( void )
 {
   CPU_SPARC_HAS_SNOOPING = set_snooping();
-
-  leon3_cpu_counter_initialize();
 }
 
 static void leon3_cpu_index_init(void)
diff --git a/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c b/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
index ea0e671..53d921a 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2014, 2016 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -15,69 +15,66 @@
 #include <leon.h>
 
 #include <rtems/counter.h>
+#include <rtems/sysinit.h>
 
-static CPU_Counter_ticks timestamp_counter_difference(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
+static void leon3_counter_initialize(void)
 {
-  return second - first;
-}
-
-static CPU_Counter_ticks clock_counter_difference(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  CPU_Counter_ticks period = rtems_configuration_get_microseconds_per_tick();
+  volatile struct irqmp_timestamp_regs *irqmp_ts;
+  volatile struct gptimer_regs *gpt;
+  unsigned int freq;
 
-  return (first + period - second) % period;
-}
+  irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
+  gpt = LEON3_Timer_Regs;
 
-static void gpt_counter_initialize(
-  volatile struct gptimer_regs *gpt,
-  size_t timer_index,
-  uint32_t frequency,
-  SPARC_Counter_difference counter_difference
-)
-{
-  _SPARC_Counter_initialize(
-    (volatile const uint32_t *) &gpt->timer[timer_index].value,
-    counter_difference
-  );
+  leon3_up_counter_enable();
 
-  rtems_counter_initialize_converter(frequency);
-}
+  if (leon3_up_counter_is_available()) {
+    /* Use the LEON4 up-counter if available */
 
-void leon3_cpu_counter_initialize(void)
-{
-  volatile struct irqmp_timestamp_regs *irqmp_ts =
-    &LEON3_IrqCtrl_Regs->timestamp[0];
-  unsigned int freq;
+    _SPARC_Counter_initialize(
+      _SPARC_Counter_read_asr23,
+      _SPARC_Counter_difference_normal,
+      NULL
+    );
 
-  if (leon3_irqmp_has_timestamp(irqmp_ts)) {
+    freq = leon3_up_counter_frequency();
+    rtems_counter_initialize_converter(freq);
+  } else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
     /* Use the interrupt controller timestamp counter if available */
 
     /* Enable interrupt timestamping for an arbitrary interrupt line */
     irqmp_ts->control = 0x1;
 
     _SPARC_Counter_initialize(
-      (volatile const uint32_t *) &irqmp_ts->counter,
-      timestamp_counter_difference
+      _SPARC_Counter_read_address,
+      _SPARC_Counter_difference_normal,
+      (volatile const uint32_t *) &irqmp_ts->counter
     );
 
-    /* Get and set the frequency */
-    rtems_counter_initialize_converter(
-      ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev));
-  } else if (LEON3_Timer_Regs != NULL) {
-      /* Fall back to the first GPTIMER if available */
-      freq = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
+    freq = ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev);
+    rtems_counter_initialize_converter(freq);
+  } else if (gpt != NULL) {
+    /* Fall back to the first GPTIMER if available */
+
+    _SPARC_Counter_initialize(
+      _SPARC_Counter_read_address,
+      _SPARC_Counter_difference_clock_period,
+      (volatile const uint32_t *) &gpt->timer[LEON3_CLOCK_INDEX].value
+    );
 
-      gpt_counter_initialize(
-        LEON3_Timer_Regs,
-        LEON3_CLOCK_INDEX,
-        freq / (LEON3_Timer_Regs->scaler_reload - 1),
-        clock_counter_difference
-      );
+    freq = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
+    rtems_counter_initialize_converter(freq / (gpt->scaler_reload - 1));
   }
 }
+
+RTEMS_SYSINIT_ITEM(
+  leon3_counter_initialize,
+  RTEMS_SYSINIT_BSP_START,
+  RTEMS_SYSINIT_ORDER_THIRD
+);
+
+SPARC_Counter _SPARC_Counter = {
+  .counter_read = _SPARC_Counter_read_address,
+  .counter_difference = _SPARC_Counter_difference_one,
+  .counter_address = (uint32_t *) &_SPARC_Counter
+};
diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
index b7f372c..4a0c382 100644
--- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
+++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
@@ -451,10 +451,12 @@ dont_do_the_window:
         subcc    %l7, 1, %l7             ! outermost interrupt handler?
         bnz      dont_switch_stacks      ! No, then do not switch stacks
 
-#if defined( RTEMS_PROFILING )
-         sethi   %hi(SYM(_SPARC_Counter)), %o5
-        ld       [%o5 + %lo(SYM(_SPARC_Counter))], %l4
-        ld       [%l4], %o5
+#if defined(RTEMS_PROFILING)
+         sethi   %hi(_SPARC_Counter), %o5
+        ld       [%o5 + %lo(_SPARC_Counter)], %l4
+        call     %l4, 0
+         nop
+        mov      %o0, %o5
 #else
          nop
 #endif
@@ -536,13 +538,15 @@ pil_fixed:
                                         !   WAS LOADED WHEN ISF WAS SAVED!!!
         mov      %l3, %o0               ! o0 = 1st arg = vector number
         call     %g4, 0
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
          mov     %o5, %l3               ! save interrupt entry instant
         cmp      %l7, 0
         bne      profiling_not_outer_most_exit
          nop
         ta       SPARC_SWTRAP_IRQDIS    ! Call interrupt disable trap handler
-        ld       [%l4], %o2             ! o2 = 3rd arg = interrupt exit instant
+        call     %l4, 0                 ! Call _SPARC_Counter.counter_read
+         nop
+        mov      %o0, %o2               ! o2 = 3rd arg = interrupt exit instant
         mov      %l3, %o1               ! o1 = 2nd arg = interrupt entry instant
         call     SYM(_Profiling_Outer_most_interrupt_entry_and_exit), 0
          mov     %g6, %o0               ! o0 = 1st arg = per-CPU control
diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am
index edebbb6..11b5d11 100644
--- a/cpukit/score/cpu/sparc/Makefile.am
+++ b/cpukit/score/cpu/sparc/Makefile.am
@@ -14,6 +14,7 @@ libscorecpu_a_SOURCES = cpu.c cpu_asm.S
 libscorecpu_a_SOURCES += sparc-context-volatile-clobber.S
 libscorecpu_a_SOURCES += sparc-context-validate.S
 libscorecpu_a_SOURCES += sparc-counter.c
+libscorecpu_a_SOURCES += sparc-counter-asm.S
 libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
 
 include $(srcdir)/preinstall.am
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index ea90e36..c87618d 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -1304,6 +1304,8 @@ static inline uint32_t CPU_swap_u32(
 
 typedef uint32_t CPU_Counter_ticks;
 
+typedef CPU_Counter_ticks ( *SPARC_Counter_read )( void );
+
 typedef CPU_Counter_ticks (*SPARC_Counter_difference)(
   CPU_Counter_ticks second,
   CPU_Counter_ticks first
@@ -1311,46 +1313,57 @@ typedef CPU_Counter_ticks (*SPARC_Counter_difference)(
 
 /*
  * The SPARC processors supported by RTEMS have no built-in CPU counter
- * support.  We have to use some hardware counter module for this purpose.  The
- * BSP must provide a 32-bit register which contains the current CPU counter
- * value and a function for the difference calculation.  It can use for example
- * the GPTIMER instance used for the clock driver.
+ * support.  We have to use some hardware counter module for this purpose, for
+ * example the GPTIMER instance used by the clock driver.  The BSP must provide
+ * an implementation of the CPU counter read and difference functions.  This
+ * allows the use of dynamic hardware enumeration.
  */
 typedef struct {
-  volatile const CPU_Counter_ticks *counter_register;
-  SPARC_Counter_difference counter_difference;
+  SPARC_Counter_read                counter_read;
+  SPARC_Counter_difference          counter_difference;
+  volatile const CPU_Counter_ticks *counter_address;
 } SPARC_Counter;
 
 extern SPARC_Counter _SPARC_Counter;
 
+CPU_Counter_ticks _SPARC_Counter_read_address( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_asr23( void );
+
+CPU_Counter_ticks _SPARC_Counter_difference_normal(
+  CPU_Counter_ticks second,
+  CPU_Counter_ticks first
+);
+
+CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
+  CPU_Counter_ticks second,
+  CPU_Counter_ticks first
+);
+
 /*
  * Returns always a value of one regardless of the parameters.  This prevents
  * an infinite loop in rtems_counter_delay_ticks().  Its only a reasonably safe
  * default.
  */
-CPU_Counter_ticks _SPARC_Counter_difference_default(
+CPU_Counter_ticks _SPARC_Counter_difference_one(
   CPU_Counter_ticks second,
   CPU_Counter_ticks first
 );
 
-static inline bool _SPARC_Counter_is_default( void )
-{
-  return _SPARC_Counter.counter_difference
-    == _SPARC_Counter_difference_default;
-}
-
 static inline void _SPARC_Counter_initialize(
-  volatile const CPU_Counter_ticks *counter_register,
-  SPARC_Counter_difference counter_difference
+  SPARC_Counter_read                counter_read,
+  SPARC_Counter_difference          counter_difference,
+  volatile const CPU_Counter_ticks *counter_address
 )
 {
-  _SPARC_Counter.counter_register = counter_register;
+  _SPARC_Counter.counter_read = counter_read;
   _SPARC_Counter.counter_difference = counter_difference;
+  _SPARC_Counter.counter_address = counter_address;
 }
 
 static inline CPU_Counter_ticks _CPU_Counter_read( void )
 {
-  return *_SPARC_Counter.counter_register;
+  return ( *_SPARC_Counter.counter_read )();
 }
 
 static inline CPU_Counter_ticks _CPU_Counter_difference(
@@ -1358,7 +1371,7 @@ static inline CPU_Counter_ticks _CPU_Counter_difference(
   CPU_Counter_ticks first
 )
 {
-  return (*_SPARC_Counter.counter_difference)( second, first );
+  return ( *_SPARC_Counter.counter_difference )( second, first );
 }
 
 #endif /* ASM */
diff --git a/cpukit/score/cpu/sparc/sparc-counter-asm.S b/cpukit/score/cpu/sparc/sparc-counter-asm.S
new file mode 100644
index 0000000..8ed079f
--- /dev/null
+++ b/cpukit/score/cpu/sparc/sparc-counter-asm.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+	.section	".text"
+	.align	4
+
+	PUBLIC(_SPARC_Counter_read_address)
+SYM(_SPARC_Counter_read_address):
+	sethi	%hi(_SPARC_Counter + 8), %o0
+	ld	[%o0 + %lo(_SPARC_Counter + 8)], %o0
+	jmp	%o7 + 8
+	 ld	[%o0], %o0
+
+	PUBLIC(_SPARC_Counter_read_asr23)
+SYM(_SPARC_Counter_read_asr23):
+	jmp	%o7 + 8
+	 mov	%asr23, %o0
diff --git a/cpukit/score/cpu/sparc/sparc-counter.c b/cpukit/score/cpu/sparc/sparc-counter.c
index d254503..658a47c 100644
--- a/cpukit/score/cpu/sparc/sparc-counter.c
+++ b/cpukit/score/cpu/sparc/sparc-counter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2014, 2016 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -17,18 +17,32 @@
 #endif
 
 #include <rtems/score/cpu.h>
+#include <rtems/config.h>
 
-static CPU_Counter_ticks _SPARC_Counter_register_dummy;
+CPU_Counter_ticks _SPARC_Counter_difference_normal(
+  CPU_Counter_ticks second,
+  CPU_Counter_ticks first
+)
+{
+  return second - first;
+}
 
-CPU_Counter_ticks _SPARC_Counter_difference_default(
+CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
   CPU_Counter_ticks second,
   CPU_Counter_ticks first
 )
 {
-  return 1;
+  CPU_Counter_ticks period;
+
+  period = rtems_configuration_get_microseconds_per_tick();
+
+  return ( first + period - second ) % period;
 }
 
-SPARC_Counter _SPARC_Counter = {
-  .counter_register = &_SPARC_Counter_register_dummy,
-  .counter_difference = _SPARC_Counter_difference_default
-};
+CPU_Counter_ticks _SPARC_Counter_difference_one(
+  CPU_Counter_ticks second,
+  CPU_Counter_ticks first
+)
+{
+  return 1;
+}



More information about the vc mailing list