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