1 /*
2  * Copyright (c) 2018 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: Define general SM framework, The modules can implement state machine
22  * using framework, it provides framework for state, event, state transition,
23  * event handling
24  *
25  * The module, whoever implement SM using this framework need to define an array
26  * of structures (of type struct wlan_sm_state_info) as below,
27  * for example, sample state array definition
28  *
29  * struct wlan_sm_state_info sm_info[] = {
30  *     {
31  *         (uint8_t) WLAN_VDEV_S_INIT,
32  *         (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
33  *         (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
34  *         true,
35  *         "INIT",
36  *         mlme_vdev_state_init_entry, --> gets invoked on entering the state
37  *         mlme_vdev_state_init_exit, --> gets invoked before exiting the state
38  *         mlme_vdev_state_init_event  --> gets invoked on event dispatch
39  *     },
40  *     {
41  *         (uint8_t) WLAN_VDEV_S_START,
42  *         (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
43  *         (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
44  *         true,
45  *         "START",
46  *         mlme_vdev_state_start_entry,
47  *         mlme_vdev_state_start_exit,
48  *         mlme_vdev_state_start_event
49  *     },
50  *     {
51  *        (uint8_t) WLAN_VDEV_S_DFS_CAC_WAIT,
52  *        (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
53  *        (uint8_t) WLAN_SM_ENGINE_STATE_NONE,
54  *        true,
55  *        "DFS_CAC_WAIT",
56  *        mlme_vdev_state_dfs_cac_wait_entry,
57  *        mlme_vdev_state_dfs_cac_wait_exit,
58  *        mlme_vdev_state_dfs_cac_wait_event
59  *     },
60  *     ...
61  *  };
62  *
63  *  Invoke wlan_sm_create() with this state array as below
64  *
65  *  sm = wlan_sm_create("VDEV_SM", vdev_obj, WLAN_VDEV_S_INIT, sm_info, 3,
66  *                       event_names[], num_events);
67  *
68  *  on successful creation, invoke below functions to dispatch events and state
69  *  transition
70  *
71  *  Event dispatch:
72  *    wlan_sm_dispatch(sm, start_event_id, 0, NULL);
73  *
74  *  State transition:
75  *     wlan_sm_transition_to(sm, WLAN_VDEV_S_INIT);
76  *
77  *
78  */
79 #ifndef _WLAN_SM_ENGINE_H_
80 #define _WLAN_SM_ENGINE_H_
81 
82 #include <qdf_types.h>
83 #include <qdf_atomic.h>
84 #include <wlan_sm_engine_dbg.h>
85 
86 /* invalid state */
87 #define WLAN_SM_ENGINE_STATE_NONE 255
88 /* invalid event */
89 #define WLAN_SM_ENGINE_EVENT_NONE 255
90 
91 #define WLAN_SM_ENGINE_MAX_STATE_NAME 128
92 #define WLAN_SM_ENGINE_MAX_NAME   64
93 #define WLAN_SM_ENGINE_MAX_STATES 200
94 #define WLAN_SM_ENGINE_MAX_EVENTS 200
95 
96 /**
97  * struct wlan_sm_state_info - state structure definition
98  * @state:             State id
99  * @parent_state:      Parent state id (optional)
100  * @initial_substate:  Initial sub state of this state
101  * @has_substates:     flag to specify, whether it has sub states
102  * @name:              Name of the state
103  * @wlan_sm_entry:    State entry callback pointer
104  * @wlan_sm_exit:     State exit callback pointer
105  * @wlan_sm_event:    State event callback pointer
106  */
107 struct wlan_sm_state_info {
108 	uint8_t state;
109 	uint8_t parent_state;
110 	uint8_t initial_substate;
111 	uint8_t has_substates;
112 	const char *name;
113 	void (*wlan_sm_entry) (void *ctx);
114 	void (*wlan_sm_exit) (void *ctx);
115 	bool (*wlan_sm_event) (void *ctx, uint16_t event,
116 			       uint16_t event_data_len, void *event_data);
117 };
118 
119 /**
120  * struct wlan_sm - state machine structure
121  * @name:                 Name of the statemachine
122  * @cur_state:            Current state (state/sub-state)
123  * @num_states:           Number of states
124  * @last_event:           Holds the last handled event of SM
125  * @state_info:           Initialized States' table
126  * @ctx:                  Holds the caller's context
127  * @in_state_transition:  Flag to check whether state transition is in progress
128  * @event_names:          Array of event names
129  * @num_event_names:      Number of event names
130  * @history:              Holds the SM history pointer
131  */
132 struct wlan_sm {
133 	uint8_t name[WLAN_SM_ENGINE_MAX_NAME];
134 	uint8_t cur_state;
135 	uint8_t num_states;
136 	uint8_t last_event;
137 	struct wlan_sm_state_info *state_info;
138 	void *ctx;
139 	qdf_atomic_t in_state_transition;
140 	const char **event_names;
141 	uint32_t num_event_names;
142 #ifdef SM_ENG_HIST_ENABLE
143 	struct wlan_sm_history history;
144 #endif
145 };
146 
147 #define WLAN_SM_ENGINE_ENTRY(name, state, parent, initsubstate, has_substates) \
148 	{ state, parent, initsubstate, has_substates, \
149 	"##name", wlan_sm_##name_entry, wlan_sm_##name_exit,\
150 	wlan_sm_##name_event }
151 
152 /*
153  * flag definitions
154  */
155 #define WLAN_SM_ENGINE_ASYNCHRONOUS  0x0  /* run SM asynchronously */
156 #define WLAN_SM_ENGINE_SYNCHRONOUS   0x1  /* run SM synchronously */
157 
158 /**
159  * wlan_sm_create() - SM create
160  * @name: Name of SM owner module
161  * @ctx: caller pointer, used on invoking callbacks
162  * @init_state: Default state of the SM
163  * @state_info: States' definitions
164  * @num_states: Number of states
165  * @event_names: Event name table
166  * @num_event_names: Number of events
167  *
168  * Creates SM object, initializes with init_state, stores the name and owner
169  * module pointer, states definition table, and event name table
170  *
171  * Return: Handle to struct wlan_sm on successful creation,
172  *         NULL on Failure
173  */
174 struct wlan_sm *wlan_sm_create(const char *name, void *ctx,
175 			       uint8_t init_state,
176 			       struct wlan_sm_state_info *state_info,
177 			       uint8_t num_states,
178 			       const char **event_names,
179 			       uint32_t num_event_names);
180 
181 /**
182  * wlan_sm_delete() - SM delete
183  * @sm: state machine handle
184  *
185  * Delete SM object
186  *
187  * Return: void
188  */
189 void wlan_sm_delete(struct wlan_sm *sm);
190 
191 /**
192  * wlan_sm_dispatch() - API to notify event to SM
193  * @sm: state machine handle
194  * @event: event id
195  * @event_data_len: Size of event data
196  * @event_data: Event data
197  *
198  * Notifies event to SM, it invokes event callback of the current state of SM
199  *
200  * Return: QDF_STATUS_SUCCESS for handling
201  *         QDF_STATUS_E_INVAL for not handling
202  */
203 QDF_STATUS wlan_sm_dispatch(struct wlan_sm *sm, uint16_t event,
204 			    uint16_t event_data_len, void *event_data);
205 
206 /**
207  * wlan_sm_transition_to() - API to move the state of SM
208  * @sm: state machine handle
209  * @state: State id
210  *
211  * Moves the SM's state
212  *
213  * Return: void
214  */
215 void wlan_sm_transition_to(struct wlan_sm *sm, uint8_t state);
216 
217 /**
218  * wlan_sm_get_lastevent() - API to get last dispatched event
219  * @sm: state machine handle
220  *
221  * Gets the last dispatched event
222  *
223  * Return: event id
224  */
225 uint8_t wlan_sm_get_lastevent(struct wlan_sm *sm);
226 
227 /**
228  * wlan_sm_get_current_state() - API to get current state of SM
229  * @sm: state machine handle
230  *
231  * Gets the current state of SM
232  *
233  * Return: state id
234  */
235 uint8_t wlan_sm_get_current_state(struct wlan_sm *sm);
236 
237 /**
238  * wlan_sm_get_current_state_name() - API to get current state's name of SM
239  * @sm: state machine handle
240  *
241  * Gets the current state name of SM
242  *
243  * Return: name of the state
244  */
245 const char *wlan_sm_get_current_state_name(struct wlan_sm *sm);
246 
247 /**
248  * wlan_sm_get_state_name() - API to get state's name
249  * @sm: state machine handle
250  * @state: state id
251  *
252  * Gets the given state name of SM
253  *
254  * Return: name of the state
255  */
256 const char *wlan_sm_get_state_name(struct wlan_sm *sm, uint8_t state);
257 
258 /**
259  * wlan_sm_reset() - API to reset SM state
260  * @sm: state machine handle
261  * @init_state: state to reset SM
262  *
263  * Resets the SM to given state
264  *
265  * Return: void
266  */
267 void wlan_sm_reset(struct wlan_sm *sm, uint8_t init_state);
268 
269 #endif
270