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