summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamesh Thomas <ramesh.thomas@intel.com>2017-04-08 16:17:14 -0700
committerAnas Nashif <nashif@linux.intel.com>2017-04-27 13:46:32 +0000
commitb414cc56f5298529d55d6783c11061886b5646bb (patch)
tree33bbffd8494195f47bdc371343d0935006ddd8e9
parent0beffbe6bef1d99b3bd93fb9e7c893874cd8d562 (diff)
timer: tickless: arcv2: Add tickless kernel support
Add tickless kernel support. Sets timer always in one shot mode to the time the kernel scheduler needs the next timer event. Uses mili seconds as the scheduling time unit. Jira: ZEP-1817 Change-Id: Ia2e63711cdd9d7d9c241b9ff08a606aa79575012 Signed-off-by: Ramesh Thomas <ramesh.thomas@intel.com>
-rw-r--r--drivers/timer/arcv2_timer0.c151
1 files changed, 148 insertions, 3 deletions
diff --git a/drivers/timer/arcv2_timer0.c b/drivers/timer/arcv2_timer0.c
index f52fed0f8..c367d88f6 100644
--- a/drivers/timer/arcv2_timer0.c
+++ b/drivers/timer/arcv2_timer0.c
@@ -70,10 +70,16 @@ static volatile u32_t accumulated_cycle_count;
#ifdef CONFIG_TICKLESS_IDLE
static u32_t __noinit max_system_ticks;
-static u32_t __noinit programmed_limit;
static u32_t __noinit programmed_ticks;
-static int straddled_tick_on_idle_enter;
extern s32_t _sys_idle_elapsed_ticks;
+#ifndef CONFIG_TICKLESS_KERNEL
+static u32_t __noinit programmed_limit;
+static int straddled_tick_on_idle_enter;
+#endif
+#endif
+
+#ifdef CONFIG_TICKLESS_KERNEL
+static volatile int timer_expired;
#endif
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
@@ -160,6 +166,14 @@ static ALWAYS_INLINE void update_accumulated_count(void)
}
#endif /* CONFIG_TICKLESS_IDLE */
+#ifdef CONFIG_TICKLESS_KERNEL
+static inline void program_max_cycles(void)
+{
+ timer0_limit_register_set(max_system_ticks * cycles_per_tick);
+ timer_expired = 0;
+}
+#endif
+
/**
*
* @brief System clock periodic tick handler
@@ -172,10 +186,36 @@ static ALWAYS_INLINE void update_accumulated_count(void)
void _timer_int_handler(void *unused)
{
ARG_UNUSED(unused);
-
/* clear the interrupt by writing 0 to IP bit of the control register */
timer0_control_register_set(_ARC_V2_TMR_CTRL_NH | _ARC_V2_TMR_CTRL_IE);
+#ifdef CONFIG_TICKLESS_KERNEL
+ if (!programmed_ticks) {
+ if (_sys_clock_always_on) {
+ _sys_clock_tick_count = _get_elapsed_clock_time();
+ program_max_cycles();
+ }
+ return;
+ }
+
+ _sys_idle_elapsed_ticks = programmed_ticks;
+
+ /*
+ * Clear programmed ticks before announcing elapsed time so
+ * that recursive calls to _update_elapsed_time() will not
+ * announce already consumed elapsed time
+ */
+ programmed_ticks = 0;
+ timer_expired = 1;
+
+ _sys_clock_tick_announce();
+
+ /* _sys_clock_tick_announce() could cause new programming */
+ if (!programmed_ticks && _sys_clock_always_on) {
+ _sys_clock_tick_count = _get_elapsed_clock_time();
+ program_max_cycles();
+ }
+#else
#if defined(CONFIG_TICKLESS_IDLE)
timer0_limit_register_set(cycles_per_tick - 1);
__ASSERT_EVAL({},
@@ -189,8 +229,86 @@ void _timer_int_handler(void *unused)
#endif
update_accumulated_count();
+#endif
+}
+
+#ifdef CONFIG_TICKLESS_KERNEL
+u32_t _get_program_time(void)
+{
+ return programmed_ticks;
+}
+
+u32_t _get_remaining_program_time(void)
+{
+ if (programmed_ticks == 0) {
+ return 0;
+ }
+
+ if (timer0_control_register_get() & _ARC_V2_TMR_CTRL_IP) {
+ return 0;
+ }
+ return programmed_ticks -
+ (timer0_count_register_get() / cycles_per_tick);
+}
+
+u32_t _get_elapsed_program_time(void)
+{
+ if (programmed_ticks == 0) {
+ return 0;
+ }
+
+ if (timer0_control_register_get() & _ARC_V2_TMR_CTRL_IP) {
+ return programmed_ticks;
+ }
+ return timer0_count_register_get() / cycles_per_tick;
+}
+
+void _set_time(u32_t time)
+{
+ if (!time) {
+ programmed_ticks = 0;
+ return;
+ }
+
+ programmed_ticks = time > max_system_ticks ? max_system_ticks : time;
+
+ _sys_clock_tick_count = _get_elapsed_clock_time();
+
+ timer0_limit_register_set(programmed_ticks * cycles_per_tick);
+ timer0_count_register_set(0);
+
+ timer_expired = 0;
+}
+
+void _enable_sys_clock(void)
+{
+ if (!programmed_ticks) {
+ program_max_cycles();
+ }
}
+static inline u64_t get_elapsed_count(void)
+{
+ u64_t elapsed;
+
+ if (timer_expired
+ || (timer0_control_register_get() & _ARC_V2_TMR_CTRL_IP)) {
+ elapsed = timer0_limit_register_get();
+ } else {
+ elapsed = timer0_count_register_get();
+ }
+
+ elapsed += _sys_clock_tick_count * cycles_per_tick;
+
+ return elapsed;
+}
+
+u64_t _get_elapsed_clock_time(void)
+{
+ return get_elapsed_count() / cycles_per_tick;
+}
+#endif
+
#if defined(CONFIG_TICKLESS_IDLE)
/*
* @brief initialize the tickless idle feature
@@ -218,6 +336,18 @@ static void tickless_idle_init(void)
void _timer_idle_enter(s32_t ticks)
{
+#ifdef CONFIG_TICKLESS_KERNEL
+ if (ticks != K_FOREVER) {
+ /* Need to reprogram only if current program is smaller */
+ if (ticks > programmed_ticks) {
+ _set_time(ticks);
+ }
+ } else {
+ programmed_ticks = 0;
+ timer0_control_register_set(timer0_control_register_get() &
+ ~_ARC_V2_TMR_CTRL_IE);
+ }
+#else
u32_t status;
if ((ticks == K_FOREVER) || (ticks > max_system_ticks)) {
@@ -247,6 +377,7 @@ void _timer_idle_enter(s32_t ticks)
u32_t timer_count = timer0_count_register_get(),
timer_count <= programmed_limit,
"timer_count: %d, limit %d\n", timer_count, programmed_limit);
+#endif
}
/*
@@ -261,6 +392,15 @@ void _timer_idle_enter(s32_t ticks)
void _timer_idle_exit(void)
{
+#ifdef CONFIG_TICKLESS_KERNEL
+ if (!programmed_ticks && _sys_clock_always_on) {
+ if (!(timer0_control_register_get() & _ARC_V2_TMR_CTRL_IE)) {
+ timer0_control_register_set(_ARC_V2_TMR_CTRL_NH |
+ _ARC_V2_TMR_CTRL_IE);
+ }
+ program_max_cycles();
+ }
+#else
if (straddled_tick_on_idle_enter) {
/* Aborting the tickless idle due to a straddled tick. */
straddled_tick_on_idle_enter = 0;
@@ -315,6 +455,7 @@ void _timer_idle_exit(void)
u32_t timer_count = timer0_count_register_get(),
timer_count <= (cycles_per_tick - 1),
"timer_count: %d, limit %d\n", timer_count, cycles_per_tick-1);
+#endif
}
#else
static void tickless_idle_init(void) {}
@@ -415,6 +556,9 @@ int sys_clock_device_ctrl(struct device *port, u32_t ctrl_command,
u32_t _timer_cycle_get_32(void)
{
+#ifdef CONFIG_TICKLESS_KERNEL
+return (u32_t) get_elapsed_count();
+#else
u32_t acc, count;
do {
@@ -423,6 +567,7 @@ u32_t _timer_cycle_get_32(void)
} while (acc != accumulated_cycle_count);
return acc + count;
+#endif
}
#if defined(CONFIG_SYSTEM_CLOCK_DISABLE)