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