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