summaryrefslogtreecommitdiff
path: root/drivers/s390/net/fsm.h
blob: a4510cf590341494b28aae9c7b2df184057b5a32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#ifndef _FSM_H_
#define _FSM_H_

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/atomic.h>

/**
 * Define this to get debugging messages.
 */
#define FSM_DEBUG         0

/**
 * Define this to get debugging massages for
 * timer handling.
 */
#define FSM_TIMER_DEBUG   0

/**
 * Define these to record a history of
 * Events/Statechanges and print it if a
 * action_function is not found.
 */
#define FSM_DEBUG_HISTORY 0
#define FSM_HISTORY_SIZE  40

struct fsm_instance_t;

/**
 * Definition of an action function, called by a FSM
 */
typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *);

/**
 * Internal jump table for a FSM
 */
typedef struct {
	fsm_function_t *jumpmatrix;
	int nr_events;
	int nr_states;
	const char **event_names;
	const char **state_names;
} fsm;

#if FSM_DEBUG_HISTORY
/**
 * Element of State/Event history used for debugging.
 */
typedef struct {
	int state;
	int event;
} fsm_history;
#endif

/**
 * Representation of a FSM
 */
typedef struct fsm_instance_t {
	fsm *f;
	atomic_t state;
	char name[16];
	void *userdata;
	int userint;
	wait_queue_head_t wait_q;
#if FSM_DEBUG_HISTORY
	int         history_index;
	int         history_size;
	fsm_history history[FSM_HISTORY_SIZE];
#endif
} fsm_instance;

/**
 * Description of a state-event combination
 */
typedef struct {
	int cond_state;
	int cond_event;
	fsm_function_t function;
} fsm_node;

/**
 * Description of a FSM Timer.
 */
typedef struct {
	fsm_instance *fi;
	struct timer_list tl;
	int expire_event;
	void *event_arg;
} fsm_timer;

/**
 * Creates an FSM
 *
 * @param name        Name of this instance for logging purposes.
 * @param state_names An array of names for all states for logging purposes.
 * @param event_names An array of names for all events for logging purposes.
 * @param nr_states   Number of states for this instance.
 * @param nr_events   Number of events for this instance.
 * @param tmpl        An array of fsm_nodes, describing this FSM.
 * @param tmpl_len    Length of the describing array.
 * @param order       Parameter for allocation of the FSM data structs.
 */
extern fsm_instance *
init_fsm(char *name, const char **state_names,
	 const char **event_names,
	 int nr_states, int nr_events, const fsm_node *tmpl,
	 int tmpl_len, gfp_t order);

/**
 * Releases an FSM
 *
 * @param fi Pointer to an FSM, previously created with init_fsm.
 */
extern void kfree_fsm(fsm_instance *fi);

#if FSM_DEBUG_HISTORY
extern void
fsm_print_history(fsm_instance *fi);

extern void
fsm_record_history(fsm_instance *fi, int state, int event);
#endif

/**
 * Emits an event to a FSM.
 * If an action function is defined for the current state/event combination,
 * this function is called.
 *
 * @param fi    Pointer to FSM which should receive the event.
 * @param event The event do be delivered.
 * @param arg   A generic argument, handed to the action function.
 *
 * @return      0  on success,
 *              1  if current state or event is out of range
 *              !0 if state and event in range, but no action defined.
 */
static inline int
fsm_event(fsm_instance *fi, int event, void *arg)
{
	fsm_function_t r;
	int state = atomic_read(&fi->state);

	if ((state >= fi->f->nr_states) ||
	    (event >= fi->f->nr_events)       ) {
		printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n",
			fi->name, (long)state,(long)fi->f->nr_states, event,
			(long)fi->f->nr_events);
#if FSM_DEBUG_HISTORY
		fsm_print_history(fi);
#endif
		return 1;
	}
	r = fi->f->jumpmatrix[fi->f->nr_states * event + state];
	if (r) {
#if FSM_DEBUG
		printk(KERN_DEBUG "fsm(%s): state %s event %s\n",
		       fi->name, fi->f->state_names[state],
		       fi->f->event_names[event]);
#endif
#if FSM_DEBUG_HISTORY
		fsm_record_history(fi, state, event);
#endif
		r(fi, event, arg);
		return 0;
	} else {
#if FSM_DEBUG || FSM_DEBUG_HISTORY
		printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n",
		       fi->name, fi->f->event_names[event],
		       fi->f->state_names[state]);
#endif
#if FSM_DEBUG_HISTORY
		fsm_print_history(fi);
#endif
		return !0;
	}
}

/**
 * Modifies the state of an FSM.
 * This does <em>not</em> trigger an event or calls an action function.
 *
 * @param fi    Pointer to FSM
 * @param state The new state for this FSM.
 */
static inline void
fsm_newstate(fsm_instance *fi, int newstate)
{
	atomic_set(&fi->state,newstate);
#if FSM_DEBUG_HISTORY
	fsm_record_history(fi, newstate, -1);
#endif
#if FSM_DEBUG
	printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name,
		fi->f->state_names[newstate]);
#endif
	wake_up(&fi->wait_q);
}

/**
 * Retrieves the state of an FSM
 *
 * @param fi Pointer to FSM
 *
 * @return The current state of the FSM.
 */
static inline int
fsm_getstate(fsm_instance *fi)
{
	return atomic_read(&fi->state);
}

/**
 * Retrieves the name of the state of an FSM
 *
 * @param fi Pointer to FSM
 *
 * @return The current state of the FSM in a human readable form.
 */
extern const char *fsm_getstate_str(fsm_instance *fi);

/**
 * Initializes a timer for an FSM.
 * This prepares an fsm_timer for usage with fsm_addtimer.
 *
 * @param fi    Pointer to FSM
 * @param timer The timer to be initialized.
 */
extern void fsm_settimer(fsm_instance *fi, fsm_timer *);

/**
 * Clears a pending timer of an FSM instance.
 *
 * @param timer The timer to clear.
 */
extern void fsm_deltimer(fsm_timer *timer);

/**
 * Adds and starts a timer to an FSM instance.
 *
 * @param timer    The timer to be added. The field fi of that timer
 *                 must have been set to point to the instance.
 * @param millisec Duration, after which the timer should expire.
 * @param event    Event, to trigger if timer expires.
 * @param arg      Generic argument, provided to expiry function.
 *
 * @return         0 on success, -1 if timer is already active.
 */
extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg);

/**
 * Modifies a timer of an FSM.
 *
 * @param timer    The timer to modify.
 * @param millisec Duration, after which the timer should expire.
 * @param event    Event, to trigger if timer expires.
 * @param arg      Generic argument, provided to expiry function.
 */
extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg);

#endif /* _FSM_H_ */