xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_cmd_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 DEBUG_CMD_FSM_MODULE */
22 
23 #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
24 #ifdef FSM_DBG_MEM_OVERWRITE
25 #define _os_kmem_alloc(a, b) fsm_kmalloc(b)
26 #define _os_kmem_free(a, b, c) fsm_kfree(b, c)
27 #endif
28 
29 #define pstr(s) (s +_os_strlen((u8 *)s))
30 #define lstr(s, l) (size_t)(l - _os_strlen((u8 *)s))
31 
32 #ifdef CONFIG_RTW_SCAN_FSM
33 struct _adapter;
34 #endif
35 #define MAX_POWER_ON_TIME	100
36 #define WDOG_ALARM_ID		1
37 #define WD_DURATION		2000 /* 2sec */
38 
39 enum CMD_STATE_ST {
40 	CMD_ST_IDLE,
41 	CMD_ST_REQ_PWR,
42 	CMD_ST_SERVICE
43 };
44 
45 enum CMD_EV_ID {
46 	CMD_EV_REQ_PWR,
47 	CMD_EV_DO_JOB,
48 	CMD_EV_JOB_NOTIFY,
49 	CMD_EV_PWR_ON_OK,
50 	CMD_EV_PWR_ON_TIMEOUT,
51 	CMD_EV_PWR_EXPIRE,
52 	CMD_EV_WD_EXPIRE,
53 	CMD_EV_WD_DO_JOB,
54 	CMD_EV_MAX
55 };
56 
57 static int cmd_idle_st_hdl(void *obj, u16 event, void *param);
58 static int cmd_req_pwr_st_hdl(void *obj, u16 event, void *param);
59 static int cmd_service_st_hdl(void *obj, u16 event, void *param);
60 
61 /* STATE table */
62 static struct fsm_state_ent cmd_state_tbl[] = {
63 	ST_ENT(CMD_ST_IDLE, cmd_idle_st_hdl),
64 	ST_ENT(CMD_ST_REQ_PWR, cmd_req_pwr_st_hdl),
65 	ST_ENT(CMD_ST_SERVICE, cmd_service_st_hdl),
66 };
67 
68 /* EVENT table */
69 static struct fsm_event_ent cmd_event_tbl[] = {
70 	EV_ENT(CMD_EV_REQ_PWR),
71 	EV_ENT(CMD_EV_DO_JOB),
72 	EV_ENT(CMD_EV_JOB_NOTIFY),
73 	EV_ENT(CMD_EV_PWR_ON_OK),
74 	EV_ENT(CMD_EV_PWR_ON_TIMEOUT),
75 	EV_ENT(CMD_EV_PWR_EXPIRE),
76 	EV_DBG(CMD_EV_WD_EXPIRE),
77 	EV_ENT(CMD_EV_WD_DO_JOB),
78 	EV_ENT(CMD_EV_MAX) /* EV_MAX for fsm safety checking */
79 };
80 
81 /*
82  * command thread state sub function
83  */
84 
cmd_pm_cb(void * phl,void * hdl,void * ctx,enum rtw_phl_status stat)85 void cmd_pm_cb(void *phl, void *hdl, void *ctx, enum rtw_phl_status stat)
86 {
87 	struct _cmd_obj *pcmd = (struct _cmd_obj *)ctx;
88 
89 	if (stat == RTW_PHL_STATUS_SUCCESS)
90 		phl_fsm_gen_msg(phl, pcmd->fsm_obj, NULL, 0, CMD_EV_PWR_ON_OK);
91 	else
92 		phl_fsm_gen_msg(phl, pcmd->fsm_obj, NULL, 0, FSM_EV_CANCEL);
93 }
94 
cmd_dequeue_job(struct _cmd_obj * pcmd)95 int cmd_dequeue_job(struct _cmd_obj *pcmd)
96 {
97 	void *d = phl_to_drvpriv(pcmd->phl_info);
98 	struct fsm_msg *msg;
99 
100 	msg = phl_fsm_dequeue_ext(pcmd->fsm);
101 	if (msg == NULL)
102 		return -1;
103 
104 	if (phl_fsm_sent_msg(pcmd->fsm_obj, msg) != RTW_PHL_STATUS_SUCCESS) {
105 		if (msg->param && msg->param_sz)
106 			_os_kmem_free(d, (u8 *)msg->param, msg->param_sz);
107 		_os_kmem_free(d, (u8 *)msg, sizeof(*msg));
108 		return -1;
109 	}
110 	return 0;
111 }
112 
cmd_do_wdog_job(struct _cmd_obj * pcmd)113 static void cmd_do_wdog_job(struct _cmd_obj *pcmd)
114 {
115 #if defined(PHL_PLATFORM_LINUX)
116 	void *d = phl_to_drvpriv(pcmd->phl_info);
117 	struct phl_cmd_job *job;
118 
119 	/* Tempoary test in Linux,
120 	 * make sure Windows doesn't run to here
121 	 */
122 
123 	_os_mutex_lock(d, &pcmd->wd_q_lock);
124 	phl_list_for_loop(job, struct phl_cmd_job, &pcmd->wd_q, list) {
125 		job->u.cmd.fptr(job->u.cmd.priv, job->u.cmd.parm, false);
126 
127 #ifdef DEBUG_CMD_FSM_MODULE
128                FSM_INFO(pcmd->fsm, "%s: wdog %s:%s\n",
129                        phl_fsm_obj_name(pcmd->fsm_obj),
130                        job_name(pcmd, (u8)job->id),
131                        (char *)job->u.cmd.name);
132 #endif
133 	}
134 	_os_mutex_unlock(d, &pcmd->wd_q_lock);
135 	rtw_phl_watchdog_callback(pcmd->phl_info);
136 #endif
137 }
138 
cmd_add_wdog_event(struct _cmd_obj * pcmd)139 static void cmd_add_wdog_event(struct _cmd_obj *pcmd)
140 {
141 	struct fsm_msg *msg;
142 
143 	msg = phl_fsm_new_msg(pcmd->fsm_obj, CMD_EV_WD_DO_JOB);
144 	if (msg == NULL)
145 		return;
146 	/* Always enqueue msg to extra queue */
147 	phl_fsm_enqueue_ext(pcmd->fsm, msg, 0);
148 }
149 
150 /*
151  * CMD state handler
152  */
153 
154 /*
155  * cmd idle handler
156  * This state has no power; Able to run no_io job
157  * For jobs don't need to request power (no_io job)
158  */
cmd_idle_st_hdl(void * obj,u16 event,void * param)159 static int cmd_idle_st_hdl(void *obj, u16 event, void *param)
160 {
161 	struct _cmd_obj *pcmd = (struct _cmd_obj *)obj;
162 	int rtn = FSM_FREE_PARAM;
163 
164 	/* has no power */
165 	switch (event) {
166 	case FSM_EV_SWITCH_IN:
167 		phl_fsm_set_alarm_ext(pcmd->fsm_obj,
168 			WD_DURATION, CMD_EV_WD_EXPIRE, WDOG_ALARM_ID, NULL);
169 		break;
170 
171 	case FSM_EV_STATE_IN:
172 		break;
173 
174 	case CMD_EV_WD_EXPIRE:
175 
176 		/* restart watchdog alarm */
177 		phl_fsm_set_alarm_ext(pcmd->fsm_obj,
178 			WD_DURATION, CMD_EV_WD_EXPIRE, WDOG_ALARM_ID, NULL);
179 
180 		if (pcmd->wdog_pwr_level < PWR_BASIC_IO) {
181 			cmd_do_wdog_job(pcmd);
182 			break;
183 		}
184 		/* We need to request power */
185 		cmd_add_wdog_event(pcmd);
186 
187 		/* fall through */
188 
189 	case CMD_EV_REQ_PWR:
190 		phl_fsm_state_goto(pcmd->fsm_obj, CMD_ST_REQ_PWR);
191 		break;
192 
193 	case CMD_EV_JOB_NOTIFY:
194 		cmd_dequeue_job(pcmd);
195 		break;
196 
197 	case CMD_EV_DO_JOB:
198 		/* TODO check MUST BE no_io cmd */
199 		rtn = phl_cmd_do_job(pcmd, param);
200 		break;
201 
202 	case FSM_EV_STATE_OUT:
203 		break;
204 
205 	case FSM_EV_SWITCH_OUT:
206 		phl_fsm_cancel_alarm_ext(pcmd->fsm_obj, WDOG_ALARM_ID);
207 		break;
208 
209 	default:
210 		break;
211 	}
212 	return rtn;
213 }
214 
215 /* This stete is designed to request power */
cmd_req_pwr_st_hdl(void * obj,u16 event,void * param)216 static int cmd_req_pwr_st_hdl(void *obj, u16 event, void *param)
217 {
218 	struct _cmd_obj *pcmd = (struct _cmd_obj *)obj;
219 	struct fsm_msg *msg;
220 	int rtn = FSM_FREE_PARAM;
221 	enum rtw_phl_status phl_st;
222 
223 	switch (event) {
224 	case FSM_EV_STATE_IN:
225 
226 		/* TODO: request power */
227 		phl_st = RTW_PHL_STATUS_SUCCESS;
228 
229 		if (phl_st == RTW_PHL_STATUS_PENDING) {
230 			/* we have to wait CMD_EV_PWR_ON_OK */
231 			phl_fsm_set_alarm(pcmd->fsm_obj,
232 				MAX_POWER_ON_TIME, CMD_EV_PWR_ON_TIMEOUT);
233 			break;
234 		}
235 
236 		if (phl_st != RTW_PHL_STATUS_SUCCESS) {
237 			FSM_ERR(pcmd->fsm, "%s: power on fail(%d)\n",
238 				phl_fsm_obj_name(pcmd->fsm_obj), phl_st);
239 			phl_fsm_state_goto(pcmd->fsm_obj, CMD_ST_IDLE);
240 
241 			/* drop fail cmd */
242 			msg = phl_fsm_dequeue_ext(pcmd->fsm);
243 			if (msg != NULL)
244 				cmd_discard_msg_job(pcmd, msg);
245 			break;
246 		}
247 
248 		/* RTW_PHL_STATUS_SUCCESS */
249 		/* fall through */
250 
251 	case CMD_EV_PWR_ON_OK:
252 		pcmd->has_power = true;
253 		phl_fsm_state_goto(pcmd->fsm_obj, CMD_ST_SERVICE);
254 		break;
255 
256 	case CMD_EV_PWR_ON_TIMEOUT:
257 	case FSM_EV_CANCEL:
258 		phl_fsm_state_goto(pcmd->fsm_obj, CMD_ST_IDLE);
259 		break;
260 
261 	case CMD_EV_WD_EXPIRE:
262 		/* restart watchdog alarm */
263 		phl_fsm_set_alarm_ext(pcmd->fsm_obj,
264 			WD_DURATION, CMD_EV_WD_EXPIRE, WDOG_ALARM_ID, NULL);
265 
266 		/* enqueue watchdog job */
267 		cmd_add_wdog_event(pcmd);
268 		break;
269 
270 	case FSM_EV_STATE_OUT:
271 		phl_fsm_cancel_alarm(pcmd->fsm_obj);
272 		break;
273 
274 	default:
275 		break;
276 	}
277 	return rtn;
278 }
279 
280 /* This state has basic power supply.
281  * Able to do both PWR_BASIC_IO and PWR_NO_IO jobs.
282  */
283 
cmd_service_st_hdl(void * obj,u16 event,void * param)284 static int cmd_service_st_hdl(void *obj, u16 event, void *param)
285 {
286 	struct _cmd_obj *pcmd = (struct _cmd_obj *)obj;
287 	struct phl_cmd_job *job;
288 	int rtn = FSM_FREE_PARAM;
289 
290 	switch (event) {
291 	case FSM_EV_STATE_IN:
292 	case CMD_EV_JOB_NOTIFY:
293 		cmd_dequeue_job(pcmd);
294 		break;
295 
296 	case CMD_EV_DO_JOB:
297 
298 		rtn = phl_cmd_do_job(pcmd, param);
299 
300 		/* hold power for a while */
301 		job = (struct phl_cmd_job *)param;
302 		if (job->pwr_level >= PWR_BASIC_IO)
303 			phl_fsm_set_alarm(pcmd->fsm_obj,
304 				MAX_POWER_ON_TIME, CMD_EV_PWR_EXPIRE);
305 
306 		/* dequeue jobs */
307 		cmd_dequeue_job(pcmd);
308 		break;
309 
310 	case CMD_EV_WD_EXPIRE:
311 	case CMD_EV_WD_DO_JOB:
312 
313 		cmd_do_wdog_job(pcmd);
314 
315 		/* hold power for a while */
316 		phl_fsm_set_alarm(pcmd->fsm_obj,
317 			MAX_POWER_ON_TIME, CMD_EV_PWR_EXPIRE);
318 
319 		/* restart watchdog alarm */
320 		phl_fsm_set_alarm_ext(pcmd->fsm_obj,
321 			WD_DURATION, CMD_EV_WD_EXPIRE, WDOG_ALARM_ID, NULL);
322 		break;
323 
324 	case CMD_EV_PWR_EXPIRE:
325 
326 		/* make sure no more commands */
327 		if (cmd_dequeue_job(pcmd) >= 0)
328 			break;
329 
330 		/* no more commands */
331 		/* fall through */
332 
333 	case FSM_EV_CANCEL:
334 		phl_fsm_state_goto(pcmd->fsm_obj, CMD_ST_IDLE);
335 		break;
336 
337 	case FSM_EV_STATE_OUT:
338 		phl_fsm_cancel_alarm(pcmd->fsm_obj);
339 		pcmd->has_power = false;
340 		break;
341 
342 	default:
343 		break;
344 	}
345 	return rtn;
346 }
347 
cmd_dump_obj(void * obj,char * p,int * sz)348 static void cmd_dump_obj(void *obj, char *p, int *sz)
349 {
350 	/* nothing to do for now */
351 }
352 
cmd_dump_fsm(void * fsm,char * p,int * sz)353 static void cmd_dump_fsm(void *fsm, char *p, int *sz)
354 {
355 	/* nothing to do for now */
356 }
357 
cmd_dbg_help(struct _cmd_obj * pcmd,char * p,int * sz)358 static void cmd_dbg_help(struct _cmd_obj *pcmd, char *p, int *sz)
359 {
360 	int len = *sz;
361 
362 	_os_snprintf(pstr(p), lstr(p, len),
363 		"usage:\n\t<%s> <wdog>,<pause|resume>\n",
364 		phl_fsm_obj_name(pcmd->fsm_obj));
365 	*sz = len;
366 }
367 
cmd_debug(void * obj,char input[][MAX_ARGV],u32 input_num,char * output,u32 * out_len)368 static void cmd_debug(void *obj, char input[][MAX_ARGV], u32 input_num,
369 	char *output, u32 *out_len)
370 {
371 	struct _cmd_obj *pcmd = (struct _cmd_obj *)obj;
372 	char *ptr = output;
373 	int len = *out_len;
374 
375 	if (input_num <  2) {
376 		cmd_dbg_help(pcmd, ptr, &len);
377 		goto done;
378 	}
379 
380 	if (!_os_strcmp(input[0], "wdog")) {
381 		if (!_os_strcmp(input[1], "pause")) {
382 			/* wdog,pause */
383 			rtw_phl_cmd_pause_wdog(pcmd->phl_info, "debug cmd");
384 
385 			_os_snprintf(pstr(ptr), lstr(ptr, len),
386 				"\n%s: pause watchdog\n",
387 				phl_fsm_obj_name(pcmd->fsm_obj));
388 
389 		} else if (!_os_strcmp(input[1], "resume")) {
390 			/* wdog,resume */
391 			rtw_phl_cmd_resume_wdog(pcmd->phl_info, "debug cmd");
392 			_os_snprintf(pstr(ptr), lstr(ptr, len),
393 				"\n%s: resume watchdog\n",
394 				phl_fsm_obj_name(pcmd->fsm_obj));
395 		}
396 	} else
397 		cmd_dbg_help(pcmd, ptr, &len);
398 done:
399 	*out_len = len;
400 }
401 
402 /* return value
403  *	0: timeout
404  *     >0: success
405  */
wait_completion(void * d,struct phl_cmd_job * job,int m_sec)406 static int wait_completion(void *d, struct phl_cmd_job *job, int m_sec)
407 {
408 	job->wait.max_wait_time = m_sec;
409 	job->wait.submit_time = _os_get_cur_time_ms();
410 
411 	_os_event_init(d, &(job->wait.done));
412 
413 	/* wait here */
414 	return _os_event_wait(d, &(job->wait.done), m_sec);
415 }
416 
417 /* For EXTERNAL application to create a cmd FSM */
418 /* @root: FSM root structure
419  * @phl_info: private data structure to invoke hal/phl function
420  *
421  * return
422  * fsm_main: FSM main structure (Do NOT expose)
423  */
phl_cmd_new_fsm(struct fsm_root * root,struct phl_info_t * phl_info)424 struct fsm_main *phl_cmd_new_fsm(struct fsm_root *root,
425 	struct phl_info_t *phl_info)
426 {
427 	void *d = phl_to_drvpriv(phl_info);
428 	struct fsm_main *fsm = NULL;
429 	struct rtw_phl_fsm_tb tb;
430 
431 
432 	_os_mem_set(d, &tb, 0, sizeof(tb));
433 	tb.max_state = sizeof(cmd_state_tbl)/sizeof(cmd_state_tbl[0]);
434 	tb.max_event = sizeof(cmd_event_tbl)/sizeof(cmd_event_tbl[0]);
435 	tb.state_tbl = cmd_state_tbl;
436 	tb.evt_tbl = cmd_event_tbl;
437 	tb.dump_obj = cmd_dump_obj;
438 	tb.dump_fsm = cmd_dump_fsm;
439 	tb.dbg_level = FSM_DBG_WARN;
440 	tb.evt_level = FSM_DBG_WARN;
441 	tb.debug = cmd_debug;
442 
443 	fsm = phl_fsm_init_fsm(root, "cmd", phl_info, &tb);
444 
445 	return fsm;
446 }
447 
448 /* For EXTERNAL application to destory cmd fsm */
449 /* @fsm: see fsm_main
450  */
phl_cmd_destory_fsm(struct fsm_main * fsm)451 void phl_cmd_destory_fsm(struct fsm_main *fsm)
452 {
453 	if (fsm == NULL)
454 		return;
455 
456 	/* deinit fsm local variable if has */
457 
458 	/* call FSM Framewro to deinit fsm */
459 	phl_fsm_deinit_fsm(fsm);
460 }
461 
462 /* For EXTERNAL application to create command object */
463 /* @fsm: FSM main structure which created by phl_cmd_new_fsm()
464  * @phl_info: private data structure to invoke hal/phl function
465  *
466  * return
467  * _cmd_obj: structure of command object (Do NOT expose)
468  */
phl_cmd_new_obj(struct fsm_main * fsm,struct phl_info_t * phl_info)469 struct _cmd_obj *phl_cmd_new_obj(struct fsm_main *fsm,
470 	struct phl_info_t *phl_info)
471 {
472 	void *d = phl_to_drvpriv(phl_info);
473 	struct fsm_obj *obj;
474 	struct _cmd_obj *pcmd;
475 
476 
477 	pcmd = phl_fsm_new_obj(fsm, (void **)&obj, sizeof(*pcmd));
478 
479 	if (pcmd == NULL) {
480 		FSM_ERR(fsm, "cmd: malloc obj fail\n");
481 		return NULL;
482 	}
483 	pcmd->fsm = fsm;
484 	pcmd->fsm_obj = obj;
485 	pcmd->phl_info = phl_info;
486 	pcmd->has_power = false;
487 
488 	cmd_set_job_tbl(pcmd);
489 	INIT_LIST_HEAD(&pcmd->wd_q);
490 	_os_mutex_init(d, &pcmd->wd_q_lock);
491 
492 	return pcmd;
493 }
494 
495 /* For EXTERNAL application to destory command object */
496 /* @pcmd: local created command object
497  *
498  */
phl_cmd_destory_obj(struct _cmd_obj * pcmd)499 void phl_cmd_destory_obj(struct _cmd_obj *pcmd)
500 {
501 	void *d;
502 	struct phl_cmd_job *job, *job_t;
503 
504 	if (pcmd == NULL)
505 		return;
506 
507 	d = phl_to_drvpriv(pcmd->phl_info);
508 
509 	/* deinit and free all local variables */
510 
511 	/* watchdog job */
512 	/* TODO spin lock is not necessary */
513 	phl_list_for_loop_safe(job, job_t,
514 		struct phl_cmd_job, &pcmd->wd_q, list) {
515 
516 		_os_mutex_lock(d, &pcmd->wd_q_lock);
517 		list_del(&job->list);
518 		_os_mutex_unlock(d, &pcmd->wd_q_lock);
519 
520 		if (job->id == JOB_RUN_FUNC) {
521 
522 			if (job->u.cmd.parm && job->u.cmd.parm_sz != 0)
523 				_os_kmem_free(d, (u8 *)job->u.cmd.parm,
524 					job->u.cmd.parm_sz);
525 			_os_kmem_free(d, (u8 *)job, sizeof(*job));
526 
527 		} else {
528 			FSM_ERR(pcmd->fsm, "%s: free wdog %s fail\n",
529 				phl_fsm_obj_name(pcmd->fsm_obj),
530 				job_name(pcmd, (u8)job->id));
531 		}
532 	}
533 	_os_mutex_deinit(d, &pcmd->wd_q_lock);
534 
535 	/* inform FSM framewory to recycle fsm_obj */
536 	phl_fsm_destory_obj(pcmd->fsm_obj);
537 }
538 
539 /* For EXTERNAL application to pause all watchdog jobs (expose) */
540 /* @phl: phl private structure
541  * @reason: reason for pause watchdog (option)
542  */
rtw_phl_cmd_pause_wdog(void * phl,char * reason)543 enum rtw_phl_status rtw_phl_cmd_pause_wdog(void *phl, char *reason)
544 {
545 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
546 	struct _cmd_obj *pcmd = phl_info->cmd_obj;
547 
548 	phl_fsm_pause_alarm_ext(pcmd->fsm_obj, WDOG_ALARM_ID);
549 	pcmd->wdog_pause_num++;
550 
551 	FSM_INFO(pcmd->fsm, "%s: pause wdog (%s) %d\n",
552 		phl_fsm_obj_name(pcmd->fsm_obj),
553 		(reason == NULL) ? "" : reason, pcmd->wdog_pause_num);
554 
555 	return RTW_PHL_STATUS_SUCCESS;
556 }
557 
558 /* For EXTERNAL application to resume all watchdog jobs (expose) */
559 /* @phl: phl private structure
560  * @reason: reason for resume watchdog (option)
561  */
rtw_phl_cmd_resume_wdog(void * phl,char * reason)562 enum rtw_phl_status rtw_phl_cmd_resume_wdog(void *phl, char *reason)
563 {
564 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
565 	struct _cmd_obj *pcmd = phl_info->cmd_obj;
566 
567 	FSM_INFO(pcmd->fsm, "%s: resume wdog (%s) %d\n",
568 		phl_fsm_obj_name(pcmd->fsm_obj),
569 		(reason == NULL) ? "" : reason, pcmd->wdog_pause_num);
570 
571 	if (pcmd->wdog_pause_num == 0)
572 		return RTW_PHL_STATUS_FAILURE;
573 
574 	if (--(pcmd->wdog_pause_num) != 0)
575 		return RTW_PHL_STATUS_SUCCESS;
576 
577 	/* reset timer to original period */
578 	phl_fsm_set_alarm_ext(pcmd->fsm_obj,
579 		WD_DURATION, CMD_EV_WD_EXPIRE, WDOG_ALARM_ID, NULL);
580 
581 	phl_fsm_resume_alarm_ext(pcmd->fsm_obj, WDOG_ALARM_ID);
582 
583 	return RTW_PHL_STATUS_SUCCESS;
584 }
585 
586 /* For EXTERNAL application to register watchdog job (expose) */
587 /* @phl: phl private structure
588  * @func: function pointer to be runed
589  * @priv: 1st param of function pointer
590  * @parm: 2nd param of function pointer
591  * @name: function name for debug message (optional)
592  * @pwr: refers to enum PWR_LEVEL
593  */
rtw_phl_job_reg_wdog(void * phl,int (* fptr)(void * priv,void * param,bool discard),void * priv,void * parm,int parm_sz,char * name,enum PWR_LEVEL pwr)594 enum rtw_phl_status rtw_phl_job_reg_wdog(void *phl,
595 	int (*fptr)(void *priv, void *param, bool discard),
596 	void *priv, void *parm, int parm_sz, char *name, enum PWR_LEVEL pwr)
597 {
598 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
599 	struct _cmd_obj *pcmd = phl_info->cmd_obj;
600 	struct phl_cmd_job *job;
601 	void *d = phl_to_drvpriv(phl_info);
602 	char wd[] = "wdog";
603 
604 	if (phl_info->cmd_obj == NULL) {
605 		PHL_ERR("cmd: %s fsm module doesn't init \n", __func__);
606 		return -1;
607 	}
608 
609 	/* allocate memory for job parameter */
610 	job = _os_kmem_alloc(d, sizeof(*job));
611 	if (job == NULL) {
612 		FSM_ERR(pcmd->fsm, "%s: alloc wdog job fail\n",
613 			phl_fsm_obj_name(pcmd->fsm_obj));
614 		return RTW_PHL_STATUS_RESOURCE;
615 	}
616 
617 	_os_mem_set(d, job, 0, sizeof(job));
618 	job->id = JOB_RUN_FUNC;
619 	job->pwr_level = pwr;
620 	job->u.cmd.fptr = fptr;
621 	job->u.cmd.priv = priv;
622 	job->u.cmd.parm = parm;
623 	job->u.cmd.parm_sz = parm_sz;
624 	_os_mem_set(d, job->u.cmd.name, 0, RTW_PHL_JOB_NAME_LEN);
625 	if (name != NULL)
626 		_os_mem_cpy(d, job->u.cmd.name, name,
627 			MIN((RTW_PHL_JOB_NAME_LEN - 1),
628 			_os_strlen((u8 *)name)));
629 	else
630 		_os_mem_cpy(d, job->u.cmd.name, wd,
631 			MIN((RTW_PHL_JOB_NAME_LEN - 1),
632 			_os_strlen((u8 *)wd)));
633 
634 	pcmd->wdog_pwr_level = (u8)MAX(pwr, pcmd->wdog_pwr_level);
635 
636 	_os_mutex_lock(d, &pcmd->wd_q_lock);
637 	list_add_tail(&job->list, &pcmd->wd_q);
638 	_os_mutex_unlock(d, &pcmd->wd_q_lock);
639 
640 	FSM_INFO(pcmd->fsm, "%s: wdog hooks %s, pwr_level = %d\n",
641 		phl_fsm_obj_name(pcmd->fsm_obj),
642 		job->u.cmd.name, pwr);
643 
644 	return RTW_PHL_STATUS_SUCCESS;
645 }
646 
647 /* For EXTERNAL application to invoke command service (expose) */
648 /* @pcmd: cmd object
649  * @msg: refert to struct fsm_msg
650  */
phl_cmd_enqueue_and_wait_job(struct _cmd_obj * pcmd,struct fsm_msg * msg)651 enum rtw_phl_status phl_cmd_enqueue_and_wait_job(struct _cmd_obj *pcmd,
652 	struct fsm_msg *msg)
653 {
654 	struct phl_cmd_job *job = (struct phl_cmd_job *)msg->param;
655 	void *d = phl_to_drvpriv(pcmd->phl_info);
656 	int max_wait_time = 1000;
657 	int remain = 0;
658 
659 #if 0
660 	FSM_INFO(pcmd->fsm, "%s: enqueue %s:%s\n",
661 		phl_fsm_obj_name(pcmd->fsm_obj),
662 		job_name(pcmd, (u8)job->id), (char *)job->u.cmd.name);
663 #endif
664 	/* Always enqueue msg to extra queue */
665 	phl_fsm_enqueue_ext(pcmd->fsm, msg, 0);
666 
667 	if ((pcmd->has_power == false) && (job->pwr_level >= PWR_BASIC_IO))
668 		/* request power */
669 		phl_fsm_gen_msg(pcmd->phl_info,
670 			pcmd->fsm_obj, NULL, 0, CMD_EV_REQ_PWR);
671 	else
672 		phl_fsm_gen_msg(pcmd->phl_info,
673 			pcmd->fsm_obj, NULL, 0, CMD_EV_JOB_NOTIFY);
674 
675 	if (job->wait.sync == JOB_WAIT_COMPLETION) {
676 
677 		job->wait.result = JOB_SUCCESS;
678 		/* WAIT completion; context switch */
679 		remain = wait_completion(d, job, max_wait_time);
680 		if (remain == 0) {
681 			job->wait.result = JOB_TIMEOUT;
682 			FSM_WARN(pcmd->fsm, "job: %s timeout %d ms\n",
683 				job_name(pcmd, (u8)job->id), max_wait_time);
684 			return RTW_PHL_STATUS_FAILURE;
685 		}
686 	}
687 	return RTW_PHL_STATUS_SUCCESS;
688 }
689 
690 /* For EXTERNAL application to invoke command service (expose) */
691 /* @phl: refer to struct phl_info_t
692  * @pjob: job to be completed
693  */
phl_cmd_complete_job(void * phl,struct phl_cmd_job * pjob)694 enum rtw_phl_status phl_cmd_complete_job(void *phl, struct phl_cmd_job *pjob)
695 {
696 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
697 	struct _cmd_obj *pcmd = phl_info->cmd_obj;
698 	struct phl_cmd_job *job;
699 	struct fsm_msg *msg;
700 	void *d = phl_to_drvpriv(pcmd->phl_info);
701 
702 	if (pjob == NULL)
703 		return RTW_PHL_STATUS_FAILURE;
704 
705 #ifdef HAS_NO_COMPLETION
706 	if (pjob->wait.sync == JOB_WAIT_COMPLETION) {
707 		pjob->wait.sync = JOB_ASYNC;
708 		FSM_ERR(pcmd->fsm,
709 			"cmd: %s doesn't support SYNC mdoe use ASYNC mode\n",
710 			job_name(pcmd, (u8)pjob->id));
711 	}
712 #endif
713 	/* NEW message to start cmd service */
714 	msg = phl_fsm_new_msg(pcmd->fsm_obj, CMD_EV_DO_JOB);
715 	if (msg == NULL) {
716 		FSM_ERR(pcmd->fsm, "cmd: alloc msg fail\n");
717 		return RTW_PHL_STATUS_RESOURCE;
718 	}
719 
720 	/* allocate memory for command parameter */
721 	if (pjob->wait.sync == JOB_WAIT_COMPLETION) {
722 		/* TODO check interrupt context */
723 		/* SYNC mode, use call loacl job varable */
724 		job = pjob;
725 	} else {
726 		/* ASYNC mode */
727 		/* allocate memory for command parameter */
728 		job = _os_kmem_alloc(d, sizeof(*job));
729 		if (job == NULL) {
730 			FSM_ERR(pcmd->fsm, "cmd: alloc job fail\n");
731 			_os_kmem_free(d, (u8 *)msg, sizeof(*msg));
732 			return RTW_PHL_STATUS_RESOURCE;
733 		}
734 		_os_mem_cpy(d, job, pjob, sizeof(*job));
735 	}
736 	msg->param = (void *)job;
737 	msg->param_sz = sizeof(*job);
738 
739 	return phl_cmd_enqueue_and_wait_job(pcmd, msg);
740 }
741 
742 /* For EXTERNAL application to start command service (expose) */
743 /* @pcmd: cmd object
744  */
phl_cmd_start(struct _cmd_obj * pcmd)745 enum rtw_phl_status phl_cmd_start(struct _cmd_obj *pcmd)
746 {
747 	/* Start FSM */
748 	return phl_fsm_start_fsm(pcmd->fsm);
749 }
750 
751 /* For EXTERNAL application to stop cmd obj
752  * @phl_info: private data structure to invoke hal/phl function
753  *
754  */
phl_fsm_cmd_stop(struct phl_info_t * phl_info)755 void phl_fsm_cmd_stop(struct phl_info_t *phl_info)
756 {
757 	struct _cmd_obj *pcmd = phl_info->cmd_obj;
758 	//void *d = phl_to_drvpriv(pcmd->phl_info);
759 	struct phl_cmd_job *job;
760 	struct fsm_msg *msg;
761 
762 	while ((msg = phl_fsm_dequeue_ext(pcmd->fsm)) != NULL) {
763 		job = (struct phl_cmd_job *)msg->param;
764 		cmd_discard_msg_job(pcmd, msg);
765 	}
766 
767 	phl_fsm_stop_fsm(phl_info->cmd_fsm);
768 }
769 
770 /* For EXTERNAL application to stop cmd service (expose) */
771 /* @pcmd: cmd job will be cancelled
772  */
phl_cmd_cancel(struct _cmd_obj * pcmd)773 enum rtw_phl_status phl_cmd_cancel(struct _cmd_obj *pcmd)
774 {
775 #ifdef PHL_INCLUDE_FSM
776 	return phl_fsm_cancel_obj(pcmd->fsm_obj);
777 #else
778 	return RTW_PHL_STATUS_FAILURE;
779 #endif /* PHL_INCLUDE_FSM */
780 }
781 #endif /*CONFIG_FSM*/
782 
783