xref: /linux/include/rv/da_monitor.h (revision d2ba6e9c0ae54b3d0973e23d8806cd9a16b9faef)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
4  *
5  * Deterministic automata (DA) monitor functions, to be used together
6  * with automata models in C generated by the dot2k tool.
7  *
8  * The dot2k tool is available at tools/verification/dot2k/
9  *
10  * For further information, see:
11  *   Documentation/trace/rv/monitor_synthesis.rst
12  */
13 
14 #ifndef _RV_DA_MONITOR_H
15 #define _RV_DA_MONITOR_H
16 
17 #include <rv/automata.h>
18 #include <linux/rv.h>
19 #include <linux/stringify.h>
20 #include <linux/bug.h>
21 #include <linux/sched.h>
22 
23 /*
24  * Per-cpu variables require a unique name although static in some
25  * configurations (e.g. CONFIG_DEBUG_FORCE_WEAK_PER_CPU or alpha modules).
26  */
27 #define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME)
28 
29 static struct rv_monitor rv_this;
30 
react(enum states curr_state,enum events event)31 static void react(enum states curr_state, enum events event)
32 {
33 	rv_react(&rv_this,
34 		 "rv: monitor %s does not allow event %s on state %s\n",
35 		 __stringify(MONITOR_NAME),
36 		 model_get_event_name(event),
37 		 model_get_state_name(curr_state));
38 }
39 
40 /*
41  * da_monitor_reset - reset a monitor and setting it to init state
42  */
da_monitor_reset(struct da_monitor * da_mon)43 static inline void da_monitor_reset(struct da_monitor *da_mon)
44 {
45 	da_mon->monitoring = 0;
46 	da_mon->curr_state = model_get_initial_state();
47 }
48 
49 /*
50  * da_monitor_start - start monitoring
51  *
52  * The monitor will ignore all events until monitoring is set to true. This
53  * function needs to be called to tell the monitor to start monitoring.
54  */
da_monitor_start(struct da_monitor * da_mon)55 static inline void da_monitor_start(struct da_monitor *da_mon)
56 {
57 	da_mon->curr_state = model_get_initial_state();
58 	da_mon->monitoring = 1;
59 }
60 
61 /*
62  * da_monitoring - returns true if the monitor is processing events
63  */
da_monitoring(struct da_monitor * da_mon)64 static inline bool da_monitoring(struct da_monitor *da_mon)
65 {
66 	return da_mon->monitoring;
67 }
68 
69 /*
70  * da_monitor_enabled - checks if the monitor is enabled
71  */
da_monitor_enabled(void)72 static inline bool da_monitor_enabled(void)
73 {
74 	/* global switch */
75 	if (unlikely(!rv_monitoring_on()))
76 		return 0;
77 
78 	/* monitor enabled */
79 	if (unlikely(!rv_this.enabled))
80 		return 0;
81 
82 	return 1;
83 }
84 
85 /*
86  * da_monitor_handling_event - checks if the monitor is ready to handle events
87  */
da_monitor_handling_event(struct da_monitor * da_mon)88 static inline bool da_monitor_handling_event(struct da_monitor *da_mon)
89 {
90 	if (!da_monitor_enabled())
91 		return 0;
92 
93 	/* monitor is actually monitoring */
94 	if (unlikely(!da_monitoring(da_mon)))
95 		return 0;
96 
97 	return 1;
98 }
99 
100 #if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
101 /*
102  * Event handler for implicit monitors. Implicit monitor is the one which the
103  * handler does not need to specify which da_monitor to manipulate. Examples
104  * of implicit monitor are the per_cpu or the global ones.
105  *
106  * Retry in case there is a race between getting and setting the next state,
107  * warn and reset the monitor if it runs out of retries. The monitor should be
108  * able to handle various orders.
109  */
110 
da_event(struct da_monitor * da_mon,enum events event)111 static inline bool da_event(struct da_monitor *da_mon, enum events event)
112 {
113 	enum states curr_state, next_state;
114 
115 	curr_state = READ_ONCE(da_mon->curr_state);
116 	for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
117 		next_state = model_get_next_state(curr_state, event);
118 		if (next_state == INVALID_STATE) {
119 			react(curr_state, event);
120 			CONCATENATE(trace_error_, MONITOR_NAME)(
121 				    model_get_state_name(curr_state),
122 				    model_get_event_name(event));
123 			return false;
124 		}
125 		if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
126 			CONCATENATE(trace_event_, MONITOR_NAME)(
127 				    model_get_state_name(curr_state),
128 				    model_get_event_name(event),
129 				    model_get_state_name(next_state),
130 				    model_is_final_state(next_state));
131 			return true;
132 		}
133 	}
134 
135 	trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
136 	pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
137 		" retries reached for event %s, resetting monitor %s",
138 		model_get_event_name(event), __stringify(MONITOR_NAME));
139 	return false;
140 }
141 
142 #elif RV_MON_TYPE == RV_MON_PER_TASK
143 /*
144  * Event handler for per_task monitors.
145  *
146  * Retry in case there is a race between getting and setting the next state,
147  * warn and reset the monitor if it runs out of retries. The monitor should be
148  * able to handle various orders.
149  */
150 
da_event(struct da_monitor * da_mon,struct task_struct * tsk,enum events event)151 static inline bool da_event(struct da_monitor *da_mon, struct task_struct *tsk,
152 			    enum events event)
153 {
154 	enum states curr_state, next_state;
155 
156 	curr_state = READ_ONCE(da_mon->curr_state);
157 	for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
158 		next_state = model_get_next_state(curr_state, event);
159 		if (next_state == INVALID_STATE) {
160 			react(curr_state, event);
161 			CONCATENATE(trace_error_, MONITOR_NAME)(tsk->pid,
162 				    model_get_state_name(curr_state),
163 				    model_get_event_name(event));
164 			return false;
165 		}
166 		if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
167 			CONCATENATE(trace_event_, MONITOR_NAME)(tsk->pid,
168 				    model_get_state_name(curr_state),
169 				    model_get_event_name(event),
170 				    model_get_state_name(next_state),
171 				    model_is_final_state(next_state));
172 			return true;
173 		}
174 	}
175 
176 	trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
177 	pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
178 		" retries reached for event %s, resetting monitor %s",
179 		model_get_event_name(event), __stringify(MONITOR_NAME));
180 	return false;
181 }
182 #endif /* RV_MON_TYPE */
183 
184 #if RV_MON_TYPE == RV_MON_GLOBAL
185 /*
186  * Functions to define, init and get a global monitor.
187  */
188 
189 /*
190  * global monitor (a single variable)
191  */
192 static struct da_monitor DA_MON_NAME;
193 
194 /*
195  * da_get_monitor - return the global monitor address
196  */
da_get_monitor(void)197 static struct da_monitor *da_get_monitor(void)
198 {
199 	return &DA_MON_NAME;
200 }
201 
202 /*
203  * da_monitor_reset_all - reset the single monitor
204  */
da_monitor_reset_all(void)205 static void da_monitor_reset_all(void)
206 {
207 	da_monitor_reset(da_get_monitor());
208 }
209 
210 /*
211  * da_monitor_init - initialize a monitor
212  */
da_monitor_init(void)213 static inline int da_monitor_init(void)
214 {
215 	da_monitor_reset_all();
216 	return 0;
217 }
218 
219 /*
220  * da_monitor_destroy - destroy the monitor
221  */
da_monitor_destroy(void)222 static inline void da_monitor_destroy(void) { }
223 
224 #elif RV_MON_TYPE == RV_MON_PER_CPU
225 /*
226  * Functions to define, init and get a per-cpu monitor.
227  */
228 
229 /*
230  * per-cpu monitor variables
231  */
232 static DEFINE_PER_CPU(struct da_monitor, DA_MON_NAME);
233 
234 /*
235  * da_get_monitor - return current CPU monitor address
236  */
da_get_monitor(void)237 static struct da_monitor *da_get_monitor(void)
238 {
239 	return this_cpu_ptr(&DA_MON_NAME);
240 }
241 
242 /*
243  * da_monitor_reset_all - reset all CPUs' monitor
244  */
da_monitor_reset_all(void)245 static void da_monitor_reset_all(void)
246 {
247 	struct da_monitor *da_mon;
248 	int cpu;
249 
250 	for_each_cpu(cpu, cpu_online_mask) {
251 		da_mon = per_cpu_ptr(&DA_MON_NAME, cpu);
252 		da_monitor_reset(da_mon);
253 	}
254 }
255 
256 /*
257  * da_monitor_init - initialize all CPUs' monitor
258  */
da_monitor_init(void)259 static inline int da_monitor_init(void)
260 {
261 	da_monitor_reset_all();
262 	return 0;
263 }
264 
265 /*
266  * da_monitor_destroy - destroy the monitor
267  */
da_monitor_destroy(void)268 static inline void da_monitor_destroy(void) { }
269 
270 #elif RV_MON_TYPE == RV_MON_PER_TASK
271 /*
272  * Functions to define, init and get a per-task monitor.
273  */
274 
275 /*
276  * The per-task monitor is stored a vector in the task struct. This variable
277  * stores the position on the vector reserved for this monitor.
278  */
279 static int task_mon_slot = RV_PER_TASK_MONITOR_INIT;
280 
281 /*
282  * da_get_monitor - return the monitor in the allocated slot for tsk
283  */
da_get_monitor(struct task_struct * tsk)284 static inline struct da_monitor *da_get_monitor(struct task_struct *tsk)
285 {
286 	return &tsk->rv[task_mon_slot].da_mon;
287 }
288 
da_monitor_reset_all(void)289 static void da_monitor_reset_all(void)
290 {
291 	struct task_struct *g, *p;
292 	int cpu;
293 
294 	read_lock(&tasklist_lock);
295 	for_each_process_thread(g, p)
296 		da_monitor_reset(da_get_monitor(p));
297 	for_each_present_cpu(cpu)
298 		da_monitor_reset(da_get_monitor(idle_task(cpu)));
299 	read_unlock(&tasklist_lock);
300 }
301 
302 /*
303  * da_monitor_init - initialize the per-task monitor
304  *
305  * Try to allocate a slot in the task's vector of monitors. If there
306  * is an available slot, use it and reset all task's monitor.
307  */
da_monitor_init(void)308 static int da_monitor_init(void)
309 {
310 	int slot;
311 
312 	slot = rv_get_task_monitor_slot();
313 	if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT)
314 		return slot;
315 
316 	task_mon_slot = slot;
317 
318 	da_monitor_reset_all();
319 	return 0;
320 }
321 
322 /*
323  * da_monitor_destroy - return the allocated slot
324  */
da_monitor_destroy(void)325 static inline void da_monitor_destroy(void)
326 {
327 	if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) {
328 		WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME));
329 		return;
330 	}
331 	rv_put_task_monitor_slot(task_mon_slot);
332 	task_mon_slot = RV_PER_TASK_MONITOR_INIT;
333 }
334 #endif /* RV_MON_TYPE */
335 
336 #if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
337 /*
338  * Handle event for implicit monitor: da_get_monitor() will figure out
339  * the monitor.
340  */
341 
__da_handle_event(struct da_monitor * da_mon,enum events event)342 static inline void __da_handle_event(struct da_monitor *da_mon,
343 				     enum events event)
344 {
345 	bool retval;
346 
347 	retval = da_event(da_mon, event);
348 	if (!retval)
349 		da_monitor_reset(da_mon);
350 }
351 
352 /*
353  * da_handle_event - handle an event
354  */
da_handle_event(enum events event)355 static inline void da_handle_event(enum events event)
356 {
357 	struct da_monitor *da_mon = da_get_monitor();
358 	bool retval;
359 
360 	retval = da_monitor_handling_event(da_mon);
361 	if (!retval)
362 		return;
363 
364 	__da_handle_event(da_mon, event);
365 }
366 
367 /*
368  * da_handle_start_event - start monitoring or handle event
369  *
370  * This function is used to notify the monitor that the system is returning
371  * to the initial state, so the monitor can start monitoring in the next event.
372  * Thus:
373  *
374  * If the monitor already started, handle the event.
375  * If the monitor did not start yet, start the monitor but skip the event.
376  */
da_handle_start_event(enum events event)377 static inline bool da_handle_start_event(enum events event)
378 {
379 	struct da_monitor *da_mon;
380 
381 	if (!da_monitor_enabled())
382 		return 0;
383 
384 	da_mon = da_get_monitor();
385 
386 	if (unlikely(!da_monitoring(da_mon))) {
387 		da_monitor_start(da_mon);
388 		return 0;
389 	}
390 
391 	__da_handle_event(da_mon, event);
392 
393 	return 1;
394 }
395 
396 /*
397  * da_handle_start_run_event - start monitoring and handle event
398  *
399  * This function is used to notify the monitor that the system is in the
400  * initial state, so the monitor can start monitoring and handling event.
401  */
da_handle_start_run_event(enum events event)402 static inline bool da_handle_start_run_event(enum events event)
403 {
404 	struct da_monitor *da_mon;
405 
406 	if (!da_monitor_enabled())
407 		return 0;
408 
409 	da_mon = da_get_monitor();
410 
411 	if (unlikely(!da_monitoring(da_mon)))
412 		da_monitor_start(da_mon);
413 
414 	__da_handle_event(da_mon, event);
415 
416 	return 1;
417 }
418 
419 #elif RV_MON_TYPE == RV_MON_PER_TASK
420 /*
421  * Handle event for per task.
422  */
423 
__da_handle_event(struct da_monitor * da_mon,struct task_struct * tsk,enum events event)424 static inline void __da_handle_event(struct da_monitor *da_mon,
425 				     struct task_struct *tsk, enum events event)
426 {
427 	bool retval;
428 
429 	retval = da_event(da_mon, tsk, event);
430 	if (!retval)
431 		da_monitor_reset(da_mon);
432 }
433 
434 /*
435  * da_handle_event - handle an event
436  */
da_handle_event(struct task_struct * tsk,enum events event)437 static inline void da_handle_event(struct task_struct *tsk, enum events event)
438 {
439 	struct da_monitor *da_mon = da_get_monitor(tsk);
440 	bool retval;
441 
442 	retval = da_monitor_handling_event(da_mon);
443 	if (!retval)
444 		return;
445 
446 	__da_handle_event(da_mon, tsk, event);
447 }
448 
449 /*
450  * da_handle_start_event - start monitoring or handle event
451  *
452  * This function is used to notify the monitor that the system is returning
453  * to the initial state, so the monitor can start monitoring in the next event.
454  * Thus:
455  *
456  * If the monitor already started, handle the event.
457  * If the monitor did not start yet, start the monitor but skip the event.
458  */
da_handle_start_event(struct task_struct * tsk,enum events event)459 static inline bool da_handle_start_event(struct task_struct *tsk,
460 					 enum events event)
461 {
462 	struct da_monitor *da_mon;
463 
464 	if (!da_monitor_enabled())
465 		return 0;
466 
467 	da_mon = da_get_monitor(tsk);
468 
469 	if (unlikely(!da_monitoring(da_mon))) {
470 		da_monitor_start(da_mon);
471 		return 0;
472 	}
473 
474 	__da_handle_event(da_mon, tsk, event);
475 
476 	return 1;
477 }
478 
479 /*
480  * da_handle_start_run_event - start monitoring and handle event
481  *
482  * This function is used to notify the monitor that the system is in the
483  * initial state, so the monitor can start monitoring and handling event.
484  */
da_handle_start_run_event(struct task_struct * tsk,enum events event)485 static inline bool da_handle_start_run_event(struct task_struct *tsk,
486 					     enum events event)
487 {
488 	struct da_monitor *da_mon;
489 
490 	if (!da_monitor_enabled())
491 		return 0;
492 
493 	da_mon = da_get_monitor(tsk);
494 
495 	if (unlikely(!da_monitoring(da_mon)))
496 		da_monitor_start(da_mon);
497 
498 	__da_handle_event(da_mon, tsk, event);
499 
500 	return 1;
501 }
502 #endif /* RV_MON_TYPE */
503 
504 #endif
505