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