diff --git a/doc/acrn.doxyfile b/doc/acrn.doxyfile index 0d0748603..57a9924de 100644 --- a/doc/acrn.doxyfile +++ b/doc/acrn.doxyfile @@ -808,6 +808,7 @@ INPUT = custom-doxygen/mainpage.md \ ../hypervisor/include/public/acrn_common.h \ ../hypervisor/include/public/acrn_hv_defs.h \ ../hypervisor/include/arch/x86/guest/vcpu.h \ + ../hypervisor/include/arch/x86/timer.h \ ../hypervisor/arch/x86/trusty.c \ ../devicemodel/include/virtio.h \ ../hypervisor/include/arch/x86/ioapic.h \ diff --git a/doc/developer-guides/hld/hv-timer.rst b/doc/developer-guides/hld/hv-timer.rst index 8c4c56c49..ce157bc72 100644 --- a/doc/developer-guides/hld/hv-timer.rst +++ b/doc/developer-guides/hld/hv-timer.rst @@ -24,37 +24,27 @@ tsc-deadline timer mode by writing the local APIC LVT register. Data Structures and APIs ************************ -.. note:: API link to hv_timer and per_cpu_timer structs in include/arch/x86/timer.h - And to the function APIs there too. +Interfaces Design +================= -Before adding a timer, we must initialize the timer with -*initialize_timer*. The processor generates a timer interrupt when the -value of timer-stamp counter is greater than or equal to the *fire_tsc* -field. If you want to add a periodic timer, you should also pass the -period (unit in tsc cycles), otherwise, period_in_cycle will be ignored. -When the timer interrupt is generated, it will call the callback -function *func* with parameter *priv_data*. +.. doxygenfunction:: initialize_timer + :project: Project ACRN -The *initialize_timer* function only initialize the timer data -structure; it will not program the ``IA32_TSC_DEADLINE_MSR`` to generate -the timer interrupt. If you want to generate a timer interrupt, you must -call *add_timer* to add the timer to the *per_cpu_timer* timer_list. In -return, we will chose the nearest expired timer on the timer_list and -program ``IA32_TSC_DEADLINE_MSR`` by writing its value to fire_ts. Then -when the fire_tsc expires, it raises the interrupt whose callback raises -a softirq. We will handle the software interrupt before the VM reenters -the guest. (Currently, the hypervisor only uses the timer for the -console). +.. doxygenfunction:: timer_expired + :project: Project ACRN -The timer softirq handler will check each expired timer on its -timer_list. Before calling the expired timer callback handler, it will -remove the timer from its logical cpu timer_list. After calling the -timer callback handler, it will re-add the timer to the timer_list if -it's a periodic timer. If you want to modify a timer before it expires, -you should call del_timer to remove the timer from the timer_list, then -call add_timer again after updating the timer fields. +.. doxygenfunction:: add_timer + :project: Project ACRN -.. note:: +.. doxygenfunction:: del_timer + :project: Project ACRN + +.. doxygenfunction:: timer_init + :project: Project ACRN + +.. doxygenfunction:: check_tsc + :project: Project ACRN + +.. doxygenfunction:: calibrate_tsc + :project: Project ACRN - Only call initialize_timer only once for each timer. - Don't call add_timer or del_timer in the timer callback function. diff --git a/hypervisor/include/arch/x86/timer.h b/hypervisor/include/arch/x86/timer.h index e2688c793..c28cd5853 100644 --- a/hypervisor/include/arch/x86/timer.h +++ b/hypervisor/include/arch/x86/timer.h @@ -7,36 +7,62 @@ #ifndef TIMER_H #define TIMER_H +/** + * @brief Timer + * + * @defgroup timer ACRN Timer + * @{ + */ + typedef void (*timer_handle_t)(void *data); +/** + * @brief Definition of timer tick mode + */ enum tick_mode { - TICK_MODE_ONESHOT = 0, - TICK_MODE_PERIODIC, + TICK_MODE_ONESHOT = 0, /**< one-shot mode */ + TICK_MODE_PERIODIC, /**< periodic mode */ }; +/** + * @brief Definition of timers for per-cpu + */ struct per_cpu_timers { - struct list_head timer_list; /* it's for runtime active timer list */ + struct list_head timer_list; /**< it's for runtime active timer list */ }; +/** + * @brief Definition of timer + */ struct hv_timer { - struct list_head node; /* link all timers */ - enum tick_mode mode; /* timer mode: one-shot or periodic */ - uint64_t fire_tsc; /* tsc deadline to interrupt */ - uint64_t period_in_cycle; /* period of the periodic timer in unit of TSC cycles */ - timer_handle_t func; /* callback if time reached */ - void *priv_data; /* func private data */ + struct list_head node; /**< link all timers */ + enum tick_mode mode; /**< timer mode: one-shot or periodic */ + uint64_t fire_tsc; /**< tsc deadline to interrupt */ + uint64_t period_in_cycle; /**< period of the periodic timer in unit of TSC cycles */ + timer_handle_t func; /**< callback if time reached */ + void *priv_data; /**< func private data */ }; -/* - * Don't initialize a timer twice if it has been add to the timer list - * after call add_timer. If u want, delete the timer from the list first. +/* External Interfaces */ + +/** + * @brief Initialize a timer structure. + * + * @param[in] timer Pointer to timer. + * @param[in] func irq callback if time reached. + * @param[in] priv_data func private data. + * @param[in] fire_tsc tsc deadline to interrupt. + * @param[in] mode timer mode. + * @param[in] period_in_cycle period of the periodic timer in unit of TSC cycles. + * + * @remark Don't initialize a timer twice if it has been added to the timer list + * after calling add_timer. If you want to, delete the timer from the list first. + * + * @return None */ static inline void initialize_timer(struct hv_timer *timer, - timer_handle_t func, - void *priv_data, - uint64_t fire_tsc, - int mode, - uint64_t period_in_cycle) + timer_handle_t func, void *priv_data, + uint64_t fire_tsc, int mode, uint64_t period_in_cycle) { if (timer != NULL) { timer->func = func; @@ -48,19 +74,62 @@ static inline void initialize_timer(struct hv_timer *timer, } } +/** + * @brief Check a timer whether expired. + * + * @param[in] timer Pointer to timer. + * + * @retval true if the timer is expired, false otherwise. + */ static inline bool timer_expired(const struct hv_timer *timer) { return ((timer->fire_tsc == 0UL) || (rdtsc() >= timer->fire_tsc)); } -/* - * Don't call add_timer/del_timer in the timer callback function. +/** + * @brief Add a timer. + * + * @param[in] timer Pointer to timer. + * + * @retval 0 on success + * @retval -EINVAL timer has an invalid value + * + * @remark Don't call it in the timer callback function or interrupt content. */ int add_timer(struct hv_timer *timer); + +/** + * @brief Delete a timer. + * + * @param[in] timer Pointer to timer. + * + * @return None + * + * @remark Don't call it in the timer callback function or interrupt content. + */ void del_timer(struct hv_timer *timer); +/** + * @brief Initialize timer. + * + * @return None + */ void timer_init(void); + +/** + * @brief Check tsc to make sure rdtsc is enabled. + */ void check_tsc(void); + +/** + * @brief Calibrate tsc. + * + * @return None + */ void calibrate_tsc(void); +/** + * @} + */ + #endif /* TIMER_H */