linux/drivers/s390/net/fsm.c
<<
>>
Prefs
   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
  12MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
  13MODULE_DESCRIPTION("Finite state machine helper functions");
  14MODULE_LICENSE("GPL");
  15
  16fsm_instance *
  17init_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        strlcpy(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
  72void
  73kfree_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
  87void
  88fsm_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
 112void
 113fsm_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
 123const char *
 124fsm_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
 132static void
 133fsm_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
 143void
 144fsm_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
 154void
 155fsm_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
 164int
 165fsm_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 */
 182void
 183fsm_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
 199EXPORT_SYMBOL(init_fsm);
 200EXPORT_SYMBOL(kfree_fsm);
 201EXPORT_SYMBOL(fsm_settimer);
 202EXPORT_SYMBOL(fsm_deltimer);
 203EXPORT_SYMBOL(fsm_addtimer);
 204EXPORT_SYMBOL(fsm_modtimer);
 205EXPORT_SYMBOL(fsm_getstate_str);
 206
 207#if FSM_DEBUG_HISTORY
 208EXPORT_SYMBOL(fsm_print_history);
 209EXPORT_SYMBOL(fsm_record_history);
 210#endif
 211