xref: /openbmc/linux/drivers/s390/net/fsm.h (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds #ifndef _FSM_H_
31da177e4SLinus Torvalds #define _FSM_H_
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds #include <linux/kernel.h>
61da177e4SLinus Torvalds #include <linux/types.h>
71da177e4SLinus Torvalds #include <linux/timer.h>
81da177e4SLinus Torvalds #include <linux/time.h>
91da177e4SLinus Torvalds #include <linux/slab.h>
101da177e4SLinus Torvalds #include <linux/sched.h>
111da177e4SLinus Torvalds #include <linux/string.h>
1260063497SArun Sharma #include <linux/atomic.h>
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds /**
151da177e4SLinus Torvalds  * Define this to get debugging messages.
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds #define FSM_DEBUG         0
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds /**
201da177e4SLinus Torvalds  * Define this to get debugging massages for
211da177e4SLinus Torvalds  * timer handling.
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds #define FSM_TIMER_DEBUG   0
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds /**
261da177e4SLinus Torvalds  * Define these to record a history of
271da177e4SLinus Torvalds  * Events/Statechanges and print it if a
281da177e4SLinus Torvalds  * action_function is not found.
291da177e4SLinus Torvalds  */
301da177e4SLinus Torvalds #define FSM_DEBUG_HISTORY 0
311da177e4SLinus Torvalds #define FSM_HISTORY_SIZE  40
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds struct fsm_instance_t;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds /**
361da177e4SLinus Torvalds  * Definition of an action function, called by a FSM
371da177e4SLinus Torvalds  */
381da177e4SLinus Torvalds typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *);
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds /**
411da177e4SLinus Torvalds  * Internal jump table for a FSM
421da177e4SLinus Torvalds  */
431da177e4SLinus Torvalds typedef struct {
441da177e4SLinus Torvalds 	fsm_function_t *jumpmatrix;
451da177e4SLinus Torvalds 	int nr_events;
461da177e4SLinus Torvalds 	int nr_states;
471da177e4SLinus Torvalds 	const char **event_names;
481da177e4SLinus Torvalds 	const char **state_names;
491da177e4SLinus Torvalds } fsm;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
521da177e4SLinus Torvalds /**
531da177e4SLinus Torvalds  * Element of State/Event history used for debugging.
541da177e4SLinus Torvalds  */
551da177e4SLinus Torvalds typedef struct {
561da177e4SLinus Torvalds 	int state;
571da177e4SLinus Torvalds 	int event;
581da177e4SLinus Torvalds } fsm_history;
591da177e4SLinus Torvalds #endif
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /**
621da177e4SLinus Torvalds  * Representation of a FSM
631da177e4SLinus Torvalds  */
641da177e4SLinus Torvalds typedef struct fsm_instance_t {
651da177e4SLinus Torvalds 	fsm *f;
661da177e4SLinus Torvalds 	atomic_t state;
671da177e4SLinus Torvalds 	char name[16];
681da177e4SLinus Torvalds 	void *userdata;
691da177e4SLinus Torvalds 	int userint;
701e1815beSFrank Blaschka 	wait_queue_head_t wait_q;
711da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
721da177e4SLinus Torvalds 	int         history_index;
731da177e4SLinus Torvalds 	int         history_size;
741da177e4SLinus Torvalds 	fsm_history history[FSM_HISTORY_SIZE];
751da177e4SLinus Torvalds #endif
761da177e4SLinus Torvalds } fsm_instance;
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /**
791da177e4SLinus Torvalds  * Description of a state-event combination
801da177e4SLinus Torvalds  */
811da177e4SLinus Torvalds typedef struct {
821da177e4SLinus Torvalds 	int cond_state;
831da177e4SLinus Torvalds 	int cond_event;
841da177e4SLinus Torvalds 	fsm_function_t function;
851da177e4SLinus Torvalds } fsm_node;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds /**
881da177e4SLinus Torvalds  * Description of a FSM Timer.
891da177e4SLinus Torvalds  */
901da177e4SLinus Torvalds typedef struct {
911da177e4SLinus Torvalds 	fsm_instance *fi;
921da177e4SLinus Torvalds 	struct timer_list tl;
931da177e4SLinus Torvalds 	int expire_event;
941da177e4SLinus Torvalds 	void *event_arg;
951da177e4SLinus Torvalds } fsm_timer;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds /**
981da177e4SLinus Torvalds  * Creates an FSM
991da177e4SLinus Torvalds  *
1001da177e4SLinus Torvalds  * @param name        Name of this instance for logging purposes.
1011da177e4SLinus Torvalds  * @param state_names An array of names for all states for logging purposes.
1021da177e4SLinus Torvalds  * @param event_names An array of names for all events for logging purposes.
1031da177e4SLinus Torvalds  * @param nr_states   Number of states for this instance.
1041da177e4SLinus Torvalds  * @param nr_events   Number of events for this instance.
1051da177e4SLinus Torvalds  * @param tmpl        An array of fsm_nodes, describing this FSM.
1061da177e4SLinus Torvalds  * @param tmpl_len    Length of the describing array.
1071da177e4SLinus Torvalds  * @param order       Parameter for allocation of the FSM data structs.
1081da177e4SLinus Torvalds  */
1091da177e4SLinus Torvalds extern fsm_instance *
1101da177e4SLinus Torvalds init_fsm(char *name, const char **state_names,
1111da177e4SLinus Torvalds 	 const char **event_names,
1121da177e4SLinus Torvalds 	 int nr_states, int nr_events, const fsm_node *tmpl,
113b4e3ca1aSAl Viro 	 int tmpl_len, gfp_t order);
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds /**
1161da177e4SLinus Torvalds  * Releases an FSM
1171da177e4SLinus Torvalds  *
1181da177e4SLinus Torvalds  * @param fi Pointer to an FSM, previously created with init_fsm.
1191da177e4SLinus Torvalds  */
1201da177e4SLinus Torvalds extern void kfree_fsm(fsm_instance *fi);
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
1231da177e4SLinus Torvalds extern void
1241da177e4SLinus Torvalds fsm_print_history(fsm_instance *fi);
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds extern void
1271da177e4SLinus Torvalds fsm_record_history(fsm_instance *fi, int state, int event);
1281da177e4SLinus Torvalds #endif
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds /**
1311da177e4SLinus Torvalds  * Emits an event to a FSM.
1321da177e4SLinus Torvalds  * If an action function is defined for the current state/event combination,
1331da177e4SLinus Torvalds  * this function is called.
1341da177e4SLinus Torvalds  *
1351da177e4SLinus Torvalds  * @param fi    Pointer to FSM which should receive the event.
1361da177e4SLinus Torvalds  * @param event The event do be delivered.
1371da177e4SLinus Torvalds  * @param arg   A generic argument, handed to the action function.
1381da177e4SLinus Torvalds  *
1391da177e4SLinus Torvalds  * @return      0  on success,
1401da177e4SLinus Torvalds  *              1  if current state or event is out of range
1411da177e4SLinus Torvalds  *              !0 if state and event in range, but no action defined.
1421da177e4SLinus Torvalds  */
1434448aaf0SAdrian Bunk static inline int
fsm_event(fsm_instance * fi,int event,void * arg)1441da177e4SLinus Torvalds fsm_event(fsm_instance *fi, int event, void *arg)
1451da177e4SLinus Torvalds {
1461da177e4SLinus Torvalds 	fsm_function_t r;
1471da177e4SLinus Torvalds 	int state = atomic_read(&fi->state);
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 	if ((state >= fi->f->nr_states) ||
1501da177e4SLinus Torvalds 	    (event >= fi->f->nr_events)       ) {
1511da177e4SLinus Torvalds 		printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n",
1521da177e4SLinus Torvalds 			fi->name, (long)state,(long)fi->f->nr_states, event,
1531da177e4SLinus Torvalds 			(long)fi->f->nr_events);
1541da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
1551da177e4SLinus Torvalds 		fsm_print_history(fi);
1561da177e4SLinus Torvalds #endif
1571da177e4SLinus Torvalds 		return 1;
1581da177e4SLinus Torvalds 	}
1591da177e4SLinus Torvalds 	r = fi->f->jumpmatrix[fi->f->nr_states * event + state];
1601da177e4SLinus Torvalds 	if (r) {
1611da177e4SLinus Torvalds #if FSM_DEBUG
1621da177e4SLinus Torvalds 		printk(KERN_DEBUG "fsm(%s): state %s event %s\n",
1631da177e4SLinus Torvalds 		       fi->name, fi->f->state_names[state],
1641da177e4SLinus Torvalds 		       fi->f->event_names[event]);
1651da177e4SLinus Torvalds #endif
1661da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
1671da177e4SLinus Torvalds 		fsm_record_history(fi, state, event);
1681da177e4SLinus Torvalds #endif
1691da177e4SLinus Torvalds 		r(fi, event, arg);
1701da177e4SLinus Torvalds 		return 0;
1711da177e4SLinus Torvalds 	} else {
1721da177e4SLinus Torvalds #if FSM_DEBUG || FSM_DEBUG_HISTORY
1731da177e4SLinus Torvalds 		printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n",
1741da177e4SLinus Torvalds 		       fi->name, fi->f->event_names[event],
1751da177e4SLinus Torvalds 		       fi->f->state_names[state]);
1761da177e4SLinus Torvalds #endif
1771da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
1781da177e4SLinus Torvalds 		fsm_print_history(fi);
1791da177e4SLinus Torvalds #endif
1801da177e4SLinus Torvalds 		return !0;
1811da177e4SLinus Torvalds 	}
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds /**
1851da177e4SLinus Torvalds  * Modifies the state of an FSM.
1861da177e4SLinus Torvalds  * This does <em>not</em> trigger an event or calls an action function.
1871da177e4SLinus Torvalds  *
1881da177e4SLinus Torvalds  * @param fi    Pointer to FSM
1891da177e4SLinus Torvalds  * @param state The new state for this FSM.
1901da177e4SLinus Torvalds  */
1914448aaf0SAdrian Bunk static inline void
fsm_newstate(fsm_instance * fi,int newstate)1921da177e4SLinus Torvalds fsm_newstate(fsm_instance *fi, int newstate)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds 	atomic_set(&fi->state,newstate);
1951da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
1961da177e4SLinus Torvalds 	fsm_record_history(fi, newstate, -1);
1971da177e4SLinus Torvalds #endif
1981da177e4SLinus Torvalds #if FSM_DEBUG
1991da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name,
2001da177e4SLinus Torvalds 		fi->f->state_names[newstate]);
2011da177e4SLinus Torvalds #endif
2021e1815beSFrank Blaschka 	wake_up(&fi->wait_q);
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds /**
2061da177e4SLinus Torvalds  * Retrieves the state of an FSM
2071da177e4SLinus Torvalds  *
2081da177e4SLinus Torvalds  * @param fi Pointer to FSM
2091da177e4SLinus Torvalds  *
2101da177e4SLinus Torvalds  * @return The current state of the FSM.
2111da177e4SLinus Torvalds  */
2124448aaf0SAdrian Bunk static inline int
fsm_getstate(fsm_instance * fi)2131da177e4SLinus Torvalds fsm_getstate(fsm_instance *fi)
2141da177e4SLinus Torvalds {
2151da177e4SLinus Torvalds 	return atomic_read(&fi->state);
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds /**
2191da177e4SLinus Torvalds  * Retrieves the name of the state of an FSM
2201da177e4SLinus Torvalds  *
2211da177e4SLinus Torvalds  * @param fi Pointer to FSM
2221da177e4SLinus Torvalds  *
2231da177e4SLinus Torvalds  * @return The current state of the FSM in a human readable form.
2241da177e4SLinus Torvalds  */
2251da177e4SLinus Torvalds extern const char *fsm_getstate_str(fsm_instance *fi);
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds /**
2281da177e4SLinus Torvalds  * Initializes a timer for an FSM.
2291da177e4SLinus Torvalds  * This prepares an fsm_timer for usage with fsm_addtimer.
2301da177e4SLinus Torvalds  *
2311da177e4SLinus Torvalds  * @param fi    Pointer to FSM
2321da177e4SLinus Torvalds  * @param timer The timer to be initialized.
2331da177e4SLinus Torvalds  */
2341da177e4SLinus Torvalds extern void fsm_settimer(fsm_instance *fi, fsm_timer *);
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds /**
2371da177e4SLinus Torvalds  * Clears a pending timer of an FSM instance.
2381da177e4SLinus Torvalds  *
2391da177e4SLinus Torvalds  * @param timer The timer to clear.
2401da177e4SLinus Torvalds  */
2411da177e4SLinus Torvalds extern void fsm_deltimer(fsm_timer *timer);
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds /**
2441da177e4SLinus Torvalds  * Adds and starts a timer to an FSM instance.
2451da177e4SLinus Torvalds  *
2461da177e4SLinus Torvalds  * @param timer    The timer to be added. The field fi of that timer
2471da177e4SLinus Torvalds  *                 must have been set to point to the instance.
2481da177e4SLinus Torvalds  * @param millisec Duration, after which the timer should expire.
2491da177e4SLinus Torvalds  * @param event    Event, to trigger if timer expires.
2501da177e4SLinus Torvalds  * @param arg      Generic argument, provided to expiry function.
2511da177e4SLinus Torvalds  *
2521da177e4SLinus Torvalds  * @return         0 on success, -1 if timer is already active.
2531da177e4SLinus Torvalds  */
2541da177e4SLinus Torvalds extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg);
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds /**
2571da177e4SLinus Torvalds  * Modifies a timer of an FSM.
2581da177e4SLinus Torvalds  *
2591da177e4SLinus Torvalds  * @param timer    The timer to modify.
2601da177e4SLinus Torvalds  * @param millisec Duration, after which the timer should expire.
2611da177e4SLinus Torvalds  * @param event    Event, to trigger if timer expires.
2621da177e4SLinus Torvalds  * @param arg      Generic argument, provided to expiry function.
2631da177e4SLinus Torvalds  */
2641da177e4SLinus Torvalds extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg);
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds #endif /* _FSM_H_ */
267