xref: /openbmc/linux/drivers/s390/net/fsm.c (revision 1e1815be87e45ce512f998ab35e9554c25031f4d)
11da177e4SLinus Torvalds /**
21da177e4SLinus Torvalds  * A generic FSM based on fsm used in isdn4linux
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include "fsm.h"
71da177e4SLinus Torvalds #include <linux/module.h>
81da177e4SLinus Torvalds #include <linux/timer.h>
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
111da177e4SLinus Torvalds MODULE_DESCRIPTION("Finite state machine helper functions");
121da177e4SLinus Torvalds MODULE_LICENSE("GPL");
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds fsm_instance *
151da177e4SLinus Torvalds init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
16b4e3ca1aSAl Viro 		int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)
171da177e4SLinus Torvalds {
181da177e4SLinus Torvalds 	int i;
191da177e4SLinus Torvalds 	fsm_instance *this;
201da177e4SLinus Torvalds 	fsm_function_t *m;
211da177e4SLinus Torvalds 	fsm *f;
221da177e4SLinus Torvalds 
2388abaab4SEric Sesterhenn 	this = kzalloc(sizeof(fsm_instance), order);
241da177e4SLinus Torvalds 	if (this == NULL) {
251da177e4SLinus Torvalds 		printk(KERN_WARNING
261da177e4SLinus Torvalds 			"fsm(%s): init_fsm: Couldn't alloc instance\n", name);
271da177e4SLinus Torvalds 		return NULL;
281da177e4SLinus Torvalds 	}
291da177e4SLinus Torvalds 	strlcpy(this->name, name, sizeof(this->name));
30*1e1815beSFrank Blaschka 	init_waitqueue_head(&this->wait_q);
311da177e4SLinus Torvalds 
3288abaab4SEric Sesterhenn 	f = kzalloc(sizeof(fsm), order);
331da177e4SLinus Torvalds 	if (f == NULL) {
341da177e4SLinus Torvalds 		printk(KERN_WARNING
351da177e4SLinus Torvalds 			"fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
361da177e4SLinus Torvalds 		kfree_fsm(this);
371da177e4SLinus Torvalds 		return NULL;
381da177e4SLinus Torvalds 	}
391da177e4SLinus Torvalds 	f->nr_events = nr_events;
401da177e4SLinus Torvalds 	f->nr_states = nr_states;
411da177e4SLinus Torvalds 	f->event_names = event_names;
421da177e4SLinus Torvalds 	f->state_names = state_names;
431da177e4SLinus Torvalds 	this->f = f;
441da177e4SLinus Torvalds 
4588abaab4SEric Sesterhenn 	m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);
461da177e4SLinus Torvalds 	if (m == NULL) {
471da177e4SLinus Torvalds 		printk(KERN_WARNING
481da177e4SLinus Torvalds 			"fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
491da177e4SLinus Torvalds 		kfree_fsm(this);
501da177e4SLinus Torvalds 		return NULL;
511da177e4SLinus Torvalds 	}
521da177e4SLinus Torvalds 	f->jumpmatrix = m;
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	for (i = 0; i < tmpl_len; i++) {
551da177e4SLinus Torvalds 		if ((tmpl[i].cond_state >= nr_states) ||
561da177e4SLinus Torvalds 		    (tmpl[i].cond_event >= nr_events)   ) {
571da177e4SLinus Torvalds 			printk(KERN_ERR
581da177e4SLinus Torvalds 				"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
591da177e4SLinus Torvalds 				name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
601da177e4SLinus Torvalds 				(long)tmpl[i].cond_event, (long)f->nr_events);
611da177e4SLinus Torvalds 			kfree_fsm(this);
621da177e4SLinus Torvalds 			return NULL;
631da177e4SLinus Torvalds 		} else
641da177e4SLinus Torvalds 			m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
651da177e4SLinus Torvalds 				tmpl[i].function;
661da177e4SLinus Torvalds 	}
671da177e4SLinus Torvalds 	return this;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds void
711da177e4SLinus Torvalds kfree_fsm(fsm_instance *this)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	if (this) {
741da177e4SLinus Torvalds 		if (this->f) {
751da177e4SLinus Torvalds 			kfree(this->f->jumpmatrix);
761da177e4SLinus Torvalds 			kfree(this->f);
771da177e4SLinus Torvalds 		}
781da177e4SLinus Torvalds 		kfree(this);
791da177e4SLinus Torvalds 	} else
801da177e4SLinus Torvalds 		printk(KERN_WARNING
811da177e4SLinus Torvalds 			"fsm: kfree_fsm called with NULL argument\n");
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
851da177e4SLinus Torvalds void
861da177e4SLinus Torvalds fsm_print_history(fsm_instance *fi)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds 	int idx = 0;
891da177e4SLinus Torvalds 	int i;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	if (fi->history_size >= FSM_HISTORY_SIZE)
921da177e4SLinus Torvalds 		idx = fi->history_index;
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
951da177e4SLinus Torvalds 	for (i = 0; i < fi->history_size; i++) {
961da177e4SLinus Torvalds 		int e = fi->history[idx].event;
971da177e4SLinus Torvalds 		int s = fi->history[idx++].state;
981da177e4SLinus Torvalds 		idx %= FSM_HISTORY_SIZE;
991da177e4SLinus Torvalds 		if (e == -1)
1001da177e4SLinus Torvalds 			printk(KERN_DEBUG "  S=%s\n",
1011da177e4SLinus Torvalds 			       fi->f->state_names[s]);
1021da177e4SLinus Torvalds 		else
1031da177e4SLinus Torvalds 			printk(KERN_DEBUG "  S=%s E=%s\n",
1041da177e4SLinus Torvalds 			       fi->f->state_names[s],
1051da177e4SLinus Torvalds 			       fi->f->event_names[e]);
1061da177e4SLinus Torvalds 	}
1071da177e4SLinus Torvalds 	fi->history_size = fi->history_index = 0;
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds void
1111da177e4SLinus Torvalds fsm_record_history(fsm_instance *fi, int state, int event)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds 	fi->history[fi->history_index].state = state;
1141da177e4SLinus Torvalds 	fi->history[fi->history_index++].event = event;
1151da177e4SLinus Torvalds 	fi->history_index %= FSM_HISTORY_SIZE;
1161da177e4SLinus Torvalds 	if (fi->history_size < FSM_HISTORY_SIZE)
1171da177e4SLinus Torvalds 		fi->history_size++;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds #endif
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds const char *
1221da177e4SLinus Torvalds fsm_getstate_str(fsm_instance *fi)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	int st = atomic_read(&fi->state);
1251da177e4SLinus Torvalds 	if (st >= fi->f->nr_states)
1261da177e4SLinus Torvalds 		return "Invalid";
1271da177e4SLinus Torvalds 	return fi->f->state_names[st];
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds static void
1311da177e4SLinus Torvalds fsm_expire_timer(fsm_timer *this)
1321da177e4SLinus Torvalds {
1331da177e4SLinus Torvalds #if FSM_TIMER_DEBUG
1341da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
1351da177e4SLinus Torvalds 	       this->fi->name, this);
1361da177e4SLinus Torvalds #endif
1371da177e4SLinus Torvalds 	fsm_event(this->fi, this->expire_event, this->event_arg);
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds void
1411da177e4SLinus Torvalds fsm_settimer(fsm_instance *fi, fsm_timer *this)
1421da177e4SLinus Torvalds {
1431da177e4SLinus Torvalds 	this->fi = fi;
1441da177e4SLinus Torvalds 	this->tl.function = (void *)fsm_expire_timer;
1451da177e4SLinus Torvalds 	this->tl.data = (long)this;
1461da177e4SLinus Torvalds #if FSM_TIMER_DEBUG
1471da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
1481da177e4SLinus Torvalds 	       this);
1491da177e4SLinus Torvalds #endif
1501da177e4SLinus Torvalds 	init_timer(&this->tl);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds void
1541da177e4SLinus Torvalds fsm_deltimer(fsm_timer *this)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds #if FSM_TIMER_DEBUG
1571da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
1581da177e4SLinus Torvalds 		this);
1591da177e4SLinus Torvalds #endif
1601da177e4SLinus Torvalds 	del_timer(&this->tl);
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds int
1641da177e4SLinus Torvalds fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
1651da177e4SLinus Torvalds {
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #if FSM_TIMER_DEBUG
1681da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
1691da177e4SLinus Torvalds 	       this->fi->name, this, millisec);
1701da177e4SLinus Torvalds #endif
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	init_timer(&this->tl);
1731da177e4SLinus Torvalds 	this->tl.function = (void *)fsm_expire_timer;
1741da177e4SLinus Torvalds 	this->tl.data = (long)this;
1751da177e4SLinus Torvalds 	this->expire_event = event;
1761da177e4SLinus Torvalds 	this->event_arg = arg;
1771da177e4SLinus Torvalds 	this->tl.expires = jiffies + (millisec * HZ) / 1000;
1781da177e4SLinus Torvalds 	add_timer(&this->tl);
1791da177e4SLinus Torvalds 	return 0;
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds /* FIXME: this function is never used, why */
1831da177e4SLinus Torvalds void
1841da177e4SLinus Torvalds fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds #if FSM_TIMER_DEBUG
1881da177e4SLinus Torvalds 	printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
1891da177e4SLinus Torvalds 		this->fi->name, this, millisec);
1901da177e4SLinus Torvalds #endif
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	del_timer(&this->tl);
1931da177e4SLinus Torvalds 	init_timer(&this->tl);
1941da177e4SLinus Torvalds 	this->tl.function = (void *)fsm_expire_timer;
1951da177e4SLinus Torvalds 	this->tl.data = (long)this;
1961da177e4SLinus Torvalds 	this->expire_event = event;
1971da177e4SLinus Torvalds 	this->event_arg = arg;
1981da177e4SLinus Torvalds 	this->tl.expires = jiffies + (millisec * HZ) / 1000;
1991da177e4SLinus Torvalds 	add_timer(&this->tl);
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds EXPORT_SYMBOL(init_fsm);
2031da177e4SLinus Torvalds EXPORT_SYMBOL(kfree_fsm);
2041da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_settimer);
2051da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_deltimer);
2061da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_addtimer);
2071da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_modtimer);
2081da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_getstate_str);
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY
2111da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_print_history);
2121da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_record_history);
2131da177e4SLinus Torvalds #endif
214