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);