[rtems commit] Simplify _CPU_Counter_difference()

Sebastian Huber sebh at rtems.org
Fri Dec 7 13:33:23 UTC 2018


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu May  3 13:03:27 2018 +0200

Simplify _CPU_Counter_difference()

In order to simplify the use of CPU counter values it is beneficial to
have monotonic increasing values within the range of the CPU counter
ticks data type, e.g. 32-bit unsigned integer.  This eases the use of
CPU counter timestamps in external tools which do not know the details
of the CPU counter hardware.  The CPU counter is the fastest way to get
a time on an RTEMS system.

Such a CPU counter may be also used as the timecounter.  Use it on SPARC
for this purpose to simplify the clock drivers.

Update #3456.

---

 bsps/or1k/generic_or1k/clock/clockdrv.c            |   8 --
 bsps/shared/dev/cpucounter/cpucounterdiff.c        |  23 ----
 bsps/sparc/erc32/clock/ckinit.c                    | 138 ++++++++++-----------
 bsps/sparc/leon2/clock/ckinit.c                    |  93 ++++++++------
 bsps/sparc/leon3/clock/ckinit.c                    | 126 +++++++------------
 bsps/sparc/leon3/include/leon.h                    |   6 +
 bsps/sparc/leon3/start/cpucounter.c                |  32 ++---
 c/src/lib/libbsp/sparc/leon2/Makefile.am           |   1 -
 cpukit/Makefile.am                                 |   1 -
 cpukit/score/cpu/no_cpu/include/rtems/score/cpu.h  |   7 +-
 cpukit/score/cpu/or1k/include/rtems/score/cpu.h    |   7 +-
 cpukit/score/cpu/sparc/include/rtems/score/cpu.h   |  23 ++--
 .../cpu/sparc/include/rtems/score/sparcimpl.h      |  61 ++++-----
 cpukit/score/cpu/sparc/sparc-counter-asm.S         | 105 +++++++++++++++-
 cpukit/score/cpu/sparc/sparc-counter.c             |  48 -------
 15 files changed, 332 insertions(+), 347 deletions(-)

diff --git a/bsps/or1k/generic_or1k/clock/clockdrv.c b/bsps/or1k/generic_or1k/clock/clockdrv.c
index 44365aa..7b8a07f 100644
--- a/bsps/or1k/generic_or1k/clock/clockdrv.c
+++ b/bsps/or1k/generic_or1k/clock/clockdrv.c
@@ -109,14 +109,6 @@ static void generic_or1k_clock_initialize(void)
   rtems_timecounter_install(&or1ksim_tc);
 }
 
-CPU_Counter_ticks _CPU_Counter_difference(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  return second - first;
-}
-
 #define Clock_driver_support_at_tick() generic_or1k_clock_at_tick()
 
 #define Clock_driver_support_initialize_hardware() generic_or1k_clock_initialize()
diff --git a/bsps/shared/dev/cpucounter/cpucounterdiff.c b/bsps/shared/dev/cpucounter/cpucounterdiff.c
deleted file mode 100644
index d77945d..0000000
--- a/bsps/shared/dev/cpucounter/cpucounterdiff.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2014 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.
- */
-
-#include <rtems/score/cpu.h>
-
-CPU_Counter_ticks _CPU_Counter_difference(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  return second - first;
-}
diff --git a/bsps/sparc/erc32/clock/ckinit.c b/bsps/sparc/erc32/clock/ckinit.c
index e7c5b07..6d6a335 100644
--- a/bsps/sparc/erc32/clock/ckinit.c
+++ b/bsps/sparc/erc32/clock/ckinit.c
@@ -24,103 +24,97 @@
 
 #include <bsp.h>
 #include <bspopts.h>
-#include <rtems/counter.h>
+#include <rtems/sysinit.h>
 #include <rtems/timecounter.h>
 #include <rtems/score/sparcimpl.h>
 
-#define ERC32_REAL_TIME_CLOCK_FREQUENCY 1000000
-
-/*
- *  The Real Time Clock Counter Timer uses this trap type.
- */
-#define CLOCK_VECTOR ERC32_TRAP_TYPE( ERC32_INTERRUPT_REAL_TIME_CLOCK )
-
-#define Clock_driver_support_install_isr( _new ) \
-  set_vector( _new, CLOCK_VECTOR, 1 )
-
-#define Clock_driver_support_set_interrupt_affinity( _online_processors ) \
-  do { \
-    (void) _online_processors; \
-  } while (0)
-
 extern int CLOCK_SPEED;
 
-static rtems_timecounter_simple erc32_tc;
+#define ERC32_REAL_TIME_CLOCK_FREQUENCY 1000000
 
-static uint32_t erc32_tc_get( rtems_timecounter_simple *tc )
-{
-  return ERC32_MEC.Real_Time_Clock_Counter;
-}
+static struct timecounter erc32_tc;
 
-static bool erc32_tc_is_pending( rtems_timecounter_simple *tc )
+static void erc32_clock_init( void )
 {
-  return ERC32_Is_interrupt_pending( ERC32_INTERRUPT_REAL_TIME_CLOCK );
+  struct timecounter *tc;
+
+  tc = &erc32_tc;
+  tc->tc_get_timecount = _SPARC_Get_timecount_clock;
+  tc->tc_counter_mask = 0xffffffff;
+  tc->tc_frequency = ERC32_REAL_TIME_CLOCK_FREQUENCY;
+  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+  rtems_timecounter_install(tc);
 }
 
-static uint32_t erc32_tc_get_timecount( struct timecounter *tc )
+uint32_t _CPU_Counter_frequency(void)
 {
-  return rtems_timecounter_simple_downcounter_get(
-    tc,
-    erc32_tc_get,
-    erc32_tc_is_pending
-  );
+  return ERC32_REAL_TIME_CLOCK_FREQUENCY;
 }
 
-static void erc32_tc_at_tick( rtems_timecounter_simple *tc )
+static void erc32_clock_at_tick( void )
 {
-  /* Nothing to do */
-}
+  SPARC_Counter *counter;
+  rtems_interrupt_level level;
 
-static void erc32_tc_tick( void )
-{
-  rtems_timecounter_simple_downcounter_tick(
-    &erc32_tc,
-    erc32_tc_get,
-    erc32_tc_at_tick
-  );
+  counter = &_SPARC_Counter_mutable;
+  rtems_interrupt_local_disable(level);
+
+  ERC32_Clear_interrupt( ERC32_INTERRUPT_REAL_TIME_CLOCK );
+  counter->accumulated += counter->interval;
+
+  rtems_interrupt_local_enable(level);
 }
 
-static void erc32_counter_initialize( void )
+static void erc32_clock_initialize_early( void )
 {
-  _SPARC_Counter_initialize(
-    _SPARC_Counter_read_address,
-    _SPARC_Counter_difference_clock_period,
-    &ERC32_MEC.Real_Time_Clock_Counter
+  SPARC_Counter *counter;
+
+  /* approximately 1 us per countdown */
+  ERC32_MEC.Real_Time_Clock_Scalar = CLOCK_SPEED - 1;
+  ERC32_MEC.Real_Time_Clock_Counter =
+    rtems_configuration_get_microseconds_per_tick();
+  ERC32_MEC_Set_Real_Time_Clock_Timer_Control(
+      ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING |
+      ERC32_MEC_TIMER_COUNTER_LOAD_SCALER |
+      ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER
+  );
+  ERC32_MEC_Set_Real_Time_Clock_Timer_Control(
+    ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING |
+    ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO
   );
-}
 
-uint32_t _CPU_Counter_frequency(void)
-{
-  return ERC32_REAL_TIME_CLOCK_FREQUENCY;
+  counter = &_SPARC_Counter_mutable;
+  counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
+  counter->read = _SPARC_Counter_read_clock;
+  counter->counter_register = &ERC32_MEC.Real_Time_Clock_Counter,
+  counter->pending_register = &ERC32_MEC.Interrupt_Pending;
+  counter->pending_mask = UINT32_C(1) << ERC32_INTERRUPT_REAL_TIME_CLOCK;
+  counter->accumulated = rtems_configuration_get_microseconds_per_tick();
+  counter->interval = rtems_configuration_get_microseconds_per_tick();
 }
 
-#define Clock_driver_support_initialize_hardware() \
+RTEMS_SYSINIT_ITEM(
+  erc32_clock_initialize_early,
+  RTEMS_SYSINIT_CPU_COUNTER,
+  RTEMS_SYSINIT_ORDER_FIRST
+);
+
+/*
+ *  The Real Time Clock Counter Timer uses this trap type.
+ */
+#define CLOCK_VECTOR ERC32_TRAP_TYPE( ERC32_INTERRUPT_REAL_TIME_CLOCK )
+
+#define Clock_driver_support_install_isr( _new ) \
+  set_vector( _new, CLOCK_VECTOR, 1 )
+
+#define Clock_driver_support_set_interrupt_affinity( _online_processors ) \
   do { \
-    /* approximately 1 us per countdown */ \
-    ERC32_MEC.Real_Time_Clock_Scalar  = CLOCK_SPEED - 1; \
-    ERC32_MEC.Real_Time_Clock_Counter = \
-      rtems_configuration_get_microseconds_per_tick(); \
-    \
-    ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \
-        ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \
-        ERC32_MEC_TIMER_COUNTER_LOAD_SCALER | \
-        ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER \
-    ); \
-    \
-    ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \
-        ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \
-        ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO \
-    );  \
-    rtems_timecounter_simple_install( \
-        &erc32_tc, \
-        ERC32_REAL_TIME_CLOCK_FREQUENCY, \
-        rtems_configuration_get_microseconds_per_tick(), \
-        erc32_tc_get_timecount \
-    ); \
-    erc32_counter_initialize(); \
+    (void) _online_processors; \
   } while (0)
 
-#define Clock_driver_timecounter_tick() erc32_tc_tick()
+#define Clock_driver_support_at_tick() erc32_clock_at_tick()
+
+#define Clock_driver_support_initialize_hardware() erc32_clock_init()
 
 #include "../../../shared/dev/clock/clockimpl.h"
 
diff --git a/bsps/sparc/leon2/clock/ckinit.c b/bsps/sparc/leon2/clock/ckinit.c
index f622975..2707c7d 100644
--- a/bsps/sparc/leon2/clock/ckinit.c
+++ b/bsps/sparc/leon2/clock/ckinit.c
@@ -24,42 +24,73 @@
 
 #include <bsp.h>
 #include <bspopts.h>
+#include <rtems/sysinit.h>
 #include <rtems/timecounter.h>
 #include <rtems/score/sparcimpl.h>
 
-static rtems_timecounter_simple leon2_tc;
+extern int CLOCK_SPEED;
+
+#define LEON2_TIMER_1_FREQUENCY 1000000
+
+static struct timecounter leon2_tc;
 
-static uint32_t leon2_tc_get( rtems_timecounter_simple *tc )
+static void leon2_clock_init( void )
 {
-  return LEON_REG.Timer_Counter_1;
+  struct timecounter *tc;
+
+  tc = &leon2_tc;
+  tc->tc_get_timecount = _SPARC_Get_timecount_clock;
+  tc->tc_counter_mask = 0xffffffff;
+  tc->tc_frequency = LEON2_TIMER_1_FREQUENCY;
+  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+  rtems_timecounter_install(tc);
 }
 
-static bool leon2_tc_is_pending( rtems_timecounter_simple *tc )
+static void leon2_clock_at_tick( void )
 {
-  return LEON_Is_interrupt_pending( LEON_INTERRUPT_TIMER1 );
+  SPARC_Counter *counter;
+  rtems_interrupt_level level;
+
+  counter = &_SPARC_Counter_mutable;
+  rtems_interrupt_local_disable(level);
+
+  LEON_Clear_interrupt( LEON_INTERRUPT_TIMER1 );
+  counter->accumulated += counter->interval;
+
+  rtems_interrupt_local_enable(level);
 }
 
-static uint32_t leon2_tc_get_timecount( struct timecounter *tc )
+static void leon2_clock_initialize_early( void )
 {
-  return rtems_timecounter_simple_downcounter_get(
-    tc,
-    leon2_tc_get,
-    leon2_tc_is_pending
+  SPARC_Counter *counter;
+
+  LEON_REG.Timer_Reload_1 =
+    rtems_configuration_get_microseconds_per_tick() - 1;
+  LEON_REG.Timer_Control_1 = (
+    LEON_REG_TIMER_COUNTER_ENABLE_COUNTING |
+      LEON_REG_TIMER_COUNTER_RELOAD_AT_ZERO |
+      LEON_REG_TIMER_COUNTER_LOAD_COUNTER
   );
-}
 
-static void leon2_tc_at_tick( rtems_timecounter_simple *tc )
-{
-  /* Nothing to do */
+  counter = &_SPARC_Counter_mutable;
+  counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
+  counter->read = _SPARC_Counter_read_clock;
+  counter->counter_register = &LEON_REG.Timer_Counter_1;
+  counter->pending_register = &LEON_REG.Interrupt_Pending;
+  counter->pending_mask = UINT32_C(1) << LEON_INTERRUPT_TIMER1;
+  counter->accumulated = rtems_configuration_get_microseconds_per_tick();
+  counter->interval = rtems_configuration_get_microseconds_per_tick();
 }
 
-static void leon2_tc_tick( void )
+RTEMS_SYSINIT_ITEM(
+  leon2_clock_initialize_early,
+  RTEMS_SYSINIT_CPU_COUNTER,
+  RTEMS_SYSINIT_ORDER_FIRST
+);
+
+uint32_t _CPU_Counter_frequency(void)
 {
-  rtems_timecounter_simple_downcounter_tick(
-    &leon2_tc,
-    leon2_tc_get,
-    leon2_tc_at_tick
-  );
+  return LEON2_TIMER_1_FREQUENCY;
 }
 
 /*
@@ -71,27 +102,9 @@ static void leon2_tc_tick( void )
 #define Clock_driver_support_install_isr( _new ) \
   set_vector( _new, CLOCK_VECTOR, 1 )
 
-extern int CLOCK_SPEED;
+#define Clock_driver_support_at_tick() leon2_clock_at_tick()
 
-#define Clock_driver_support_initialize_hardware() \
-  do { \
-    LEON_REG.Timer_Reload_1 = \
-        rtems_configuration_get_microseconds_per_tick() - 1; \
-    \
-    LEON_REG.Timer_Control_1 = ( \
-      LEON_REG_TIMER_COUNTER_ENABLE_COUNTING |  \
-        LEON_REG_TIMER_COUNTER_RELOAD_AT_ZERO | \
-        LEON_REG_TIMER_COUNTER_LOAD_COUNTER  \
-    ); \
-    rtems_timecounter_simple_install( \
-      &leon2_tc, \
-      1000000, \
-      rtems_configuration_get_microseconds_per_tick(), \
-      leon2_tc_get_timecount \
-    ); \
-  } while (0)
-
-#define Clock_driver_timecounter_tick() leon2_tc_tick()
+#define Clock_driver_support_initialize_hardware() leon2_clock_init()
 
 #include "../../../shared/dev/clock/clockimpl.h"
 
diff --git a/bsps/sparc/leon3/clock/ckinit.c b/bsps/sparc/leon3/clock/ckinit.c
index 0cd78ea..fecbf32 100644
--- a/bsps/sparc/leon3/clock/ckinit.c
+++ b/bsps/sparc/leon3/clock/ckinit.c
@@ -27,6 +27,7 @@
 #include <rtems/rtems/intr.h>
 #include <ambapp.h>
 #include <rtems/score/profiling.h>
+#include <rtems/score/sparcimpl.h>
 #include <rtems/timecounter.h>
 
 /* The LEON3 BSP Timer driver can rely on the Driver Manager if the
@@ -42,59 +43,7 @@ static int clkirq;
 
 static void (*leon3_tc_tick)(void);
 
-static rtems_timecounter_simple leon3_tc;
-
-#ifndef RTEMS_SMP
-static uint32_t leon3_tc_get(rtems_timecounter_simple *tc)
-{
-  return LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
-}
-
-static bool leon3_tc_is_pending(rtems_timecounter_simple *tc)
-{
-  return LEON_Is_interrupt_pending(clkirq);
-}
-
-static void leon3_tc_at_tick( rtems_timecounter_simple *tc )
-{
-  /* Nothing to do */
-}
-
-static uint32_t leon3_tc_get_timecount(struct timecounter *tc)
-{
-  return rtems_timecounter_simple_downcounter_get(
-    tc,
-    leon3_tc_get,
-    leon3_tc_is_pending
-  );
-}
-
-static void leon3_tc_tick_simple(void)
-{
-  rtems_timecounter_simple_downcounter_tick(
-    &leon3_tc,
-    leon3_tc_get,
-    leon3_tc_at_tick
-  );
-}
-#endif
-
-static uint32_t leon3_tc_get_timecount_up_counter(struct timecounter *tc)
-{
-  return leon3_up_counter_low();
-}
-
-static uint32_t leon3_tc_get_timecount_irqmp(struct timecounter *tc)
-{
-  return LEON3_IrqCtrl_Regs->timestamp[0].counter;
-}
-
-#ifdef RTEMS_SMP
-static uint32_t leon3_tc_get_timecount_second_timer(struct timecounter *tc)
-{
-  return 0xffffffff - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX + 1].value;
-}
-#endif
+static struct timecounter leon3_tc;
 
 #ifdef RTEMS_PROFILING
 #define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
@@ -146,12 +95,23 @@ static void leon3_tc_tick_irqmp_timestamp_init(void)
   rtems_timecounter_tick();
 }
 
-#ifdef RTEMS_SMP
-static void leon3_tc_tick_second_timer(void)
+static void leon3_tc_tick_default(void)
 {
+#ifndef RTEMS_SMP
+  SPARC_Counter *counter;
+  rtems_interrupt_level level;
+
+  counter = &_SPARC_Counter_mutable;
+  rtems_interrupt_local_disable(level);
+
+  LEON3_IrqCtrl_Regs->iclear = counter->pending_mask;
+  counter->accumulated += counter->interval;
+
+  rtems_interrupt_local_enable(level);
+#endif
+
   rtems_timecounter_tick();
 }
-#endif
 
 static void leon3_tc_do_tick(void)
 {
@@ -196,9 +156,11 @@ static void leon3_clock_initialize(void)
 {
   volatile struct irqmp_timestamp_regs *irqmp_ts;
   volatile struct gptimer_regs *gpt;
+  struct timecounter *tc;
 
   irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
   gpt = LEON3_Timer_Regs;
+  tc = &leon3_tc;
 
   gpt->timer[LEON3_CLOCK_INDEX].reload =
     rtems_configuration_get_microseconds_per_tick() - 1;
@@ -210,10 +172,8 @@ static void leon3_clock_initialize(void)
 
   if (leon3_up_counter_is_available()) {
     /* Use the LEON4 up-counter if available */
-    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_up_counter;
-    leon3_tc.tc.tc_counter_mask = 0xffffffff;
-    leon3_tc.tc.tc_frequency = leon3_up_counter_frequency();
-    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+    tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
+    tc->tc_frequency = leon3_up_counter_frequency();
 
 #ifdef RTEMS_PROFILING
     if (!leon3_irqmp_has_timestamp(irqmp_ts)) {
@@ -222,13 +182,11 @@ static void leon3_clock_initialize(void)
 #endif
 
     leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
-    rtems_timecounter_install(&leon3_tc.tc);
   } else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
     /* Use the interrupt controller timestamp counter if available */
-    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_irqmp;
-    leon3_tc.tc.tc_counter_mask = 0xffffffff;
-    leon3_tc.tc.tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
-    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+    tc->tc_get_timecount = _SPARC_Get_timecount_up;
+    tc->tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
+
     leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
 
     /*
@@ -236,8 +194,6 @@ static void leon3_clock_initialize(void)
      * counter.  Use an arbitrary interrupt source.
      */
     irqmp_ts->control = 0x1;
-
-    rtems_timecounter_install(&leon3_tc.tc);
   } else {
 #ifdef RTEMS_SMP
     /*
@@ -245,24 +201,32 @@ static void leon3_clock_initialize(void)
      * controller.  At least on SMP configurations we must use a second timer
      * in free running mode for the timecounter.
      */
-    gpt->timer[LEON3_CLOCK_INDEX + 1].ctrl =
+    gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl =
       GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_IE;
-    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_second_timer;
-    leon3_tc.tc.tc_counter_mask = 0xffffffff;
-    leon3_tc.tc.tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
-    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
-    leon3_tc_tick = leon3_tc_tick_second_timer;
-    rtems_timecounter_install(&leon3_tc.tc);
+
+    tc->tc_get_timecount = _SPARC_Get_timecount_down;
 #else
-    leon3_tc_tick = leon3_tc_tick_simple;
-    rtems_timecounter_simple_install(
-      &leon3_tc,
-      LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
-      rtems_configuration_get_microseconds_per_tick(),
-      leon3_tc_get_timecount
-    );
+    SPARC_Counter *counter;
+
+    counter = &_SPARC_Counter_mutable;
+    counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
+    counter->read = _SPARC_Counter_read_clock;
+    counter->counter_register = &gpt->timer[LEON3_CLOCK_INDEX].value;
+    counter->pending_register = &LEON3_IrqCtrl_Regs->ipend;
+    counter->pending_mask = UINT32_C(1) << clkirq;
+    counter->accumulated = rtems_configuration_get_microseconds_per_tick();
+    counter->interval = rtems_configuration_get_microseconds_per_tick();
+
+    tc->tc_get_timecount = _SPARC_Get_timecount_clock;
 #endif
+
+    tc->tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
+    leon3_tc_tick = leon3_tc_tick_default;
   }
+
+  tc->tc_counter_mask = 0xffffffff;
+  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+  rtems_timecounter_install(tc);
 }
 
 #define Clock_driver_support_initialize_hardware() \
diff --git a/bsps/sparc/leon3/include/leon.h b/bsps/sparc/leon3/include/leon.h
index 758b760..afe0d91 100644
--- a/bsps/sparc/leon3/include/leon.h
+++ b/bsps/sparc/leon3/include/leon.h
@@ -333,6 +333,12 @@ extern rtems_interrupt_lock LEON3_IrqCtrl_Lock;
   #define LEON3_CLOCK_INDEX 0
 #endif
 
+#if defined(RTEMS_SMP)
+#define LEON3_COUNTER_GPTIMER_INDEX (LEON3_CLOCK_INDEX + 1)
+#else
+#define LEON3_COUNTER_GPTIMER_INDEX LEON3_CLOCK_INDEX
+#endif
+
 /*
  * We assume that a boot loader (usually GRMON) initialized the GPTIMER 0 to
  * run with 1MHz.  This is used to determine all clock frequencies of the PnP
diff --git a/bsps/sparc/leon3/start/cpucounter.c b/bsps/sparc/leon3/start/cpucounter.c
index f583d9b..007bb6d 100644
--- a/bsps/sparc/leon3/start/cpucounter.c
+++ b/bsps/sparc/leon3/start/cpucounter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2014, 2018 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -29,46 +29,38 @@ static void leon3_counter_initialize(void)
 {
   volatile struct irqmp_timestamp_regs *irqmp_ts;
   volatile struct gptimer_regs *gpt;
+  SPARC_Counter *counter;
 
   irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
   gpt = LEON3_Timer_Regs;
+  counter = &_SPARC_Counter_mutable;
 
   leon3_up_counter_enable();
 
   if (leon3_up_counter_is_available()) {
     /* Use the LEON4 up-counter if available */
-
-    _SPARC_Counter_initialize(
-      _SPARC_Counter_read_asr23,
-      _SPARC_Counter_difference_normal,
-      NULL
-    );
+    counter->read_isr_disabled = _SPARC_Counter_read_asr23;
+    counter->read = _SPARC_Counter_read_asr23;
 
     leon3_counter_frequency = leon3_up_counter_frequency();
   } else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
     /* Use the interrupt controller timestamp counter if available */
+    counter->read_isr_disabled = _SPARC_Counter_read_up;
+    counter->read = _SPARC_Counter_read_up;
+    counter->counter_register = &LEON3_IrqCtrl_Regs->timestamp[0].counter;
 
     /* Enable interrupt timestamping for an arbitrary interrupt line */
     irqmp_ts->control = 0x1;
 
-    _SPARC_Counter_initialize(
-      _SPARC_Counter_read_address,
-      _SPARC_Counter_difference_normal,
-      (volatile const uint32_t *) &irqmp_ts->counter
-    );
-
     leon3_counter_frequency = ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev);
   } else if (gpt != NULL) {
     /* Fall back to the first GPTIMER if available */
+    counter->read_isr_disabled = _SPARC_Counter_read_down;
+    counter->read = _SPARC_Counter_read_down;
+    counter->counter_register = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].value;
 
     /* Enable timer just in case no clock driver is configured */
-    gpt->timer[LEON3_CLOCK_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN;
-
-    _SPARC_Counter_initialize(
-      _SPARC_Counter_read_address,
-      _SPARC_Counter_difference_clock_period,
-      (volatile const uint32_t *) &gpt->timer[LEON3_CLOCK_INDEX].value
-    );
+    gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN;
 
     leon3_counter_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev) /
       (gpt->scaler_reload + 1);
diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
index 7471007..72946c0 100644
--- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
@@ -26,7 +26,6 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspfatal-default.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspreset-empty.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon2/start/bspstart.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/shared/start/bspgetworkarea.c
-librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/cpucounter/cpucounterfrequency.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/getentropy/getentropy-cpucounter.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/sbrk.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon2/start/setvec.c
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 5e7d471..188001a 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -1753,7 +1753,6 @@ librtemscpu_a_SOURCES += score/cpu/sparc/sparc-access.S
 librtemscpu_a_SOURCES += score/cpu/sparc/sparc-context-validate.S
 librtemscpu_a_SOURCES += score/cpu/sparc/sparc-context-volatile-clobber.S
 librtemscpu_a_SOURCES += score/cpu/sparc/sparc-counter-asm.S
-librtemscpu_a_SOURCES += score/cpu/sparc/sparc-counter.c
 librtemscpu_a_SOURCES += score/cpu/sparc/syscall.S
 librtemscpu_a_SOURCES += score/cpu/sparc/window.S
 
diff --git a/cpukit/score/cpu/no_cpu/include/rtems/score/cpu.h b/cpukit/score/cpu/no_cpu/include/rtems/score/cpu.h
index 7ab09d9..6b6094a 100644
--- a/cpukit/score/cpu/no_cpu/include/rtems/score/cpu.h
+++ b/cpukit/score/cpu/no_cpu/include/rtems/score/cpu.h
@@ -1219,10 +1219,13 @@ CPU_Counter_ticks _CPU_Counter_read( void );
  *
  * @return Returns second minus first modulo counter period.
  */
-CPU_Counter_ticks _CPU_Counter_difference(
+static inline CPU_Counter_ticks _CPU_Counter_difference(
   CPU_Counter_ticks second,
   CPU_Counter_ticks first
-);
+)
+{
+  return second - first;
+}
 
 #ifdef RTEMS_SMP
   /**
diff --git a/cpukit/score/cpu/or1k/include/rtems/score/cpu.h b/cpukit/score/cpu/or1k/include/rtems/score/cpu.h
index 0d1566a..663a175 100644
--- a/cpukit/score/cpu/or1k/include/rtems/score/cpu.h
+++ b/cpukit/score/cpu/or1k/include/rtems/score/cpu.h
@@ -712,10 +712,13 @@ uint32_t _CPU_Counter_frequency( void );
 
 CPU_Counter_ticks _CPU_Counter_read( void );
 
-CPU_Counter_ticks _CPU_Counter_difference(
+static inline CPU_Counter_ticks _CPU_Counter_difference(
   CPU_Counter_ticks second,
   CPU_Counter_ticks first
-);
+)
+{
+  return second - first;
+}
 
 /** Type that can store a 32-bit integer or a pointer. */
 typedef uintptr_t CPU_Uint32ptr;
diff --git a/cpukit/score/cpu/sparc/include/rtems/score/cpu.h b/cpukit/score/cpu/sparc/include/rtems/score/cpu.h
index 252aa40..abc813c 100644
--- a/cpukit/score/cpu/sparc/include/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/include/rtems/score/cpu.h
@@ -1103,29 +1103,28 @@ uint32_t _CPU_Counter_frequency( void );
 
 typedef CPU_Counter_ticks ( *SPARC_Counter_read )( void );
 
-typedef CPU_Counter_ticks ( *SPARC_Counter_difference )(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-);
-
 /*
  * The SPARC processors supported by RTEMS have no built-in CPU counter
  * 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.
+ * an implementation of the CPU counter read function.  This allows the use of
+ * dynamic hardware enumeration.
  */
 typedef struct {
-  SPARC_Counter_read                counter_read;
-  SPARC_Counter_difference          counter_difference;
-  volatile const CPU_Counter_ticks *counter_address;
+  SPARC_Counter_read                read_isr_disabled;
+  SPARC_Counter_read                read;
+  volatile const CPU_Counter_ticks *counter_register;
+  volatile const uint32_t          *pending_register;
+  uint32_t                          pending_mask;
+  CPU_Counter_ticks                 accumulated;
+  CPU_Counter_ticks                 interval;
 } SPARC_Counter;
 
 extern const SPARC_Counter _SPARC_Counter;
 
 static inline CPU_Counter_ticks _CPU_Counter_read( void )
 {
-  return ( *_SPARC_Counter.counter_read )();
+  return ( *_SPARC_Counter.read )();
 }
 
 static inline CPU_Counter_ticks _CPU_Counter_difference(
@@ -1133,7 +1132,7 @@ static inline CPU_Counter_ticks _CPU_Counter_difference(
   CPU_Counter_ticks first
 )
 {
-  return ( *_SPARC_Counter.counter_difference )( second, first );
+  return second - first;
 }
 
 /** Type that can store a 32-bit integer or a pointer. */
diff --git a/cpukit/score/cpu/sparc/include/rtems/score/sparcimpl.h b/cpukit/score/cpu/sparc/include/rtems/score/sparcimpl.h
index 81b4441..edc03bd 100644
--- a/cpukit/score/cpu/sparc/include/rtems/score/sparcimpl.h
+++ b/cpukit/score/cpu/sparc/include/rtems/score/sparcimpl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2016, 2018 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -21,6 +21,8 @@
 extern "C" {
 #endif /* __cplusplus */
 
+struct timecounter;
+
 /*
  * Provides a mutable alias to _SPARC_Counter for use in
  * _SPARC_Counter_initialize().  The _SPARC_Counter and _SPARC_Counter_mutable
@@ -28,40 +30,27 @@ extern "C" {
  */
 extern SPARC_Counter _SPARC_Counter_mutable;
 
-CPU_Counter_ticks _SPARC_Counter_read_address( void );
+void _SPARC_Counter_at_tick_clock( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_default( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_up( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_down( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_clock_isr_disabled( void );
+
+CPU_Counter_ticks _SPARC_Counter_read_clock( void );
 
 CPU_Counter_ticks _SPARC_Counter_read_asr23( void );
 
-CPU_Counter_ticks _SPARC_Counter_difference_normal(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-);
+uint32_t _SPARC_Get_timecount_up( struct timecounter * );
 
-CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-);
+uint32_t _SPARC_Get_timecount_down( struct timecounter * );
 
-/*
- * 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_one(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-);
-
-static inline void _SPARC_Counter_initialize(
-  SPARC_Counter_read                counter_read,
-  SPARC_Counter_difference          counter_difference,
-  volatile const CPU_Counter_ticks *counter_address
-)
-{
-  _SPARC_Counter_mutable.counter_read = counter_read;
-  _SPARC_Counter_mutable.counter_difference = counter_difference;
-  _SPARC_Counter_mutable.counter_address = counter_address;
-}
+uint32_t _SPARC_Get_timecount_clock( struct timecounter * );
+
+uint32_t _SPARC_Get_timecount_asr23( struct timecounter * );
 
 /*
  * Defines the _SPARC_Counter and _SPARC_Counter_mutable global variables.
@@ -75,12 +64,16 @@ static inline void _SPARC_Counter_initialize(
     "\t.section\t.data._SPARC_Counter,\"aw\", at progbits\n" \
     "\t.align\t4\n" \
     "\t.type\t_SPARC_Counter, #object\n" \
-    "\t.size\t_SPARC_Counter, 12\n" \
+    "\t.size\t_SPARC_Counter, 28\n" \
     "_SPARC_Counter:\n" \
     "_SPARC_Counter_mutable:\n" \
-    "\t.long\t_SPARC_Counter_read_address\n" \
-    "\t.long\t_SPARC_Counter_difference_one\n" \
-    "\t.long\t_SPARC_Counter\n" \
+    "\t.long\t_SPARC_Counter_read_default\n" \
+    "\t.long\t_SPARC_Counter_read_default\n" \
+    "\t.long\t0\n" \
+    "\t.long\t0\n" \
+    "\t.long\t0\n" \
+    "\t.long\t0\n" \
+    "\t.long\t0\n" \
     "\t.previous\n" \
   )
 
diff --git a/cpukit/score/cpu/sparc/sparc-counter-asm.S b/cpukit/score/cpu/sparc/sparc-counter-asm.S
index 8ed079f..6f3e61c 100644
--- a/cpukit/score/cpu/sparc/sparc-counter-asm.S
+++ b/cpukit/score/cpu/sparc/sparc-counter-asm.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2016, 2018 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -18,17 +18,116 @@
 
 #include <rtems/asm.h>
 
+	/*
+	 * All functions except _SPARC_Counter_read_clock() in this module are
+	 * sometimes called with traps disabled.
+	 */
+
 	.section	".text"
 	.align	4
 
-	PUBLIC(_SPARC_Counter_read_address)
-SYM(_SPARC_Counter_read_address):
+	PUBLIC(_SPARC_Counter_read_default)
+SYM(_SPARC_Counter_read_default):
+	sethi	%hi(_SPARC_Counter + 12), %o1
+	ld	[%o1 + %lo(_SPARC_Counter + 12)], %o0
+	add	%o0, 1, %o0
+	jmp	%o7 + 8
+	 st	%o0, [%o1 + %lo(_SPARC_Counter + 12)]
+
+	PUBLIC(_SPARC_Counter_read_up)
+	PUBLIC(_SPARC_Get_timecount_up)
+SYM(_SPARC_Counter_read_up):
+SYM(_SPARC_Get_timecount_up):
 	sethi	%hi(_SPARC_Counter + 8), %o0
 	ld	[%o0 + %lo(_SPARC_Counter + 8)], %o0
 	jmp	%o7 + 8
 	 ld	[%o0], %o0
 
+	PUBLIC(_SPARC_Counter_read_down)
+	PUBLIC(_SPARC_Get_timecount_down)
+SYM(_SPARC_Counter_read_down):
+SYM(_SPARC_Get_timecount_down):
+	sethi	%hi(_SPARC_Counter + 8), %o0
+	ld	[%o0 + %lo(_SPARC_Counter + 8)], %o0
+	ld	[%o0], %o0
+	jmp	%o7 + 8
+	 xnor	%g0, %o0, %o0
+
+	/*
+	 * For the corresponding C code is something like this:
+	 *
+	 * CPU_Counter_ticks _SPARC_Counter_read_clock_isr_disabled( void )
+	 * {
+	 *   const SPARC_Counter *ctr;
+	 *   CPU_Counter_ticks    ticks;
+	 *   CPU_Counter_ticks    accumulated;
+	 *
+	 *   ctr = &_SPARC_Counter;
+	 *   ticks = *ctr->counter_register;
+	 *   accumulated = ctr->accumulated;
+	 *
+	 *   if ( ( *ctr->pending_register & ctr->pending_mask ) != 0 ) {
+	 *     ticks = *ctr->counter_register;
+	 *     accumulated += ctr->interval;
+	 *   }
+	 *
+	 *   return accumulated - ticks;
+	 * }
+	 */
+	PUBLIC(_SPARC_Counter_read_clock_isr_disabled)
+SYM(_SPARC_Counter_read_clock_isr_disabled):
+	sethi	%hi(_SPARC_Counter), %o5
+	or	%o5, %lo(_SPARC_Counter), %o5
+	ld	[%o5 + 8], %o3
+	ld	[%o5 + 12], %o4
+	ld	[%o5 + 16], %o2
+	ld	[%o3], %o0
+	ld	[%o4], %o1
+	btst	%o1, %o2
+	bne	.Lpending_isr_disabled
+	 ld	[%o5 + 20], %o4
+	jmp	%o7 + 8
+	 sub	%o4, %o0, %o0
+.Lpending_isr_disabled:
+	ld	[%o5 + 24], %o5
+	ld	[%o3], %o0
+	add	%o4, %o5, %o4
+	jmp	%o7 + 8
+	 sub	%o4, %o0, %o0
+
+	/*
+	 * For the corresponding C code see
+	 * _SPARC_Counter_read_clock_isr_disabled() above.
+	 */
+	PUBLIC(_SPARC_Counter_read_clock)
+	PUBLIC(_SPARC_Get_timecount_clock)
+SYM(_SPARC_Counter_read_clock):
+SYM(_SPARC_Get_timecount_clock):
+	sethi	%hi(_SPARC_Counter), %o5
+	or	%o5, %lo(_SPARC_Counter), %o5
+	ta	SPARC_SWTRAP_IRQDIS
+	ld	[%o5 + 8], %o3
+	ld	[%o5 + 12], %o4
+	ld	[%o5 + 16], %o2
+	ld	[%o3], %o0
+	ld	[%o4], %o1
+	btst	%o1, %o2
+	bne	.Lpending
+	 ld	[%o5 + 20], %o4
+	ta	SPARC_SWTRAP_IRQEN
+	jmp	%o7 + 8
+	 sub	%o4, %o0, %o0
+.Lpending:
+	ld	[%o5 + 24], %o5
+	ld	[%o3], %o0
+	ta	SPARC_SWTRAP_IRQEN
+	add	%o4, %o5, %o4
+	jmp	%o7 + 8
+	 sub	%o4, %o0, %o0
+
 	PUBLIC(_SPARC_Counter_read_asr23)
+	PUBLIC(_SPARC_Get_timecount_asr23)
 SYM(_SPARC_Counter_read_asr23):
+SYM(_SPARC_Get_timecount_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
deleted file mode 100644
index 9bc4061..0000000
--- a/cpukit/score/cpu/sparc/sparc-counter.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014, 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/score/sparcimpl.h>
-#include <rtems/config.h>
-
-CPU_Counter_ticks _SPARC_Counter_difference_normal(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  return second - first;
-}
-
-CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  CPU_Counter_ticks period;
-
-  period = rtems_configuration_get_microseconds_per_tick();
-
-  return ( first + period - second ) % period;
-}
-
-CPU_Counter_ticks _SPARC_Counter_difference_one(
-  CPU_Counter_ticks second,
-  CPU_Counter_ticks first
-)
-{
-  return 1;
-}



More information about the vc mailing list