[PATCH v3 24/38] bsp/leon3: Add LEON3_IRQAMP_PROBE_TIMESTAMP
Sebastian Huber
sebastian.huber at embedded-brains.de
Wed Jul 12 13:50:03 UTC 2023
---
bsps/sparc/leon3/clock/ckinit.c | 198 ++++++++++++--------
bsps/sparc/leon3/start/cpucounter.c | 103 ++++++----
spec/build/bsps/sparc/leon3/grp.yml | 2 +
spec/build/bsps/sparc/leon3/optirqampts.yml | 22 +++
4 files changed, 207 insertions(+), 118 deletions(-)
create mode 100644 spec/build/bsps/sparc/leon3/optirqampts.yml
diff --git a/bsps/sparc/leon3/clock/ckinit.c b/bsps/sparc/leon3/clock/ckinit.c
index fc20577634..fb07e0bf01 100644
--- a/bsps/sparc/leon3/clock/ckinit.c
+++ b/bsps/sparc/leon3/clock/ckinit.c
@@ -64,11 +64,29 @@
/* LEON3 Timer system interrupt number */
static int clkirq;
-static void (*leon3_tc_tick)(void);
-
static struct timecounter leon3_tc;
-#ifdef RTEMS_PROFILING
+static void leon3_tc_tick_default(void)
+{
+#if !defined(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();
+}
+
+#if defined(RTEMS_PROFILING)
+static void (*leon3_tc_tick)(void) = leon3_tc_tick_default;
+
#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
static void leon3_tc_tick_irqmp_timestamp(void)
@@ -84,11 +102,9 @@ static void leon3_tc_tick_irqmp_timestamp(void)
rtems_timecounter_tick();
}
-#endif
static void leon3_tc_tick_irqmp_timestamp_init(void)
{
-#ifdef RTEMS_PROFILING
/*
* Ignore the first clock interrupt, since it contains the sequential system
* initialization time. Do the timestamp initialization on the fly.
@@ -113,32 +129,18 @@ static void leon3_tc_tick_irqmp_timestamp_init(void)
if (done) {
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
}
-#endif
-
- rtems_timecounter_tick();
-}
-
-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 /* RTEMS_PROFILING */
static void leon3_tc_do_tick(void)
{
+#if defined(RTEMS_PROFILING)
(*leon3_tc_tick)();
+#else
+ leon3_tc_tick_default();
+#endif
}
#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
@@ -181,9 +183,87 @@ static void bsp_clock_handler_install(rtems_interrupt_handler isr)
#define Clock_driver_support_set_interrupt_affinity(online_processors) \
bsp_interrupt_set_affinity(clkirq, online_processors)
+static void leon3_clock_use_up_counter(struct timecounter *tc)
+{
+ tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
+ tc->tc_frequency = leon3_up_counter_frequency();
+
+#if defined(RTEMS_PROFILING)
+ if (irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs) == NULL) {
+ bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
+ }
+
+ leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
+#endif
+
+ rtems_timecounter_install(tc);
+}
+
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
+static void leon3_clock_use_irqamp_timestamp(
+ struct timecounter *tc,
+ irqamp_timestamp *irqmp_ts
+)
+{
+ tc->tc_get_timecount = _SPARC_Get_timecount_up;
+#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
+ tc->tc_frequency = leon3_processor_local_bus_frequency();
+#else
+ tc->tc_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev);
+#endif
+
+#if defined(RTEMS_PROFILING)
+ leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
+#endif
+
+ /*
+ * At least one TSISEL field must be non-zero to enable the timestamp
+ * counter. Use an arbitrary interrupt source.
+ */
+ grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
+
+ rtems_timecounter_install(tc);
+}
+#endif
+
+static void leon3_clock_use_gptimer(
+ struct timecounter *tc,
+ gptimer_timer *timer
+)
+{
+#ifdef RTEMS_SMP
+ /*
+ * The GR712RC for example has no timestamp unit in the interrupt
+ * controller. At least on SMP configurations we must use a second timer
+ * in free running mode for the timecounter. The timer is initialized by
+ * leon3_counter_initialize().
+ */
+ tc->tc_get_timecount = _SPARC_Get_timecount_down;
+#else
+ 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 = &timer->tcntval;
+ 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,
+
+ rtems_timecounter_install(tc);
+}
+
static void leon3_clock_initialize(void)
{
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
irqamp_timestamp *irqmp_ts;
+#endif
gptimer_timer *timer;
struct timecounter *tc;
@@ -198,73 +278,29 @@ static void leon3_clock_initialize(void)
GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS | GPTIMER_TCTRL_LD | GPTIMER_TCTRL_IE
);
- irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
tc = &leon3_tc;
+ tc->tc_counter_mask = 0xffffffff;
+ tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+
leon3_up_counter_enable();
if (leon3_up_counter_is_available()) {
/* Use the LEON4 up-counter if available */
- tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
- tc->tc_frequency = leon3_up_counter_frequency();
+ leon3_clock_use_up_counter(tc);
+ return;
+ }
-#ifdef RTEMS_PROFILING
- if (irqmp_ts == NULL) {
- bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
- }
-#endif
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
+ irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
- leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
- } else if (irqmp_ts != NULL) {
+ if (irqmp_ts != NULL) {
/* Use the interrupt controller timestamp counter if available */
- tc->tc_get_timecount = _SPARC_Get_timecount_up;
-#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
- tc->tc_frequency = leon3_processor_local_bus_frequency();
-#else
- tc->tc_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev);
-#endif
-
- leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
-
- /*
- * At least one TSISEL field must be non-zero to enable the timestamp
- * counter. Use an arbitrary interrupt source.
- */
- grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
- } else {
-#ifdef RTEMS_SMP
- /*
- * The GR712RC for example has no timestamp unit in the interrupt
- * controller. At least on SMP configurations we must use a second timer
- * in free running mode for the timecounter.
- */
- grlib_store_32(
- &LEON3_Timer_Regs->timer[LEON3_COUNTER_GPTIMER_INDEX].tctrl,
- GPTIMER_TCTRL_EN | GPTIMER_TCTRL_IE
- );
-
- tc->tc_get_timecount = _SPARC_Get_timecount_down;
-#else
- 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 = &timer->tcntval;
- 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;
+ leon3_clock_use_irqamp_timestamp(tc, irqmp_ts);
+ return;
}
+#endif
- tc->tc_counter_mask = 0xffffffff;
- tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
- rtems_timecounter_install(tc);
+ leon3_clock_use_gptimer(tc, timer);
}
#define Clock_driver_support_initialize_hardware() \
diff --git a/bsps/sparc/leon3/start/cpucounter.c b/bsps/sparc/leon3/start/cpucounter.c
index 57fd487009..18fc8099f2 100644
--- a/bsps/sparc/leon3/start/cpucounter.c
+++ b/bsps/sparc/leon3/start/cpucounter.c
@@ -39,60 +39,89 @@ uint32_t _CPU_Counter_frequency(void)
return leon3_counter_frequency;
}
+static void leon3_counter_use_up_counter(SPARC_Counter *counter)
+{
+ counter->read_isr_disabled = _SPARC_Counter_read_asr23;
+ counter->read = _SPARC_Counter_read_asr23;
+
+ leon3_counter_frequency = leon3_up_counter_frequency();
+}
+
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
+static void leon3_counter_use_irqamp_timestamp(
+ SPARC_Counter *counter,
+ irqamp_timestamp *irqmp_ts
+)
+{
+ counter->read_isr_disabled = _SPARC_Counter_read_up;
+ counter->read = _SPARC_Counter_read_up;
+ counter->counter_register = &irqmp_ts->itcnt;
+
+ /* Enable interrupt timestamping for an arbitrary interrupt line */
+ grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
+
+#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
+ leon3_counter_frequency = leon3_processor_local_bus_frequency();
+#else
+ leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_IrqCtrl_Adev);
+#endif
+}
+#endif
+
+static void leon3_counter_use_gptimer(SPARC_Counter *counter, gptimer *gpt)
+{
+ gptimer_timer *timer;
+
+ timer = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX];
+ counter->read_isr_disabled = _SPARC_Counter_read_down;
+ counter->read = _SPARC_Counter_read_down;
+ counter->counter_register = &timer->tcntval;
+
+ /* Make timer free running */
+ grlib_store_32(&timer->trldval, 0xffffffff);
+ grlib_store_32(&timer->tctrl, GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS);
+
+#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
+ leon3_counter_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
+#else
+ leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev) /
+ (grlib_load_32(&gpt->sreload) + 1);
+#endif
+}
+
static void leon3_counter_initialize(void)
{
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
irqamp_timestamp *irqmp_ts;
+#endif
gptimer *gpt;
SPARC_Counter *counter;
- irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
- 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 */
- counter->read_isr_disabled = _SPARC_Counter_read_asr23;
- counter->read = _SPARC_Counter_read_asr23;
-
- leon3_counter_frequency = leon3_up_counter_frequency();
- } else if (irqmp_ts != NULL) {
- /* 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 = &irqmp_ts->itcnt;
+ leon3_counter_use_up_counter(counter);
+ return;
+ }
- /* Enable interrupt timestamping for an arbitrary interrupt line */
- grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
+#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
+ irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
-#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
- leon3_counter_frequency = leon3_processor_local_bus_frequency();
-#else
- leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_IrqCtrl_Adev);
+ if (irqmp_ts != NULL) {
+ /* Use the interrupt controller timestamp counter if available */
+ leon3_counter_use_irqamp_timestamp(counter, irqmp_ts);
+ return;
+ }
#endif
- } else if (gpt != NULL) {
- gptimer_timer *timer;
- uint32_t tctrl;
-
- /* Fall back to the first GPTIMER if available */
- timer = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX];
- counter->read_isr_disabled = _SPARC_Counter_read_down;
- counter->read = _SPARC_Counter_read_down;
- counter->counter_register = &timer->tcntval;
- /* Enable timer just in case no clock driver is configured */
- grlib_store_32(&timer->trldval, 0xffffffff);
- tctrl = grlib_load_32(&timer->tctrl);
- tctrl |= GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS | GPTIMER_TCTRL_LD;
- grlib_store_32(&timer->tctrl, tctrl);
+ gpt = LEON3_Timer_Regs;
-#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
- leon3_counter_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
-#else
- leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev) /
- (grlib_load_32(&gpt->sreload) + 1);
-#endif
+ if (gpt != NULL) {
+ /* Fall back to the first GPTIMER if available */
+ leon3_counter_use_gptimer(counter, gpt);
}
}
diff --git a/spec/build/bsps/sparc/leon3/grp.yml b/spec/build/bsps/sparc/leon3/grp.yml
index 7bb09d268f..9d9f7d2750 100644
--- a/spec/build/bsps/sparc/leon3/grp.yml
+++ b/spec/build/bsps/sparc/leon3/grp.yml
@@ -38,6 +38,8 @@ links:
uid: optgptimerbase
- role: build-dependency
uid: optirqampbase
+- role: build-dependency
+ uid: optirqampts
- role: build-dependency
uid: optconirq
- role: build-dependency
diff --git a/spec/build/bsps/sparc/leon3/optirqampts.yml b/spec/build/bsps/sparc/leon3/optirqampts.yml
new file mode 100644
index 0000000000..df214e0cfd
--- /dev/null
+++ b/spec/build/bsps/sparc/leon3/optirqampts.yml
@@ -0,0 +1,22 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH & Co. KG
+actions:
+- get-boolean: null
+- define-condition: null
+build-type: option
+default:
+- enabled-by:
+ - sparc/gr712rc
+ - sparc/gr740
+ - sparc/ut699
+ - sparc/ut700
+ value: false
+enabled-by: true
+links: []
+name: LEON3_IRQAMP_PROBE_TIMESTAMP
+description: |
+ If this option is set to true, then the interrupt timestamping feature of the
+ IRQ(A)MP is probed. If it is available, then it may be used for the CPU
+ counter and interrupt profiling.
+type: build
--
2.35.3
More information about the devel
mailing list