xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_fsm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2019 - 2020 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * Author: vincent_fann@realtek.com
15  *
16  *****************************************************************************/
17 #include "phl_headers.h"
18 
19 #ifdef CONFIG_FSM
20 
21 #define PHL_DEBUG_FSM
22 
23 #define CLOCK_NUM 10
24 #define CLOCK_UNIT 10
25 #define IS_CLK_OFF(clk) (clk->remain < 0) /* Negative value means disabled */
26 #define IS_CLK_ON(clk) (clk->remain >= 0)
27 #define IS_CLK_EXP(clk) (clk->remain < (CLOCK_UNIT >> 1)) /* expire */
28 
29 #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
30 #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
31 #define pstr(s) (s +_os_strlen((u8 *)s))
32 #define lstr(s, l) (size_t)(l - _os_strlen((u8 *)s))
33 
34 #define FSM_INITIAL_STATE 0
35 
36 #ifdef FSM_DBG_MEM_OVERWRITE
fsm_kmalloc(u32 sz)37 void *fsm_kmalloc(u32 sz)
38 {
39 	char *ptr;
40 
41 	ptr = kmalloc(sz+4, GFP_KERNEL);
42 	memset(ptr+sz, 0xff, 4);
43 	PHL_INFO("+AA %p %d\n", ptr, sz);
44 	return ptr;
45 }
46 
fsm_kfree(void * ptr,u32 sz)47 void fsm_kfree(void *ptr, u32 sz)
48 {
49 	u32 ptn = 0xffffffff;
50 	u32 *p = (u32 *)(ptr+sz);
51 
52 	PHL_INFO("-AA %p %d", ptr, sz);
53 	if ((*p&ptn) != ptn) {
54 		PHL_ERR("- %p %d", ptr, sz);
55 		PHL_ERR("OVER WRITE %x\n", ptn);
56 	}
57 	kfree(ptr);
58 }
59 #define _os_kmem_alloc(a, b) fsm_kmalloc(b)
60 #define _os_kmem_free(a, b, c) fsm_kfree(b, c)
61 #endif
62 
63 struct fsm_event_ent int_event_tbl[] = {
64 	EV_ENT(FSM_INT_EV_MASK),
65 	EV_ENT(FSM_EV_CANCEL),
66 	EV_ENT(FSM_EV_TIMER_EXPIRE),
67 	EV_ENT(FSM_EV_END),
68 
69 	EV_ENT(FSM_EV_SWITCH_IN),
70 	EV_ENT(FSM_EV_SWITCH_OUT),
71 	EV_ENT(FSM_EV_STATE_IN),
72 	EV_ENT(FSM_EV_STATE_OUT),
73 
74 	/* Global event for announcement */
75 	/* BE CAUREFUL the EVENT ORDER
76 	 * please also modify enum FSM_EV_ID{} in phl_fsm.h
77 	 */
78 	EV_ENT(FSM_GB_SCAN_START),
79 	EV_ENT(FSM_GB_SCAN_COMPLETE),
80 
81 	EV_ENT(FSM_EV_MAX)
82 };
83 
84 /*
85  * FSM status
86  */
87 enum FSM_STATUS {
88 	FSM_STATUS_NONE,	/* default value */
89 
90 	FSM_STATUS_INITIALIZED, /* insert module ok,
91 				 * all mem/queue/timer were allocated
92 				 * has a pending thread
93 				 * phl_fsm_new_fsm()
94 				 * phl_fsm_stop_fsm()
95 				 */
96 
97 	FSM_STATUS_READY,	/* interface up, schedule thread, timer.
98 				 * Does NOT receive message
99 				 * phl_fsm_start_fsm()
100 				 */
101 
102 	FSM_STATUS_ENABLE,	/* Normal running; Reack msg
103 				 * Internal use
104 				 * fsm_enable()
105 				 */
106 
107 	FSM_STATUS_DISABLE,	/* Does NOT reack msg, able to receiving msg
108 				 * Internal use
109 				 * fsm_disable()
110 				 */
111 };
112 
113 /* @obj: obj that will be infomred to when time's up
114  * @counter: clock time period
115  * @event: event that will delivered when time's up
116  * @end: end time
117  * @pause: stop countdown
118  */
119 struct fsm_clock {
120 	u16 event;
121 	void *priv;
122 	u8 pause;
123 	u32 start;
124 	u32 end;
125 	int remain; /* ms */
126 };
127 
128 struct fsm_queue {
129 	struct	list_head q;
130 	_os_lock lock;
131 };
132 
133 struct fsm_main {
134 	struct list_head list;
135 	char name[FSM_NAME_LEN];
136 	u8 status;
137 	u8 obj_cnt;
138 	u8 oid_seq; /* starts from 1 */
139 	u8 en_clock_num;
140 	_os_lock clock_lock;
141 
142 	_os_thread thread;
143 	_os_timer fsm_timer; /* unit in ms */
144 
145 	struct fsm_root *root;
146 	struct fsm_queue obj_queue;
147 	struct fsm_queue msg_queue;
148 	struct fsm_queue evt_queue;
149 	_os_sema msg_ready;
150 	bool should_stop;
151 
152 	/* extra custom queue; for fsm private */
153 	struct fsm_queue ext_queue;
154 
155 	struct phl_info_t *phl_info; /* phl_info */
156 	struct rtw_phl_fsm_tb tb;
157 };
158 
159 /*
160  * @event: event id
161  * @param: additional param of the event
162  * @param_sz: param size
163  */
164 struct fsm_evt {
165 	struct list_head list;
166 	u16 event; /* event id */
167 	struct fsm_main *fsm;
168 
169 	void *param;
170 	int param_sz;
171 };
172 
173 /* @obj_id: object id
174  * @state: current state
175  * @prive: object's private date
176  */
177 struct fsm_obj {
178 	struct list_head list;
179 	u8 oid;
180 	u8 state;
181 	char name[FSM_NAME_LEN];
182 	struct fsm_clock clock[CLOCK_NUM];
183 	struct fsm_main *fsm;
184 
185 	void *custom_obj;
186 	int custom_len; /* custom obj length */
187 
188 	/* Global event use */
189 	struct gbl_param my_gbl_req; /* my announcemnt to all */
190 	struct fsm_queue gbl_queue; /* all received global events */
191 	u16 gbl_q_len; /* number of received global event */
192 };
193 
194 /* Main structure to handle all standalone fsm */
195 struct fsm_root {
196 	_os_thread thread;
197 	struct list_head list;
198 	struct fsm_queue q_share_thd;
199 	struct fsm_queue q_alone_thd;
200 	struct phl_info_t *phl_info;
201 	u8 gbl_seq;
202 
203 	_os_sema msg_ready;
204 
205 	u32 status; /* refer to enum FSM_ROOT_STATUS_FLAGS */
206 };
207 
208 /* Static function porto type */
209 static int fsm_handler(struct fsm_main *fsm);
210 static char *fsm_state_name(struct fsm_main *fsm, u8 state);
211 static u8 fsm_get_evt_level(struct fsm_main *fsm, u16 event);
212 
fsm_status_set(struct fsm_main * fsm,enum FSM_STATUS status)213 static void fsm_status_set(struct fsm_main *fsm, enum FSM_STATUS status)
214 {
215 	fsm->status = status;
216 }
217 
fsm_status(struct fsm_main * fsm)218 static enum FSM_STATUS fsm_status(struct fsm_main *fsm)
219 {
220 	return fsm->status;
221 }
222 
223 /* unit ms */
phl_fsm_time_pass(u32 start)224 u32 phl_fsm_time_pass(u32 start)
225 {
226 	u32 now = _os_get_cur_time_ms();
227 	u32 pass;
228 
229 	if (start <= now)
230 		pass = now - start;
231 	else
232 		pass = 0xffffffff - start + now;
233 
234 	return pass;
235 }
236 
phl_fsm_time_left(u32 start,u32 end)237 u32 phl_fsm_time_left(u32 start, u32 end)
238 {
239 	u32 total, pass;
240 	int left = 0;
241 
242 	pass = phl_fsm_time_pass(start);
243 
244 	if (end >= start)
245 		total = end - start;
246 	else
247 		total = 0xffffffff - start + end;
248 
249 	left = total - pass;
250 
251 	if (left < 0)
252 		left = 0;
253 
254 	return (u32)left;
255 }
256 
257 #if 0
258 static struct fsm_main *fsm_dequeue_fsm(struct fsm_root *root, u8 fsm_mode)
259 {
260 	void *d = phl_to_drvpriv(root->phl_info);
261 	struct fsm_main *fsm;
262 	struct fsm_queue *queue = (fsm_mode == FSM_ALONE_THREAD) ?
263 					(&root->q_alone_thd) : (&root->q_share_thd);
264 
265 	if (list_empty(&queue->q))
266 		return NULL;
267 
268 	_os_spinlock(d, &queue->lock, _bh, NULL);
269 	fsm = list_first_entry(&queue->q, struct fsm_main, list);
270 	list_del(&fsm->list);
271 	_os_spinunlock(d, &queue->lock, _bh, NULL);
272 	return fsm;
273 }
274 
275 static struct fsm_obj *fsm_dequeue_obj(struct fsm_main *fsm)
276 {
277 	void *d = phl_to_drvpriv(fsm->phl_info);
278 	struct fsm_obj *obj;
279 
280 	if (list_empty(&fsm->obj_queue.q))
281 		return NULL;
282 
283 	_os_spinlock(d, &fsm->obj_queue.lock, _bh, NULL);
284 	obj = list_first_entry(&fsm->obj_queue.q, struct fsm_obj, list);
285 	list_del(&obj->list);
286 	_os_spinunlock(d, &fsm->obj_queue.lock, _bh, NULL);
287 	return obj;
288 }
289 #endif
290 
fsm_dequeue_msg(struct fsm_main * fsm)291 static struct fsm_msg *fsm_dequeue_msg(struct fsm_main *fsm)
292 {
293 	void *d = phl_to_drvpriv(fsm->phl_info);
294 	struct fsm_msg *msg;
295 
296 	if (list_empty(&fsm->msg_queue.q))
297 		return NULL;
298 
299 	_os_spinlock(d, &fsm->msg_queue.lock, _bh, NULL);
300 	msg = list_first_entry(&fsm->msg_queue.q, struct fsm_msg, list);
301 	list_del(&msg->list);
302 	_os_spinunlock(d, &fsm->msg_queue.lock, _bh, NULL);
303 	return msg;
304 }
305 
fsm_dequeue_evt(struct fsm_main * fsm)306 static struct fsm_evt *fsm_dequeue_evt(struct fsm_main *fsm)
307 {
308 	void *d = phl_to_drvpriv(fsm->phl_info);
309 	struct fsm_evt *evt;
310 
311 	if (list_empty(&fsm->evt_queue.q))
312 		return NULL;
313 
314 	_os_spinlock(d, &fsm->evt_queue.lock, _bh, NULL);
315 	evt = list_first_entry(&fsm->evt_queue.q, struct fsm_evt, list);
316 	list_del(&evt->list);
317 	_os_spinunlock(d, &fsm->evt_queue.lock, _bh, NULL);
318 	return evt;
319 }
320 
321 /* For EXTERNAL application to enqueue message to extra queue (expose)
322  *
323  * @fsm: fsm that object belonged to
324  * @msg: message to be enqueued
325  * @to_head: enqueue message to the head
326  */
phl_fsm_enqueue_ext(struct fsm_main * fsm,struct fsm_msg * msg,u8 to_head)327 int phl_fsm_enqueue_ext(struct fsm_main *fsm, struct fsm_msg *msg, u8 to_head)
328 {
329 	void *d = phl_to_drvpriv(fsm->phl_info);
330 	struct fsm_queue *queue = &fsm->ext_queue;
331 
332 	_os_spinlock(d, &queue->lock, _bh, NULL);
333 	if (to_head)
334 		list_add(&msg->list, &queue->q);
335 	else
336 		list_add_tail(&msg->list, &queue->q);
337 	_os_spinunlock(d, &queue->lock, _bh, NULL);
338 
339 	return 0;
340 }
341 
342 /* For EXTERNAL application to dequeue message from extra queue (expose)
343  *
344  * @fsm: fsm that object belonged to
345  */
phl_fsm_dequeue_ext(struct fsm_main * fsm)346 struct fsm_msg *phl_fsm_dequeue_ext(struct fsm_main *fsm)
347 {
348 	void *d = phl_to_drvpriv(fsm->phl_info);
349 	struct fsm_msg *msg;
350 
351 	if (list_empty(&fsm->ext_queue.q))
352 		return NULL;
353 
354 	_os_spinlock(d, &fsm->ext_queue.lock, _bh, NULL);
355 	msg = list_first_entry(&fsm->ext_queue.q, struct fsm_msg, list);
356 	list_del(&msg->list);
357 	_os_spinunlock(d, &fsm->ext_queue.lock, _bh, NULL);
358 	return msg;
359 }
360 
361 /* For EXTERNAL application to dequeue message from extra queue (expose)
362  *
363  * @fsm: fsm that object belonged to
364  */
phl_fsm_is_ext_queue_empty(struct fsm_main * fsm)365 int phl_fsm_is_ext_queue_empty(struct fsm_main *fsm)
366 {
367 	return list_empty(&fsm->ext_queue.q);
368 }
369 
fsm_new_oid(struct fsm_main * fsm)370 static int fsm_new_oid(struct fsm_main *fsm)
371 {
372 	u8 oid = fsm->oid_seq++;
373 
374 	if (fsm->oid_seq == 0xFF) {
375 		PHL_WARN("%s: reach MAX object ID 0x%x\n",
376 			fsm->name, oid);
377 	}
378 	return oid;
379 }
380 
fsm_enqueue_list(void * d,struct fsm_main * fsm,struct fsm_queue * queue,struct list_head * list)381 static int fsm_enqueue_list(void *d, struct fsm_main *fsm,
382 	struct fsm_queue *queue, struct list_head *list)
383 {
384 	_os_spinlock(d, &queue->lock, _bh, NULL);
385 	list_add_tail(list, &queue->q);
386 	_os_spinunlock(d, &queue->lock, _bh, NULL);
387 	return 0;
388 }
389 
fsm_state_run(struct fsm_obj * obj,u16 event,void * param)390 static enum fsm_run_rtn fsm_state_run(struct fsm_obj *obj,
391 	u16 event, void *param)
392 {
393 	struct fsm_main *fsm = obj->fsm;
394 
395 	/* TODO protect incorrect event */
396 
397 	FSM_EV_MSG(fsm, fsm_get_evt_level(fsm, event),
398 		"%s-%d %-18s    %s\n", fsm->name, obj->oid,
399 		fsm_state_name(fsm, obj->state), phl_fsm_evt_name(obj, event));
400 
401 	return fsm->tb.state_tbl[obj->state].fsm_func(obj->custom_obj,
402 		event, param);
403 }
404 
fsm_remove_all_queuing_msg(struct fsm_main * fsm)405 static void fsm_remove_all_queuing_msg(struct fsm_main *fsm)
406 {
407 	struct fsm_msg *msg;
408 	struct fsm_evt *evt;
409 	void *d = phl_to_drvpriv(fsm->phl_info);
410 
411 	/* go through msg queue and free everything */
412 	while ((msg = fsm_dequeue_msg(fsm)) != NULL) {
413 		if (msg->param)
414 			_os_kmem_free(d, (void *)msg->param, msg->param_sz);
415 		_os_kmem_free(d, (void *)msg, sizeof(*msg));
416 	}
417 
418 	/* go through event queue and free everything */
419 	while ((evt = fsm_dequeue_evt(fsm)) != NULL) {
420 		if (evt->param)
421 			_os_kmem_free(d, (void *)evt->param, evt->param_sz);
422 		_os_kmem_free(d, (void *)evt, sizeof(*evt));
423 	}
424 
425 	/* go through ext queue and free everything */
426 	while ((msg = phl_fsm_dequeue_ext(fsm)) != NULL) {
427 		if (msg->param)
428 			_os_kmem_free(d, (void *)msg->param, msg->param_sz);
429 		_os_kmem_free(d, (void *)msg, sizeof(*msg));
430 	}
431 }
432 
fsm_cancel_all_running_obj(struct fsm_main * fsm)433 static int fsm_cancel_all_running_obj(struct fsm_main *fsm)
434 {
435 	struct fsm_obj *obj;
436 
437 	phl_list_for_loop(obj, struct fsm_obj, &fsm->obj_queue.q, list) {
438 		phl_fsm_gen_msg(fsm->phl_info, obj, NULL, 0, FSM_EV_CANCEL);
439 	}
440 
441 	return 0;
442 }
443 
phl_fsm_dbg_level(struct fsm_main * fsm,u8 level)444 u8 phl_fsm_dbg_level(struct fsm_main *fsm, u8 level)
445 {
446 	if (fsm->tb.dbg_level >= level)
447 		return fsm->tb.dbg_level;
448 
449 	return 0;
450 }
451 
phl_fsm_evt_level(struct fsm_main * fsm,u8 level)452 u8 phl_fsm_evt_level(struct fsm_main *fsm, u8 level)
453 {
454 	if (fsm->tb.evt_level >= level)
455 		return fsm->tb.evt_level;
456 
457 	return 0;
458 }
459 
fsm_get_evt_level(struct fsm_main * fsm,u16 event)460 static u8 fsm_get_evt_level(struct fsm_main *fsm, u16 event)
461 {
462 	u16 ev;
463 
464 	/* fsm internal event */
465 	if (event & FSM_INT_EV_MASK) {
466 		ev = (u8)(event & ~(FSM_EV_MASK));
467 		return int_event_tbl[ev].evt_level;
468 	}
469 
470 	if (event == FSM_EV_UNKNOWN)
471 		return FSM_DBG_INFO;
472 
473 	if (event > fsm->tb.max_event)
474 		return FSM_DBG_INFO;
475 
476 	/* user event */
477 	return fsm->tb.evt_tbl[event].evt_level;
478 }
479 
fsm_init_queue(void * d,struct fsm_queue * queue)480 static void fsm_init_queue(void *d, struct fsm_queue *queue)
481 {
482 	INIT_LIST_HEAD(&queue->q);
483 	_os_spinlock_init(d, &queue->lock);
484 }
485 
fsm_deinit_queue(void * d,struct fsm_queue * queue)486 static void fsm_deinit_queue(void *d, struct fsm_queue *queue)
487 {
488 	_os_spinlock_free(d, &queue->lock);
489 }
490 
491 /* For External obj to check sould stop status
492  *
493  * @fsm: fsm to get state
494  */
phl_fsm_should_stop(struct fsm_main * fsm)495 bool phl_fsm_should_stop(struct fsm_main *fsm)
496 {
497 	return fsm->should_stop;
498 }
499 
fsm_thread_share(void * param)500 int fsm_thread_share(void *param)
501 {
502 	struct fsm_main *fsm, *fsm_t;
503 	struct fsm_root *root = (struct fsm_root *)param;
504 	void *d = phl_to_drvpriv(root->phl_info);
505 
506 	while (1) {
507 
508 		_os_sema_down(d, &root->msg_ready);
509 		if (_os_thread_check_stop(d, &(root->thread)))
510 			break;
511 		phl_list_for_loop_safe(fsm, fsm_t,
512 			struct fsm_main, &root->q_share_thd.q, list) {
513 			if (fsm_status(fsm) == FSM_STATUS_ENABLE)
514 				fsm_handler(fsm);
515 		}
516 	}
517 	_os_thread_wait_stop(d, &root->thread);
518 	PHL_INFO("fsm: [root] thread down\n");
519 
520 	return 0;
521 }
522 
fsm_thread_alone(void * param)523 int fsm_thread_alone(void *param)
524 {
525 	struct fsm_main *fsm = (struct fsm_main *)param;
526 	void *d = phl_to_drvpriv(fsm->phl_info);
527 
528 	while (1) {
529 
530 		_os_sema_down(d, &fsm->msg_ready);
531 		if (_os_thread_check_stop(d, &(fsm->thread)))
532 			break;
533 
534 		if (fsm_status(fsm) == FSM_STATUS_ENABLE)
535 			fsm_handler(fsm);
536 	}
537 	_os_thread_wait_stop(d, &fsm->thread);
538 	FSM_INFO(fsm, "fsm: [%s] thread down\n", fsm->name);
539 
540 	return 0;
541 }
542 
fsm_get_obj(struct fsm_main * fsm,u8 oid)543 static struct fsm_obj *fsm_get_obj(struct fsm_main *fsm, u8 oid)
544 {
545 	struct fsm_obj *obj, *obj_t;
546 	void *d = phl_to_drvpriv(fsm->phl_info);
547 
548 
549 	_os_spinlock(d, &fsm->obj_queue.lock, _bh, NULL);
550 	phl_list_for_loop_safe(obj, obj_t,
551 		struct fsm_obj, &fsm->obj_queue.q, list) {
552 		if (oid == (obj->oid)) {
553 			_os_spinunlock(d, &fsm->obj_queue.lock, _bh, NULL);
554 			return obj;
555 		}
556 	}
557 	_os_spinunlock(d, &fsm->obj_queue.lock, _bh, NULL);
558 	return NULL;
559 }
560 
phl_fsm_new_msg(struct fsm_obj * obj,u16 event)561 struct fsm_msg *phl_fsm_new_msg(struct fsm_obj *obj, u16 event)
562 {
563 #ifdef PHL_INCLUDE_FSM
564 	struct fsm_msg *msg = NULL;
565 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
566 
567 	if (fsm_status(obj->fsm) != FSM_STATUS_ENABLE) {
568 		PHL_ERR("%s: is out of service, ignore message %s!\n",
569 			obj->fsm->name, phl_fsm_evt_name(obj, event));
570 		return NULL;
571 	}
572 
573 	msg = (struct fsm_msg *)_os_kmem_alloc(d, sizeof(*msg));
574 
575 	if (msg == NULL)
576 		return NULL;
577 
578 	_os_mem_set(d, msg, 0, sizeof(*msg));
579 	msg->event = event;
580 
581 	if (obj) {
582 		msg->fsm = obj->fsm;
583 		msg->oid = obj->oid;
584 	}
585 	return msg;
586 #else
587 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
588 	return NULL;
589 #endif
590 }
591 
phl_fsm_sent_msg(struct fsm_obj * obj,struct fsm_msg * msg)592 enum rtw_phl_status phl_fsm_sent_msg(struct fsm_obj *obj, struct fsm_msg *msg)
593 {
594 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
595 
596 	if (fsm_status(obj->fsm) != FSM_STATUS_ENABLE) {
597 		PHL_ERR("fsm: %s is out of service, ignore message %s!\n",
598 			obj->fsm->name, phl_fsm_evt_name(obj, msg->event));
599 		return RTW_PHL_STATUS_RESOURCE;
600 	}
601 	fsm_enqueue_list(d, obj->fsm, &obj->fsm->msg_queue, &msg->list);
602 
603 	if (obj->fsm->tb.mode == FSM_ALONE_THREAD)
604 		_os_sema_up(d, &obj->fsm->msg_ready);
605 	else
606 		_os_sema_up(d, &obj->fsm->root->msg_ready);
607 
608 	return RTW_PHL_STATUS_SUCCESS;
609 }
610 
fsm_new_timer_msg(struct fsm_obj * obj,u16 event,void * priv)611 static struct fsm_msg *fsm_new_timer_msg(struct fsm_obj *obj,
612 	u16 event, void *priv)
613 {
614 	struct fsm_msg *msg = NULL;
615 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
616 
617 	msg = (struct fsm_msg *)_os_kmem_alloc(d, sizeof(*msg));
618 	if (msg == NULL)
619 		return msg;
620 
621 	_os_mem_set(d, msg, 0, sizeof(*msg));
622 	msg->event = event;
623 	msg->oid = obj->oid;
624 	msg->param = priv;
625 
626 	return msg;
627 }
628 
fsm_post_message(struct fsm_obj * obj,u16 event,void * priv)629 static int fsm_post_message(struct fsm_obj *obj, u16 event, void *priv)
630 {
631 	struct fsm_msg *msg;
632 	struct fsm_main *fsm = obj->fsm;
633 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
634 
635 	msg = fsm_new_timer_msg(obj, event, priv);
636 	if (msg == NULL)
637 		return -1;
638 
639 	fsm_enqueue_list(d, fsm, &fsm->msg_queue, &msg->list);
640 	if (obj->fsm->tb.mode == FSM_ALONE_THREAD)
641 		_os_sema_up(d, &fsm->msg_ready);
642 	else
643 		_os_sema_up(d, &fsm->root->msg_ready);
644 	return 0;
645 }
646 
fsm_timer_callback(void * context)647 void fsm_timer_callback(void *context)
648 {
649 	struct fsm_main *fsm = (struct fsm_main *)context;
650 	void *d = phl_to_drvpriv(fsm->phl_info);
651 	struct fsm_obj *obj;
652 	struct fsm_clock *clk;
653 	int i;
654 
655 	_os_set_timer(d, &fsm->fsm_timer, CLOCK_UNIT);
656 
657 	if (fsm->en_clock_num == 0)
658 		return;
659 
660 	/* go through clock and descrease timer
661 	 * if timer was expired, issue event
662 	 */
663 	phl_list_for_loop(obj, struct fsm_obj, &fsm->obj_queue.q, list) {
664 
665 		_os_spinlock(d, &obj->fsm->clock_lock, _bh, NULL);
666 		for (i = 0; i < CLOCK_NUM; i++) {
667 
668 			clk = &obj->clock[i];
669 
670 			if (IS_CLK_OFF(clk) || clk->pause)
671 				continue;
672 
673 			clk->remain = (int)phl_fsm_time_left(clk->start,
674 				clk->end);
675 			//(clk->remain < 0 ) ? 0 : clk->remain;
676 
677 			/* timer expired */
678 			if (!IS_CLK_EXP(clk))
679 				continue;
680 #ifdef PHL_DBG_FSM
681 			FSM_DBG(obj->fsm, "%s: expire in %d ms\n",
682 				phl_fsm_evt_name(obj, clk->event),
683 				phl_fsm_time_pass(clk->start));
684 #endif
685 			clk->end = 0;
686 			clk->remain = -1;
687 			/* send message to obj */
688 
689 			/* check fsm status before posting */
690 			if (fsm_status(fsm) != FSM_STATUS_INITIALIZED &&
691 			    fsm_status(fsm) != FSM_STATUS_DISABLE)
692 				fsm_post_message(obj, clk->event, clk->priv);
693 
694 			fsm->en_clock_num--;
695 		}
696 		_os_spinunlock(d, &obj->fsm->clock_lock, _bh, NULL);
697 	}
698 }
699 
700 /* allocate and init fsm resource */
phl_fsm_init_fsm(struct fsm_root * root,const char * name,void * priv,struct rtw_phl_fsm_tb * tb)701 struct fsm_main *phl_fsm_init_fsm(struct fsm_root *root, const char *name,
702 	void *priv, struct rtw_phl_fsm_tb *tb)
703 {
704 #ifdef PHL_INCLUDE_FSM
705 	struct fsm_main *fsm;
706 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
707 	void *d = phl_to_drvpriv(phl_info);
708 	//char name_t[FSM_NAME_LEN+10];
709 
710 	/* check event table */
711 	if (tb->evt_tbl[tb->max_event-1].event != tb->max_event-1) {
712 		PHL_ERR("Event mismatch ? Is max event = %d != %d ?\n",
713 			tb->evt_tbl[tb->max_event-1].event,
714 			tb->max_event-1);
715 		return NULL;
716 	}
717 
718 	/* check state table */
719 	if (tb->state_tbl[tb->max_state-1].state != tb->max_state-1) {
720 		PHL_ERR("State mismatch ? Is max state = %d != %d) ?\n",
721 			tb->state_tbl[tb->max_state-1].state,
722 			tb->max_state-1);
723 		return NULL;
724 	}
725 
726 	fsm = (struct fsm_main *)_os_kmem_alloc(d, sizeof(*fsm));
727 
728 	if (fsm == NULL)
729 		return NULL;
730 
731 	_os_mem_set(d, fsm, 0, sizeof(*fsm));
732 	_os_mem_cpy(d, &fsm->tb, (void *)tb, sizeof(*tb));
733 	_os_mem_cpy(d, &fsm->name, (void *)name,
734 		MIN(FSM_NAME_LEN-1, _os_strlen((u8 *)name)));
735 
736 	fsm->root = root;
737 	fsm->phl_info = phl_info;
738 
739 	fsm_init_queue(d, &(fsm->obj_queue));
740 	fsm_init_queue(d, &(fsm->msg_queue));
741 	fsm_init_queue(d, &(fsm->evt_queue));
742 	fsm_init_queue(d, &(fsm->ext_queue));
743 	_os_spinlock_init(d, &fsm->clock_lock);
744 
745 	_os_init_timer(d, &fsm->fsm_timer, fsm_timer_callback, fsm, "fsm");
746 	fsm->oid_seq = 1;
747 
748 	/* link fsm_main to fsm_root */
749 	if (tb->mode == FSM_ALONE_THREAD) {
750 		_os_sema_init(d, &fsm->msg_ready, 0);
751 		fsm_enqueue_list(d, fsm, &root->q_alone_thd, &fsm->list);
752 	} else
753 		fsm_enqueue_list(d, fsm, &root->q_share_thd, &fsm->list);
754 
755 	FSM_INFO(fsm, "fsm: [%s] initialized\n", fsm->name);
756 	fsm_status_set(fsm, FSM_STATUS_INITIALIZED);
757 	return fsm;
758 #else
759 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
760 	return NULL;
761 #endif /* PHL_INCLUDE_FSM */
762 }
763 
764 /* For EXTERNAL application to deinit fsm (expose)
765  * @fsm: see struct fsm_main
766  */
phl_fsm_deinit_fsm(struct fsm_main * fsm)767 enum rtw_phl_status phl_fsm_deinit_fsm(struct fsm_main *fsm)
768 {
769 	void *d = phl_to_drvpriv(fsm->phl_info);
770 	struct fsm_obj *obj, *obj_t;
771 
772 	_os_release_timer(d, &fsm->fsm_timer);
773 
774 	/* remove fsm form link list */
775 	list_del(&fsm->list);
776 
777 	phl_list_for_loop_safe(obj, obj_t,
778 		struct fsm_obj, &fsm->obj_queue.q, list) {
779 
780 		list_del(&obj->list);
781 		phl_fsm_flush_gbl(obj);
782 		fsm_deinit_queue(d, &(obj->gbl_queue));
783 		/* free custom_obj */
784 		_os_kmem_free(d, obj->custom_obj, obj->custom_len);
785 
786 		/* free fsm_obj */
787 		_os_kmem_free(d, obj, sizeof(*obj));
788 	}
789 	fsm_deinit_queue(d, &(fsm->obj_queue));
790 	fsm_deinit_queue(d, &(fsm->msg_queue));
791 	fsm_deinit_queue(d, &(fsm->evt_queue));
792 	fsm_deinit_queue(d, &(fsm->ext_queue));
793 	_os_spinlock_free(d, &fsm->clock_lock);
794 
795 	if (fsm->tb.mode == FSM_ALONE_THREAD)
796 		_os_sema_free(d, &fsm->msg_ready);
797 
798 	FSM_INFO(fsm, "fsm: [%s] uninitilized\n", fsm->name);
799 	_os_kmem_free(d, fsm, sizeof(*fsm));
800 
801 	return RTW_PHL_STATUS_SUCCESS;
802 }
803 
phl_fsm_evt_name(struct fsm_obj * obj,u16 event)804 char *phl_fsm_evt_name(struct fsm_obj *obj, u16 event)
805 {
806 	struct fsm_main *fsm = obj->fsm;
807 	u8 ev;
808 
809 	/* TODO handle global, internal, user event */
810 	/* global event */
811 	if (event & FSM_GBL_EV_MASK)
812 		return "global";
813 
814 	/* fsm internal event */
815 	if (event & FSM_INT_EV_MASK) {
816 		ev = (u8)(event & ~(FSM_EV_MASK));
817 		return int_event_tbl[ev].name;
818 	}
819 
820 	if (event == FSM_EV_UNKNOWN)
821 		return "FSM_EV_UNKNOWN";
822 
823 	if (event > fsm->tb.max_event)
824 		return "undefine";
825 
826 	/* user event */
827 	return fsm->tb.evt_tbl[event].name;
828 }
829 
fsm_state_name(struct fsm_main * fsm,u8 state)830 static char *fsm_state_name(struct fsm_main *fsm, u8 state)
831 {
832 	if (state > fsm->tb.max_state)
833 		return "unknown";
834 
835 	return fsm->tb.state_tbl[state].name;
836 }
837 
838 /* For EXTERNAL application to get state id (expose)
839  *
840  * @obj: obj to get state
841  */
phl_fsm_state_id(struct fsm_obj * obj)842 u8 phl_fsm_state_id(struct fsm_obj *obj)
843 {
844 	return obj->state;
845 }
846 
847 /**  init obj internal variable
848  *
849  * @fsm: fsm that object belonged to
850  * default init to the 1st state in state_tbl
851 
852  */
fsm_obj_switch_in(struct fsm_obj * obj)853 static void fsm_obj_switch_in(struct fsm_obj *obj)
854 {
855 	struct fsm_main *fsm = obj->fsm;
856 	//void *d = phl_to_drvpriv(fsm->phl_info);
857 
858 	/* default init to the 1st state in state_tbl */
859 	obj->state = fsm->tb.state_tbl[0].state;
860 	FSM_INFO(fsm, "%s-%d %-18s -> %s\n", fsm->name, obj->oid,
861 		"switch in", fsm_state_name(fsm, obj->state));
862 
863 	/* make it alive! Hello OBJ! */
864 	fsm_state_run(obj, FSM_EV_SWITCH_IN, NULL);
865 }
866 
867 /**  deinit obj internal variable
868  *
869  * @fsm: fsm that object belonged to
870  * default init to the 1st state in state_tbl
871 
872  */
fsm_obj_switch_out(struct fsm_obj * obj)873 static void fsm_obj_switch_out(struct fsm_obj *obj)
874 {
875 	struct fsm_main *fsm = obj->fsm;
876 	//void *d = phl_to_drvpriv(fsm->phl_info);
877 
878 	/* default init to the 1st state in state_tbl */
879 	obj->state = fsm->tb.state_tbl[0].state;
880 	FSM_INFO(fsm, "%s-%d %-18s -> %s\n", fsm->name, obj->oid,
881 		"switch out", fsm_state_name(fsm, obj->state));
882 
883 	/* make it alive! Hello OBJ! */
884 	fsm_state_run(obj, FSM_EV_SWITCH_OUT, NULL);
885 }
886 
887 /* For EXTERNAL application to new a fsm object (expose)
888  *
889  * @fsm: fsm that object belonged to
890  * @fsm_obj: obj param when calling FSM framework function
891  * @priv_len: custom obj length
892  *
893  * return value: NULL	:fail
894  *		 other	:cusomer obj handler (success)
895  */
phl_fsm_new_obj(struct fsm_main * fsm,void ** fsm_obj,int sz)896 void *phl_fsm_new_obj(struct fsm_main *fsm,
897 	void **fsm_obj, int sz)
898 {
899 #ifdef PHL_INCLUDE_FSM
900 	void *d = phl_to_drvpriv(fsm->phl_info);
901 	struct fsm_obj *obj;
902 	int i;
903 
904 	obj = (struct fsm_obj *)_os_kmem_alloc(d, sizeof(*obj));
905 	if (obj == NULL)
906 		return NULL;
907 
908 	_os_mem_set(d, obj, 0, sizeof(*obj));
909 	obj->custom_obj = _os_kmem_alloc(d, sz);
910 
911 	if (obj->custom_obj == NULL) {
912 		_os_kmem_free(d, obj, sizeof(*obj));
913 		return NULL;
914 	}
915 	_os_mem_set(d, obj->custom_obj, 0, sz);
916 
917 	for (i = 0; i < CLOCK_NUM; i++)
918 		obj->clock[i].remain = -1; /* Negative means disable */
919 
920 	fsm_init_queue(d, &(obj->gbl_queue));
921 	obj->custom_len = sz;
922 	obj->oid = (u8)fsm_new_oid(fsm);
923 	obj->fsm = fsm;
924 
925 	_os_mem_set(d, obj->name, 0, FSM_NAME_LEN);
926 	_os_snprintf(obj->name, FSM_NAME_LEN,
927 		"%s-%d", obj->fsm->name, obj->oid);
928 	*fsm_obj = obj;
929 	fsm_enqueue_list(d, fsm, &fsm->obj_queue, &obj->list);
930 
931 	return obj->custom_obj;
932 #else
933 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
934 	return NULL;
935 #endif /* PHL_INCLUDE_FSM */
936 }
937 
938 /* For EXTERNAL application to destory a fsm object (expose)
939  *
940  * @fsm_obj: obj param when calling FSM framework function
941  */
phl_fsm_destory_obj(struct fsm_obj * obj)942 void phl_fsm_destory_obj(struct fsm_obj *obj)
943 {
944 	struct fsm_main *fsm = obj->fsm;
945 	void *d = phl_to_drvpriv(fsm->phl_info);
946 
947 	list_del(&obj->list);
948 	phl_fsm_flush_gbl(obj);
949 	fsm_deinit_queue(d, &(obj->gbl_queue));
950 
951 	/* free custom_obj */
952 	_os_kmem_free(d, obj->custom_obj, obj->custom_len);
953 
954 	/* free fsm_obj */
955 	_os_kmem_free(d, obj, sizeof(*obj));
956 }
957 
phl_fsm_is_alarm_off_ext(struct fsm_obj * obj,u8 id)958 bool phl_fsm_is_alarm_off_ext(struct fsm_obj *obj, u8 id)
959 {
960 	struct fsm_clock *clock = &obj->clock[id];
961 
962 	return IS_CLK_OFF(clock);
963 }
964 
phl_fsm_is_alarm_off(struct fsm_obj * obj)965 bool phl_fsm_is_alarm_off(struct fsm_obj *obj)
966 {
967 	struct fsm_clock *clock = &obj->clock[0];
968 
969 	return IS_CLK_OFF(clock);
970 }
971 
fsm_set_alarm(struct fsm_obj * obj,int ms,u16 event,u8 id,void * priv)972 static void fsm_set_alarm(struct fsm_obj *obj, int ms,
973 	u16 event, u8 id, void *priv)
974 {
975 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
976 	struct fsm_clock *clock = &obj->clock[id];
977 	u32 now;
978 
979 	if (ms == 0)
980 		fsm_post_message(obj, event, priv);
981 
982 	_os_spinlock(d, &obj->fsm->clock_lock, _bh, NULL);
983 	/* turn on clock from off */
984 	if (IS_CLK_OFF(clock))
985 		obj->fsm->en_clock_num++;
986 
987 	now = _os_get_cur_time_ms();
988 	clock->event = event;
989 	clock->priv = priv;
990 	clock->start = now;
991 	clock->end = now + ms;
992 	clock->remain = (int)phl_fsm_time_left(clock->start, clock->end);
993 	_os_spinunlock(d, &obj->fsm->clock_lock, _bh, NULL);
994 
995 #ifdef PHL_DBG_FSM
996 	FSM_DBG(obj->fsm, "%s:%s now=0x%08x, end=0x%08x, remain=0x%08x\n",
997 		phl_fsm_obj_name(obj), phl_fsm_evt_name(obj, event),
998 		clock->start, clock->end, clock->remain);
999 #endif
1000 }
1001 
1002 /* For EXTERNAL application to extend alarm time (expose)
1003  *
1004  * @obj: obj param when calling FSM framework function
1005  * @event: alarm will issue this event while timer expired
1006  * @ms: time period for the alarm
1007  *	remain time does not less than 'ms'
1008  * @id: alarm id; start from 1
1009  */
phl_fsm_extend_alarm_ext(struct fsm_obj * obj,int ms,u8 id)1010 void phl_fsm_extend_alarm_ext(struct fsm_obj *obj, int ms, u8 id)
1011 
1012 {
1013 	struct fsm_clock *clk = &obj->clock[id];
1014 	int remain = ms;
1015 
1016 	if (id == 0 || id >= CLOCK_NUM) {
1017 		PHL_ERR("%s: %s_%d fail\n",
1018 			phl_fsm_obj_name(obj), __func__, id);
1019 		return;
1020 	}
1021 
1022 	if (IS_CLK_OFF(clk))
1023 		return;
1024 
1025 	remain = MAX((int)phl_fsm_time_left(clk->start, clk->end), ms);
1026 	phl_fsm_set_alarm_ext(obj, remain, clk->event, id, clk->priv);
1027 }
1028 
1029 /* For EXTERNAL application to setup alarm (expose)
1030  *
1031  * @obj: obj param when calling FSM framework function
1032  * @event: alarm will issue this event while timer expired
1033  * @ms: time period for the alarm
1034  * @id: alarm id; start from 1
1035  */
phl_fsm_set_alarm(struct fsm_obj * obj,int ms,u16 event)1036 void phl_fsm_set_alarm(struct fsm_obj *obj, int ms, u16 event)
1037 {
1038 	fsm_set_alarm(obj, ms, event, 0, NULL);
1039 }
1040 
1041 /* For EXTERNAL application to setup alarm_ext (expose)
1042  *
1043  * @obj: obj param when calling FSM framework function
1044  * @event: alarm will issue this event while timer expired
1045  * @ms: time period for the alarm
1046  * @id: alarm id; start from 1
1047  * @priv: priv from caller
1048  */
phl_fsm_set_alarm_ext(struct fsm_obj * obj,int ms,u16 event,u8 id,void * priv)1049 void phl_fsm_set_alarm_ext(struct fsm_obj *obj,
1050 	int ms, u16 event, u8 id, void *priv)
1051 {
1052 	if (id >= CLOCK_NUM) {
1053 		PHL_ERR("%s: set alarm_ext_%d to %d ms fail\n",
1054 			phl_fsm_obj_name(obj), id, ms);
1055 		return;
1056 	}
1057 	fsm_set_alarm(obj, ms, event, id, priv);
1058 }
1059 
fsm_cancel_alarm(struct fsm_obj * obj,u8 id)1060 static void fsm_cancel_alarm(struct fsm_obj *obj, u8 id)
1061 {
1062 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1063 	struct fsm_clock *clock = &obj->clock[id];
1064 
1065 	_os_spinlock(d, &obj->fsm->clock_lock, _bh, NULL);
1066 	/* turn off clock from on */
1067 	if (IS_CLK_ON(clock))
1068 		obj->fsm->en_clock_num--;
1069 
1070 	//obj->clock[id].counter = -1;
1071 	obj->clock[id].end = 0;
1072 	obj->clock[id].remain = -1;
1073 	obj->clock[id].pause = 0;
1074 	_os_spinunlock(d, &obj->fsm->clock_lock, _bh, NULL);
1075 }
1076 
1077 /* For EXTERNAL application to cancel alarm (expose)
1078  *
1079  * @obj: obj param when calling FSM framework function
1080  */
phl_fsm_cancel_alarm(struct fsm_obj * obj)1081 void phl_fsm_cancel_alarm(struct fsm_obj *obj)
1082 {
1083 	fsm_cancel_alarm(obj, 0);
1084 }
1085 
1086 /* For EXTERNAL application to cancel alarm_ext (expose)
1087  *
1088  * @obj: obj param when calling FSM framework function
1089  * @id: alarm id; start from 1
1090  */
phl_fsm_cancel_alarm_ext(struct fsm_obj * obj,u8 id)1091 void phl_fsm_cancel_alarm_ext(struct fsm_obj *obj, u8 id)
1092 {
1093 	if (id == 0 || id >= CLOCK_NUM) {
1094 		PHL_ERR("%s: cancel alarm_ext_%d fail\n",
1095 			phl_fsm_obj_name(obj), id);
1096 		return;
1097 	}
1098 	fsm_cancel_alarm(obj, id);
1099 }
1100 
fsm_pause_alarm(struct fsm_obj * obj,u8 id)1101 static void fsm_pause_alarm(struct fsm_obj *obj, u8 id)
1102 {
1103 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1104 
1105 	_os_spinlock(d, &obj->fsm->clock_lock, _bh, NULL);
1106 	obj->clock[id].pause = 1;
1107 	_os_spinunlock(d, &obj->fsm->clock_lock, _bh, NULL);
1108 }
1109 
1110 /* For EXTERNAL application to pause alarm (expose)
1111  *
1112  * @obj: obj param when calling FSM framework function
1113  */
phl_fsm_pause_alarm(struct fsm_obj * obj)1114 void phl_fsm_pause_alarm(struct fsm_obj *obj)
1115 {
1116 	fsm_pause_alarm(obj, 0);
1117 }
1118 
1119 /* For EXTERNAL application to pause alarm_ext (expose)
1120  *
1121  * @obj: obj param when calling FSM framework function
1122  * @id: alarm id; start from 1
1123  */
phl_fsm_pause_alarm_ext(struct fsm_obj * obj,u8 id)1124 void phl_fsm_pause_alarm_ext(struct fsm_obj *obj, u8 id)
1125 {
1126 	if (id == 0 || id >= CLOCK_NUM) {
1127 		PHL_ERR("%s: pause alarm_%d fail\n", phl_fsm_obj_name(obj), id);
1128 		return;
1129 	}
1130 	fsm_pause_alarm(obj, id);
1131 }
1132 
fsm_resume_alarm(struct fsm_obj * obj,u8 id)1133 static void fsm_resume_alarm(struct fsm_obj *obj, u8 id)
1134 {
1135 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1136 	u32 cur = _os_get_cur_time_ms();
1137 
1138 	/* extrend end time */
1139 	_os_spinlock(d, &obj->fsm->clock_lock, _bh, NULL);
1140 	obj->clock[id].end = cur + obj->clock[id].remain;
1141 	obj->clock[id].pause = 0;
1142 	_os_spinunlock(d, &obj->fsm->clock_lock, _bh, NULL);
1143 }
1144 
1145 /* For EXTERNAL application to resume alarm (expose)
1146  *
1147  * @obj: obj param when calling FSM framework function
1148  */
phl_fsm_resume_alarm(struct fsm_obj * obj)1149 void phl_fsm_resume_alarm(struct fsm_obj *obj)
1150 {
1151 	fsm_resume_alarm(obj, 0);
1152 }
1153 
1154 /* For EXTERNAL application to resume alarm_ext (expose)
1155  *
1156  * @obj: obj param when calling FSM framework function
1157  * @id: alarm id; start from 1
1158  */
phl_fsm_resume_alarm_ext(struct fsm_obj * obj,u8 id)1159 void phl_fsm_resume_alarm_ext(struct fsm_obj *obj, u8 id)
1160 {
1161 	if (id == 0 || id >= CLOCK_NUM) {
1162 		PHL_ERR("%s: resume alarm_ext_%d fail\n",
1163 			phl_fsm_obj_name(obj), id);
1164 		return;
1165 	}
1166 	fsm_resume_alarm(obj, id);
1167 }
1168 
1169 /* For EXTERNAL application to change state (expose)
1170  *
1171  * @obj: obj that changes state
1172  * @new_state: new state
1173  */
phl_fsm_state_goto(struct fsm_obj * obj,u8 new_state)1174 void phl_fsm_state_goto(struct fsm_obj *obj, u8 new_state)
1175 {
1176 	struct fsm_main *fsm = NULL;
1177 
1178 	if (obj->state == new_state)
1179 		return;
1180 
1181 	fsm = obj->fsm;
1182 
1183 	fsm_state_run(obj, FSM_EV_STATE_OUT, NULL);
1184 
1185 	FSM_MSG(fsm, FSM_DBG_DBG, "\n");
1186 	FSM_MSG(fsm, FSM_DBG_DBG, "%s-%d %-18s -> %s\n", fsm->name, obj->oid,
1187 		fsm_state_name(fsm, obj->state),
1188 		fsm_state_name(fsm, new_state));
1189 
1190 	obj->state = new_state; /* new state */
1191 	fsm_state_run(obj, FSM_EV_STATE_IN, NULL);
1192 }
1193 
fsm_user_evt_handler(struct fsm_main * fsm)1194 static void fsm_user_evt_handler(struct fsm_main *fsm)
1195 {
1196 	void *d = phl_to_drvpriv(fsm->phl_info);
1197 	struct fsm_msg *msg;
1198 	struct fsm_obj *obj;
1199 	int rtn = FSM_FREE_PARAM;
1200 
1201 
1202 	while ((msg = fsm_dequeue_msg(fsm)) != NULL) {
1203 
1204 		rtn = FSM_FREE_PARAM;
1205 		obj = fsm_get_obj(fsm, msg->oid);
1206 
1207 		if (obj == NULL) {
1208 			PHL_WARN("%s-%d: obj not found\n",
1209 				fsm->name, msg->oid);
1210 			goto obj_not_found;
1211 		}
1212 
1213 		/* DO NOT deliver event when fsm->should_stop is true */
1214 		if ((fsm->should_stop == true) &&
1215 			(obj->state == FSM_INITIAL_STATE) &&
1216 			(msg->event < FSM_INT_EV_MASK)) {
1217 
1218 			PHL_INFO("%s: should stop skip msg %s\n",
1219 				phl_fsm_obj_name(obj),
1220 				phl_fsm_evt_name(obj, msg->event));
1221 				goto skip_msg;
1222 		}
1223 
1224 		/* run state machine */
1225 		rtn = fsm_state_run(obj, msg->event, msg->param);
1226 skip_msg:
1227 obj_not_found:
1228 		if ((rtn == FSM_FREE_PARAM) &&
1229 			(msg->param_sz > 0) &&
1230 			(msg->param != NULL))
1231 			_os_kmem_free(d, (void *)msg->param, msg->param_sz);
1232 		_os_kmem_free(d, (void *)msg, sizeof(*msg));
1233 	}
1234 }
1235 
fsm_update_status(struct fsm_main * fsm)1236 static int fsm_update_status(struct fsm_main *fsm)
1237 {
1238 	struct fsm_obj *obj;
1239 
1240 	phl_list_for_loop(obj, struct fsm_obj, &fsm->obj_queue.q, list) {
1241 		if (obj->state != FSM_INITIAL_STATE) {
1242 			PHL_INFO("%s: state %s\n",
1243 				phl_fsm_obj_name(obj),
1244 				fsm_state_name(fsm, obj->state));
1245 			return 0;
1246 		}
1247 	}
1248 
1249 	/* all objs are at INITAL_STATE
1250 	 * fsm module is ready to stop
1251 	 */
1252 	fsm_status_set(fsm, FSM_STATUS_INITIALIZED);
1253 
1254 	return 0;
1255 }
1256 
fsm_handler(struct fsm_main * fsm)1257 static int fsm_handler(struct fsm_main *fsm)
1258 {
1259 	/* USER EVENT */
1260 	fsm_user_evt_handler(fsm);
1261 
1262 	if (fsm->should_stop == true)
1263 		fsm_update_status(fsm);
1264 
1265 	return 0;
1266 }
1267 
1268 /* For EXTERNAL application to get fsm name (expose)
1269  * @fsm: fsm to be get name
1270  */
phl_fsm_fsm_name(struct fsm_main * fsm)1271 char *phl_fsm_fsm_name(struct fsm_main *fsm)
1272 {
1273 	return fsm->name;
1274 }
1275 
1276 /* For EXTERNAL application to get obj name (expose)
1277  * @obj: obj to be get name
1278  * For example: scan-1 (sacn obj with object id 1)
1279  */
phl_fsm_obj_name(struct fsm_obj * obj)1280 char *phl_fsm_obj_name(struct fsm_obj *obj)
1281 {
1282 	return obj->name;
1283 }
1284 
1285 /* For EXTERNAL application to cancel sma (expose)
1286  * @obj: obj job will be cancelled
1287  */
phl_fsm_cancel_obj(struct fsm_obj * obj)1288 enum rtw_phl_status phl_fsm_cancel_obj(struct fsm_obj *obj)
1289 {
1290 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1291 	struct fsm_msg *msg;
1292 	int rtn;
1293 
1294 	/* NEW message to cancel obj task */
1295 	msg = phl_fsm_new_msg(obj, FSM_EV_CANCEL);
1296 	if (msg == NULL) {
1297 		PHL_ERR("%s: alloc msg fail\n", obj->fsm->name);
1298 		return RTW_PHL_STATUS_RESOURCE;
1299 	}
1300 	rtn = phl_fsm_sent_msg(obj, msg);
1301 
1302 	if (rtn != RTW_PHL_STATUS_SUCCESS)
1303 		_os_kmem_free(d, msg, sizeof(*msg));
1304 
1305 	return rtn;
1306 }
1307 
1308 /* For EXTERNAL application to init FSM framework (expose) */
1309 /* @obj: obj job will be cancelled
1310  */
phl_fsm_init_root(void * priv)1311 struct fsm_root *phl_fsm_init_root(void *priv)
1312 {
1313 #ifdef PHL_INCLUDE_FSM
1314 	struct fsm_root *root;
1315 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
1316 	void *d = phl_to_drvpriv(phl_info);
1317 	int max, size;
1318 
1319 	/* check size of internal event table */
1320 	max = FSM_EV_MAX & ~(int_event_tbl[0].event);
1321 	size = sizeof(int_event_tbl)/sizeof(int_event_tbl)[0];
1322 	if (size != max + 1) {
1323 		PHL_ERR("fsm: int_event_tbl[%d] != %d size mismatch!!",
1324 			size, max);
1325 		return NULL;
1326 	}
1327 	root = (struct fsm_root *)_os_kmem_alloc(d, sizeof(*root));
1328 	if (root == NULL)
1329 		return NULL;
1330 
1331 	_os_mem_set(d, root, 0, sizeof(*root));
1332 	fsm_init_queue(d, &(root->q_share_thd));
1333 	fsm_init_queue(d, &(root->q_alone_thd));
1334 
1335 	_os_sema_init(d, &root->msg_ready, 0);
1336 	root->phl_info = phl_info;
1337 
1338 	PHL_INFO("fsm: [root] initialized\n");
1339 	return root;
1340 #else
1341 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
1342 	return 0;
1343 #endif /* PHL_INCLUDE_FSM */
1344 }
1345 
1346 /* For EXTERNAL application to deinit FSM framework (expose)
1347  * @root: FSM framework handler
1348  */
phl_fsm_deinit_root(struct fsm_root * root)1349 void phl_fsm_deinit_root(struct fsm_root *root)
1350 {
1351 #ifdef PHL_INCLUDE_FSM
1352 	void *d = phl_to_drvpriv(root->phl_info);
1353 	void *c = NULL;
1354 
1355 	fsm_deinit_queue(d, &(root->q_alone_thd));
1356 	fsm_deinit_queue(d, &(root->q_share_thd));
1357 
1358 	_os_sema_free(d, &root->msg_ready);
1359 
1360 	/* free fsm_root */
1361 	_os_kmem_free(d, root, sizeof(*root));
1362 
1363 	FSM_INFO(c, "fsm: [root] uninitilized\n");
1364 #else
1365 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
1366 #endif /* PHL_INCLUDE_FSM */
1367 }
1368 
1369 /* For EXTERNAL application to start fsm root (expose)
1370  * @fsm: see struct fsm_main
1371  */
phl_fsm_start_root(struct fsm_root * root)1372 enum rtw_phl_status phl_fsm_start_root(struct fsm_root *root)
1373 {
1374 	void *d = phl_to_drvpriv(root->phl_info);
1375 
1376 #ifdef CONFIG_LINUX_THREAD
1377 	root->thread = kthread_create(fsm_thread_share, root,
1378 			"fsm_thread_share");
1379 	wake_up_process(root->thread);
1380 #else
1381 	_os_thread_init(d, &(root->thread), fsm_thread_share, root,
1382 			"fsm_thread_share");
1383 	_os_thread_schedule(d, &(root->thread));
1384 #endif
1385 	return RTW_PHL_STATUS_SUCCESS;
1386 }
1387 
1388 /* For EXTERNAL application to stop fsm root (expose)
1389  * @fsm: see struct fsm_main
1390  */
phl_fsm_stop_root(struct fsm_root * root)1391 enum rtw_phl_status phl_fsm_stop_root(struct fsm_root *root)
1392 {
1393 	void *d = phl_to_drvpriv(root->phl_info);
1394 	void *c = NULL;
1395 
1396 	_os_thread_stop(d, &(root->thread));
1397 	_os_sema_up(d, &root->msg_ready);
1398 	_os_thread_deinit(d, &(root->thread));
1399 
1400 	FSM_INFO(c, "fsm: [root] stopped\n");
1401 
1402 	return RTW_PHL_STATUS_SUCCESS;
1403 }
1404 
1405 /* For EXTERNAL application to start fsm (expose)
1406  * @fsm: see struct fsm_main
1407  */
phl_fsm_start_fsm(struct fsm_main * fsm)1408 enum rtw_phl_status phl_fsm_start_fsm(struct fsm_main *fsm)
1409 {
1410 	void *d = phl_to_drvpriv(fsm->phl_info);
1411 	struct fsm_obj *obj;
1412 
1413 	phl_list_for_loop(obj, struct fsm_obj, &fsm->obj_queue.q, list) {
1414 		fsm_obj_switch_in(obj);
1415 	}
1416 	if (fsm->tb.mode == FSM_ALONE_THREAD) {
1417 		_os_thread_init(d, &(fsm->thread), fsm_thread_alone, fsm,
1418 				"fsm_thread_alone");
1419 		_os_thread_schedule(d, &(fsm->thread));
1420 	}
1421 
1422 	_os_set_timer(d, &fsm->fsm_timer, CLOCK_UNIT);
1423 	fsm->status = FSM_STATUS_READY;
1424 
1425 	fsm_status_set(fsm, FSM_STATUS_ENABLE);
1426 	FSM_INFO(fsm, "fsm: [%s] started\n", fsm->name);
1427 
1428 	return RTW_PHL_STATUS_SUCCESS;
1429 }
1430 
1431 #define WAIT_DUR 10
1432 #define WAIT_TIMES 20
1433 /* For EXTERNAL application to stop fsm (expose)
1434  * @fsm: see struct fsm_main
1435  */
phl_fsm_stop_fsm(struct fsm_main * fsm)1436 enum rtw_phl_status phl_fsm_stop_fsm(struct fsm_main *fsm)
1437 {
1438 	void *d = phl_to_drvpriv(fsm->phl_info);
1439 	struct fsm_obj *obj;
1440 	int wait = WAIT_TIMES;
1441 
1442 	fsm->should_stop = true;
1443 
1444 	/* CANCEL all objs within fsm */
1445 	fsm_cancel_all_running_obj(fsm);
1446 
1447 	/* wait fsm module finish its task elegantly */
1448 	while ((fsm->status != FSM_STATUS_INITIALIZED) && --wait)
1449 		_os_sleep_ms(d, WAIT_DUR);
1450 
1451 	if (wait < (WAIT_TIMES >> 1))
1452 		FSM_INFO(fsm, "%s: take %dms to disable\n",
1453 			fsm->name, (WAIT_TIMES-wait)*WAIT_DUR);
1454 
1455 	fsm_status_set(fsm, FSM_STATUS_DISABLE);
1456 
1457 	_os_spinlock(d, &fsm->clock_lock, _bh, NULL);
1458 	_os_cancel_timer(d, &fsm->fsm_timer);
1459 	_os_spinunlock(d, &fsm->clock_lock, _bh, NULL);
1460 
1461 	phl_list_for_loop(obj, struct fsm_obj, &fsm->obj_queue.q, list) {
1462 		fsm_obj_switch_out(obj);
1463 		phl_fsm_flush_gbl(obj);
1464 	}
1465 	fsm_remove_all_queuing_msg(fsm);
1466 
1467 	if (fsm->tb.mode == FSM_ALONE_THREAD) {
1468 		_os_thread_stop(d, &(fsm->thread));
1469 		_os_sema_up(d, &fsm->msg_ready);
1470 		_os_thread_deinit(d, &(fsm->thread));
1471 	}
1472 	fsm->should_stop = false;
1473 
1474 	FSM_INFO(fsm, "fsm: [%s] stopped\n", fsm->name);
1475 
1476 	return RTW_PHL_STATUS_SUCCESS;
1477 }
1478 
1479 /* For EXTERNAL application to generate message buffer (expose)
1480  * Generate message quickly and simply
1481  * @phl: phl_info_t
1482  * @obj: fsm_obj (msg receiver)
1483  * @pbuf: message parameter
1484  * @sz: message parameter size
1485  * @event: event for the message
1486  */
phl_fsm_gen_msg(void * phl,struct fsm_obj * obj,void * pbuf,u32 sz,u16 event)1487 enum rtw_phl_status phl_fsm_gen_msg(void *phl, struct fsm_obj *obj,
1488 	void *pbuf, u32 sz, u16 event)
1489 {
1490 #ifdef PHL_INCLUDE_FSM
1491 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1492 	struct fsm_msg *msg;
1493 	void *d = phl_to_drvpriv(phl_info);
1494 	void *param = NULL;
1495 	int rtn = RTW_PHL_STATUS_RESOURCE;
1496 
1497 	/* NEW mem for message */
1498 	msg = phl_fsm_new_msg(obj, event);
1499 	if (msg == NULL) {
1500 		FSM_ERR(obj->fsm, "%s: alloc msg %s fail\n",
1501 			phl_fsm_obj_name(obj),
1502 			phl_fsm_evt_name(obj, event));
1503 		goto msg_fail;
1504 	}
1505 
1506 	/* NEW mem for param */
1507 	if (pbuf && sz) {
1508 		param = _os_kmem_alloc(d, sz);
1509 		if (param == NULL) {
1510 			FSM_ERR(obj->fsm,
1511 				"%s: alloc param %s fail\n",
1512 				phl_fsm_obj_name(obj),
1513 				phl_fsm_evt_name(obj, event));
1514 			goto param_fail;
1515 		}
1516 		_os_mem_cpy(d, param, pbuf, sz);
1517 	}
1518 	msg->param = (void *)param;
1519 	msg->param_sz = sz;
1520 
1521 	rtn = phl_fsm_sent_msg(obj, msg);
1522 
1523 	if (rtn != RTW_PHL_STATUS_SUCCESS)
1524 		goto send_fail;
1525 
1526 	return rtn;
1527 
1528 send_fail:
1529 	if (msg->param && msg->param_sz)
1530 		_os_kmem_free(d, msg->param, msg->param_sz);
1531 param_fail:
1532 	_os_kmem_free(d, msg, sizeof(*msg));
1533 msg_fail:
1534 
1535 	return rtn;
1536 #else
1537 	PHL_WARN("fsm: %s exclude FSM\n", __func__);
1538 	return RTW_PHL_STATUS_FAILURE;
1539 #endif /* PHL_INCLUDE_FSM */
1540 }
1541 
phl_fsm_flush_gbl(struct fsm_obj * obj)1542 enum rtw_phl_status phl_fsm_flush_gbl(struct fsm_obj *obj)
1543 {
1544 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1545 	struct gbl_param *p;
1546 
1547 	_os_mem_set(d, &obj->my_gbl_req, 0, sizeof(obj->my_gbl_req));
1548 
1549 	/* flush obj->gbl_queue */
1550 	phl_list_for_loop(p,
1551 		struct gbl_param, &obj->gbl_queue.q, list) {
1552 
1553 		list_del(&p->list);
1554 		FSM_WARN(obj->fsm, "%s: del non replied %s:%s #%d\n",
1555 			phl_fsm_obj_name(obj),
1556 			phl_fsm_obj_name(p->obj_from),
1557 			phl_fsm_evt_name(obj, p->event), p->seq);
1558 
1559 		_os_kmem_free(d, (void *)p, sizeof(*p));
1560 	}
1561 	obj->gbl_q_len = 0;
1562 
1563 	return RTW_PHL_STATUS_SUCCESS;
1564 }
1565 
1566 /* For EXTERNAL fsm module to announce global msg (expose)
1567  *
1568  * !!! ONLY ALLOW fsm MODULE to call !!!
1569  * !!! Otherwise will have reaing issue !!!
1570  *
1571  * Global msg will go throughs all fsm modules
1572  * Limitation:
1573  *	Only supports ONE Glboal announcement at a time
1574  *	The latest one always overwrite previous one
1575  *
1576  * reference: phl_fsm_gbl_not_reply_num()
1577  *
1578  * @obj: fsm_obj
1579  * @gbl_evt: Global event to be announced
1580  * @cb_evt: call back event when things was done
1581  * return: wait time(ms); 0: success, waiting is not necessary
1582  *	when wait > 0; callee will reply event to caller within ms
1583  *	negative value: fail
1584  */
phl_fsm_gbl_msg_announce(struct fsm_obj * obj,u16 gbl_evt,u16 cb_evt)1585 int phl_fsm_gbl_msg_announce(struct fsm_obj *obj, u16 gbl_evt, u16 cb_evt)
1586 {
1587 	struct fsm_root *root = obj->fsm->root;
1588 	void *d = phl_to_drvpriv(root->phl_info);
1589 	struct fsm_main *fsm = obj->fsm;
1590 	struct fsm_main *fsm_t;
1591 	struct fsm_obj *obj_t;
1592 	int i;
1593 
1594 	if (obj->my_gbl_req.count > 0) {
1595 		/* Should not happen!!
1596 		 * Have ongoing announcement
1597 		 * We are waiting for some GBL event reply
1598 		 */
1599 		for (i = 0; i < PHL_FSM_MAX_WAIT_OCUNT; i++) {
1600 			if (obj->my_gbl_req.wait_list[i])
1601 				FSM_WARN(fsm,
1602 					"%s: drop not replied %s:%s #%d\n",
1603 					phl_fsm_obj_name(obj),
1604 					phl_fsm_obj_name(
1605 						obj->my_gbl_req.wait_list[i]),
1606 					phl_fsm_evt_name(obj,
1607 						obj->my_gbl_req.event),
1608 					obj->my_gbl_req.seq);
1609 		}
1610 	}
1611 
1612 	/* create param for announcement */
1613 	_os_mem_set(d, &obj->my_gbl_req, 0, sizeof(obj->my_gbl_req));
1614 	obj->my_gbl_req.event = gbl_evt;
1615 	obj->my_gbl_req.cb_evt = cb_evt;
1616 	obj->my_gbl_req.obj_from = obj;
1617 	if (obj->fsm->root->gbl_seq == 0) /* 0 reserved */
1618 		obj->fsm->root->gbl_seq = 1;
1619 	obj->my_gbl_req.seq = obj->fsm->root->gbl_seq++;
1620 
1621 	/* GLOBAL EVENT will go through all fsms */
1622 	phl_list_for_loop(fsm_t, struct fsm_main, &root->q_share_thd.q, list) {
1623 		if (fsm_status(fsm_t) != FSM_STATUS_ENABLE) {
1624 			FSM_INFO(fsm_t, "fsm: [%s] disabled, skip %s\n",
1625 				phl_fsm_fsm_name(fsm_t),
1626 				phl_fsm_evt_name(obj, gbl_evt));
1627 				continue;
1628 		}
1629 		/* go through objs */
1630 		phl_list_for_loop(obj_t, struct fsm_obj,
1631 			&fsm_t->obj_queue.q, list) {
1632 
1633 			/* skip myself */
1634 			if (obj_t == obj)
1635 				continue;
1636 
1637 			fsm_state_run(obj_t, gbl_evt, &obj->my_gbl_req);
1638 
1639 			if (obj->my_gbl_req.result < 0) {
1640 				FSM_ERR(fsm_t,
1641 					"%s: announce %s to %s fail(%d)\n",
1642 					phl_fsm_obj_name(obj),
1643 					phl_fsm_evt_name(obj_t, gbl_evt),
1644 					phl_fsm_obj_name(obj_t),
1645 					obj->my_gbl_req.result);
1646 
1647 				return obj->my_gbl_req.result;
1648 			}
1649 		}
1650 	}
1651 	return obj->my_gbl_req.wait_ms;
1652 }
1653 
1654 /** For GBL announcer to get the number of un-replied fsm (espose)
1655  *
1656  * !!! ONLY ALLOW fsm MODULE to call !!!
1657  *
1658  * reference: phl_fsm_gbl_msg_announce()
1659  * @obj: fsm_obj
1660  * @param: see gbl_param
1661  * return: 0 means there is no non-reply reqest, it's ready to go;
1662  *	   otherwise yet ready
1663  */
phl_fsm_gbl_not_reply_num(struct fsm_obj * obj,struct gbl_param * param)1664 int phl_fsm_gbl_not_reply_num(struct fsm_obj *obj, struct gbl_param *param)
1665 {
1666 	if (param == NULL)
1667 		return obj->my_gbl_req.count;
1668 
1669 	/* we don't have any waitting reply; GBL may be cancelled earlier */
1670 	if (obj->my_gbl_req.obj_from == NULL) {
1671 		FSM_WARN(obj->fsm, "%s: doesn't expect reply %s:%s #%d\n",
1672 			phl_fsm_obj_name(obj),
1673 			phl_fsm_obj_name(param->obj_to),
1674 			phl_fsm_evt_name(obj, param->event), param->seq);
1675 		return -1;
1676 	}
1677 	/* Are we looking for receiving event ? */
1678 	if (param->event != obj->my_gbl_req.event)
1679 		return -2;
1680 
1681 	if (param->seq != obj->my_gbl_req.seq)
1682 		return -3;
1683 
1684 	FSM_INFO(obj->fsm, "%s: got reply %s:%s #%d\n",
1685 		phl_fsm_obj_name(obj),
1686 		phl_fsm_obj_name(param->obj_to),
1687 		phl_fsm_evt_name(obj, param->event), param->seq);
1688 
1689 	/* clear incoming reporter from waitting list */
1690 	param->wait_list[param->count] = NULL;
1691 
1692 	return --obj->my_gbl_req.count;
1693 }
1694 
1695 /** For Global event reciver to inform announcer to wait confirmation (espose)
1696  *
1697  * !!! ONLY ALLOW fsm MODULE to call !!!
1698  *
1699  * Call the function if Global receiver know that it can't finish task in time
1700  * Global event receiver expect FSM_EV_GBL_REPLY to confirm task is finish
1701  * reference : phl_fsm_gbl_msg_release()
1702  *
1703  * @obj: see fsm_obj
1704  * @param: see gbl_param
1705  * @ms: How long(max) can finish task according to received Global event
1706  *	caller will set an alarm to react if we can't finish the job on time
1707  * return: negative value : fail
1708  *	   postive value : seq number of this GBL event
1709  */
phl_fsm_gbl_msg_hold(struct fsm_obj * obj,struct gbl_param * param,u32 ms)1710 int phl_fsm_gbl_msg_hold(struct fsm_obj *obj,
1711 	struct gbl_param *param, u32 ms)
1712 {
1713 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1714 	struct gbl_param *p;
1715 
1716 	if (param->count >= PHL_FSM_MAX_WAIT_OCUNT) {
1717 		param->result = -(GBL_ST_WAIT_REACH_MAX);
1718 		FSM_ERR(obj->fsm, "%s: hold %s reach max counter %d (%d)",
1719 			phl_fsm_obj_name(obj),
1720 			phl_fsm_evt_name(obj, param->event), param->count,
1721 			param->result);
1722 		return param->result;
1723 	}
1724 
1725 	if (obj->gbl_q_len >= PHL_FSM_MAX_WAIT_OCUNT) {
1726 		param->result = -(GBL_ST_REPLY_REACH_MAX);
1727 		FSM_ERR(obj->fsm, "%s: reply %s reach max counter %d (%d)",
1728 			phl_fsm_obj_name(obj),
1729 			phl_fsm_evt_name(obj, param->event),
1730 			obj->gbl_q_len, param->result);
1731 		return param->result;
1732 	}
1733 
1734 	p = (struct gbl_param *)_os_kmem_alloc(d, sizeof(*p));
1735 
1736 	if (p == NULL) {
1737 		param->result = -GBL_ST_ALLOC_MEM_FAIL;
1738 		FSM_ERR(obj->fsm, "%s: reply %s, alloc mem fail (%d)",
1739 			phl_fsm_obj_name(obj),
1740 			phl_fsm_evt_name(obj, param->event),
1741 			param->result);
1742 		return param->result;
1743 	}
1744 
1745 	/* fill info to inform caller that we need time to process */
1746 	param->obj_to = obj;
1747 	param->wait_list[param->count] = obj;
1748 	param->wait_ms = MAX(param->wait_ms, ms);
1749 	param->count++;
1750 
1751 	/* save param for replying later */
1752 	_os_mem_cpy(d, p, (void *)param, sizeof(*param));
1753 	fsm_enqueue_list(d, obj->fsm, &obj->gbl_queue, &p->list);
1754 
1755 	FSM_DBG(obj->fsm, "%s: require %d ms to handle %s:%s #%d\n",
1756 			phl_fsm_obj_name(obj), ms,
1757 			phl_fsm_obj_name(param->obj_from),
1758 			phl_fsm_evt_name(obj, param->event),
1759 			param->seq);
1760 
1761 	return p->seq;
1762 }
1763 
1764 /** For Global event reciver to inform announcer that task was done (espose)
1765  *
1766  * !!! ONLY ALLOW fsm MODULE to call !!!
1767  *
1768  * Call the function when Global receiver finish the task
1769  * This is a ASYNC confirmation to Global event announcer
1770  * Global event announcer will receive FSM_EV_GBL_REPLY when function is called
1771  * reference: phl_fsm_gbl_msg_hold()
1772  *
1773  * @obj: see fsm_obj
1774  * @param: see gbl_param
1775  * @obj: see fsm_obj
1776  * @event: event to be replied
1777  * @seq: event to be replied
1778  * @result: result to be replied
1779  */
phl_fsm_gbl_msg_release(struct fsm_obj * obj,u16 event,u32 seq,enum gbl_evt_result result)1780 enum rtw_phl_status phl_fsm_gbl_msg_release(struct fsm_obj *obj,
1781 	u16 event, u32 seq, enum gbl_evt_result result)
1782 {
1783 	void *d = phl_to_drvpriv(obj->fsm->phl_info);
1784 	struct gbl_param *p, *p_t;
1785 
1786 	/* handle multiple Global event requests
1787 	 * go through link list to get reply param according to event
1788 	 */
1789 
1790 	phl_list_for_loop_safe(p, p_t,
1791 		struct gbl_param, &obj->gbl_queue.q, list) {
1792 		if ((event == p->event) && (seq == p->seq)) {
1793 
1794 			p->result = result;
1795 			FSM_INFO(obj->fsm, "%s: reply %s:%s #%d, result %d\n",
1796 				phl_fsm_obj_name(obj),
1797 				phl_fsm_obj_name(p->obj_from),
1798 				phl_fsm_evt_name(obj, event), p->seq, result);
1799 
1800 			phl_fsm_gen_msg(obj->fsm->phl_info, p->obj_from,
1801 				p, sizeof(*p), p->cb_evt);
1802 
1803 			list_del(&p->list);
1804 			_os_kmem_free(d, (void *)p, sizeof(*p));
1805 			break;
1806 		}
1807 	}
1808 	return RTW_PHL_STATUS_SUCCESS;
1809 }
1810 
1811 /** Debug funcitons
1812  *
1813  */
1814 #ifdef PHL_DEBUG_FSM
fsm_dbg_dump_fsm_queue(struct fsm_queue * fsmq,char * s,int * sz,bool detail)1815 static void fsm_dbg_dump_fsm_queue(struct fsm_queue *fsmq,
1816 	char *s, int *sz,bool detail)
1817 {
1818 	struct fsm_main *fsm, *fsm_t;
1819 
1820 	char *ptr = s;
1821 	int len = *sz;
1822 
1823 	phl_list_for_loop_safe(fsm, fsm_t,
1824 		struct fsm_main, &fsmq->q, list) {
1825 		_os_snprintf(pstr(ptr), lstr(ptr, len), "\t%4s : %s\n", fsm->name,
1826 			fsm->tb.mode ? "STANDALONE":"SHARE");
1827 
1828 		if (fsm->tb.dump_fsm && detail) {
1829 			len = lstr(ptr, len);
1830 			ptr = pstr(ptr);
1831 			fsm->tb.dump_fsm(fsm, ptr, &len);
1832 		}
1833 	}
1834 	*sz = len;
1835 }
1836 
1837 static void fsm_dbg_help(struct fsm_main *fsm, char *s, int *sz, bool detail);
fsm_dbg_dump_fsm(struct fsm_main * fsm,char * s,int * sz,bool detail)1838 static void fsm_dbg_dump_fsm(struct fsm_main *fsm,
1839 	char *s, int *sz, bool detail)
1840 {
1841 	int len = *sz;
1842 	char *ptr = s;
1843 
1844 	_os_snprintf(pstr(ptr), lstr(ptr, len), "\t%4s : %s\n", fsm->name,
1845 		fsm->tb.mode ? "STANDALONE":"SHARE");
1846 
1847 	if (fsm->tb.dump_fsm && detail) {
1848 		len = lstr(ptr, len);
1849 		ptr = pstr(ptr);
1850 		fsm->tb.dump_fsm(fsm, ptr, &len);
1851 	}
1852 
1853 }
1854 
fsm_dbg_dump_state(struct fsm_main * fsm,char * s,int * sz,bool detail)1855 static void fsm_dbg_dump_state(struct fsm_main *fsm,
1856 	char *s, int *sz, bool detail)
1857 {
1858 	int i;
1859 	int len = *sz;
1860 
1861 	_os_snprintf(pstr(s), lstr(s, len),
1862 		"[%s] state table\n", fsm->name);
1863 	for (i = 0; i < fsm->tb.max_state; i++)
1864 		_os_snprintf(pstr(s), lstr(s, len), "\t%4d : %s\n",
1865 			i, fsm->tb.state_tbl[i].name);
1866 	*sz = len;
1867 }
1868 
fsm_dbg_dump_event(struct fsm_main * fsm,char * s,int * sz,bool detail)1869 static void fsm_dbg_dump_event(struct fsm_main *fsm,
1870 	char *s, int *sz, bool detail)
1871 {
1872 	int i, max;
1873 	int len = *sz;
1874 
1875 	/* internal event */
1876 	_os_snprintf(pstr(s), lstr(s, len), "[Internal] event table\n");
1877 
1878 	max = FSM_EV_END & ~(int_event_tbl[0].event); /* FSM_INT_EV_MASK */
1879 	for (i = 1; i < max; i++)
1880 		_os_snprintf(pstr(s), lstr(s, len), "\t0x%4x : %s\n",
1881 			int_event_tbl[i].event, int_event_tbl[i].name);
1882 
1883 	/* user event */
1884 	_os_snprintf(pstr(s), lstr(s, len), "\n[%s] event table max %d\n", fsm->name, fsm->tb.max_event);
1885 	for (i = 0; i < fsm->tb.max_event-1; i++)
1886 		_os_snprintf(pstr(s), lstr(s, len), "\t0x%4x : %s\n",
1887 			fsm->tb.evt_tbl[i].event, fsm->tb.evt_tbl[i].name);
1888 	*sz = len;
1889 }
1890 
fsm_dbg_dump_obj(struct fsm_main * fsm,char * s,int * sz,bool detail)1891 static void fsm_dbg_dump_obj(struct fsm_main *fsm,
1892 	char *s, int *sz, bool detail)
1893 {
1894 	struct fsm_obj *obj, *obj_t;
1895 	int len = *sz;
1896 	char *ptr = s;
1897 
1898 	phl_list_for_loop_safe(obj, obj_t,
1899 		struct fsm_obj, &fsm->obj_queue.q, list) {
1900 
1901 		_os_snprintf(pstr(ptr), lstr(ptr, len), "%s-%d : state %s",
1902 			fsm->name, obj->oid, fsm_state_name(fsm, obj->state));
1903 
1904 		if (fsm->tb.dump_obj && detail) {
1905 			len = lstr(ptr, len);
1906 			ptr = pstr(ptr);
1907 			fsm->tb.dump_obj(obj->custom_obj, ptr, &len);
1908 		}
1909 	}
1910 	*sz = len;
1911 }
1912 
fsm_dbg_max(struct fsm_main * fsm,char * s,int * sz,bool detail)1913 static void fsm_dbg_max(struct fsm_main *fsm, char *s, int *sz, bool detail)
1914 {
1915 	int len = *sz;
1916 
1917 	_os_snprintf(pstr(s), lstr(s, len),
1918 		"ERR: fsm %s sould not run to here!!\n", __func__);
1919 	*sz = len;
1920 }
1921 
1922 struct fsm_debug_ent {
1923 	char *opt;
1924 	void (*func)(struct fsm_main *fsm, char *s, int *sz, bool detail);
1925 	char *desc;
1926 };
1927 
1928 struct fsm_debug_ent debug_opt[] = {
1929 	{"help", fsm_dbg_help, "help message"},
1930 	{"fsm", fsm_dbg_dump_fsm, "all fsm name"},
1931 	{"st", fsm_dbg_dump_state, "state name"},
1932 	{"ev", fsm_dbg_dump_event, "event name"},
1933 	{"obj", fsm_dbg_dump_obj, "obj detail"},
1934 	{"max", fsm_dbg_max, "max_opt"}
1935 };
1936 
_fsm_dbg_help(struct fsm_root * root,char * s,int * sz,bool detail)1937 static void _fsm_dbg_help(struct fsm_root *root, char *s, int *sz, bool detail)
1938 {
1939 	int i, max_opt;
1940 	int len = *sz;
1941 	char *ptr = s;
1942 
1943 	_os_snprintf(pstr(ptr), lstr(ptr, len),
1944 		"usage:\tfsm d <fsm_name> <option>\n");
1945 	_os_snprintf(pstr(ptr), lstr(ptr, len),
1946 		"\tfsm p,<obj_name> <priv_dbg_cmd> ....\n");
1947 	_os_snprintf(pstr(ptr), lstr(ptr, len),
1948 		"\tfsm s,<obj_name> <EVENT>\n");
1949 	_os_snprintf(pstr(ptr), lstr(ptr, len),
1950 		"\tfsm w,<fsm_name> <dbg_level|ev_level> <0-5(dbg)>\n");
1951 
1952 	_os_snprintf(pstr(s), lstr(ptr, len), "\nfsm_name:\n");
1953 
1954 	len = lstr(ptr, len);
1955 	ptr = pstr(ptr);
1956 	fsm_dbg_dump_fsm_queue(&root->q_share_thd, ptr, &len, detail);
1957 
1958 	len = lstr(ptr, len);
1959 	ptr = pstr(ptr);
1960 	fsm_dbg_dump_fsm_queue(&root->q_alone_thd, ptr, &len, detail);
1961 
1962 	_os_snprintf(pstr(ptr), lstr(ptr, len), "\noption:\n");
1963 	max_opt = sizeof(debug_opt)/sizeof(debug_opt[0]);
1964 	for (i = 0; i < max_opt-1; i++)
1965 		_os_snprintf(pstr(ptr), lstr(ptr, len), "%12s : %s\n",
1966 			debug_opt[i].opt, debug_opt[i].desc);
1967 	*sz = len;
1968 }
1969 
fsm_dbg_help(struct fsm_main * fsm,char * s,int * sz,bool detail)1970 static void fsm_dbg_help(struct fsm_main *fsm, char *s, int *sz, bool detail)
1971 {
1972 	_fsm_dbg_help(fsm->root, s, sz, false);
1973 }
1974 
get_fsm_by_name(struct fsm_root * root,char * name)1975 struct fsm_main *get_fsm_by_name(struct fsm_root *root, char *name)
1976 {
1977 	void *d = phl_to_drvpriv(root->phl_info);
1978 	struct fsm_main *fsm, *fsm_t;
1979 	u32 len = _os_strlen((u8 *)name);
1980 
1981 	if (len > FSM_NAME_LEN)
1982 		return NULL;
1983 
1984 	phl_list_for_loop_safe(fsm, fsm_t,
1985 		struct fsm_main, &root->q_share_thd.q, list) {
1986 		if (_os_strlen((u8 *)fsm->name) == len &&
1987 			_os_mem_cmp(d, fsm->name, name, len) == 0)
1988 			return fsm;
1989 	}
1990 
1991 	phl_list_for_loop_safe(fsm, fsm_t,
1992 		struct fsm_main, &root->q_alone_thd.q, list) {
1993 		if (_os_strlen((u8 *)fsm->name) == len &&
1994 			_os_mem_cmp(d, fsm->name, name, len) == 0)
1995 			return fsm;
1996 	}
1997 	return NULL;
1998 }
1999 
fsm_get_evt_id(struct fsm_main * fsm,char * event)2000 static u16 fsm_get_evt_id(struct fsm_main *fsm, char *event)
2001 {
2002 	void *d = phl_to_drvpriv(fsm->phl_info);
2003 	int i;
2004 	u32 len = _os_strlen((u8 *)event);
2005 
2006 	/* internal event */
2007 	for (i = 0; i < (sizeof(int_event_tbl)/sizeof(int_event_tbl[0])); i++) {
2008 		if (_os_strlen((u8 *)int_event_tbl[i].name) == len &&
2009 			_os_mem_cmp(d, int_event_tbl[i].name, event, len) == 0)
2010 			return int_event_tbl[i].event;
2011 	}
2012 
2013 	/* user event */
2014 	for (i = 0; i < fsm->tb.max_event; i++) {
2015 		if (_os_strlen((u8 *)fsm->tb.evt_tbl[i].name) == len &&
2016 			_os_mem_cmp(d,
2017 				fsm->tb.evt_tbl[i].name, event, len) == 0)
2018 			return fsm->tb.evt_tbl[i].event;
2019 	}
2020 	return FSM_EV_UNKNOWN;
2021 }
2022 #endif /* PHL_DEBUG_FSM */
2023 
2024 /* For EXTERNAL application to debug fsm (expose)
2025  * @phl_info: phl main struct
2026  * @input: input cmd
2027  * @input_num: num of cmd param
2028  * @output: output buffer
2029  * @out_len: MAX output buffer len
2030  *
2031  * d: dump fsm info
2032  *	fsm <d> <fsm_name> <fsm|st|ev|obj>
2033  * p: private cmd to fsm module
2034  *	fsm <p> <obj_name> <cmd to fsm module>
2035  * s: send event to fsm
2036  *	fsm <s> <obj_name> <ev>
2037  * w: write debug level
2038  *	fsm <w> <fsm_name> <dbg_level|evt_level> <0-5>
2039  */
phl_fsm_dbg(struct phl_info_t * phl_info,char input[][MAX_ARGV],u32 input_num,char * output,u32 out_len)2040 void phl_fsm_dbg(struct phl_info_t *phl_info, char input[][MAX_ARGV],
2041 		      u32 input_num, char *output, u32 out_len)
2042 {
2043 #ifdef PHL_DEBUG_FSM
2044 	struct phl_info_t *phl = (struct phl_info_t *)phl_info;
2045 	void *d = phl_to_drvpriv(phl);
2046 	struct fsm_root *root = phl->fsm_root;
2047 	struct fsm_main *fsm = NULL;
2048 	struct fsm_obj *obj = NULL;
2049 	struct fsm_msg *msg;
2050 	int i, max_opt, len = out_len;
2051 	char fsm_name[FSM_NAME_LEN], opt[FSM_NAME_LEN], cmd[FSM_NAME_LEN];
2052 	char c, *ptr, *sp;
2053 	u8 obj_id = 0;
2054 	u16 ev_id;
2055 
2056 	ptr = output;
2057 	/* fsm <cmd> <fsm_name> <opt> : fsm d cmd ev
2058 	 * fsm <cmd> <fsm_name> <evt> : fsm s cmd-1 FSM_EV_CANCEL
2059 	 */
2060 	if (input_num < 4)
2061 		goto help;
2062 
2063 	_os_mem_set(d, cmd, 0, FSM_NAME_LEN);
2064 	_os_mem_cpy(d, cmd, input[1],
2065 		MIN(_os_strlen((u8 *)input[1]), FSM_NAME_LEN));
2066 
2067 	_os_mem_set(d, fsm_name, 0, FSM_NAME_LEN);
2068 	_os_mem_cpy(d, fsm_name, input[2],
2069 		MIN(_os_strlen((u8 *)input[2]), FSM_NAME_LEN));
2070 
2071 	_os_mem_set(d, opt, 0, FSM_NAME_LEN);
2072 	_os_mem_cpy(d, opt, input[3],
2073 		MIN(_os_strlen((u8 *)input[3]), FSM_NAME_LEN));
2074 
2075 	c = (char)*cmd;
2076 	/* read obj_id
2077 	 * if fsm_name is "cmd-1" then obj number is "1"
2078 	 */
2079 	sp = _os_strchr((const char *)fsm_name, '-');
2080 
2081 	if (sp != NULL) {
2082 		*sp = '\0';
2083 		if (_os_sscanf(sp+1, "%hhd", &obj_id) != 1) {
2084 			_os_snprintf(pstr(ptr), lstr(ptr, len),
2085 				"ERR: fsm[%s] miss obj_id\n", fsm_name);
2086 			return;
2087 		}
2088 	} else
2089 		obj_id = 1; /* assume obj-1 */
2090 
2091 	/* search fsm by name */
2092 	fsm = get_fsm_by_name(root, (char *)fsm_name);
2093 	if (fsm == NULL) {
2094 		_os_snprintf(pstr(ptr), lstr(ptr, len),
2095 			"ERR: fsm[%s] not found\n", fsm_name);
2096 		return;
2097 	}
2098 
2099 	obj = fsm_get_obj(fsm, obj_id);
2100 	if (obj == NULL) {
2101 		_os_snprintf(pstr(ptr), lstr(ptr, len),
2102 			"ERR: fsm[%s] miss obj_%d\n", fsm_name, obj_id);
2103 		return;
2104 	}
2105 
2106 	switch (c) {
2107 	case 'd':
2108 		/* dump status */
2109 		max_opt = sizeof(debug_opt)/sizeof(debug_opt)[0];
2110 		for (i = 0; i < max_opt-1; i++) {
2111 			if (_os_strlen((u8 *)debug_opt[i].opt) == \
2112 				_os_strlen((u8 *)opt) &&
2113 				_os_mem_cmp(d, debug_opt[i].opt, opt,
2114 				_os_strlen((u8 *)opt)) == 0) {
2115 
2116 				len = lstr(ptr, len);
2117 				ptr = pstr(ptr);
2118 				debug_opt[i].func(fsm, ptr, &len, true);
2119 				break;
2120 			}
2121 		}
2122 		break;
2123 
2124 	case 'p':
2125 		/* call fsm private degug function */
2126 		if ((fsm != NULL) && (obj != NULL) && (fsm->tb.debug != NULL)){
2127 			len = lstr(ptr, len);
2128 			ptr = pstr(ptr);
2129 			fsm->tb.debug(obj->custom_obj, &input[3],
2130 				(input_num - 3), ptr, (u32 *)&len);
2131 		}
2132 		break;
2133 
2134 	case 's':
2135 		/* get event id */
2136 		ev_id = fsm_get_evt_id(fsm, (char *)opt);
2137 
2138 		if (ev_id == FSM_EV_UNKNOWN) {
2139 			_os_snprintf(pstr(ptr), lstr(ptr, len),
2140 				"\n\nERR: fsm[%s] unknown event %s\n",
2141 				fsm_name, opt);
2142 			len = lstr(ptr, len);
2143 			ptr = pstr(ptr);
2144 			fsm_dbg_dump_event(fsm, ptr, &len, false);
2145 			break;
2146 		}
2147 
2148 		if (obj != NULL) {
2149 			msg = phl_fsm_new_msg(obj, ev_id);
2150 
2151 			/* send event */
2152 			if (phl_fsm_sent_msg(obj, msg) != RTW_PHL_STATUS_SUCCESS)
2153 				_os_kmem_free(d, msg, sizeof(*msg));
2154 		}
2155 
2156 		break;
2157 
2158 	case 'w':
2159 		/* write cfg */
2160 		/* fsm w,<fsm_name>,<dbg_level|ev_level>,<0-5(dbg)> */
2161 
2162 		sp = _os_strchr((const char *)opt, ',');
2163 		if (sp == NULL)
2164 			goto help;
2165 
2166 		*sp = '\0';
2167 		if (_os_sscanf(sp+1, "%d", &i) != 1)
2168 			goto help;
2169 
2170 		if ((i<0) || (i>5))
2171 			goto help;
2172 
2173 		if (!_os_strcmp(opt, "dbg_level")) {
2174 			fsm->tb.dbg_level = (u8)i;
2175 			_os_snprintf(pstr(ptr), lstr(ptr, len),
2176 				"\n%s: set debug level to %d\n",
2177 				phl_fsm_fsm_name(fsm), i);
2178 		} else if (!_os_strcmp(opt, "evt_level")) {
2179 			_os_snprintf(pstr(ptr), lstr(ptr, len),
2180 				"\n%s: set event level to %d\n",
2181 				phl_fsm_fsm_name(fsm), i);
2182 			//fsm->tb.evt_level = (u8)i;
2183 		} else
2184 			goto help;
2185 		break;
2186 
2187 	default:
2188 		goto help;
2189 	}
2190 	return;
2191 help:
2192 	len = lstr(ptr, len);
2193 	ptr = pstr(ptr);
2194 	_fsm_dbg_help(fsm->root, ptr, &len, false);
2195 #endif /* PHL_DEBUG_FSM */
2196 }
2197 #endif /*CONFIG_FSM*/
2198