/** * * @brief System clock tick handler * * This routine handles the system clock tick interrupt. A TICK_EVENT event * is pushed onto the kernel stack. * * @return N/A */ void _timer_int_handler(void *unused) { ARG_UNUSED(unused); #if defined(CONFIG_HPET_TIMER_LEVEL_LOW) || defined(CONFIG_HPET_TIMER_LEVEL_HIGH) /* Acknowledge interrupt */ *_HPET_GENERAL_INT_STATUS = 1; #endif #ifdef CONFIG_INT_LATENCY_BENCHMARK uint32_t delta = *_HPET_MAIN_COUNTER_VALUE - main_count_expected_value; if (_hw_irq_to_c_handler_latency > delta) { /* keep the lowest value observed */ _hw_irq_to_c_handler_latency = delta; } /* compute the next expected main counter value */ main_count_expected_value += main_count_first_irq_value; #endif #ifndef CONFIG_TICKLESS_IDLE /* * one more tick has occurred -- don't need to do anything special since * timer is already configured to interrupt on the following tick */ _sys_clock_tick_announce(); #else /* see if interrupt was triggered while timer was being reprogrammed */ if (stale_irq_check) { stale_irq_check = 0; if (_hpetMainCounterAtomic() < *_HPET_TIMER0_COMPARATOR) { return; /* ignore "stale" interrupt */ } } /* configure timer to expire on next tick */ counter_last_value = *_HPET_TIMER0_COMPARATOR; *_HPET_TIMER0_CONFIG_CAPS |= HPET_Tn_VAL_SET_CNF; *_HPET_TIMER0_COMPARATOR = counter_last_value + counter_load_value; programmed_ticks = 1; _sys_clock_final_tick_announce(); #endif /* !CONFIG_TICKLESS_IDLE */ }
void _timer_int_handler(void *unused /* parameter is not used */ ) { ARG_UNUSED(unused); #ifdef CONFIG_TICKLESS_IDLE if (timer_mode == TIMER_MODE_ONE_SHOT) { if (!timer_known_to_have_expired) { uint32_t cycles; /* * The timer fired unexpectedly. This is due to one of two cases: * 1. Entering tickless idle straddled a tick. * 2. Leaving tickless idle straddled the final tick. * Due to the timer reprogramming in _timer_idle_exit(), case #2 * can be handled as a fall-through. * * NOTE: Although the cycle count is supposed to stop decrementing * once it hits zero in one-shot mode, not all targets implement * this properly (and continue to decrement). Thus, we have to * perform a second comparison to check for wrap-around. */ cycles = current_count_register_get(); if ((cycles > 0) && (cycles < programmed_cycles)) { /* Case 1 */ _sys_idle_elapsed_ticks = 0; } } /* Return the timer to periodic mode */ initial_count_register_set(cycles_per_tick - 1); periodic_mode_set(); timer_known_to_have_expired = false; timer_mode = TIMER_MODE_PERIODIC; } _sys_clock_final_tick_announce(); /* track the accumulated cycle count */ accumulated_cycle_count += cycles_per_tick * _sys_idle_elapsed_ticks; #else /* track the accumulated cycle count */ accumulated_cycle_count += cycles_per_tick; _sys_clock_tick_announce(); #endif /*CONFIG_TICKLESS_IDLE*/ }
/** * * @brief System clock periodic tick handler * * This routine handles the system clock periodic tick interrupt. It always * announces one tick. * * @return N/A */ 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({}, 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); _sys_clock_final_tick_announce(); #else _sys_clock_tick_announce(); #endif update_accumulated_count(); #endif }
/** * * @brief System clock tick handler * * This routine handles the system clock tick interrupt. A TICK_EVENT event * is pushed onto the kernel stack. * * The symbol for this routine is either _timer_int_handler. * * @return N/A */ void _timer_int_handler(void *unused) { ARG_UNUSED(unused); #ifdef CONFIG_EXECUTION_BENCHMARKING extern void read_systick_start_of_tick_handler(void); read_systick_start_of_tick_handler(); #endif #ifdef CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT extern void _sys_k_event_logger_interrupt(void); _sys_k_event_logger_interrupt(); #endif #ifdef CONFIG_SYS_POWER_MANAGEMENT s32_t numIdleTicks; /* * All interrupts are disabled when handling idle wakeup. * For tickless idle, this ensures that the calculation and programming * of * the device for the next timer deadline is not interrupted. * For non-tickless idle, this ensures that the clearing of the kernel * idle * state is not interrupted. * In each case, _sys_power_save_idle_exit is called with interrupts * disabled. */ __asm__(" cpsid i"); /* PRIMASK = 1 */ #ifdef CONFIG_TICKLESS_IDLE #if defined(CONFIG_TICKLESS_KERNEL) if (!idle_original_ticks) { if (_sys_clock_always_on) { _sys_clock_tick_count = _get_elapsed_clock_time(); /* clear overflow tracking flag as it is accounted */ timer_overflow = 0; sysTickStop(); idle_original_ticks = max_system_ticks; sysTickReloadSet(max_load_value); sysTickStart(); sys_tick_reload(); } __asm__(" cpsie i"); /* re-enable interrupts (PRIMASK = 0) */ _ExcExit(); return; } idle_mode = IDLE_NOT_TICKLESS; _sys_idle_elapsed_ticks = idle_original_ticks; /* * Clear programmed ticks before announcing elapsed time so * that recursive calls to _update_elapsed_time() will not * announce already consumed elapsed time */ idle_original_ticks = 0; _sys_clock_tick_announce(); /* _sys_clock_tick_announce() could cause new programming */ if (!idle_original_ticks && _sys_clock_always_on) { _sys_clock_tick_count = _get_elapsed_clock_time(); /* clear overflow tracking flag as it is accounted */ timer_overflow = 0; sysTickStop(); sysTickReloadSet(max_load_value); sysTickStart(); sys_tick_reload(); } #else /* * If this a wakeup from a completed tickless idle or after * _timer_idle_exit has processed a partial idle, return * to the normal tick cycle. */ if (timer_mode == TIMER_MODE_ONE_SHOT) { sysTickStop(); sysTickReloadSet(default_load_value); sysTickStart(); timer_mode = TIMER_MODE_PERIODIC; } /* set the number of elapsed ticks and announce them to the kernel */ if (idle_mode == IDLE_TICKLESS) { /* tickless idle completed without interruption */ idle_mode = IDLE_NOT_TICKLESS; _sys_idle_elapsed_ticks = idle_original_ticks + 1; /* actual # of idle ticks */ _sys_clock_tick_announce(); } else { _sys_clock_final_tick_announce(); } /* accumulate total counter value */ clock_accumulated_count += default_load_value * _sys_idle_elapsed_ticks; #endif #else /* !CONFIG_TICKLESS_IDLE */ /* * No tickless idle: * Update the total tick count and announce this tick to the kernel. */ clock_accumulated_count += sys_clock_hw_cycles_per_tick; _sys_clock_tick_announce(); #endif /* CONFIG_TICKLESS_IDLE */ numIdleTicks = _NanoIdleValGet(); /* get # of idle ticks requested */ if (numIdleTicks) { _NanoIdleValClear(); /* clear kernel idle setting */ /* * Complete idle processing. * Note that for tickless idle, nothing will be done in * _timer_idle_exit. */ _sys_power_save_idle_exit(numIdleTicks); } __asm__(" cpsie i"); /* re-enable interrupts (PRIMASK = 0) */ #else /* !CONFIG_SYS_POWER_MANAGEMENT */ /* accumulate total counter value */ clock_accumulated_count += sys_clock_hw_cycles_per_tick; /* * one more tick has occurred -- don't need to do anything special since * timer is already configured to interrupt on the following tick */ _sys_clock_tick_announce(); #endif /* CONFIG_SYS_POWER_MANAGEMENT */ #ifdef CONFIG_EXECUTION_BENCHMARKING extern void read_systick_end_of_tick_handler(void); read_systick_end_of_tick_handler(); #endif extern void _ExcExit(void); _ExcExit(); }