xref: /optee_os/core/include/kernel/callout.h (revision cf707bd0d6955a19c8b024acae3c46f78088648f)
1*cf707bd0SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */
2*cf707bd0SJens Wiklander /*
3*cf707bd0SJens Wiklander  * Copyright (c) 2024, Linaro Limited
4*cf707bd0SJens Wiklander  */
5*cf707bd0SJens Wiklander 
6*cf707bd0SJens Wiklander #ifndef __KERNEL_CALLOUT_H
7*cf707bd0SJens Wiklander #define __KERNEL_CALLOUT_H
8*cf707bd0SJens Wiklander 
9*cf707bd0SJens Wiklander #include <stdbool.h>
10*cf707bd0SJens Wiklander #include <stdint.h>
11*cf707bd0SJens Wiklander #include <sys/queue.h>
12*cf707bd0SJens Wiklander 
13*cf707bd0SJens Wiklander /*
14*cf707bd0SJens Wiklander  * struct callout - callout reference
15*cf707bd0SJens Wiklander  * @callback:	  function to be called when a callout expires
16*cf707bd0SJens Wiklander  * @expiry_value: callout expiry time counter value
17*cf707bd0SJens Wiklander  * @period:	  ticks to next timeout
18*cf707bd0SJens Wiklander  * @link:	  linked list element
19*cf707bd0SJens Wiklander  *
20*cf707bd0SJens Wiklander  * @callback is called from an interrupt handler so thread resources must
21*cf707bd0SJens Wiklander  * not be used. The main callout service lock is held while @callback is
22*cf707bd0SJens Wiklander  * called so callout_rem() and callout_add() can't be used, but it is safe
23*cf707bd0SJens Wiklander  * to call callout_set_next_timeout() if the call period should be changed.
24*cf707bd0SJens Wiklander  * @callback returns true if it should be called again in @period ticks
25*cf707bd0SJens Wiklander  * or false if the callout should be removed and inactivated. Returning
26*cf707bd0SJens Wiklander  * false from @callback is the equivalent of calling callout_rem() on the
27*cf707bd0SJens Wiklander  * callout reference.
28*cf707bd0SJens Wiklander  */
29*cf707bd0SJens Wiklander struct callout {
30*cf707bd0SJens Wiklander 	bool (*callback)(struct callout *co);
31*cf707bd0SJens Wiklander 	uint64_t expiry_value;
32*cf707bd0SJens Wiklander 	uint64_t period;
33*cf707bd0SJens Wiklander 	TAILQ_ENTRY(callout) link;
34*cf707bd0SJens Wiklander };
35*cf707bd0SJens Wiklander 
36*cf707bd0SJens Wiklander /*
37*cf707bd0SJens Wiklander  * callout_add() - Add a callout
38*cf707bd0SJens Wiklander  * @co:		callout reference
39*cf707bd0SJens Wiklander  * @callback:	callback function accociated with the callout
40*cf707bd0SJens Wiklander  * @ms:		time to next callout in milliseconds
41*cf707bd0SJens Wiklander  *
42*cf707bd0SJens Wiklander  * Adds a callout to the callout service with an associated callback
43*cf707bd0SJens Wiklander  * function @callback that is to be called in @ms milliseconds.
44*cf707bd0SJens Wiklander  *
45*cf707bd0SJens Wiklander  * If callout_add() is called before callout_service_init() has been called
46*cf707bd0SJens Wiklander  * then it will be called @ms milliseconds after callout_service_init() has
47*cf707bd0SJens Wiklander  * been called.
48*cf707bd0SJens Wiklander  *
49*cf707bd0SJens Wiklander  * The callout structure can reside in global data or on the heap. It's
50*cf707bd0SJens Wiklander  * safe to embed it inside another struct, but it must not be freed until
51*cf707bd0SJens Wiklander  * removed with callout_rem() or equivalent.
52*cf707bd0SJens Wiklander  *
53*cf707bd0SJens Wiklander  * The function takes the main callout service for synchronization so it
54*cf707bd0SJens Wiklander  * can't be called from within a callback function in a callout or there's
55*cf707bd0SJens Wiklander  * deadlock.
56*cf707bd0SJens Wiklander  */
57*cf707bd0SJens Wiklander void callout_add(struct callout *co, bool (*callback)(struct callout *co),
58*cf707bd0SJens Wiklander 		 uint32_t ms);
59*cf707bd0SJens Wiklander 
60*cf707bd0SJens Wiklander /*
61*cf707bd0SJens Wiklander  * callout_rem() - Remove a callout
62*cf707bd0SJens Wiklander  * @co:		callout reference
63*cf707bd0SJens Wiklander  *
64*cf707bd0SJens Wiklander  * Removes a callout previously added to the callout service with
65*cf707bd0SJens Wiklander  * callout_add(). Note that when the callback function in a callout
66*cf707bd0SJens Wiklander  * returns false the callout is also removed.
67*cf707bd0SJens Wiklander  *
68*cf707bd0SJens Wiklander  * It's safe to try to remove a callback even if it isn't active any
69*cf707bd0SJens Wiklander  * longer. Nothing will happen in that case, but it's guaranteed to be
70*cf707bd0SJens Wiklander  * inactive and it's safe to free the memory after callout_rem() has
71*cf707bd0SJens Wiklander  * returned.
72*cf707bd0SJens Wiklander  */
73*cf707bd0SJens Wiklander void callout_rem(struct callout *co);
74*cf707bd0SJens Wiklander 
75*cf707bd0SJens Wiklander /*
76*cf707bd0SJens Wiklander  * callout_set_next_timeout() - set time to next callout
77*cf707bd0SJens Wiklander  * @co:		callout reference
78*cf707bd0SJens Wiklander  * @ms:		time to next callout in milliseconds
79*cf707bd0SJens Wiklander  *
80*cf707bd0SJens Wiklander  * Updates the @co->ticks field with the new number of ticks based on @ms.
81*cf707bd0SJens Wiklander  * This value is used to when to calculate the time of the next callout
82*cf707bd0SJens Wiklander  * following then one already set.
83*cf707bd0SJens Wiklander  *
84*cf707bd0SJens Wiklander  * Must only be called from @co->callback() when the callout is triggered.
85*cf707bd0SJens Wiklander  */
86*cf707bd0SJens Wiklander void callout_set_next_timeout(struct callout *co, uint32_t ms);
87*cf707bd0SJens Wiklander 
88*cf707bd0SJens Wiklander /*
89*cf707bd0SJens Wiklander  * struct callout_timer_desc - callout timer descriptor
90*cf707bd0SJens Wiklander  * @disable_timeout:	disables the timer from triggering an interrupt
91*cf707bd0SJens Wiklander  * @set_next_timeout:	sets the next timeout and enables the timer
92*cf707bd0SJens Wiklander  * @ms_to_ticks:	converts milliseconds to ticks, the counter value
93*cf707bd0SJens Wiklander  *			unit
94*cf707bd0SJens Wiklander  * @get_now:		get the current counter value
95*cf707bd0SJens Wiklander  * @is_per_cpu:		flag to indicate if this timer is per CPU (true) or
96*cf707bd0SJens Wiklander  *			global (false).
97*cf707bd0SJens Wiklander  *
98*cf707bd0SJens Wiklander  * This descriptor provides an abstract timer interface first used by
99*cf707bd0SJens Wiklander  * callout_service_init() and then stored to be used by
100*cf707bd0SJens Wiklander  * callout_service_cb().
101*cf707bd0SJens Wiklander  *
102*cf707bd0SJens Wiklander  * When @is_per_cpu is true there is one private timer per CPU so
103*cf707bd0SJens Wiklander  * @disable_timeout() and @set_next_timeout() only affects the timer on the
104*cf707bd0SJens Wiklander  * current CPU. If for instance @set_next_timeout() is called on a new CPU
105*cf707bd0SJens Wiklander  * compared to last time the timer on the old CPU will remain unchanged.
106*cf707bd0SJens Wiklander  * Timer interrupts may trigger based on obsolete configuration, the
107*cf707bd0SJens Wiklander  * callout service is expected to handle this gracefully.
108*cf707bd0SJens Wiklander  */
109*cf707bd0SJens Wiklander struct callout_timer_desc {
110*cf707bd0SJens Wiklander 	void (*disable_timeout)(const struct callout_timer_desc *desc);
111*cf707bd0SJens Wiklander 	void (*set_next_timeout)(const struct callout_timer_desc *desc,
112*cf707bd0SJens Wiklander 				 uint64_t expiry_value);
113*cf707bd0SJens Wiklander 	uint64_t (*ms_to_ticks)(const struct callout_timer_desc *desc,
114*cf707bd0SJens Wiklander 				uint32_t ms);
115*cf707bd0SJens Wiklander 	uint64_t (*get_now)(const struct callout_timer_desc *desc);
116*cf707bd0SJens Wiklander 	bool is_per_cpu;
117*cf707bd0SJens Wiklander };
118*cf707bd0SJens Wiklander 
119*cf707bd0SJens Wiklander /*
120*cf707bd0SJens Wiklander  * callout_service_init() - Initialize the callout service
121*cf707bd0SJens Wiklander  * @desc:	Pointer to the timer interface
122*cf707bd0SJens Wiklander  *
123*cf707bd0SJens Wiklander  * The callout service is initialized with the supplied timer interface
124*cf707bd0SJens Wiklander  */
125*cf707bd0SJens Wiklander void callout_service_init(const struct callout_timer_desc *desc);
126*cf707bd0SJens Wiklander 
127*cf707bd0SJens Wiklander /*
128*cf707bd0SJens Wiklander  * callout_service_cb() - Callout service callback
129*cf707bd0SJens Wiklander  *
130*cf707bd0SJens Wiklander  * Called from interrupt service function for the timer.
131*cf707bd0SJens Wiklander  */
132*cf707bd0SJens Wiklander void callout_service_cb(void);
133*cf707bd0SJens Wiklander 
134*cf707bd0SJens Wiklander #endif /*__KERNEL_CALLOUT_H*/
135