xref: /openbmc/linux/drivers/s390/net/fsm.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * A generic FSM based on fsm used in isdn4linux
4   *
5   */
6  
7  #include "fsm.h"
8  #include <linux/module.h>
9  #include <linux/slab.h>
10  #include <linux/timer.h>
11  
12  MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
13  MODULE_DESCRIPTION("Finite state machine helper functions");
14  MODULE_LICENSE("GPL");
15  
16  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)17  init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
18  		int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)
19  {
20  	int i;
21  	fsm_instance *this;
22  	fsm_function_t *m;
23  	fsm *f;
24  
25  	this = kzalloc(sizeof(fsm_instance), order);
26  	if (this == NULL) {
27  		printk(KERN_WARNING
28  			"fsm(%s): init_fsm: Couldn't alloc instance\n", name);
29  		return NULL;
30  	}
31  	strscpy(this->name, name, sizeof(this->name));
32  	init_waitqueue_head(&this->wait_q);
33  
34  	f = kzalloc(sizeof(fsm), order);
35  	if (f == NULL) {
36  		printk(KERN_WARNING
37  			"fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
38  		kfree_fsm(this);
39  		return NULL;
40  	}
41  	f->nr_events = nr_events;
42  	f->nr_states = nr_states;
43  	f->event_names = event_names;
44  	f->state_names = state_names;
45  	this->f = f;
46  
47  	m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);
48  	if (m == NULL) {
49  		printk(KERN_WARNING
50  			"fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
51  		kfree_fsm(this);
52  		return NULL;
53  	}
54  	f->jumpmatrix = m;
55  
56  	for (i = 0; i < tmpl_len; i++) {
57  		if ((tmpl[i].cond_state >= nr_states) ||
58  		    (tmpl[i].cond_event >= nr_events)   ) {
59  			printk(KERN_ERR
60  				"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
61  				name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
62  				(long)tmpl[i].cond_event, (long)f->nr_events);
63  			kfree_fsm(this);
64  			return NULL;
65  		} else
66  			m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
67  				tmpl[i].function;
68  	}
69  	return this;
70  }
71  
72  void
kfree_fsm(fsm_instance * this)73  kfree_fsm(fsm_instance *this)
74  {
75  	if (this) {
76  		if (this->f) {
77  			kfree(this->f->jumpmatrix);
78  			kfree(this->f);
79  		}
80  		kfree(this);
81  	} else
82  		printk(KERN_WARNING
83  			"fsm: kfree_fsm called with NULL argument\n");
84  }
85  
86  #if FSM_DEBUG_HISTORY
87  void
fsm_print_history(fsm_instance * fi)88  fsm_print_history(fsm_instance *fi)
89  {
90  	int idx = 0;
91  	int i;
92  
93  	if (fi->history_size >= FSM_HISTORY_SIZE)
94  		idx = fi->history_index;
95  
96  	printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
97  	for (i = 0; i < fi->history_size; i++) {
98  		int e = fi->history[idx].event;
99  		int s = fi->history[idx++].state;
100  		idx %= FSM_HISTORY_SIZE;
101  		if (e == -1)
102  			printk(KERN_DEBUG "  S=%s\n",
103  			       fi->f->state_names[s]);
104  		else
105  			printk(KERN_DEBUG "  S=%s E=%s\n",
106  			       fi->f->state_names[s],
107  			       fi->f->event_names[e]);
108  	}
109  	fi->history_size = fi->history_index = 0;
110  }
111  
112  void
fsm_record_history(fsm_instance * fi,int state,int event)113  fsm_record_history(fsm_instance *fi, int state, int event)
114  {
115  	fi->history[fi->history_index].state = state;
116  	fi->history[fi->history_index++].event = event;
117  	fi->history_index %= FSM_HISTORY_SIZE;
118  	if (fi->history_size < FSM_HISTORY_SIZE)
119  		fi->history_size++;
120  }
121  #endif
122  
123  const char *
fsm_getstate_str(fsm_instance * fi)124  fsm_getstate_str(fsm_instance *fi)
125  {
126  	int st = atomic_read(&fi->state);
127  	if (st >= fi->f->nr_states)
128  		return "Invalid";
129  	return fi->f->state_names[st];
130  }
131  
132  static void
fsm_expire_timer(struct timer_list * t)133  fsm_expire_timer(struct timer_list *t)
134  {
135  	fsm_timer *this = from_timer(this, t, tl);
136  #if FSM_TIMER_DEBUG
137  	printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
138  	       this->fi->name, this);
139  #endif
140  	fsm_event(this->fi, this->expire_event, this->event_arg);
141  }
142  
143  void
fsm_settimer(fsm_instance * fi,fsm_timer * this)144  fsm_settimer(fsm_instance *fi, fsm_timer *this)
145  {
146  	this->fi = fi;
147  #if FSM_TIMER_DEBUG
148  	printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
149  	       this);
150  #endif
151  	timer_setup(&this->tl, fsm_expire_timer, 0);
152  }
153  
154  void
fsm_deltimer(fsm_timer * this)155  fsm_deltimer(fsm_timer *this)
156  {
157  #if FSM_TIMER_DEBUG
158  	printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
159  		this);
160  #endif
161  	del_timer(&this->tl);
162  }
163  
164  int
fsm_addtimer(fsm_timer * this,int millisec,int event,void * arg)165  fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
166  {
167  
168  #if FSM_TIMER_DEBUG
169  	printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
170  	       this->fi->name, this, millisec);
171  #endif
172  
173  	timer_setup(&this->tl, fsm_expire_timer, 0);
174  	this->expire_event = event;
175  	this->event_arg = arg;
176  	this->tl.expires = jiffies + (millisec * HZ) / 1000;
177  	add_timer(&this->tl);
178  	return 0;
179  }
180  
181  /* FIXME: this function is never used, why */
182  void
fsm_modtimer(fsm_timer * this,int millisec,int event,void * arg)183  fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
184  {
185  
186  #if FSM_TIMER_DEBUG
187  	printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
188  		this->fi->name, this, millisec);
189  #endif
190  
191  	del_timer(&this->tl);
192  	timer_setup(&this->tl, fsm_expire_timer, 0);
193  	this->expire_event = event;
194  	this->event_arg = arg;
195  	this->tl.expires = jiffies + (millisec * HZ) / 1000;
196  	add_timer(&this->tl);
197  }
198  
199  EXPORT_SYMBOL(init_fsm);
200  EXPORT_SYMBOL(kfree_fsm);
201  EXPORT_SYMBOL(fsm_settimer);
202  EXPORT_SYMBOL(fsm_deltimer);
203  EXPORT_SYMBOL(fsm_addtimer);
204  EXPORT_SYMBOL(fsm_modtimer);
205  EXPORT_SYMBOL(fsm_getstate_str);
206  
207  #if FSM_DEBUG_HISTORY
208  EXPORT_SYMBOL(fsm_print_history);
209  EXPORT_SYMBOL(fsm_record_history);
210  #endif
211