[PATCH] sparc: Fix CPU counter support

Daniel Hellstrom daniel at gaisler.com
Mon Feb 24 14:20:26 UTC 2014


Sebastian, I think it's a good solution to rely on the GPTIMER[0].timer0 as a fallback.

Looks good to me, and should work on the TSIM/GRSIM and LEON3 hardware.

Assuming that the frequency has been initialized to 1MHz for secondary GPTIMER may be wrong when invoked from a boot loader, however this can be fixed later if determined a problem.

Thanks,
Daniel

On 02/24/2014 01:01 PM, Sebastian Huber wrote:
> 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.
> ---
>   c/src/lib/libbsp/sparc/erc32/Makefile.am          |    1 -
>   c/src/lib/libbsp/sparc/erc32/clock/ckinit.c       |   14 +++
>   c/src/lib/libbsp/sparc/leon2/Makefile.am          |    1 -
>   c/src/lib/libbsp/sparc/leon3/clock/ckinit.c       |    7 --
>   c/src/lib/libbsp/sparc/leon3/include/leon.h       |    7 ++
>   c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c |   95 ++++++++++++++------
>   cpukit/score/cpu/sparc/Makefile.am                |    1 +
>   cpukit/score/cpu/sparc/rtems/score/cpu.h          |   51 +++++++++++-
>   cpukit/score/cpu/sparc/sparc-counter.c            |   34 ++++++++
>   9 files changed, 171 insertions(+), 40 deletions(-)
>   create mode 100644 cpukit/score/cpu/sparc/sparc-counter.c
>
> diff --git a/c/src/lib/libbsp/sparc/erc32/Makefile.am b/c/src/lib/libbsp/sparc/erc32/Makefile.am
> index 61cd9dc..16aecca 100644
> --- a/c/src/lib/libbsp/sparc/erc32/Makefile.am
> +++ b/c/src/lib/libbsp/sparc/erc32/Makefile.am
> @@ -35,7 +35,6 @@ libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \
>       ../../shared/sbrk.c startup/setvec.c startup/spurious.c \
>       startup/erc32mec.c startup/boardinit.S startup/bspidle.c \
>       startup/bspdelay.c ../../sparc/shared/startup/early_malloc.c
> -libbsp_a_SOURCES += ../../shared/cpucounterread.c
>   # ISR Handler
>   libbsp_a_SOURCES += ../../sparc/shared/irq_asm.S
>   # gnatsupp
> diff --git a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
> index 1287645..1d85c32 100644
> --- a/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
> +++ b/c/src/lib/libbsp/sparc/erc32/clock/ckinit.c
> @@ -24,6 +24,7 @@
>   
>   #include <bsp.h>
>   #include <bspopts.h>
> +#include <rtems/counter.h>
>   
>   #if SIMSPARC_FAST_IDLE==1
>   #define CLOCK_DRIVER_USE_FAST_IDLE 1
> @@ -63,6 +64,14 @@ uint32_t bsp_clock_nanoseconds_since_last_tick(void)
>   #define Clock_driver_nanoseconds_since_last_tick \
>     bsp_clock_nanoseconds_since_last_tick
>   
> +static CPU_Counter_ticks erc32_counter_difference(
> +  CPU_Counter_ticks second,
> +  CPU_Counter_ticks first
> +)
> +{
> +  return (first - second) % rtems_configuration_get_microseconds_per_tick();
> +}
> +
>   #define Clock_driver_support_initialize_hardware() \
>     do { \
>       /* approximately 1 us per countdown */ \
> @@ -80,6 +89,11 @@ uint32_t bsp_clock_nanoseconds_since_last_tick(void)
>         ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \
>   	    ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO \
>       ); \
> +    _SPARC_Counter_initialize( \
> +      &ERC32_MEC.Real_Time_Clock_Counter, \
> +      erc32_counter_difference \
> +    ); \
> +    rtems_counter_initialize_converter(1000000); \
>     } while (0)
>   
>   #define Clock_driver_support_shutdown_hardware() \
> diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
> index 8bbe69b..c08f159 100644
> --- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
> +++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
> @@ -52,7 +52,6 @@ libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \
>       ../../shared/sbrk.c startup/setvec.c startup/spurious.c startup/bspidle.c \
>       ../../shared/bspinit.c startup/bspdelay.c \
>       ../../sparc/shared/startup/early_malloc.c
> -libbsp_a_SOURCES += ../../shared/cpucounterread.c
>   # ISR Handler
>   libbsp_a_SOURCES += ../../sparc/shared/irq_asm.S
>   # gnatsupp
> diff --git a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
> index e0556ba..d2aae23 100644
> --- a/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
> +++ b/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
> @@ -30,13 +30,6 @@
>    *  The Real Time Clock Counter Timer uses this trap type.
>    */
>   
> -#if defined(RTEMS_MULTIPROCESSING)
> -  #define LEON3_CLOCK_INDEX \
> -    (rtems_configuration_get_user_multiprocessing_table() ? LEON3_Cpu_Index : 0)
> -#else
> -  #define LEON3_CLOCK_INDEX 0
> -#endif
> -
>   volatile struct gptimer_regs *LEON3_Timer_Regs = 0;
>   static int clkirq;
>   
> diff --git a/c/src/lib/libbsp/sparc/leon3/include/leon.h b/c/src/lib/libbsp/sparc/leon3/include/leon.h
> index ccee1a3..e4710cd 100644
> --- a/c/src/lib/libbsp/sparc/leon3/include/leon.h
> +++ b/c/src/lib/libbsp/sparc/leon3/include/leon.h
> @@ -273,6 +273,13 @@ extern rtems_interrupt_lock LEON3_IrqCtrl_Lock;
>   #define LEON_REG_TIMER_COUNTER_DEFINED_MASK       0x00000003
>   #define LEON_REG_TIMER_COUNTER_CURRENT_MODE_MASK  0x00000003
>   
> +#if defined(RTEMS_MULTIPROCESSING)
> +  #define LEON3_CLOCK_INDEX \
> +    (rtems_configuration_get_user_multiprocessing_table() ? LEON3_Cpu_Index : 0)
> +#else
> +  #define LEON3_CLOCK_INDEX 0
> +#endif
> +
>   /* Load 32-bit word by forcing a cache-miss */
>   static inline unsigned int leon_r32_no_cache(uintptr_t addr)
>   {
> diff --git a/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c b/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
> index e773d4d..5d1ac0c 100644
> --- a/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
> +++ b/c/src/lib/libbsp/sparc/leon3/startup/cpucounter.c
> @@ -12,22 +12,53 @@
>    * http://www.rtems.com/license/LICENSE.
>    */
>   
> -#include <bsp.h>
> -#include <bsp/fatal.h>
>   #include <leon.h>
>   
>   #include <rtems/counter.h>
>   
> -static volatile struct gptimer_regs *leon3_cpu_counter_gpt;
> +static volatile struct gptimer_regs *adev_to_gpt(struct ambapp_dev *adev)
> +{
> +  return (volatile struct gptimer_regs *) DEV_TO_APB(adev)->start;
> +}
> +
> +static CPU_Counter_ticks free_counter_difference(
> +  CPU_Counter_ticks second,
> +  CPU_Counter_ticks first
> +)
> +{
> +  return first - second;
> +}
> +
> +static CPU_Counter_ticks clock_counter_difference(
> +  CPU_Counter_ticks second,
> +  CPU_Counter_ticks first
> +)
> +{
> +  return (first - second) % rtems_configuration_get_microseconds_per_tick();
> +}
> +
> +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
> +  );
> +
> +  rtems_counter_initialize_converter(frequency);
> +}
>   
>   void leon3_cpu_counter_initialize(void)
>   {
>     struct ambapp_dev *adev;
>     int idx = 1;
> -  volatile struct gptimer_regs *gpt;
> -  unsigned new_prescaler = 8;
> -  unsigned prescaler;
> -  uint32_t frequency;
> +
> +  /* Assume that GRMON initialized the timer to 1MHz */
> +  uint32_t frequency = 1000000;
>   
>     adev = (void *) ambapp_for_each(
>       &ambapp_plb,
> @@ -37,28 +68,34 @@ void leon3_cpu_counter_initialize(void)
>       ambapp_find_by_idx,
>       &idx
>     );
> -  if (adev == NULL) {
> -    bsp_fatal(LEON3_FATAL_CPU_COUNTER_INIT);
> -  }
> +  if (adev != NULL) {
> +    volatile struct gptimer_regs *gpt = adev_to_gpt(adev);
> +    unsigned new_prescaler = 8;
> +    unsigned prescaler = gpt->scaler_reload + 1;
>   
> -  gpt = (volatile struct gptimer_regs *) DEV_TO_APB(adev)->start;
> +    gpt->scaler_reload = new_prescaler - 1;
> +    gpt->timer[0].reload = 0xffffffff;
> +    gpt->timer[0].ctrl = LEON3_GPTIMER_EN | LEON3_GPTIMER_RL
> +      | LEON3_GPTIMER_LD;
>   
> -  prescaler = gpt->scaler_reload + 1;
> -  gpt->scaler_reload = new_prescaler - 1;
> -  gpt->timer[0].reload = 0xffffffff;
> -  gpt->timer[0].ctrl = LEON3_GPTIMER_EN | LEON3_GPTIMER_RL
> -    | LEON3_GPTIMER_LD;
> -
> -  leon3_cpu_counter_gpt = gpt;
> -
> -  /* Assume that GRMON initialized the timer to 1MHz */
> -  frequency = UINT32_C(1000000) * (prescaler / new_prescaler);
> -  rtems_counter_initialize_converter(frequency);
> -}
> -
> -CPU_Counter_ticks _CPU_Counter_read(void)
> -{
> -  volatile struct gptimer_regs *gpt = leon3_cpu_counter_gpt;
> -
> -  return 0U - gpt->timer[0].value;
> +    frequency = (frequency * prescaler) / new_prescaler;
> +    gpt_counter_initialize(gpt, 0, frequency, free_counter_difference);
> +  } else {
> +    adev = (void *) ambapp_for_each(
> +      &ambapp_plb,
> +      OPTIONS_ALL | OPTIONS_APB_SLVS,
> +      VENDOR_GAISLER,
> +      GAISLER_GPTIMER,
> +      ambapp_find_by_idx,
> +      NULL
> +    );
> +    if (adev != NULL) {
> +      gpt_counter_initialize(
> +        adev_to_gpt(adev),
> +        LEON3_CLOCK_INDEX,
> +        frequency,
> +        clock_counter_difference
> +      );
> +    }
> +  }
>   }
> diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am
> index 504a575..c6ea1c3 100644
> --- a/cpukit/score/cpu/sparc/Makefile.am
> +++ b/cpukit/score/cpu/sparc/Makefile.am
> @@ -11,6 +11,7 @@ include_rtems_score_HEADERS += rtems/score/cpuatomic.h
>   
>   noinst_LIBRARIES = libscorecpu.a
>   libscorecpu_a_SOURCES = cpu.c cpu_asm.S
> +libscorecpu_a_SOURCES += sparc-counter.c
>   libscorecpu_a_SOURCES += sparcv8-atomic.c
>   libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
>   
> diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
> index d68b0c0..62c7b3c 100644
> --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
> +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
> @@ -1280,14 +1280,61 @@ static inline uint32_t CPU_swap_u32(
>   
>   typedef uint32_t CPU_Counter_ticks;
>   
> -CPU_Counter_ticks _CPU_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.  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.
> + */
> +typedef struct {
> +  volatile const CPU_Counter_ticks *counter_register;
> +  SPARC_Counter_difference counter_difference;
> +} SPARC_Counter;
> +
> +extern SPARC_Counter _SPARC_Counter;
> +
> +/*
> + * 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 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.counter_register = counter_register;
> +  _SPARC_Counter.counter_difference = counter_difference;
> +}
> +
> +static inline CPU_Counter_ticks _CPU_Counter_read( void )
> +{
> +  return *_SPARC_Counter.counter_register;
> +}
>   
>   static inline CPU_Counter_ticks _CPU_Counter_difference(
>     CPU_Counter_ticks second,
>     CPU_Counter_ticks first
>   )
>   {
> -  return second - first;
> +  return (*_SPARC_Counter.counter_difference)( second, first );
>   }
>   
>   #endif /* ASM */
> diff --git a/cpukit/score/cpu/sparc/sparc-counter.c b/cpukit/score/cpu/sparc/sparc-counter.c
> new file mode 100644
> index 0000000..dc69b6b
> --- /dev/null
> +++ b/cpukit/score/cpu/sparc/sparc-counter.c
> @@ -0,0 +1,34 @@
> +/*
> + * 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.com/license/LICENSE.
> + */
> +
> +#if HAVE_CONFIG_H
> +  #include "config.h"
> +#endif
> +
> +#include <rtems/score/cpu.h>
> +
> +static CPU_Counter_ticks _SPARC_Counter_register_dummy;
> +
> +CPU_Counter_ticks _SPARC_Counter_difference_default(
> +  CPU_Counter_ticks second,
> +  CPU_Counter_ticks first
> +)
> +{
> +  return 1;
> +}
> +
> +SPARC_Counter _SPARC_Counter = {
> +  .counter_register = &_SPARC_Counter_register_dummy,
> +  .counter_difference = _SPARC_Counter_difference_default
> +};




More information about the devel mailing list