xref: /linux/drivers/s390/net/fsm.h (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _FSM_H_
3 #define _FSM_H_
4 
5 #include <linux/kernel.h>
6 #include <linux/types.h>
7 #include <linux/timer.h>
8 #include <linux/time.h>
9 #include <linux/slab.h>
10 #include <linux/sched.h>
11 #include <linux/string.h>
12 #include <linux/atomic.h>
13 
14 /*
15  * Define this to get debugging messages.
16  */
17 #define FSM_DEBUG         0
18 
19 /*
20  * Define this to get debugging massages for
21  * timer handling.
22  */
23 #define FSM_TIMER_DEBUG   0
24 
25 /*
26  * Define these to record a history of
27  * Events/Statechanges and print it if a
28  * action_function is not found.
29  */
30 #define FSM_DEBUG_HISTORY 0
31 #define FSM_HISTORY_SIZE  40
32 
33 struct fsm_instance_t;
34 
35 /*
36  * Definition of an action function, called by a FSM
37  */
38 typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *);
39 
40 /*
41  * Internal jump table for a FSM
42  */
43 typedef struct {
44 	fsm_function_t *jumpmatrix;
45 	int nr_events;
46 	int nr_states;
47 	const char **event_names;
48 	const char **state_names;
49 } fsm;
50 
51 #if FSM_DEBUG_HISTORY
52 /*
53  * Element of State/Event history used for debugging.
54  */
55 typedef struct {
56 	int state;
57 	int event;
58 } fsm_history;
59 #endif
60 
61 /*
62  * Representation of a FSM
63  */
64 typedef struct fsm_instance_t {
65 	fsm *f;
66 	atomic_t state;
67 	char name[16];
68 	void *userdata;
69 	int userint;
70 	wait_queue_head_t wait_q;
71 #if FSM_DEBUG_HISTORY
72 	int         history_index;
73 	int         history_size;
74 	fsm_history history[FSM_HISTORY_SIZE];
75 #endif
76 } fsm_instance;
77 
78 /*
79  * Description of a state-event combination
80  */
81 typedef struct {
82 	int cond_state;
83 	int cond_event;
84 	fsm_function_t function;
85 } fsm_node;
86 
87 /*
88  * Description of a FSM Timer.
89  */
90 typedef struct {
91 	fsm_instance *fi;
92 	struct timer_list tl;
93 	int expire_event;
94 	void *event_arg;
95 } fsm_timer;
96 
97 /**
98  * init_fsm - Creates a finite state machine
99  * @name: Name of this instance for logging purposes
100  * @state_names: Array of names for all states for logging purposes
101  * @event_names: Array of names for all events for logging purposes
102  * @nr_states: Number of states for this instance
103  * @nr_events: Number of events for this instance
104  * @tmpl: Pointer to fsm_node array describing this FSM
105  * @tmpl_len: Number of entries in the tmpl array
106  * @order: GFP flags for memory allocation (e.g. GFP_KERNEL)
107  *
108  * Allocates and initializes a finite state machine instance with the
109  * specified states, events, and transition table.
110  *
111  * Return: Pointer to initialized FSM instance, or NULL on failure
112  */
113 fsm_instance *init_fsm(char *name, const char **state_names,
114 		       const char **event_names, int nr_states,
115 		       int nr_events, const fsm_node *tmpl,
116 		       int tmpl_len, gfp_t order);
117 
118 /**
119  * kfree_fsm - Releases a finite state machine
120  * @fi: Pointer to FSM instance, previously created with init_fsm()
121  *
122  * Frees all memory associated with the FSM instance.
123  */
124 void kfree_fsm(fsm_instance *fi);
125 
126 #if FSM_DEBUG_HISTORY
127 void fsm_print_history(fsm_instance *fi);
128 
129 void fsm_record_history(fsm_instance *fi, int state, int event);
130 #endif
131 
132 /**
133  * fsm_event - Emits an event to a finite state machine
134  * @fi: Pointer to FSM which should receive the event
135  * @event: The event to be delivered
136  * @arg: Generic argument, passed to the action function
137  *
138  * If an action function is defined for the current state/event
139  * combination, that function is called with the provided arguments.
140  *
141  * Return:
142  * * 0 - Success, action function was called
143  * * 1 - State/event out of range, or no action function defined
144  */
145 static inline int
fsm_event(fsm_instance * fi,int event,void * arg)146 fsm_event(fsm_instance *fi, int event, void *arg)
147 {
148 	fsm_function_t r;
149 	int state = atomic_read(&fi->state);
150 
151 	if ((state >= fi->f->nr_states) ||
152 	    (event >= fi->f->nr_events)       ) {
153 		printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n",
154 			fi->name, (long)state,(long)fi->f->nr_states, event,
155 			(long)fi->f->nr_events);
156 #if FSM_DEBUG_HISTORY
157 		fsm_print_history(fi);
158 #endif
159 		return 1;
160 	}
161 	r = fi->f->jumpmatrix[fi->f->nr_states * event + state];
162 	if (r) {
163 #if FSM_DEBUG
164 		printk(KERN_DEBUG "fsm(%s): state %s event %s\n",
165 		       fi->name, fi->f->state_names[state],
166 		       fi->f->event_names[event]);
167 #endif
168 #if FSM_DEBUG_HISTORY
169 		fsm_record_history(fi, state, event);
170 #endif
171 		r(fi, event, arg);
172 		return 0;
173 	} else {
174 #if FSM_DEBUG || FSM_DEBUG_HISTORY
175 		printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n",
176 		       fi->name, fi->f->event_names[event],
177 		       fi->f->state_names[state]);
178 #endif
179 #if FSM_DEBUG_HISTORY
180 		fsm_print_history(fi);
181 #endif
182 		return !0;
183 	}
184 }
185 
186 /**
187  * fsm_newstate - Modifies the state of a finite state machine
188  * @fi: Pointer to FSM
189  * @newstate: The new state for this FSM
190  *
191  * This does not trigger an event or call an action function.
192  * Wakes up any processes waiting on the FSM's wait queue.
193  */
194 static inline void
fsm_newstate(fsm_instance * fi,int newstate)195 fsm_newstate(fsm_instance *fi, int newstate)
196 {
197 	atomic_set(&fi->state,newstate);
198 #if FSM_DEBUG_HISTORY
199 	fsm_record_history(fi, newstate, -1);
200 #endif
201 #if FSM_DEBUG
202 	printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name,
203 		fi->f->state_names[newstate]);
204 #endif
205 	wake_up(&fi->wait_q);
206 }
207 
208 /**
209  * fsm_getstate - Retrieves the current state of a finite state machine
210  * @fi: Pointer to FSM
211  *
212  * Return: Current state number
213  */
214 static inline int
fsm_getstate(fsm_instance * fi)215 fsm_getstate(fsm_instance *fi)
216 {
217 	return atomic_read(&fi->state);
218 }
219 
220 /**
221  * fsm_getstate_str - Retrieves the name of the current FSM state
222  * @fi: Pointer to FSM
223  *
224  * Return: State name string, or "Invalid" if state is out of range
225  */
226 const char *fsm_getstate_str(fsm_instance *fi);
227 
228 /**
229  * fsm_settimer - Initializes a timer for a finite state machine
230  * @fi: Pointer to FSM
231  * @this: The timer to be initialized
232  *
233  * Prepares an fsm_timer for usage with fsm_addtimer().
234  */
235 void fsm_settimer(fsm_instance *fi, fsm_timer *this);
236 
237 /**
238  * fsm_deltimer - Clears a pending timer of an FSM instance
239  * @timer: The timer to clear
240  *
241  * Stops and removes the timer. Safe to call on an inactive timer.
242  */
243 void fsm_deltimer(fsm_timer *timer);
244 
245 /**
246  * fsm_addtimer - Adds and starts a timer for an FSM instance
247  * @timer: The timer to be added (timer->fi must point to the FSM instance)
248  * @millisec: Duration in milliseconds after which the timer expires
249  * @event: Event to trigger when timer expires
250  * @arg: Generic argument provided to the event handler
251  *
252  * Starts a timer that will trigger the specified event after the given
253  * duration. The timer must have been initialized with fsm_settimer().
254  *
255  * Return: Always returns 0
256  */
257 int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg);
258 
259 /**
260  * fsm_modtimer - Modifies a timer of a finite state machine
261  * @timer: The timer to modify
262  * @millisec: New duration in milliseconds after which the timer expires
263  * @event: Event to trigger when timer expires
264  * @arg: Generic argument provided to the event handler
265  *
266  * Stops the existing timer and restarts it with new parameters.
267  */
268 void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg);
269 
270 #endif /* _FSM_H_ */
271