| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | #ifndef _KERNEL_TIME_MIGRATION_H |
| 3 | #define _KERNEL_TIME_MIGRATION_H |
| 4 | |
| 5 | /* Per group capacity. Must be a power of 2! */ |
| 6 | #define TMIGR_CHILDREN_PER_GROUP 8 |
| 7 | |
| 8 | /** |
| 9 | * struct tmigr_event - a timer event associated to a CPU |
| 10 | * @nextevt: The node to enqueue an event in the parent group queue |
| 11 | * @cpu: The CPU to which this event belongs |
| 12 | * @ignore: Hint whether the event could be ignored; it is set when |
| 13 | * CPU or group is active; |
| 14 | */ |
| 15 | struct tmigr_event { |
| 16 | struct timerqueue_node nextevt; |
| 17 | unsigned int cpu; |
| 18 | bool ignore; |
| 19 | }; |
| 20 | |
| 21 | /** |
| 22 | * struct tmigr_group - timer migration hierarchy group |
| 23 | * @lock: Lock protecting the event information and group hierarchy |
| 24 | * information during setup |
| 25 | * @parent: Pointer to the parent group. Pointer is updated when a |
| 26 | * new hierarchy level is added because of a CPU coming |
| 27 | * online the first time. Once it is set, the pointer will |
| 28 | * not be removed or updated. When accessing parent pointer |
| 29 | * lock less to decide whether to abort a propagation or |
| 30 | * not, it is not a problem. The worst outcome is an |
| 31 | * unnecessary/early CPU wake up. But do not access parent |
| 32 | * pointer several times in the same 'action' (like |
| 33 | * activation, deactivation, check for remote expiry,...) |
| 34 | * without holding the lock as it is not ensured that value |
| 35 | * will not change. |
| 36 | * @groupevt: Next event of the group which is only used when the |
| 37 | * group is !active. The group event is then queued into |
| 38 | * the parent timer queue. |
| 39 | * Ignore bit of @groupevt is set when the group is active. |
| 40 | * @next_expiry: Base monotonic expiry time of the next event of the |
| 41 | * group; It is used for the racy lockless check whether a |
| 42 | * remote expiry is required; it is always reliable |
| 43 | * @events: Timer queue for child events queued in the group |
| 44 | * @migr_state: State of the group (see union tmigr_state) |
| 45 | * @level: Hierarchy level of the group; Required during setup |
| 46 | * @numa_node: Required for setup only to make sure CPU and low level |
| 47 | * group information is NUMA local. It is set to NUMA node |
| 48 | * as long as the group level is per NUMA node (level < |
| 49 | * tmigr_crossnode_level); otherwise it is set to |
| 50 | * NUMA_NO_NODE |
| 51 | * @num_children: Counter of group children to make sure the group is only |
| 52 | * filled with TMIGR_CHILDREN_PER_GROUP; Required for setup |
| 53 | * only |
| 54 | * @groupmask: mask of the group in the parent group; is set during |
| 55 | * setup and will never change; can be read lockless |
| 56 | * @list: List head that is added to the per level |
| 57 | * tmigr_level_list; is required during setup when a |
| 58 | * new group needs to be connected to the existing |
| 59 | * hierarchy groups |
| 60 | */ |
| 61 | struct tmigr_group { |
| 62 | raw_spinlock_t lock; |
| 63 | struct tmigr_group *parent; |
| 64 | struct tmigr_event groupevt; |
| 65 | u64 next_expiry; |
| 66 | struct timerqueue_head events; |
| 67 | atomic_t migr_state; |
| 68 | unsigned int level; |
| 69 | int numa_node; |
| 70 | unsigned int num_children; |
| 71 | u8 groupmask; |
| 72 | struct list_head list; |
| 73 | }; |
| 74 | |
| 75 | /** |
| 76 | * struct tmigr_cpu - timer migration per CPU group |
| 77 | * @lock: Lock protecting the tmigr_cpu group information |
| 78 | * @online: Indicates whether the CPU is online; In deactivate path |
| 79 | * it is required to know whether the migrator in the top |
| 80 | * level group is to be set offline, while a timer is |
| 81 | * pending. Then another online CPU needs to be notified to |
| 82 | * take over the migrator role. Furthermore the information |
| 83 | * is required in CPU hotplug path as the CPU is able to go |
| 84 | * idle before the timer migration hierarchy hotplug AP is |
| 85 | * reached. During this phase, the CPU has to handle the |
| 86 | * global timers on its own and must not act as a migrator. |
| 87 | * @idle: Indicates whether the CPU is idle in the timer migration |
| 88 | * hierarchy |
| 89 | * @remote: Is set when timers of the CPU are expired remotely |
| 90 | * @tmgroup: Pointer to the parent group |
| 91 | * @groupmask: mask of tmigr_cpu in the parent group |
| 92 | * @wakeup: Stores the first timer when the timer migration |
| 93 | * hierarchy is completely idle and remote expiry was done; |
| 94 | * is returned to timer code in the idle path and is only |
| 95 | * used in idle path. |
| 96 | * @cpuevt: CPU event which could be enqueued into the parent group |
| 97 | */ |
| 98 | struct tmigr_cpu { |
| 99 | raw_spinlock_t lock; |
| 100 | bool online; |
| 101 | bool idle; |
| 102 | bool remote; |
| 103 | struct tmigr_group *tmgroup; |
| 104 | u8 groupmask; |
| 105 | u64 wakeup; |
| 106 | struct tmigr_event cpuevt; |
| 107 | }; |
| 108 | |
| 109 | /** |
| 110 | * union tmigr_state - state of tmigr_group |
| 111 | * @state: Combined version of the state - only used for atomic |
| 112 | * read/cmpxchg function |
| 113 | * &anon struct: Split version of the state - only use the struct members to |
| 114 | * update information to stay independent of endianness |
| 115 | * @active: Contains each mask bit of the active children |
| 116 | * @migrator: Contains mask of the child which is migrator |
| 117 | * @seq: Sequence counter needs to be increased when an update |
| 118 | * to the tmigr_state is done. It prevents a race when |
| 119 | * updates in the child groups are propagated in changed |
| 120 | * order. Detailed information about the scenario is |
| 121 | * given in the documentation at the begin of |
| 122 | * timer_migration.c. |
| 123 | */ |
| 124 | union tmigr_state { |
| 125 | u32 state; |
| 126 | struct { |
| 127 | u8 active; |
| 128 | u8 migrator; |
| 129 | u16 seq; |
| 130 | } __packed; |
| 131 | }; |
| 132 | |
| 133 | #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) |
| 134 | extern void tmigr_handle_remote(void); |
| 135 | extern bool tmigr_requires_handle_remote(void); |
| 136 | extern void tmigr_cpu_activate(void); |
| 137 | extern u64 tmigr_cpu_deactivate(u64 nextevt); |
| 138 | extern u64 tmigr_cpu_new_timer(u64 nextevt); |
| 139 | extern u64 tmigr_quick_check(u64 nextevt); |
| 140 | #else |
| 141 | static inline void tmigr_handle_remote(void) { } |
| 142 | static inline bool tmigr_requires_handle_remote(void) { return false; } |
| 143 | static inline void tmigr_cpu_activate(void) { } |
| 144 | #endif |
| 145 | |
| 146 | #endif |
| 147 | |