xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_cmd_general.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2019 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  *****************************************************************************/
15 #define _PHL_CMD_GENERAL_C_
16 #include "phl_headers.h"
17 
18 #ifdef CONFIG_CMD_DISP
19 
20 enum phl_cmd_sts {
21 	PHL_CMD_SUBMITTED = -1,
22 	PHL_CMD_DONE_SUCCESS = 0,
23 	PHL_CMD_DONE_TIMEOUT,
24 	PHL_CMD_DONE_CMD_ERROR,
25 	PHL_CMD_DONE_CMD_DROP,
26 	PHL_CMD_DONE_CANNOT_IO,
27 	PHL_CMD_DONE_UNKNOWN,
28 };
29 
30 struct phl_sync {
31 	u32 submit_time;
32 	u32 timeout_ms; /* 0: wait forever, >0: up to ms waiting */
33 	enum phl_cmd_sts status; /* status for operation */
34 	_os_event done;
35 };
36 
37 struct phl_cmd_sync {
38 	enum phl_msg_evt_id evt_id;
39 	struct phl_sync sync;
40 	_os_lock lock;
41 };
42 
43 struct phl_cmd_obj {
44 	enum phl_msg_evt_id evt_id; /* u8 id */
45 	u8 *buf;
46 	u32 buf_len;
47 	bool no_io;
48 	void (*cmd_complete)(void* priv, u8 *buf, u32 buf_len, enum rtw_phl_status status);
49 	/*cmd sync*/
50 	bool is_cmd_wait;
51 	_os_atomic ref_cnt;
52 	struct phl_cmd_sync cmd_sync;
53 };
54 
55 
56 #define DBG_CMD_SYNC
57 
58 #ifdef DBG_CMD_SYNC
_phl_cmd_sync_dump(struct phl_cmd_sync * cmd_sync,const char * caller)59 static void _phl_cmd_sync_dump(struct phl_cmd_sync *cmd_sync, const char *caller)
60 {
61 	PHL_INFO("[CMD_SYNC] %s\n", caller);
62 	PHL_INFO("[CMD_SYNC] evt_id:%d status:%d\n", cmd_sync->evt_id, cmd_sync->sync.status);
63 	PHL_INFO("[CMD_SYNC] take:%d ms\n", phl_get_passing_time_ms(cmd_sync->sync.submit_time));
64 }
65 #endif
66 
_phl_cmd_sync_init(struct phl_info_t * phl_info,enum phl_msg_evt_id evt_id,struct phl_cmd_sync * cmd_sync,u32 timeout_ms)67 static void _phl_cmd_sync_init(struct phl_info_t *phl_info,
68 		enum phl_msg_evt_id evt_id,
69 		struct phl_cmd_sync *cmd_sync, u32 timeout_ms)
70 {
71 	void *drv = phl_to_drvpriv(phl_info);
72 
73 	_os_spinlock_init(drv, &cmd_sync->lock);
74 	cmd_sync->evt_id = evt_id;
75 	cmd_sync->sync.timeout_ms = timeout_ms;
76 	cmd_sync->sync.submit_time = _os_get_cur_time_ms();
77 	_os_event_init(drv, &(cmd_sync->sync.done));
78 	cmd_sync->sync.status = PHL_CMD_SUBMITTED;
79 }
80 
_phl_cmd_sync_deinit(struct phl_info_t * phl_info,struct phl_cmd_sync * cmd_sync)81 static void _phl_cmd_sync_deinit(struct phl_info_t *phl_info,
82 			struct phl_cmd_sync *cmd_sync)
83 {
84 	#ifdef DBG_CMD_SYNC
85 	_phl_cmd_sync_dump(cmd_sync, __func__);
86 	#endif
87 	_os_event_free(phl_to_drvpriv(phl_info), &(cmd_sync->sync.done));
88 	_os_spinlock_free(phl_to_drvpriv(phl_info), &cmd_sync->lock);
89 }
90 
_cmd_stat_2_phl_stat(enum phl_cmd_sts status)91 inline static enum rtw_phl_status _cmd_stat_2_phl_stat(enum phl_cmd_sts status)
92 {
93 	if (status == PHL_CMD_DONE_TIMEOUT)
94 		return RTW_PHL_STATUS_CMD_TIMEOUT;
95 	else if(status == PHL_CMD_DONE_CANNOT_IO)
96 		return RTW_PHL_STATUS_CMD_CANNOT_IO;
97 	else if (status == PHL_CMD_DONE_CMD_ERROR)
98 		return RTW_PHL_STATUS_CMD_ERROR;
99 	else if (status == PHL_CMD_DONE_CMD_DROP)
100 		return RTW_PHL_STATUS_CMD_DROP;
101 	else
102 		return RTW_PHL_STATUS_CMD_SUCCESS;
103 }
104 
105 static enum rtw_phl_status
_phl_cmd_wait(struct phl_info_t * phl_info,struct phl_cmd_sync * cmd_sync)106 _phl_cmd_wait(struct phl_info_t *phl_info, struct phl_cmd_sync *cmd_sync)
107 {
108 	void *drv = phl_to_drvpriv(phl_info);
109 	u32 cmd_wait_ms = cmd_sync->sync.timeout_ms;/*0: wait forever, >0: up to ms waiting*/
110 
111 	#ifdef DBG_CMD_SYNC
112 	PHL_INFO("evt_id:%d %s in...............\n", cmd_sync->evt_id, __func__);
113 	#endif
114 
115 	if (_os_event_wait(drv, &cmd_sync->sync.done, cmd_wait_ms) == 0) {
116 		_os_spinlock(drv, &cmd_sync->lock, _bh, NULL);
117 		cmd_sync->sync.status = PHL_CMD_DONE_TIMEOUT;
118 		_os_spinunlock(drv, &cmd_sync->lock, _bh, NULL);
119 		PHL_ERR("%s evt_id:%d timeout\n", __func__, cmd_sync->evt_id);
120 	}
121 	#ifdef DBG_CMD_SYNC
122 	PHL_INFO("evt_id:%d %s out...............\n", cmd_sync->evt_id, __func__);
123 	_phl_cmd_sync_dump(cmd_sync, __func__);
124 	#endif
125 	return _cmd_stat_2_phl_stat(cmd_sync->sync.status);
126 }
127 
_phl_cmd_chk_wating_status(enum phl_cmd_sts status)128 static bool _phl_cmd_chk_wating_status(enum phl_cmd_sts status)
129 {
130 	switch (status) {
131 	case PHL_CMD_SUBMITTED:
132 		/* fall through */
133 	case PHL_CMD_DONE_UNKNOWN:
134 		return true;
135 	default:
136 		return false;
137 	}
138 }
139 
_phl_cmd_done(struct phl_info_t * phl_info,struct phl_cmd_sync * cmd_sync,enum phl_cmd_sts status)140 static void _phl_cmd_done(struct phl_info_t *phl_info,
141 		struct phl_cmd_sync *cmd_sync, enum phl_cmd_sts status)
142 {
143 	void *drv = phl_to_drvpriv(phl_info);
144 
145 	if (!cmd_sync) {
146 		PHL_ERR("%s cmd_sync is NULL\n", __func__);
147 		_os_warn_on(1);
148 		return;
149 	}
150 	#ifdef DBG_CMD_SYNC
151 	PHL_INFO("evt_id:%d %s in...............\n", cmd_sync->evt_id, __func__);
152 	#endif
153 	_os_spinlock(drv, &cmd_sync->lock, _bh, NULL);
154 	if (_phl_cmd_chk_wating_status(cmd_sync->sync.status)) {
155 		PHL_INFO("%s status:%d\n", __func__, status);
156 		cmd_sync->sync.status = status;
157 	}
158 	_os_spinunlock(drv, &cmd_sync->lock, _bh, NULL);
159 
160 	_os_event_set(drv, &cmd_sync->sync.done);
161 	#ifdef DBG_CMD_SYNC
162 	PHL_INFO("evt_id:%d %s out...............\n", cmd_sync->evt_id, __func__);
163 	_phl_cmd_sync_dump(cmd_sync, __func__);
164 	#endif
165 }
166 /********************************************************/
167 static enum rtw_phl_status
_phl_cmd_general_pre_phase_msg_hdlr(struct phl_info_t * phl_info,void * dispr,struct phl_msg * msg)168 _phl_cmd_general_pre_phase_msg_hdlr(struct phl_info_t *phl_info, void *dispr,
169 				    struct phl_msg *msg)
170 {
171 	enum phl_msg_evt_id evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
172 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
173 	struct phl_cmd_obj *phl_cmd = NULL;
174 
175 	phl_cmd = (struct phl_cmd_obj *)msg->inbuf;
176 
177 	switch (evt_id) {
178 	case MSG_EVT_DBG_RX_DUMP:
179 		/* Do Nothing */
180 		psts = RTW_PHL_STATUS_SUCCESS;
181 	break;
182 	case MSG_EVT_NONE:
183 		/* fall through */
184 	default:
185 		psts = RTW_PHL_STATUS_SUCCESS;
186 		break;
187 	}
188 
189 	return psts;
190 }
191 
192 static enum rtw_phl_status
_phl_cmd_general_post_phase_msg_hdlr(struct phl_info_t * phl_info,void * dispr,struct phl_msg * msg)193 _phl_cmd_general_post_phase_msg_hdlr(struct phl_info_t *phl_info, void *dispr,
194 				     struct phl_msg *msg)
195 {
196 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
197 	enum phl_msg_evt_id evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
198 	struct phl_cmd_obj *phl_cmd = NULL;
199 
200 	phl_cmd = (struct phl_cmd_obj *)msg->inbuf;
201 
202 	switch (evt_id) {
203 	case MSG_EVT_CHG_OP_CH_DEF_START:
204 		psts = phl_cmd_chg_op_chdef_start_hdl(phl_info, phl_cmd->buf);
205 	break;
206 
207 	case MSG_EVT_SWCH_START:
208 		psts = phl_cmd_set_ch_bw_hdl(phl_info, phl_cmd->buf);
209 	break;
210 
211 	#if defined(CONFIG_PCI_HCI) && defined(PCIE_TRX_MIT_EN)
212 	case MSG_EVT_PCIE_TRX_MIT:
213 		psts = phl_evt_pcie_trx_mit_hdlr(phl_info, phl_cmd->buf);
214 	break;
215 	#endif
216 	case MSG_EVT_DBG_RX_DUMP:
217 	{
218 		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "===> %s : MSG_EVT_DBG_RX_DUMP\n", __func__);
219 		rtw_hal_notification(phl_info->hal, MSG_EVT_DBG_RX_DUMP, HW_PHY_0);
220 		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "<=== %s : MSG_EVT_DBG_RX_DUMP\n", __func__);
221 		psts = RTW_PHL_STATUS_SUCCESS;
222 	}
223 	break;
224 	case MSG_EVT_SW_WATCHDOG:
225 		if (IS_MSG_FAIL(msg->msg_id))
226 			psts = RTW_PHL_STATUS_FAILURE;
227 		else if (IS_MSG_CANCEL(msg->msg_id))
228 			psts = RTW_PHL_STATUS_FAILURE;
229 		else
230 			psts = RTW_PHL_STATUS_SUCCESS;
231 		psts = phl_watchdog_sw_cmd_hdl(phl_info, psts);
232 	break;
233 	case MSG_EVT_HW_WATCHDOG:
234 	{
235 		if (IS_MSG_CANNOT_IO(msg->msg_id))
236 			psts = RTW_PHL_STATUS_CANNOT_IO;
237 		else if (IS_MSG_FAIL(msg->msg_id))
238 			psts = RTW_PHL_STATUS_FAILURE;
239 		else if (IS_MSG_CANCEL(msg->msg_id))
240 			psts = RTW_PHL_STATUS_FAILURE;
241 		else
242 			psts = RTW_PHL_STATUS_SUCCESS;
243 		psts = phl_watchdog_hw_cmd_hdl(phl_info, psts);
244 	}
245 	break;
246 
247 #if defined(CONFIG_USB_HCI)
248 	case MSG_EVT_FORCE_USB_SW:
249 		psts = phl_force_usb_switch(phl_info, *(u32*)(phl_cmd->buf));
250 	break;
251 	case MSG_EVT_GET_USB_SPEED:
252 		psts = phl_get_cur_usb_speed(phl_info, (u32*)(phl_cmd->buf));
253 	break;
254 	case MSG_EVT_GET_USB_SW_ABILITY:
255 		psts = phl_get_usb_support_ability(phl_info, (u32*)(phl_cmd->buf));
256 	break;
257 #endif
258 	case MSG_EVT_CFG_AMPDU:
259 		psts = phl_cmd_cfg_ampdu_hdl(phl_info, phl_cmd->buf);
260 	break;
261 
262 	case MSG_EVT_DFS_PAUSE_TX:
263 		psts = phl_cmd_dfs_tx_pause_hdl(phl_info, phl_cmd->buf);
264 	break;
265 
266 	case MSG_EVT_ROLE_RECOVER:
267 		psts = phl_role_recover(phl_info);
268 	break;
269 	case MSG_EVT_ROLE_SUSPEND:
270 		psts = phl_role_suspend(phl_info);
271 	break;
272 
273 #if defined(CONFIG_PCI_HCI)
274 	case MSG_EVT_HAL_SET_L2_LEAVE:
275 		if (rtw_hal_set_l2_leave(phl_info->hal) == RTW_HAL_STATUS_SUCCESS)
276 			psts = RTW_PHL_STATUS_SUCCESS;
277 	break;
278 #endif
279 
280 	case MSG_EVT_NOTIFY_HAL:
281 		psts = phl_notify_cmd_hdl(phl_info, phl_cmd->buf);
282 	break;
283 
284 	case MSG_EVT_ISSUE_BCN:
285 #ifdef RTW_PHL_BCN
286 		psts = phl_cmd_issue_bcn_hdl(phl_info, phl_cmd->buf);
287 #endif
288 	break;
289 	case MSG_EVT_STOP_BCN:
290 #ifdef RTW_PHL_BCN
291 		psts = phl_cmd_stop_bcn_hdl(phl_info, phl_cmd->buf);
292 #endif
293 	break;
294 
295 	case MSG_EVT_SEC_KEY:
296 		psts = phl_cmd_set_key_hdl(phl_info, phl_cmd->buf);
297 	break;
298 
299 	case MSG_EVT_ROLE_START:
300 		psts = phl_wifi_role_start_hdl(phl_info, phl_cmd->buf);
301 	break;
302 
303 	case MSG_EVT_ROLE_CHANGE:
304 		psts = phl_wifi_role_chg_hdl(phl_info, phl_cmd->buf);
305 	break;
306 
307 	case MSG_EVT_ROLE_STOP:
308 		psts = phl_wifi_role_stop_hdl(phl_info, phl_cmd->buf);
309 	break;
310 
311 	case MSG_EVT_STA_INFO_CTRL:
312 		psts = phl_cmd_alloc_stainfo_hdl(phl_info, phl_cmd->buf);
313 	break;
314 
315 	case MSG_EVT_STA_MEDIA_STATUS_UPT:
316 		psts = phl_update_media_status_hdl(phl_info, phl_cmd->buf);
317 	break;
318 
319 	case MSG_EVT_CFG_CHINFO:
320 #ifdef CONFIG_PHL_CHANNEL_INFO
321 		psts = phl_cmd_cfg_chinfo_hdl(phl_info, phl_cmd->buf);
322 #endif
323 	break;
324 
325 	case MSG_EVT_STA_CHG_STAINFO:
326 		psts = phl_cmd_change_stainfo_hdl(phl_info, phl_cmd->buf);
327 	break;
328 
329 	default:
330 		psts = RTW_PHL_STATUS_SUCCESS;
331 	break;
332 	}
333 
334 	return psts;
335 }
336 
_phl_cmd_general_init(void * phl,void * dispr,void ** priv)337 static enum phl_mdl_ret_code _phl_cmd_general_init(void *phl, void *dispr,
338 						   void **priv)
339 {
340 	*priv = phl;
341 	return MDL_RET_SUCCESS;
342 }
343 
_phl_cmd_general_deinit(void * dispr,void * priv)344 static void _phl_cmd_general_deinit(void *dispr, void *priv)
345 {
346 
347 }
348 
_phl_cmd_general_start(void * dispr,void * priv)349 static enum phl_mdl_ret_code _phl_cmd_general_start(void *dispr, void *priv)
350 {
351 	u8 dispr_idx = 0;
352 
353 	if (RTW_PHL_STATUS_SUCCESS != phl_dispr_get_idx(dispr, &dispr_idx))
354 		return MDL_RET_FAIL;
355 
356 	#if defined(CONFIG_PCI_HCI) && defined(PCIE_TRX_MIT_EN)
357 	{
358 		struct phl_info_t *phl_info = (struct phl_info_t *)priv;
359 
360 		if (RTW_PHL_STATUS_SUCCESS !=
361 		phl_pcie_trx_mit_start(phl_info, dispr_idx))
362 			return MDL_RET_FAIL;
363 	}
364 	#endif
365 
366 	return MDL_RET_SUCCESS;
367 }
368 
_stop_operation_on_general(void * phl)369 static void _stop_operation_on_general(void *phl)
370 {
371 	rtw_phl_watchdog_stop(phl);
372 }
373 
_phl_cmd_general_stop(void * dispr,void * priv)374 static enum phl_mdl_ret_code _phl_cmd_general_stop(void *dispr, void *priv)
375 {
376 	_stop_operation_on_general(priv);
377 	return MDL_RET_SUCCESS;
378 }
379 
_fail_evt_hdlr(void * dispr,void * priv,struct phl_msg * msg)380 static void _fail_evt_hdlr(void *dispr, void *priv, struct phl_msg *msg)
381 {
382 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
383 	u16 evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
384 	u8 idx = 0;
385 #ifdef CONFIG_POWER_SAVE
386 	struct phl_module_op_info op_info = {0};
387 #endif
388 
389 	phl_dispr_get_idx(dispr, &idx);
390 
391 	switch (evt_id) {
392 	case MSG_EVT_HW_WATCHDOG:
393 		/* watchdog do not need to handle fail case */
394 		PHL_DBG("%s do simple watchdog!\n", __func__);
395 		rtw_hal_simple_watchdog(phl_info->hal, false);
396 		break;
397 	default:
398 #ifdef CONFIG_POWER_SAVE
399 		op_info.op_code = PS_MDL_OP_CANCEL_PWR_REQ;
400 		op_info.inbuf = (u8 *)&evt_id;
401 		phl_disp_eng_set_bk_module_info(phl_info, idx,
402 				PHL_MDL_POWER_MGNT, &op_info);
403 #endif
404 		break;
405 	}
406 }
407 
_phl_cmd_general_msg_hdlr(void * dispr,void * priv,struct phl_msg * msg)408 static enum phl_mdl_ret_code _phl_cmd_general_msg_hdlr(void *dispr, void *priv,
409 						       struct phl_msg *msg)
410 {
411 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
412 	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
413 
414 	if (IS_MSG_FAIL(msg->msg_id)) {
415 
416 		PHL_INFO("%s :: MDL_ID(%d)_FAIL - MSG_EVT_ID=%d \n", __func__,
417 			 MSG_MDL_ID_FIELD(msg->msg_id),
418 			 MSG_EVT_ID_FIELD(msg->msg_id));
419 
420 		_fail_evt_hdlr(dispr, priv, msg);
421 
422 		return MDL_RET_FAIL;
423 	}
424 
425 	if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL)
426 		return MDL_RET_IGNORE;
427 
428 	/*
429 	 * GENERAL is optional module, msg pass through mandatory module,
430 	 * optional module, and wifi role(protocol). So msg shall be handled
431 	 * at post phase to make sure that wifi role is at valid state
432 	 * if the msg is relative to wifi role(protocol)
433 	 */
434 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
435 		status =
436 		    _phl_cmd_general_pre_phase_msg_hdlr(phl_info, dispr, msg);
437 	else
438 		status =
439 		    _phl_cmd_general_post_phase_msg_hdlr(phl_info, dispr, msg);
440 
441 	if (status != RTW_PHL_STATUS_SUCCESS)
442 		return MDL_RET_FAIL;
443 
444 	return MDL_RET_SUCCESS;
445 }
446 
447 static enum phl_mdl_ret_code
_phl_cmd_general_set_info(void * dispr,void * priv,struct phl_module_op_info * info)448 _phl_cmd_general_set_info(void *dispr, void *priv,
449 			  struct phl_module_op_info *info)
450 {
451 	return MDL_RET_SUCCESS;
452 }
453 
454 enum rtw_phl_status
phl_cmd_get_cur_cmdinfo(struct phl_info_t * phl_info,u8 band_idx,struct phl_msg * msg,u8 ** cmd,u32 * cmd_len)455 phl_cmd_get_cur_cmdinfo(struct phl_info_t *phl_info,
456 						u8 band_idx,
457 						struct phl_msg *msg,
458 						u8 **cmd,
459 						u32 *cmd_len)
460 {
461 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
462 	struct phl_cmd_obj *phl_cmd = NULL;
463 
464 	phl_cmd = (struct phl_cmd_obj *)msg->inbuf;
465 	if (NULL != phl_cmd) {
466 		*cmd = phl_cmd->buf;
467 		*cmd_len = phl_cmd->buf_len;
468 		psts = RTW_PHL_STATUS_SUCCESS;
469 	}
470 
471 	return psts;
472 }
473 
474 static enum phl_mdl_ret_code
_phl_cmd_general_query_info(void * dispr,void * priv,struct phl_module_op_info * info)475 _phl_cmd_general_query_info(void *dispr, void *priv,
476 			    struct phl_module_op_info *info)
477 {
478 	return MDL_RET_SUCCESS;
479 }
480 
phl_register_cmd_general(struct phl_info_t * phl_info)481 enum rtw_phl_status phl_register_cmd_general(struct phl_info_t *phl_info)
482 {
483 	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
484 	struct phl_cmd_dispatch_engine *disp_eng = &(phl_info->disp_eng);
485 	struct phl_bk_module_ops bk_ops;
486 	u8 band_idx = 0;
487 
488 	bk_ops.init = _phl_cmd_general_init;
489 	bk_ops.deinit = _phl_cmd_general_deinit;
490 	bk_ops.start = _phl_cmd_general_start;
491 	bk_ops.stop = _phl_cmd_general_stop;
492 	bk_ops.msg_hdlr = _phl_cmd_general_msg_hdlr;
493 	bk_ops.set_info = _phl_cmd_general_set_info;
494 	bk_ops.query_info = _phl_cmd_general_query_info;
495 
496 	for (band_idx = 0; band_idx < disp_eng->phy_num; band_idx++) {
497 		status = phl_disp_eng_register_module(phl_info, band_idx,
498 						 PHL_MDL_GENERAL, &bk_ops);
499 		if (status != RTW_PHL_STATUS_SUCCESS) {
500 			PHL_ERR(
501 			    "%s register MDL_GENRAL in cmd disp failed :%d\n",
502 			    __func__, band_idx + 1);
503 			break;
504 		}
505 	}
506 
507 	return status;
508 }
509 
510 static enum rtw_phl_status
_phl_cmd_obj_free(struct phl_info_t * phl_info,struct phl_cmd_obj * phl_cmd)511 _phl_cmd_obj_free(struct phl_info_t *phl_info, struct phl_cmd_obj *phl_cmd)
512 {
513 	void *drv = phl_to_drvpriv(phl_info);
514 
515 	if(phl_cmd == NULL) {
516 		PHL_ERR("%s phl_cmd is NULL\n", __func__);
517 		_os_warn_on(1);
518 		return RTW_PHL_STATUS_FAILURE;
519 	}
520 
521 	if (phl_cmd->is_cmd_wait == true)
522 		_phl_cmd_sync_deinit(phl_info, &phl_cmd->cmd_sync);
523 	_os_kmem_free(drv, phl_cmd, sizeof(struct phl_cmd_obj));
524 	phl_cmd = NULL;
525 	return RTW_PHL_STATUS_SUCCESS;
526 }
527 
_phl_cmd_complete(void * priv,struct phl_msg * msg)528 static void _phl_cmd_complete(void *priv, struct phl_msg *msg)
529 {
530 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
531 	void *drv = phl_to_drvpriv(phl_info);
532 	struct phl_cmd_obj *phl_cmd = (struct phl_cmd_obj *)msg->inbuf;
533 	enum phl_cmd_sts csts = PHL_CMD_DONE_UNKNOWN;
534 	enum rtw_phl_status pstst = RTW_PHL_STATUS_SUCCESS;
535 
536 	PHL_DBG("%s evt_id:%d\n", __func__, phl_cmd->evt_id);
537 
538 	if (IS_MSG_CANNOT_IO(msg->msg_id))
539 		csts = PHL_CMD_DONE_CANNOT_IO;
540 	else if (IS_MSG_FAIL(msg->msg_id))
541 		csts = PHL_CMD_DONE_CMD_ERROR;
542 	else if (IS_MSG_CANCEL(msg->msg_id))
543 		csts = PHL_CMD_DONE_CMD_DROP;
544 	else
545 		csts = PHL_CMD_DONE_SUCCESS;
546 
547 	if (phl_cmd->is_cmd_wait)
548 		_phl_cmd_done(phl_info, &phl_cmd->cmd_sync, csts);
549 
550 	pstst = _cmd_stat_2_phl_stat(csts);
551 	if (phl_cmd->cmd_complete)
552 		phl_cmd->cmd_complete(drv, phl_cmd->buf, phl_cmd->buf_len, pstst);
553 
554 	if (phl_cmd->is_cmd_wait) {
555 		#define PHL_MAX_SCHEDULE_TIMEOUT 100000
556 		u32 try_cnt = 0;
557 		u32 start = _os_get_cur_time_ms();
558 
559 		do {
560 			if (_os_atomic_read(drv, &(phl_cmd->ref_cnt)) == 1)
561 				break;
562 			_os_sleep_ms(drv, 10);
563 			try_cnt++;
564 			if (try_cnt == 50)
565 				PHL_ERR("F-%s, L-%d polling is_cmd_wait to false\n",
566 							__FUNCTION__, __LINE__);
567 		} while (phl_get_passing_time_ms(start) < PHL_MAX_SCHEDULE_TIMEOUT);
568 	}
569 
570 	_phl_cmd_obj_free(phl_info, phl_cmd);
571 }
572 
573 enum rtw_phl_status
phl_cmd_enqueue(struct phl_info_t * phl_info,enum phl_band_idx band_idx,enum phl_msg_evt_id evt_id,u8 * cmd_buf,u32 cmd_len,void (* cmd_complete)(void * priv,u8 * buf,u32 buf_len,enum rtw_phl_status status),enum phl_cmd_type cmd_type,u32 cmd_timeout)574 phl_cmd_enqueue(struct phl_info_t *phl_info,
575                 enum phl_band_idx band_idx,
576                 enum phl_msg_evt_id evt_id,
577                 u8 *cmd_buf,
578                 u32 cmd_len,
579                 void (*cmd_complete)(void* priv, u8 *buf, u32 buf_len, enum rtw_phl_status status),
580                 enum phl_cmd_type cmd_type,
581                 u32 cmd_timeout)
582 {
583 	void *drv = phl_to_drvpriv(phl_info);
584 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
585 	struct phl_cmd_obj *phl_cmd = NULL;
586 	struct phl_msg msg = {0};
587 	struct phl_msg_attribute attr = {0};
588 
589 	phl_cmd = _os_kmem_alloc(drv, sizeof(struct phl_cmd_obj));
590 	if (phl_cmd == NULL) {
591 		PHL_ERR("%s: alloc phl_cmd failed!\n", __func__);
592 		psts = RTW_PHL_STATUS_RESOURCE;
593 		goto _exit;
594 	}
595 	phl_cmd->evt_id = evt_id;
596 	phl_cmd->buf = cmd_buf;
597 	phl_cmd->buf_len = cmd_len;
598 	phl_cmd->cmd_complete = cmd_complete;
599 
600 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_GENERAL);
601 	SET_MSG_EVT_ID_FIELD(msg.msg_id, evt_id);
602 	msg.inbuf = (u8 *)phl_cmd;
603 	msg.inlen = sizeof(struct phl_cmd_obj);
604 	msg.band_idx = band_idx;
605 	attr.completion.completion = _phl_cmd_complete;
606 	attr.completion.priv = phl_info;
607 
608 	if (cmd_type == PHL_CMD_WAIT) {
609 		phl_cmd->is_cmd_wait = true;
610 		_os_atomic_set(drv, &phl_cmd->ref_cnt, 0);
611 		_phl_cmd_sync_init(phl_info, evt_id, &phl_cmd->cmd_sync, cmd_timeout);
612 	}
613 
614 	psts = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
615 	if (psts == RTW_PHL_STATUS_SUCCESS) {
616 		if (cmd_type == PHL_CMD_WAIT) {
617 			psts = _phl_cmd_wait(phl_info, &phl_cmd->cmd_sync);
618 			/*ref_cnt++ for cmd wait done*/
619 			_os_atomic_inc(drv, &phl_cmd->ref_cnt);
620 			/* Check wait cmd status */
621 			if (psts == RTW_PHL_STATUS_CMD_SUCCESS)
622 				psts = RTW_PHL_STATUS_SUCCESS;
623 		} else {
624 			psts = RTW_PHL_STATUS_SUCCESS;
625 		}
626 	} else {
627 		PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: evt_id(%d)\n", __func__, evt_id);
628 		_phl_cmd_obj_free(phl_info, phl_cmd);
629 	}
630 
631 _exit:
632 	return psts;
633 }
634 
635 enum rtw_phl_status
rtw_phl_cmd_enqueue(void * phl,enum phl_band_idx band_idx,enum phl_msg_evt_id evt_id,u8 * cmd_buf,u32 cmd_len,void (* core_cmd_complete)(void * priv,u8 * cmd,u32 cmd_len,enum rtw_phl_status status),enum phl_cmd_type cmd_type,u32 cmd_timeout)636 rtw_phl_cmd_enqueue(void *phl,
637                     enum phl_band_idx band_idx,
638                     enum phl_msg_evt_id evt_id,
639                     u8 *cmd_buf,
640                     u32 cmd_len,
641                     void (*core_cmd_complete)(void *priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status),
642                     enum phl_cmd_type cmd_type,
643                     u32 cmd_timeout)
644 {
645 	return phl_cmd_enqueue((struct phl_info_t *)phl,
646 	                       band_idx,
647 	                       evt_id,
648 	                       cmd_buf,
649 	                       cmd_len,
650 	                       core_cmd_complete,
651 	                       cmd_type,
652 	                       cmd_timeout);
653 }
654 
655 #endif /*CONFIG_CMD_DISP*/
656 
657