native: native_posix timer + irq fix
Added possibility to reconfigure CONFIG_SYS_CLOCK_TICKS_PER_SEC
for the native_posix board (before it could only be 100)
+
Fixed tickless idle support
+
Minor fixes in irq wrapping
Signed-off-by: Alberto Escolar Piedras <alpi@oticon.com>
diff --git a/arch/posix/core/cpuhalt.c b/arch/posix/core/cpuhalt.c
index 83789cd..8d829cd 100644
--- a/arch/posix/core/cpuhalt.c
+++ b/arch/posix/core/cpuhalt.c
@@ -19,6 +19,7 @@
#include "posix_core.h"
#include "posix_soc_if.h"
+#include "logging/kernel_event_logger.h"
/**
*
@@ -34,6 +35,7 @@
*/
void k_cpu_idle(void)
{
+ _sys_k_event_logger_enter_sleep();
posix_irq_full_unlock();
posix_halt_cpu();
}
@@ -60,5 +62,6 @@
void k_cpu_atomic_idle(unsigned int imask)
{
+ _sys_k_event_logger_enter_sleep();
posix_atomic_halt_cpu(imask);
}
diff --git a/arch/posix/core/swap.c b/arch/posix/core/swap.c
index 1d3bed4..98ee16e 100644
--- a/arch/posix/core/swap.c
+++ b/arch/posix/core/swap.c
@@ -102,3 +102,17 @@
}
#endif
+#ifdef CONFIG_SYS_POWER_MANAGEMENT
+/**
+ * If the kernel is in idle mode, take it out
+ */
+void posix_irq_check_idle_exit(void)
+{
+ if (_kernel.idle) {
+ s32_t idle_val = _kernel.idle;
+
+ _kernel.idle = 0;
+ _sys_power_save_idle_exit(idle_val);
+ }
+}
+#endif
diff --git a/arch/posix/include/posix_core.h b/arch/posix/include/posix_core.h
index f0001d0..96a53fb 100644
--- a/arch/posix/include/posix_core.h
+++ b/arch/posix/include/posix_core.h
@@ -42,6 +42,7 @@
void posix_core_clean_up(void);
void posix_new_thread_pre_start(void); /* defined in thread.c */
+void posix_irq_check_idle_exit(void);
#ifdef __cplusplus
}
diff --git a/boards/posix/native_posix/board_irq.h b/boards/posix/native_posix/board_irq.h
index 12ea702..f504fc2 100644
--- a/boards/posix/native_posix/board_irq.h
+++ b/boards/posix/native_posix/board_irq.h
@@ -50,12 +50,17 @@
irq_p; \
})
-
/**
- * The return of "name(void)" is the indicaton of the interrupt
+ * POSIX Architecture (board) specific ISR_DIRECT_DECLARE(),
+ * See include/irq.h for more information.
+ *
+ * The return of "name##_body(void)" is the indication of the interrupt
* (maybe) having caused a kernel decision to context switch
*
* Note that this convention is changed relative to the ARM and x86 archs
+ *
+ * All pre/post irq work of the interrupt is handled in the board
+ * posix_irq_handler() both for direct and normal interrupts together
*/
#define _ARCH_ISR_DIRECT_DECLARE(name) \
static inline int name##_body(void); \
@@ -67,7 +72,15 @@
} \
static inline int name##_body(void)
-#define _ARCH_ISR_DIRECT_PM()
+#define _ARCH_ISR_DIRECT_HEADER() do { } while (0)
+#define _ARCH_ISR_DIRECT_FOOTER(a) do { } while (0)
+
+#ifdef CONFIG_SYS_POWER_MANAGEMENT
+extern void posix_irq_check_idle_exit(void);
+#define _ARCH_ISR_DIRECT_PM() posix_irq_check_idle_exit()
+#else
+#define _ARCH_ISR_DIRECT_PM() do { } while (0)
+#endif
#ifdef __cplusplus
}
diff --git a/boards/posix/native_posix/irq_handler.c b/boards/posix/native_posix/irq_handler.c
index 2eeefb0..503cc7b 100644
--- a/boards/posix/native_posix/irq_handler.c
+++ b/boards/posix/native_posix/irq_handler.c
@@ -11,12 +11,13 @@
#include "irq_handler.h"
#include "irq_offload.h"
#include "kernel_structs.h"
+#include "kernel_internal.h"
#include "irq_ctrl.h"
#include "posix_core.h"
#include "board_soc.h"
#include "sw_isr_table.h"
#include "soc.h"
-
+#include "logging/kernel_event_logger.h"
typedef void (*normal_irq_f_ptr)(void *);
typedef int (*direct_irq_f_ptr)(void);
@@ -26,9 +27,15 @@
static int currently_running_irq = -1;
-
static inline void vector_to_irq(int irq_nbr, int *may_swap)
{
+ /*
+ * As in this architecture an irq (code) executes in 0 time,
+ * it is a bit senseless to call _int_latency_start/stop()
+ */
+ /* _int_latency_start(); */
+ _sys_k_event_logger_interrupt();
+
if (irq_vector_table[irq_nbr].func == NULL) {
posix_print_error_and_exit("Received irq %i without a "
"registered handler\n",
@@ -38,15 +45,15 @@
*may_swap |= ((direct_irq_f_ptr)
irq_vector_table[irq_nbr].func)();
} else {
+#ifdef CONFIG_SYS_POWER_MANAGEMENT
+ posix_irq_check_idle_exit();
+#endif
((normal_irq_f_ptr)irq_vector_table[irq_nbr].func)
(irq_vector_table[irq_nbr].param);
*may_swap = 1;
- /*
- * TODO: look into how this kind of ISRs are meant
- * to be wrapped
- */
}
}
+ /* _int_latency_stop(); */
}
/**
@@ -61,7 +68,7 @@
{
uint64_t irq_lock;
int irq_nbr;
- int may_swap = 0;
+ static int may_swap;
irq_lock = hw_irq_ctrl_get_current_lock();
@@ -70,8 +77,14 @@
return;
}
+ if (_kernel.nested == 0) {
+ may_swap = 0;
+ }
+
_kernel.nested++;
+ _sys_k_event_logger_exit_sleep();
+
while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) {
int last_current_running_prio = hw_irq_ctrl_get_cur_prio();
int last_running_irq = currently_running_irq;
@@ -94,16 +107,15 @@
* 3) Current thread is preemptible
* 4) Next thread to run in the ready queue is not this thread
*/
- if (may_swap &&
- (hw_irq_ctrl_get_cur_prio() == 256) &&
- (_current->base.preempt < _NON_PREEMPT_THRESHOLD) &&
- (_kernel.ready_q.cache != _current)) {
+ if (may_swap
+ && (hw_irq_ctrl_get_cur_prio() == 256)
+ && (_current->base.preempt < _NON_PREEMPT_THRESHOLD)
+ && (_kernel.ready_q.cache != _current)) {
- __swap(irq_lock);
+ _Swap(irq_lock);
}
}
-
/**
* Thru this function the IRQ controller can raise an immediate interrupt which
* will interrupt the SW itself
@@ -126,7 +138,6 @@
}
}
-
/**
* @brief Disable all interrupts on the CPU
*
@@ -222,8 +233,6 @@
return currently_running_irq;
}
-
-
/**
* Configure a static interrupt.
*
@@ -248,7 +257,6 @@
irq_vector_table[irq_p].flags = flags;
}
-
/*
* @internal
*
@@ -263,8 +271,6 @@
hw_irq_ctrl_prio_set(irq, prio);
}
-
-
/**
* Similar to ARM's NVIC_SetPendingIRQ
* set a pending IRQ from SW
@@ -278,7 +284,6 @@
hw_irq_ctrl_raise_im_from_sw(IRQn);
}
-
/**
* Similar to ARM's NVIC_ClearPendingIRQ
* clear a pending irq from SW
diff --git a/boards/posix/native_posix/timer_model.c b/boards/posix/native_posix/timer_model.c
index b41ad96..c5549d2 100644
--- a/boards/posix/native_posix/timer_model.c
+++ b/boards/posix/native_posix/timer_model.c
@@ -25,8 +25,8 @@
u64_t hw_timer_tick_timer;
u64_t hw_timer_awake_timer;
-static u64_t tick_p = 10000; /* period of the ticker */
-static unsigned int silent_ticks;
+static u64_t tick_p; /* Period of the ticker */
+static s64_t silent_ticks;
#if (CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME)
#include <time.h>
@@ -35,16 +35,17 @@
static struct timespec tv;
#endif
+extern u64_t posix_get_hw_cycle(void);
+
static void hwtimer_update_timer(void)
{
hw_timer_timer = min(hw_timer_tick_timer, hw_timer_awake_timer);
}
-
void hwtimer_init(void)
{
silent_ticks = 0;
- hw_timer_tick_timer = tick_p;
+ hw_timer_tick_timer = NEVER;
hw_timer_awake_timer = NEVER;
hwtimer_update_timer();
#if (CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME)
@@ -53,12 +54,19 @@
#endif
}
-
void hwtimer_cleanup(void)
{
}
+void hwtimer_enable(u64_t period)
+{
+ tick_p = period;
+ hw_timer_tick_timer = hwm_get_time() + tick_p;
+ hwtimer_update_timer();
+ hwm_find_next_timer();
+}
+
static void hwtimer_tick_timer_reached(void)
{
#if (CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME)
@@ -90,7 +98,6 @@
}
}
-
static void hwtimer_awake_timer_reached(void)
{
hw_timer_awake_timer = NEVER;
@@ -111,7 +118,6 @@
}
}
-
/**
* The timer HW will awake the CPU (without an interrupt) at least when <time>
* comes (it may awake it earlier)
@@ -128,10 +134,21 @@
}
}
-
-void hwtimer_set_silent_ticks(int sys_ticks)
+/**
+ * The kernel wants to skip the next sys_ticks tick interrupts
+ * If sys_ticks == 0, the next interrupt will be raised.
+ * A negative number will silence the tick interrupts effectively forever
+ */
+void hwtimer_set_silent_ticks(s64_t sys_ticks)
{
- silent_ticks = sys_ticks;
+ if (sys_ticks < 0) {
+ silent_ticks = INT64_MAX;
+ } else {
+ silent_ticks = sys_ticks;
+ }
}
-
+s64_t hwtimer_get_pending_silent_ticks(void)
+{
+ return silent_ticks;
+}
diff --git a/boards/posix/native_posix/timer_model.h b/boards/posix/native_posix/timer_model.h
index ca6768d..a60dc73 100644
--- a/boards/posix/native_posix/timer_model.h
+++ b/boards/posix/native_posix/timer_model.h
@@ -17,7 +17,9 @@
void hwtimer_cleanup(void);
void hwtimer_timer_reached(void);
void hwtimer_wake_in_time(u64_t time);
-void hwtimer_set_silent_ticks(int sys_ticks);
+void hwtimer_set_silent_ticks(s64_t sys_ticks);
+void hwtimer_enable(u64_t period);
+s64_t hwtimer_get_pending_silent_ticks(void);
#ifdef __cplusplus
}
diff --git a/drivers/timer/native_posix_timer.c b/drivers/timer/native_posix_timer.c
index accb29d..19bac09 100644
--- a/drivers/timer/native_posix_timer.c
+++ b/drivers/timer/native_posix_timer.c
@@ -15,9 +15,13 @@
#include "irq.h"
#include "device.h"
#include "drivers/system_timer.h"
+#include "sys_clock.h"
#include "timer_model.h"
#include "soc.h"
+static u64_t tick_period; /* System tick period in number of hw cycles */
+static s32_t silent_ticks;
+
/**
* Return the current HW cycle counter
* (number of microseconds since boot in 32bits)
@@ -27,14 +31,26 @@
return hwm_get_time();
}
+extern u64_t posix_get_hw_cycle(void);
+
#ifdef CONFIG_TICKLESS_IDLE
-void _timer_idle_enter(int32_t sys_ticks)
+
+/*
+ * Do not raise another ticker interrupt until the sys_ticks'th one
+ * e.g. if sys_ticks is 10, do not raise the next 9 ones
+ */
+void _timer_idle_enter(s32_t sys_ticks)
{
- hwtimer_set_silent_ticks(sys_ticks);
+ silent_ticks = sys_ticks - 1;
+ hwtimer_set_silent_ticks(silent_ticks);
}
+/*
+ * Exit from idle mode
+ */
void _timer_idle_exit(void)
{
+ silent_ticks -= hwtimer_get_pending_silent_ticks();
hwtimer_set_silent_ticks(0);
}
#endif
@@ -42,13 +58,23 @@
static void sp_timer_isr(void *arg)
{
ARG_UNUSED(arg);
+ _sys_idle_elapsed_ticks = silent_ticks + 1;
+ silent_ticks = 0;
_sys_clock_tick_announce();
}
+/*
+ * Initialize the hwtimer and setup its interrupt
+ */
int _sys_clock_driver_init(struct device *device)
{
ARG_UNUSED(device);
+ tick_period = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC /
+ CONFIG_SYS_CLOCK_TICKS_PER_SEC;
+
+ hwtimer_enable(tick_period);
+
IRQ_CONNECT(TIMER_TICK_IRQ, 1, sp_timer_isr, 0, 0);
irq_enable(TIMER_TICK_IRQ);