1f5587d1bSGabriele Monaco /* SPDX-License-Identifier: GPL-2.0 */ 2f5587d1bSGabriele Monaco /* 3f5587d1bSGabriele Monaco * Copyright (C) 2025-2028 Red Hat, Inc. Gabriele Monaco <gmonaco@redhat.com> 4f5587d1bSGabriele Monaco * 5f5587d1bSGabriele Monaco * Hybrid automata (HA) monitor functions, to be used together 6f5587d1bSGabriele Monaco * with automata models in C generated by the rvgen tool. 7f5587d1bSGabriele Monaco * 8f5587d1bSGabriele Monaco * This type of monitors extends the Deterministic automata (DA) class by 9f5587d1bSGabriele Monaco * adding a set of environment variables (e.g. clocks) that can be used to 10f5587d1bSGabriele Monaco * constraint the valid transitions. 11f5587d1bSGabriele Monaco * 12f5587d1bSGabriele Monaco * The rvgen tool is available at tools/verification/rvgen/ 13f5587d1bSGabriele Monaco * 14f5587d1bSGabriele Monaco * For further information, see: 15f5587d1bSGabriele Monaco * Documentation/trace/rv/monitor_synthesis.rst 16f5587d1bSGabriele Monaco */ 17f5587d1bSGabriele Monaco 18f5587d1bSGabriele Monaco #ifndef _RV_HA_MONITOR_H 19f5587d1bSGabriele Monaco #define _RV_HA_MONITOR_H 20f5587d1bSGabriele Monaco 21f5587d1bSGabriele Monaco #include <rv/automata.h> 22f5587d1bSGabriele Monaco 23f5587d1bSGabriele Monaco #ifndef da_id_type 24f5587d1bSGabriele Monaco #define da_id_type int 25f5587d1bSGabriele Monaco #endif 26f5587d1bSGabriele Monaco 27f5587d1bSGabriele Monaco static inline void ha_monitor_init_env(struct da_monitor *da_mon); 28f5587d1bSGabriele Monaco static inline void ha_monitor_reset_env(struct da_monitor *da_mon); 29f5587d1bSGabriele Monaco static inline void ha_setup_timer(struct ha_monitor *ha_mon); 30f5587d1bSGabriele Monaco static inline bool ha_cancel_timer(struct ha_monitor *ha_mon); 31f5587d1bSGabriele Monaco static bool ha_monitor_handle_constraint(struct da_monitor *da_mon, 32f5587d1bSGabriele Monaco enum states curr_state, 33f5587d1bSGabriele Monaco enum events event, 34f5587d1bSGabriele Monaco enum states next_state, 35f5587d1bSGabriele Monaco da_id_type id); 36f5587d1bSGabriele Monaco #define da_monitor_event_hook ha_monitor_handle_constraint 37f5587d1bSGabriele Monaco #define da_monitor_init_hook ha_monitor_init_env 38f5587d1bSGabriele Monaco #define da_monitor_reset_hook ha_monitor_reset_env 39f5587d1bSGabriele Monaco 40f5587d1bSGabriele Monaco #include <rv/da_monitor.h> 41f5587d1bSGabriele Monaco #include <linux/seq_buf.h> 42f5587d1bSGabriele Monaco 43f5587d1bSGabriele Monaco /* This simplifies things since da_mon and ha_mon coexist in the same union */ 44f5587d1bSGabriele Monaco _Static_assert(offsetof(struct ha_monitor, da_mon) == 0, 45f5587d1bSGabriele Monaco "da_mon must be the first element in an ha_mon!"); 46f5587d1bSGabriele Monaco #define to_ha_monitor(da) container_of(da, struct ha_monitor, da_mon) 47f5587d1bSGabriele Monaco 48f5587d1bSGabriele Monaco #define ENV_MAX CONCATENATE(env_max_, MONITOR_NAME) 49f5587d1bSGabriele Monaco #define ENV_MAX_STORED CONCATENATE(env_max_stored_, MONITOR_NAME) 50f5587d1bSGabriele Monaco #define envs CONCATENATE(envs_, MONITOR_NAME) 51f5587d1bSGabriele Monaco 52f5587d1bSGabriele Monaco /* Environment storage before being reset */ 53f5587d1bSGabriele Monaco #define ENV_INVALID_VALUE U64_MAX 54f5587d1bSGabriele Monaco /* Error with no event occurs only on timeouts */ 55f5587d1bSGabriele Monaco #define EVENT_NONE EVENT_MAX 56f5587d1bSGabriele Monaco #define EVENT_NONE_LBL "none" 57f5587d1bSGabriele Monaco #define ENV_BUFFER_SIZE 64 58f5587d1bSGabriele Monaco 59f5587d1bSGabriele Monaco #ifdef CONFIG_RV_REACTORS 60f5587d1bSGabriele Monaco 61f5587d1bSGabriele Monaco /* 62f5587d1bSGabriele Monaco * ha_react - trigger the reaction after a failed environment constraint 63f5587d1bSGabriele Monaco * 64f5587d1bSGabriele Monaco * The transition from curr_state with event is otherwise valid, but the 65f5587d1bSGabriele Monaco * environment constraint is false. This function can be called also with no 66f5587d1bSGabriele Monaco * event from a timer (state constraints only). 67f5587d1bSGabriele Monaco */ 68f5587d1bSGabriele Monaco static void ha_react(enum states curr_state, enum events event, char *env) 69f5587d1bSGabriele Monaco { 70f5587d1bSGabriele Monaco rv_react(&rv_this, 71f5587d1bSGabriele Monaco "rv: monitor %s does not allow event %s on state %s with env %s\n", 72f5587d1bSGabriele Monaco __stringify(MONITOR_NAME), 73f5587d1bSGabriele Monaco event == EVENT_NONE ? EVENT_NONE_LBL : model_get_event_name(event), 74f5587d1bSGabriele Monaco model_get_state_name(curr_state), env); 75f5587d1bSGabriele Monaco } 76f5587d1bSGabriele Monaco 77f5587d1bSGabriele Monaco #else /* CONFIG_RV_REACTOR */ 78f5587d1bSGabriele Monaco 79f5587d1bSGabriele Monaco static void ha_react(enum states curr_state, enum events event, char *env) { } 80f5587d1bSGabriele Monaco #endif 81f5587d1bSGabriele Monaco 82f5587d1bSGabriele Monaco /* 83f5587d1bSGabriele Monaco * model_get_state_name - return the (string) name of the given state 84f5587d1bSGabriele Monaco */ 85f5587d1bSGabriele Monaco static char *model_get_env_name(enum envs env) 86f5587d1bSGabriele Monaco { 87f5587d1bSGabriele Monaco if ((env < 0) || (env >= ENV_MAX)) 88f5587d1bSGabriele Monaco return "INVALID"; 89f5587d1bSGabriele Monaco 90f5587d1bSGabriele Monaco return RV_AUTOMATON_NAME.env_names[env]; 91f5587d1bSGabriele Monaco } 92f5587d1bSGabriele Monaco 93f5587d1bSGabriele Monaco /* 94f5587d1bSGabriele Monaco * Monitors requiring a timer implementation need to request it explicitly. 95f5587d1bSGabriele Monaco */ 96f5587d1bSGabriele Monaco #ifndef HA_TIMER_TYPE 97f5587d1bSGabriele Monaco #define HA_TIMER_TYPE HA_TIMER_NONE 98f5587d1bSGabriele Monaco #endif 99f5587d1bSGabriele Monaco 100f5587d1bSGabriele Monaco #if HA_TIMER_TYPE == HA_TIMER_WHEEL 101f5587d1bSGabriele Monaco static void ha_monitor_timer_callback(struct timer_list *timer); 102f5587d1bSGabriele Monaco #elif HA_TIMER_TYPE == HA_TIMER_HRTIMER 103f5587d1bSGabriele Monaco static enum hrtimer_restart ha_monitor_timer_callback(struct hrtimer *hrtimer); 104f5587d1bSGabriele Monaco #endif 105f5587d1bSGabriele Monaco 106f5587d1bSGabriele Monaco /* 107f5587d1bSGabriele Monaco * ktime_get_ns is expensive, since we usually don't require precise accounting 108f5587d1bSGabriele Monaco * of changes within the same event, cache the current time at the beginning of 109f5587d1bSGabriele Monaco * the constraint handler and use the cache for subsequent calls. 110f5587d1bSGabriele Monaco * Monitors without ns clocks automatically skip this. 111f5587d1bSGabriele Monaco */ 112f5587d1bSGabriele Monaco #ifdef HA_CLK_NS 113f5587d1bSGabriele Monaco #define ha_get_ns() ktime_get_ns() 114f5587d1bSGabriele Monaco #else 115f5587d1bSGabriele Monaco #define ha_get_ns() 0 116f5587d1bSGabriele Monaco #endif /* HA_CLK_NS */ 117f5587d1bSGabriele Monaco 118f5587d1bSGabriele Monaco /* Should be supplied by the monitor */ 119f5587d1bSGabriele Monaco static u64 ha_get_env(struct ha_monitor *ha_mon, enum envs env, u64 time_ns); 120f5587d1bSGabriele Monaco static bool ha_verify_constraint(struct ha_monitor *ha_mon, 121f5587d1bSGabriele Monaco enum states curr_state, 122f5587d1bSGabriele Monaco enum events event, 123f5587d1bSGabriele Monaco enum states next_state, 124f5587d1bSGabriele Monaco u64 time_ns); 125f5587d1bSGabriele Monaco 126f5587d1bSGabriele Monaco /* 127f5587d1bSGabriele Monaco * ha_monitor_reset_all_stored - reset all environment variables in the monitor 128f5587d1bSGabriele Monaco */ 129f5587d1bSGabriele Monaco static inline void ha_monitor_reset_all_stored(struct ha_monitor *ha_mon) 130f5587d1bSGabriele Monaco { 131f5587d1bSGabriele Monaco for (int i = 0; i < ENV_MAX_STORED; i++) 132f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[i], ENV_INVALID_VALUE); 133f5587d1bSGabriele Monaco } 134f5587d1bSGabriele Monaco 135f5587d1bSGabriele Monaco /* 136f5587d1bSGabriele Monaco * ha_monitor_init_env - setup timer and reset all environment 137f5587d1bSGabriele Monaco * 138f5587d1bSGabriele Monaco * Called from a hook in the DA start functions, it supplies the da_mon 139f5587d1bSGabriele Monaco * corresponding to the current ha_mon. 140f5587d1bSGabriele Monaco * Not all hybrid automata require the timer, still set it for simplicity. 141f5587d1bSGabriele Monaco */ 142f5587d1bSGabriele Monaco static inline void ha_monitor_init_env(struct da_monitor *da_mon) 143f5587d1bSGabriele Monaco { 144f5587d1bSGabriele Monaco struct ha_monitor *ha_mon = to_ha_monitor(da_mon); 145f5587d1bSGabriele Monaco 146f5587d1bSGabriele Monaco ha_monitor_reset_all_stored(ha_mon); 147f5587d1bSGabriele Monaco ha_setup_timer(ha_mon); 148f5587d1bSGabriele Monaco } 149f5587d1bSGabriele Monaco 150f5587d1bSGabriele Monaco /* 151f5587d1bSGabriele Monaco * ha_monitor_reset_env - stop timer and reset all environment 152f5587d1bSGabriele Monaco * 153f5587d1bSGabriele Monaco * Called from a hook in the DA reset functions, it supplies the da_mon 154f5587d1bSGabriele Monaco * corresponding to the current ha_mon. 155f5587d1bSGabriele Monaco * Not all hybrid automata require the timer, still clear it for simplicity. 156f5587d1bSGabriele Monaco */ 157f5587d1bSGabriele Monaco static inline void ha_monitor_reset_env(struct da_monitor *da_mon) 158f5587d1bSGabriele Monaco { 159f5587d1bSGabriele Monaco struct ha_monitor *ha_mon = to_ha_monitor(da_mon); 160f5587d1bSGabriele Monaco 161f5587d1bSGabriele Monaco /* Initialisation resets the monitor before initialising the timer */ 162f5587d1bSGabriele Monaco if (likely(da_monitoring(da_mon))) 163f5587d1bSGabriele Monaco ha_cancel_timer(ha_mon); 164f5587d1bSGabriele Monaco } 165f5587d1bSGabriele Monaco 166f5587d1bSGabriele Monaco /* 167f5587d1bSGabriele Monaco * ha_monitor_env_invalid - return true if env has not been initialised 168f5587d1bSGabriele Monaco */ 169f5587d1bSGabriele Monaco static inline bool ha_monitor_env_invalid(struct ha_monitor *ha_mon, enum envs env) 170f5587d1bSGabriele Monaco { 171f5587d1bSGabriele Monaco return READ_ONCE(ha_mon->env_store[env]) == ENV_INVALID_VALUE; 172f5587d1bSGabriele Monaco } 173f5587d1bSGabriele Monaco 174f5587d1bSGabriele Monaco static inline void ha_get_env_string(struct seq_buf *s, 175f5587d1bSGabriele Monaco struct ha_monitor *ha_mon, u64 time_ns) 176f5587d1bSGabriele Monaco { 177f5587d1bSGabriele Monaco const char *format_str = "%s=%llu"; 178f5587d1bSGabriele Monaco 179f5587d1bSGabriele Monaco for (int i = 0; i < ENV_MAX; i++) { 180f5587d1bSGabriele Monaco seq_buf_printf(s, format_str, model_get_env_name(i), 181f5587d1bSGabriele Monaco ha_get_env(ha_mon, i, time_ns)); 182f5587d1bSGabriele Monaco format_str = ",%s=%llu"; 183f5587d1bSGabriele Monaco } 184f5587d1bSGabriele Monaco } 185f5587d1bSGabriele Monaco 186f5587d1bSGabriele Monaco #if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU 187f5587d1bSGabriele Monaco static inline void ha_trace_error_env(struct ha_monitor *ha_mon, 188f5587d1bSGabriele Monaco char *curr_state, char *event, char *env, 189f5587d1bSGabriele Monaco da_id_type id) 190f5587d1bSGabriele Monaco { 191f5587d1bSGabriele Monaco CONCATENATE(trace_error_env_, MONITOR_NAME)(curr_state, event, env); 192f5587d1bSGabriele Monaco } 193*4a24127bSGabriele Monaco #elif RV_MON_TYPE == RV_MON_PER_TASK || RV_MON_TYPE == RV_MON_PER_OBJ 194*4a24127bSGabriele Monaco 195*4a24127bSGabriele Monaco #define ha_get_target(ha_mon) da_get_target(&ha_mon->da_mon) 196*4a24127bSGabriele Monaco 197f5587d1bSGabriele Monaco static inline void ha_trace_error_env(struct ha_monitor *ha_mon, 198f5587d1bSGabriele Monaco char *curr_state, char *event, char *env, 199f5587d1bSGabriele Monaco da_id_type id) 200f5587d1bSGabriele Monaco { 201f5587d1bSGabriele Monaco CONCATENATE(trace_error_env_, MONITOR_NAME)(id, curr_state, event, env); 202f5587d1bSGabriele Monaco } 203f5587d1bSGabriele Monaco #endif /* RV_MON_TYPE */ 204f5587d1bSGabriele Monaco 205f5587d1bSGabriele Monaco /* 206f5587d1bSGabriele Monaco * ha_get_monitor - return the current monitor 207f5587d1bSGabriele Monaco */ 208f5587d1bSGabriele Monaco #define ha_get_monitor(...) to_ha_monitor(da_get_monitor(__VA_ARGS__)) 209f5587d1bSGabriele Monaco 210f5587d1bSGabriele Monaco /* 211f5587d1bSGabriele Monaco * ha_monitor_handle_constraint - handle the constraint on the current transition 212f5587d1bSGabriele Monaco * 213f5587d1bSGabriele Monaco * If the monitor implementation defines a constraint in the transition from 214f5587d1bSGabriele Monaco * curr_state to event, react and trace appropriately as well as return false. 215f5587d1bSGabriele Monaco * This function is called from the hook in the DA event handle function and 216f5587d1bSGabriele Monaco * triggers a failure in the monitor. 217f5587d1bSGabriele Monaco */ 218f5587d1bSGabriele Monaco static bool ha_monitor_handle_constraint(struct da_monitor *da_mon, 219f5587d1bSGabriele Monaco enum states curr_state, 220f5587d1bSGabriele Monaco enum events event, 221f5587d1bSGabriele Monaco enum states next_state, 222f5587d1bSGabriele Monaco da_id_type id) 223f5587d1bSGabriele Monaco { 224f5587d1bSGabriele Monaco struct ha_monitor *ha_mon = to_ha_monitor(da_mon); 225f5587d1bSGabriele Monaco u64 time_ns = ha_get_ns(); 226f5587d1bSGabriele Monaco DECLARE_SEQ_BUF(env_string, ENV_BUFFER_SIZE); 227f5587d1bSGabriele Monaco 228f5587d1bSGabriele Monaco if (ha_verify_constraint(ha_mon, curr_state, event, next_state, time_ns)) 229f5587d1bSGabriele Monaco return true; 230f5587d1bSGabriele Monaco 231f5587d1bSGabriele Monaco ha_get_env_string(&env_string, ha_mon, time_ns); 232f5587d1bSGabriele Monaco ha_react(curr_state, event, env_string.buffer); 233f5587d1bSGabriele Monaco ha_trace_error_env(ha_mon, 234f5587d1bSGabriele Monaco model_get_state_name(curr_state), 235f5587d1bSGabriele Monaco model_get_event_name(event), 236f5587d1bSGabriele Monaco env_string.buffer, id); 237f5587d1bSGabriele Monaco return false; 238f5587d1bSGabriele Monaco } 239f5587d1bSGabriele Monaco 240f5587d1bSGabriele Monaco static inline void __ha_monitor_timer_callback(struct ha_monitor *ha_mon) 241f5587d1bSGabriele Monaco { 242f5587d1bSGabriele Monaco enum states curr_state = READ_ONCE(ha_mon->da_mon.curr_state); 243f5587d1bSGabriele Monaco DECLARE_SEQ_BUF(env_string, ENV_BUFFER_SIZE); 244f5587d1bSGabriele Monaco u64 time_ns = ha_get_ns(); 245f5587d1bSGabriele Monaco 246f5587d1bSGabriele Monaco ha_get_env_string(&env_string, ha_mon, time_ns); 247f5587d1bSGabriele Monaco ha_react(curr_state, EVENT_NONE, env_string.buffer); 248f5587d1bSGabriele Monaco ha_trace_error_env(ha_mon, model_get_state_name(curr_state), 249f5587d1bSGabriele Monaco EVENT_NONE_LBL, env_string.buffer, 250f5587d1bSGabriele Monaco da_get_id(&ha_mon->da_mon)); 251f5587d1bSGabriele Monaco 252f5587d1bSGabriele Monaco da_monitor_reset(&ha_mon->da_mon); 253f5587d1bSGabriele Monaco } 254f5587d1bSGabriele Monaco 255f5587d1bSGabriele Monaco /* 256f5587d1bSGabriele Monaco * The clock variables have 2 different representations in the env_store: 257f5587d1bSGabriele Monaco * - The guard representation is the timestamp of the last reset 258f5587d1bSGabriele Monaco * - The invariant representation is the timestamp when the invariant expires 259f5587d1bSGabriele Monaco * As the representations are incompatible, care must be taken when switching 260f5587d1bSGabriele Monaco * between them: the invariant representation can only be used when starting a 261f5587d1bSGabriele Monaco * timer when the previous representation was guard (e.g. no other invariant 262f5587d1bSGabriele Monaco * started since the last reset operation). 263f5587d1bSGabriele Monaco * Likewise, switching from invariant to guard representation without a reset 264f5587d1bSGabriele Monaco * can be done only by subtracting the exact value used to start the invariant. 265f5587d1bSGabriele Monaco * 266f5587d1bSGabriele Monaco * Reading the environment variable (ha_get_clk) also reflects this difference 267f5587d1bSGabriele Monaco * any reads in states that have an invariant return the (possibly negative) 268f5587d1bSGabriele Monaco * time since expiration, other reads return the time since last reset. 269f5587d1bSGabriele Monaco */ 270f5587d1bSGabriele Monaco 271f5587d1bSGabriele Monaco /* 272f5587d1bSGabriele Monaco * Helper functions for env variables describing clocks with ns granularity 273f5587d1bSGabriele Monaco */ 274f5587d1bSGabriele Monaco static inline u64 ha_get_clk_ns(struct ha_monitor *ha_mon, enum envs env, u64 time_ns) 275f5587d1bSGabriele Monaco { 276f5587d1bSGabriele Monaco return time_ns - READ_ONCE(ha_mon->env_store[env]); 277f5587d1bSGabriele Monaco } 278f5587d1bSGabriele Monaco static inline void ha_reset_clk_ns(struct ha_monitor *ha_mon, enum envs env, u64 time_ns) 279f5587d1bSGabriele Monaco { 280f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[env], time_ns); 281f5587d1bSGabriele Monaco } 282f5587d1bSGabriele Monaco static inline void ha_set_invariant_ns(struct ha_monitor *ha_mon, enum envs env, 283f5587d1bSGabriele Monaco u64 value, u64 time_ns) 284f5587d1bSGabriele Monaco { 285f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[env], time_ns + value); 286f5587d1bSGabriele Monaco } 287f5587d1bSGabriele Monaco static inline bool ha_check_invariant_ns(struct ha_monitor *ha_mon, 288f5587d1bSGabriele Monaco enum envs env, u64 time_ns) 289f5587d1bSGabriele Monaco { 290f5587d1bSGabriele Monaco return READ_ONCE(ha_mon->env_store[env]) >= time_ns; 291f5587d1bSGabriele Monaco } 292f5587d1bSGabriele Monaco /* 293f5587d1bSGabriele Monaco * ha_invariant_passed_ns - prepare the invariant and return the time since reset 294f5587d1bSGabriele Monaco */ 295f5587d1bSGabriele Monaco static inline u64 ha_invariant_passed_ns(struct ha_monitor *ha_mon, enum envs env, 296f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 297f5587d1bSGabriele Monaco { 298f5587d1bSGabriele Monaco u64 passed = 0; 299f5587d1bSGabriele Monaco 300f5587d1bSGabriele Monaco if (env < 0 || env >= ENV_MAX_STORED) 301f5587d1bSGabriele Monaco return 0; 302f5587d1bSGabriele Monaco if (ha_monitor_env_invalid(ha_mon, env)) 303f5587d1bSGabriele Monaco return 0; 304f5587d1bSGabriele Monaco passed = ha_get_env(ha_mon, env, time_ns); 305f5587d1bSGabriele Monaco ha_set_invariant_ns(ha_mon, env, expire - passed, time_ns); 306f5587d1bSGabriele Monaco return passed; 307f5587d1bSGabriele Monaco } 308f5587d1bSGabriele Monaco 309f5587d1bSGabriele Monaco /* 310f5587d1bSGabriele Monaco * Helper functions for env variables describing clocks with jiffy granularity 311f5587d1bSGabriele Monaco */ 312f5587d1bSGabriele Monaco static inline u64 ha_get_clk_jiffy(struct ha_monitor *ha_mon, enum envs env) 313f5587d1bSGabriele Monaco { 314f5587d1bSGabriele Monaco return get_jiffies_64() - READ_ONCE(ha_mon->env_store[env]); 315f5587d1bSGabriele Monaco } 316f5587d1bSGabriele Monaco static inline void ha_reset_clk_jiffy(struct ha_monitor *ha_mon, enum envs env) 317f5587d1bSGabriele Monaco { 318f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[env], get_jiffies_64()); 319f5587d1bSGabriele Monaco } 320f5587d1bSGabriele Monaco static inline void ha_set_invariant_jiffy(struct ha_monitor *ha_mon, 321f5587d1bSGabriele Monaco enum envs env, u64 value) 322f5587d1bSGabriele Monaco { 323f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[env], get_jiffies_64() + value); 324f5587d1bSGabriele Monaco } 325f5587d1bSGabriele Monaco static inline bool ha_check_invariant_jiffy(struct ha_monitor *ha_mon, 326f5587d1bSGabriele Monaco enum envs env, u64 time_ns) 327f5587d1bSGabriele Monaco { 328f5587d1bSGabriele Monaco return time_after64(READ_ONCE(ha_mon->env_store[env]), get_jiffies_64()); 329f5587d1bSGabriele Monaco 330f5587d1bSGabriele Monaco } 331f5587d1bSGabriele Monaco /* 332f5587d1bSGabriele Monaco * ha_invariant_passed_jiffy - prepare the invariant and return the time since reset 333f5587d1bSGabriele Monaco */ 334f5587d1bSGabriele Monaco static inline u64 ha_invariant_passed_jiffy(struct ha_monitor *ha_mon, enum envs env, 335f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 336f5587d1bSGabriele Monaco { 337f5587d1bSGabriele Monaco u64 passed = 0; 338f5587d1bSGabriele Monaco 339f5587d1bSGabriele Monaco if (env < 0 || env >= ENV_MAX_STORED) 340f5587d1bSGabriele Monaco return 0; 341f5587d1bSGabriele Monaco if (ha_monitor_env_invalid(ha_mon, env)) 342f5587d1bSGabriele Monaco return 0; 343f5587d1bSGabriele Monaco passed = ha_get_env(ha_mon, env, time_ns); 344f5587d1bSGabriele Monaco ha_set_invariant_jiffy(ha_mon, env, expire - passed); 345f5587d1bSGabriele Monaco return passed; 346f5587d1bSGabriele Monaco } 347f5587d1bSGabriele Monaco 348f5587d1bSGabriele Monaco /* 349f5587d1bSGabriele Monaco * Retrieve the last reset time (guard representation) from the invariant 350f5587d1bSGabriele Monaco * representation (expiration). 351f5587d1bSGabriele Monaco * It the caller's responsibility to make sure the storage was actually in the 352f5587d1bSGabriele Monaco * invariant representation (e.g. the current state has an invariant). 353f5587d1bSGabriele Monaco * The provided value must be the same used when starting the invariant. 354f5587d1bSGabriele Monaco * 355f5587d1bSGabriele Monaco * This function's access to the storage is NOT atomic, due to the rarity when 356f5587d1bSGabriele Monaco * this is used. If a monitor allows writes concurrent to this, likely 357f5587d1bSGabriele Monaco * other things are broken and need rethinking the model or additional locking. 358f5587d1bSGabriele Monaco */ 359f5587d1bSGabriele Monaco static inline void ha_inv_to_guard(struct ha_monitor *ha_mon, enum envs env, 360f5587d1bSGabriele Monaco u64 value, u64 time_ns) 361f5587d1bSGabriele Monaco { 362f5587d1bSGabriele Monaco WRITE_ONCE(ha_mon->env_store[env], READ_ONCE(ha_mon->env_store[env]) - value); 363f5587d1bSGabriele Monaco } 364f5587d1bSGabriele Monaco 365f5587d1bSGabriele Monaco #if HA_TIMER_TYPE == HA_TIMER_WHEEL 366f5587d1bSGabriele Monaco /* 367f5587d1bSGabriele Monaco * Helper functions to handle the monitor timer. 368f5587d1bSGabriele Monaco * Not all monitors require a timer, in such case the timer will be set up but 369f5587d1bSGabriele Monaco * never armed. 370f5587d1bSGabriele Monaco * Timers start since the last reset of the supplied env or from now if env is 371f5587d1bSGabriele Monaco * not an environment variable. If env was not initialised no timer starts. 372f5587d1bSGabriele Monaco * Timers can expire on any CPU unless the monitor is per-cpu, 373f5587d1bSGabriele Monaco * where we assume every event occurs on the local CPU. 374f5587d1bSGabriele Monaco */ 375f5587d1bSGabriele Monaco static void ha_monitor_timer_callback(struct timer_list *timer) 376f5587d1bSGabriele Monaco { 377f5587d1bSGabriele Monaco struct ha_monitor *ha_mon = container_of(timer, struct ha_monitor, timer); 378f5587d1bSGabriele Monaco 379f5587d1bSGabriele Monaco __ha_monitor_timer_callback(ha_mon); 380f5587d1bSGabriele Monaco } 381f5587d1bSGabriele Monaco static inline void ha_setup_timer(struct ha_monitor *ha_mon) 382f5587d1bSGabriele Monaco { 383f5587d1bSGabriele Monaco int mode = 0; 384f5587d1bSGabriele Monaco 385f5587d1bSGabriele Monaco if (RV_MON_TYPE == RV_MON_PER_CPU) 386f5587d1bSGabriele Monaco mode |= TIMER_PINNED; 387f5587d1bSGabriele Monaco timer_setup(&ha_mon->timer, ha_monitor_timer_callback, mode); 388f5587d1bSGabriele Monaco } 389f5587d1bSGabriele Monaco static inline void ha_start_timer_jiffy(struct ha_monitor *ha_mon, enum envs env, 390f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 391f5587d1bSGabriele Monaco { 392f5587d1bSGabriele Monaco u64 passed = ha_invariant_passed_jiffy(ha_mon, env, expire, time_ns); 393f5587d1bSGabriele Monaco 394f5587d1bSGabriele Monaco mod_timer(&ha_mon->timer, get_jiffies_64() + expire - passed); 395f5587d1bSGabriele Monaco } 396f5587d1bSGabriele Monaco static inline void ha_start_timer_ns(struct ha_monitor *ha_mon, enum envs env, 397f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 398f5587d1bSGabriele Monaco { 399f5587d1bSGabriele Monaco u64 passed = ha_invariant_passed_ns(ha_mon, env, expire, time_ns); 400f5587d1bSGabriele Monaco 401f5587d1bSGabriele Monaco ha_start_timer_jiffy(ha_mon, ENV_MAX_STORED, 402f5587d1bSGabriele Monaco nsecs_to_jiffies(expire - passed + TICK_NSEC - 1), time_ns); 403f5587d1bSGabriele Monaco } 404f5587d1bSGabriele Monaco /* 405f5587d1bSGabriele Monaco * ha_cancel_timer - Cancel the timer 406f5587d1bSGabriele Monaco * 407f5587d1bSGabriele Monaco * Returns: 408f5587d1bSGabriele Monaco * * 1 when the timer was active 409f5587d1bSGabriele Monaco * * 0 when the timer was not active or running a callback 410f5587d1bSGabriele Monaco */ 411f5587d1bSGabriele Monaco static inline bool ha_cancel_timer(struct ha_monitor *ha_mon) 412f5587d1bSGabriele Monaco { 413f5587d1bSGabriele Monaco return timer_delete(&ha_mon->timer); 414f5587d1bSGabriele Monaco } 415f5587d1bSGabriele Monaco #elif HA_TIMER_TYPE == HA_TIMER_HRTIMER 416f5587d1bSGabriele Monaco /* 417f5587d1bSGabriele Monaco * Helper functions to handle the monitor timer. 418f5587d1bSGabriele Monaco * Not all monitors require a timer, in such case the timer will be set up but 419f5587d1bSGabriele Monaco * never armed. 420f5587d1bSGabriele Monaco * Timers start since the last reset of the supplied env or from now if env is 421f5587d1bSGabriele Monaco * not an environment variable. If env was not initialised no timer starts. 422f5587d1bSGabriele Monaco * Timers can expire on any CPU unless the monitor is per-cpu, 423f5587d1bSGabriele Monaco * where we assume every event occurs on the local CPU. 424f5587d1bSGabriele Monaco */ 425f5587d1bSGabriele Monaco static enum hrtimer_restart ha_monitor_timer_callback(struct hrtimer *hrtimer) 426f5587d1bSGabriele Monaco { 427f5587d1bSGabriele Monaco struct ha_monitor *ha_mon = container_of(hrtimer, struct ha_monitor, hrtimer); 428f5587d1bSGabriele Monaco 429f5587d1bSGabriele Monaco __ha_monitor_timer_callback(ha_mon); 430f5587d1bSGabriele Monaco return HRTIMER_NORESTART; 431f5587d1bSGabriele Monaco } 432f5587d1bSGabriele Monaco static inline void ha_setup_timer(struct ha_monitor *ha_mon) 433f5587d1bSGabriele Monaco { 434f5587d1bSGabriele Monaco hrtimer_setup(&ha_mon->hrtimer, ha_monitor_timer_callback, 435f5587d1bSGabriele Monaco CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); 436f5587d1bSGabriele Monaco } 437f5587d1bSGabriele Monaco static inline void ha_start_timer_ns(struct ha_monitor *ha_mon, enum envs env, 438f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 439f5587d1bSGabriele Monaco { 440f5587d1bSGabriele Monaco int mode = HRTIMER_MODE_REL_HARD; 441f5587d1bSGabriele Monaco u64 passed = ha_invariant_passed_ns(ha_mon, env, expire, time_ns); 442f5587d1bSGabriele Monaco 443f5587d1bSGabriele Monaco if (RV_MON_TYPE == RV_MON_PER_CPU) 444f5587d1bSGabriele Monaco mode |= HRTIMER_MODE_PINNED; 445f5587d1bSGabriele Monaco hrtimer_start(&ha_mon->hrtimer, ns_to_ktime(expire - passed), mode); 446f5587d1bSGabriele Monaco } 447f5587d1bSGabriele Monaco static inline void ha_start_timer_jiffy(struct ha_monitor *ha_mon, enum envs env, 448f5587d1bSGabriele Monaco u64 expire, u64 time_ns) 449f5587d1bSGabriele Monaco { 450f5587d1bSGabriele Monaco u64 passed = ha_invariant_passed_jiffy(ha_mon, env, expire, time_ns); 451f5587d1bSGabriele Monaco 452f5587d1bSGabriele Monaco ha_start_timer_ns(ha_mon, ENV_MAX_STORED, 453f5587d1bSGabriele Monaco jiffies_to_nsecs(expire - passed), time_ns); 454f5587d1bSGabriele Monaco } 455f5587d1bSGabriele Monaco /* 456f5587d1bSGabriele Monaco * ha_cancel_timer - Cancel the timer 457f5587d1bSGabriele Monaco * 458f5587d1bSGabriele Monaco * Returns: 459f5587d1bSGabriele Monaco * * 1 when the timer was active 460f5587d1bSGabriele Monaco * * 0 when the timer was not active or running a callback 461f5587d1bSGabriele Monaco */ 462f5587d1bSGabriele Monaco static inline bool ha_cancel_timer(struct ha_monitor *ha_mon) 463f5587d1bSGabriele Monaco { 464f5587d1bSGabriele Monaco return hrtimer_try_to_cancel(&ha_mon->hrtimer) == 1; 465f5587d1bSGabriele Monaco } 466f5587d1bSGabriele Monaco #else /* HA_TIMER_NONE */ 467f5587d1bSGabriele Monaco /* 468f5587d1bSGabriele Monaco * Start function is intentionally not defined, monitors using timers must 469f5587d1bSGabriele Monaco * set HA_TIMER_TYPE to either HA_TIMER_WHEEL or HA_TIMER_HRTIMER. 470f5587d1bSGabriele Monaco */ 471f5587d1bSGabriele Monaco static inline void ha_setup_timer(struct ha_monitor *ha_mon) { } 472f5587d1bSGabriele Monaco static inline bool ha_cancel_timer(struct ha_monitor *ha_mon) 473f5587d1bSGabriele Monaco { 474f5587d1bSGabriele Monaco return false; 475f5587d1bSGabriele Monaco } 476f5587d1bSGabriele Monaco #endif 477f5587d1bSGabriele Monaco 478f5587d1bSGabriele Monaco #endif 479