xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_cmd_scan.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 #define _PHL_CMD_SCAN_C_
18 #include "phl_headers.h"
19 #include "phl_scan.h"
20 
21 #define param_to_phlcom(_param) 	(_param->wifi_role->phl_com)
22 
23 #ifdef CONFIG_PHL_CMD_SCAN
24 
25 
26 enum _CMD_SCAN_STATE {
27 	CMD_SCAN_ACQUIRE = BIT0,
28 	CMD_SCAN_STARTED = BIT1,
29 	CMD_SCAN_DF_IO = BIT2, /* Disable Function : IO */
30 };
31 
32 static void _cmd_scan_timer(void* role);
33 
34 #define DBG_SCAN_CHAN_DUMP
35 
36 #ifdef DBG_SCAN_CHAN_DUMP
37 static void
_cmd_estimated_swch_seq(struct rtw_phl_scan_param * param,u8 op_num)38 _cmd_estimated_swch_seq(struct rtw_phl_scan_param *param, u8 op_num)
39 {
40 	u8 chidx = 0;
41 	u8 opidx = 0;
42 	u8 total_ch_num = 0;
43 
44 	if ((param->back_op_mode == SCAN_BKOP_CNT) &&
45 		(param->back_op_ch_cnt == 0)) {
46 		PHL_ERR("%s bkop_cnt == 0\n", __func__);
47 		_os_warn_on(1);
48 		return;
49 	}
50 
51 	/*swicth channel sequence by cmd_scan's estimated */
52 	PHL_INFO("%s:: Estimated channel sequence:\n", __func__);
53 
54 	if (param->back_op_mode == SCAN_BKOP_CNT) {
55 		PHL_INFO("[SCAN_BKOP_CNT]\n");
56 		for(chidx = 0; chidx < param->ch_num; chidx++) {
57 			PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "%3d, ", param->ch[chidx].channel);
58 			total_ch_num++;
59 			if(!((chidx + 1) % param->back_op_ch_cnt)) {
60 				if (op_num) {
61 					for(opidx = 0; opidx < op_num; opidx++) {
62 						PHL_DATA(COMP_PHL_DBG, _PHL_INFO_,
63 							"[%3d], ", param->back_op_ch[opidx].channel);
64 						total_ch_num++;
65 					}
66 				}
67 			}
68 			if(!((chidx + 1) % (param->back_op_ch_cnt * 2)))
69 				PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
70 		}
71 		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
72 
73 	}
74 	#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
75 	else if (param->back_op_mode == SCAN_BKOP_TIMER) {
76 		u16 ch_dur;
77 
78 		PHL_INFO("[SCAN_BKOP_TIMER]\n");
79 		for(chidx = 0; chidx < param->ch_num; chidx++) {
80 			total_ch_num++;
81 			ch_dur = (op_num) ? param->back_op_off_ch_dur_ms : param->ch[chidx].duration;
82 			PHL_INFO("\t%3d, dur:%d(ms)\n", param->ch[chidx].channel, ch_dur);
83 		}
84 		if (op_num) {
85 			for(opidx = 0; opidx < op_num; opidx++) {
86 				total_ch_num++;
87 				PHL_INFO("\t[%3d], dur:%d(ms)\n",
88 					param->back_op_ch[opidx].channel, param->back_op_ch[opidx].duration);
89 			}
90 		}
91 		PHL_INFO("max_listen_time:%d (ms)\n", param->max_listen_time);
92 		PHL_INFO("op_ch_dur_ms:%d, off_ch_dur_ms:%d, off_ch_ext_dur_ms:%d (ms)",
93 			param->back_op_ch_dur_ms,
94 			param->back_op_off_ch_dur_ms,
95 			param->back_op_off_ch_ext_dur_ms);
96 	}
97 	#endif
98 	else if (param->back_op_mode == SCAN_BKOP_NONE) {
99 		PHL_INFO("[SCAN_BKOP_NONE]\n");
100 		for(chidx = 0; chidx < param->ch_num; chidx++) {
101 			PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "%3d, ", param->ch[chidx].channel);
102 			total_ch_num++;
103 			if(!((chidx + 1) % 6))
104 				PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
105 		}
106 		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
107 	}
108 
109 	PHL_INFO("Scan chan num:%d , Total num:%d, repeat:%d\n",
110 		param->ch_num, total_ch_num, param->repeat);
111 	PHL_INFO("--------\n");
112 }
113 #endif /*DBG_SCAN_CHAN_DUMP*/
114 
115 static void
_cmd_scan_update_chlist(void * drv,struct rtw_phl_scan_param * param)116 _cmd_scan_update_chlist(void *drv, struct rtw_phl_scan_param *param)
117 {
118 	u8 idx = 0;
119 
120 	INIT_LIST_HEAD(&param->chlist.queue);
121 	for(idx = 0; idx < param->ch_num; idx++) {
122 		INIT_LIST_HEAD(&param->ch[idx].list);
123 		pq_push(drv, &param->chlist, &param->ch[idx].list, _tail, _ps);
124 	}
125 }
126 
127 /*
128  * Insert op channel list
129  * Ex.	ch_intvl =3
130  * ch_idx : -1, 0, 1, 2,   3, 4, 5, 6
131  *					   ^		  ^
132  *					   op0~op5	  op0~op5
133  *
134  * => 0,1,2,[op0],[op1],3,4,5,[op0],[op1],6,7,8,[op0],[op1]
135  */
136 
137 static inline void
_cmd_scan_enqueue_opch(void * drv,struct rtw_phl_scan_param * param,struct phl_queue * q)138 _cmd_scan_enqueue_opch(void *drv, struct rtw_phl_scan_param *param, struct phl_queue *q)
139 {
140 	u8 idx = 0;
141 
142 	for(idx = 0; idx < MAX_WIFI_ROLE_NUMBER; idx ++) {
143 		if(param->back_op_ch[idx].channel)
144 			pq_push(drv, &param->chlist, &param->back_op_ch[idx].list, _first, _ps);
145 		else
146 			break;
147 	}
148 }
_cmd_scan_select_chnl(void * drv,struct rtw_phl_scan_param * param)149 static struct phl_scan_channel *_cmd_scan_select_chnl(
150 	void *drv, struct rtw_phl_scan_param *param)
151 {
152 	struct phl_scan_channel *scan_ch = NULL;
153 	_os_list* obj = NULL;
154 	bool back_op_is_required = (param->back_op_ch[0].channel)? true:false;
155 
156 next_ch:
157 	if(pq_pop(drv, &param->chlist, &obj, _first, _ps)) {
158 		scan_ch = (struct phl_scan_channel*)obj;
159 
160 		if(scan_ch->scan_mode == NORMAL_SCAN_MODE) {
161 			/* 1- enable,  2- BK_CNT mode, 3- prev is non-op, 4- ch_intvl's turn */
162 			if (back_op_is_required && param->back_op_mode == SCAN_BKOP_CNT) {
163 				if(param->scan_ch &&
164 				   !((param->ch_idx + 1) % param->back_op_ch_cnt)) {
165 					_cmd_scan_enqueue_opch(drv, param, &param->chlist);
166 				}
167 			}
168 			param->ch_idx++;
169 		}
170 		#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
171 		else if (scan_ch->scan_mode == P2P_LISTEN_MODE) {
172 			if (back_op_is_required && param->back_op_mode == SCAN_BKOP_TIMER) {
173 				scan_ch->duration = param->back_op_off_ch_dur_ms;
174 				_cmd_scan_enqueue_opch(drv, param, &param->chlist);
175 			}
176 			param->ch_idx++;
177 		}
178 		#endif
179 		param->scan_ch = scan_ch;
180 	}
181 	else if(param->repeat > 0) {
182 		_cmd_scan_update_chlist(drv, param);
183 		param->ch_idx = 0;
184 		/* 255 means loop forever */
185 		if (param->repeat != 255)
186 			param->repeat--;
187 		goto next_ch;
188 	}
189 	else {
190 		return NULL;
191 	}
192 
193 	PHL_INFO("%s: repeat[%d] ch_idx=[%d/%d], ch_number=%d, scan_mode= %s\n", __func__,
194 		 param->repeat, param->ch_idx, param->ch_num, param->scan_ch->channel,
195 		(param->scan_ch->scan_mode == BACKOP_MODE)? "OP_CH": "Non-OP");
196 
197 	return param->scan_ch;
198 }
199 
200 /* Notification complete */
_cmd_scan_timer_notify_cb(void * role,struct phl_msg * msg)201 void _cmd_scan_timer_notify_cb(
202 	void *role, struct phl_msg *msg)
203 {
204 	if (IS_MSG_CANNOT_IO(msg->msg_id)) {
205 		PHL_ERR("%s: SWCH_DONE failure by CANNOT IO\n", __func__);
206 		return;
207 	}
208 
209 	if (IS_MSG_CANCEL(msg->msg_id)) {
210 		/* Last event occured MSG_STATUS_PENDING */
211 		PHL_ERR("%s: SWCH_DONE pending or abort Occurred!\n", __func__);
212 
213 		_cmd_scan_timer(role);
214 	}
215 }
216 
_cmd_scan_timer(void * role)217 static void _cmd_scan_timer(void* role)
218 {
219 	struct rtw_wifi_role_t *wifi_role = (struct rtw_wifi_role_t *)role;
220 	struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
221 	struct phl_info_t *phl_info = phl_com->phl_priv;
222 	u8 band_idx = wifi_role->hw_band;
223 
224 	struct phl_msg msg = {0};
225 	struct phl_msg_attribute attr = {0};
226 
227 	PHL_INFO("%s \n", __func__);
228 
229 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
230 /** When listen state of each channel entry expired,
231  * timer callback send MSG_EVT_LISTEN_STATE_EXPIRE for additional condition check
232  * If nothing specitail occured, then send MSG_EVT_SWCH_START to proceed for the rest of channel list
233  * therefore, additional process delay for MSG_EVT_LISTEN_STATE_EXPIRE would prolong listen period
234  * */
235 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_LISTEN_STATE_EXPIRE);
236 	msg.rsvd[0] = (u8*)role;
237 	msg.band_idx = band_idx;
238 
239 	attr.completion.completion = _cmd_scan_timer_notify_cb;
240 	attr.completion.priv = role;
241 
242 	if(phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL) != RTW_PHL_STATUS_SUCCESS)
243 		PHL_ERR("%s: [SCAN_TIMER] phl_disp_eng_send_msg failed !\n", __func__);
244 }
245 
246 /* Notification complete */
_cmd_swch_done_notify_cb(void * drv,struct phl_msg * msg)247 void _cmd_swch_done_notify_cb(
248 	void *drv, struct phl_msg *msg)
249 {
250 	if (msg->inbuf) {
251 		_os_mem_free(drv, msg->inbuf, msg->inlen);
252 	}
253 }
254 
_cmd_swch_done_notify(void * dispr,void * drv,struct rtw_phl_scan_param * param)255 enum rtw_phl_status _cmd_swch_done_notify(
256 	void *dispr, void *drv, struct rtw_phl_scan_param *param)
257 {
258 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
259 	struct phl_scan_channel *scan_ch = param->scan_ch;
260 	struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
261 	struct phl_info_t *phl = (struct phl_info_t *) phl_com->phl_priv;
262 	struct phl_msg msg = {0};
263 	struct phl_msg_attribute attr = {0};
264 	u8 *info = NULL;
265 	u8 idx = 0xff;
266 
267 	info = _os_mem_alloc(drv, sizeof(struct phl_scan_channel));
268 	if (info == NULL) {
269 		PHL_ERR("%s: [SWCH_DONE] alloc buffer failed!\n", __func__);
270 		return RTW_PHL_STATUS_FAILURE;
271 	}
272 
273 	_os_mem_cpy(drv, info, scan_ch, sizeof(*scan_ch));
274 
275 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
276 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SWCH_DONE);
277 
278 	attr.opt = MSG_OPT_CLR_SNDR_MSG_IF_PENDING;
279 	attr.completion.completion = _cmd_swch_done_notify_cb;
280 	attr.completion.priv = drv;
281 
282 	msg.inbuf = info;
283 	msg.inlen = sizeof(struct phl_scan_channel);
284 	msg.rsvd[0] = (u8*)param->wifi_role;
285 	phl_dispr_get_idx(dispr, &idx);
286 	msg.band_idx = idx;
287 	pstatus = phl_disp_eng_send_msg(phl, &msg, &attr, NULL);
288 	if(pstatus != RTW_PHL_STATUS_SUCCESS) {
289 		PHL_ERR("%s: [SWCH_DONE] phl_disp_eng_send_msg failed!\n", __func__);
290 		_os_mem_free(drv, info, sizeof(struct phl_scan_channel));
291 	}
292 	return pstatus;
293 }
294 
_cmd_scan_end(void * drv,struct rtw_phl_scan_param * param)295 void _cmd_scan_end(
296 	void *drv, struct rtw_phl_scan_param *param)
297 {
298 	struct rtw_wifi_role_t *wifi_role = param->wifi_role;
299 	struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
300 	struct phl_info_t *phl_info = phl_com->phl_priv;
301 
302 	PHL_INFO("_cmd_scan_end \n");
303 
304 	param->end_time = _os_get_cur_time_ms();
305 
306 	/* dump scan time */
307 	param->total_scan_time =
308 		phl_get_passing_time_ms(param->enqueue_time);
309 
310 	pq_deinit(drv, &param->chlist);
311 
312 	/* acquire state */
313 	_os_cancel_timer(drv, &param->scan_timer);
314 	_os_release_timer(drv, &param->scan_timer);
315 
316 	if(TEST_STATUS_FLAG(param->state, CMD_SCAN_STARTED) &&
317 	   !TEST_STATUS_FLAG(param->state, CMD_SCAN_DF_IO) )
318 	{
319 		rtw_hal_com_scan_restore_tx_lifetime(phl_info->hal, wifi_role->hw_band);
320 
321 		rtw_hal_scan_set_rxfltr_by_mode(phl_info->hal, wifi_role->hw_band,
322 						false, &param->fltr_mode);
323 		rtw_hal_scan_pause_tx_fifo(phl_info->hal, wifi_role->hw_band, false);
324 
325 		rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_END, wifi_role->hw_band);
326 	}
327 
328 	if (param->ops->scan_complete)
329 		param->ops->scan_complete(param->priv, param);
330 }
331 
332 /* Notification complete */
_cmd_abort_notify_cb(void * drv,struct phl_msg * msg)333 void _cmd_abort_notify_cb(
334 	void *drv, struct phl_msg *msg)
335 {
336 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param *)msg->inbuf;
337 
338 	if(IS_MSG_CANNOT_IO(msg->msg_id))
339 		SET_STATUS_FLAG(param->state, CMD_SCAN_DF_IO);
340 
341 	_cmd_scan_end(drv, param);
342 }
343 
_cmd_abort_notify(void * dispr,void * drv,struct rtw_phl_scan_param * param,bool abort)344 void _cmd_abort_notify(void *dispr, void *drv,
345 	struct rtw_phl_scan_param *param, bool abort)
346 {
347 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
348 	struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
349 	struct phl_msg msg = {0};
350 	struct phl_msg_attribute attr = {0};
351 	struct phl_info_t *phl = (struct phl_info_t *) phl_com->phl_priv;
352 	u8 idx = 0xff;
353 
354 	if(TEST_STATUS_FLAG(param->state, CMD_SCAN_ACQUIRE))
355 	{
356 		param->result = SCAN_REQ_CANCEL;
357 
358 		SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
359 		SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SCAN_END);
360 
361 		if(abort)
362 			attr.opt = MSG_OPT_SEND_IN_ABORT;
363 		attr.completion.completion = _cmd_abort_notify_cb;
364 		attr.completion.priv = drv;
365 
366 		msg.inbuf = (u8*)param;
367 		msg.rsvd[0] = (u8*)param->wifi_role;
368 		#ifdef RTW_WKARD_MRC_ISSUE_NULL_WITH_SCAN_OPS
369 		msg.rsvd[1] = (u8*)param->ops->scan_issue_null_data;
370 		#endif
371 
372 		phl_dispr_get_idx(dispr, &idx);
373 		msg.band_idx = idx;
374 		pstatus = phl_disp_eng_send_msg(phl, &msg, &attr, NULL);
375 		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
376 			/* (1) dispr_stop
377 			   (2) idle msg empty .*/
378 
379 			PHL_ERR("%s :: [Abort] dispr_send_msg failed (0x%X)\n",
380 				__func__, pstatus);
381 
382 			if(pstatus == RTW_PHL_STATUS_UNEXPECTED_ERROR ||
383 			   TEST_STATUS_FLAG(phl_com->dev_state, RTW_DEV_SURPRISE_REMOVAL)) {
384 				/* clean sw resource only */
385 				/* (1) driver is going to unload */
386 				/* (2) Supprise remove */
387 				SET_STATUS_FLAG(param->state, CMD_SCAN_DF_IO);
388 			}
389 			_cmd_abort_notify_cb(drv, &msg);
390 		}
391 	}
392 	else {
393 		param->result = SCAN_REQ_ABORT;
394 		pq_deinit(drv, &param->chlist);
395 
396 		if (param->ops->scan_complete)
397 			param->ops->scan_complete(param->priv, param);
398 	}
399 }
400 
_cmd_scan_fail_ev_hdlr(void * dispr,void * priv,struct phl_msg * msg)401 enum phl_mdl_ret_code _cmd_scan_fail_ev_hdlr(
402 	void* dispr, void* priv, struct phl_msg* msg)
403 {
404 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
405 	struct rtw_wifi_role_t *wifi_role = param->wifi_role;
406 	struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
407 	struct phl_info_t *phl_info = phl_com->phl_priv;
408 	void *d = phlcom_to_drvpriv(phl_com);
409 	u8 idx = 0xff;
410 	struct phl_msg nextmsg = {0};
411 	struct phl_msg_attribute attr = {0};
412 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
413 
414 	SET_MSG_MDL_ID_FIELD(nextmsg.msg_id, PHL_FG_MDL_SCAN);
415 	phl_dispr_get_idx(dispr, &idx);
416 	nextmsg.band_idx = idx;
417 	switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
418 		case MSG_EVT_SCAN_START:
419 			/* fall through */
420 		case MSG_EVT_SWCH_START:
421 			/* fall through */
422 		case MSG_EVT_SWCH_DONE:
423 			PHL_INFO("SCAN_START/SWCH_START/SWCH_DONE:: failed/timeout handler \n");
424 
425 			SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SCAN_END);
426 			nextmsg.rsvd[0] = (u8*)param->wifi_role;
427 			#ifdef RTW_WKARD_MRC_ISSUE_NULL_WITH_SCAN_OPS
428 			nextmsg.rsvd[1] = (u8*)param->ops->scan_issue_null_data;
429 			#endif
430 			pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
431 			if(pstatus != RTW_PHL_STATUS_SUCCESS)
432 				PHL_ERR("%s :: [SWCH_START][1] phl_disp_eng_send_msg failed\n", __func__);
433 		break;
434 
435 		case MSG_EVT_SCAN_END:
436 			// free token
437 			// release timer
438 			PHL_INFO("MSG_EVT_SCAN_END:: failed/timeout handler \n");
439 			pstatus = phl_disp_eng_free_token(phl_info, idx, &param->token);
440 			if(pstatus == RTW_PHL_STATUS_SUCCESS)
441 			{
442 				if(IS_MSG_CANNOT_IO(msg->msg_id))
443 					SET_STATUS_FLAG(param->state, CMD_SCAN_DF_IO);
444 
445 				_cmd_scan_end(d, param);
446 			}
447 		break;
448 
449 		default:
450 			/* unknown state */
451 		break;
452 	}
453 
454 	return MDL_RET_SUCCESS;
455 }
456 
_cmd_scan_hdl_external_evt(void * dispr,void * priv,struct phl_msg * msg)457 enum phl_mdl_ret_code _cmd_scan_hdl_external_evt(
458 	void* dispr, void* priv, struct phl_msg* msg)
459 {
460 	PHL_DBG("%s :: From others MDL =%d , EVT_ID=%d\n", __func__,
461 		 MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
462 	return MDL_RET_IGNORE;
463 }
464 
_cmd_chk_ext_act_scan(struct rtw_phl_scan_param * param)465 u8 _cmd_chk_ext_act_scan(struct rtw_phl_scan_param *param)
466 {
467 #ifdef RTW_WKARD_CMD_SCAN_EXTEND_ACTIVE_SCAN
468 	/** suppose to query the time of last recieved beacon in current channel here
469 	 * then change state to EXT_ACT_SCAN_TRIGGER if needed
470 	 * but, PHL does not store bss list at the moment, therefore,
471 	 * core layer use set_info (FG_REQ_OP_NOTIFY_BCN_RCV) to notify scan module incoming bcn
472 	 * and change state to EXT_ACT_SCAN_TRIGGER accordingly.
473 	*/
474 #endif
475 	if (param->scan_ch->type == RTW_PHL_SCAN_PASSIVE &&
476 	    param->scan_ch->ext_act_scan == EXT_ACT_SCAN_TRIGGER) {
477 		if (param->ops->scan_issue_pbreq)
478 			param->ops->scan_issue_pbreq(param->priv, param);
479 		param->scan_ch->ext_act_scan = EXT_ACT_SCAN_DONE;
480 		return true;
481 	}
482 	return false;
483 }
484 
485 void
_cmd_scan_start(struct phl_info_t * phl_info,struct rtw_wifi_role_t * wifi_role,struct rtw_phl_scan_param * param)486 _cmd_scan_start(struct phl_info_t *phl_info,
487 		struct rtw_wifi_role_t *wifi_role,
488 		struct rtw_phl_scan_param *param)
489 {
490 	rtw_hal_scan_pause_tx_fifo(phl_info->hal, wifi_role->hw_band, true);
491 	rtw_hal_scan_set_rxfltr_by_mode(phl_info->hal, wifi_role->hw_band,
492 					true, &param->fltr_mode);
493 	rtw_hal_com_scan_set_tx_lifetime(phl_info->hal, wifi_role->hw_band);
494 }
495 
_cmd_scan_hdl_internal_evt(void * dispr,void * priv,struct phl_msg * msg)496 enum phl_mdl_ret_code _cmd_scan_hdl_internal_evt(
497 	void* dispr, void* priv, struct phl_msg* msg)
498 {
499 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
500 	struct rtw_wifi_role_t *wifi_role = param->wifi_role;
501 	struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
502 	struct phl_info_t *phl_info = phl_com->phl_priv;
503 	void *d = phlcom_to_drvpriv(phl_com);
504 	u32 diff_time = 0;
505 
506 	struct phl_msg nextmsg = {0};
507 	struct phl_msg_attribute attr = {0};
508 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
509 	u8 idx = 0xff;
510 	struct phl_scan_channel *scan_ch = NULL;
511 	bool tx_pause = true;
512 	struct rtw_chan_def chdef = {0};
513 
514 	phl_dispr_get_idx(dispr, &idx);
515 	diff_time = phl_get_passing_time_ms(param->enqueue_time);
516 
517 	if (param->max_scan_time && diff_time >= param->max_scan_time) {
518 		PHL_WARN("%s:: Timeout! %d > max_time %d\n",
519 				 __func__, diff_time, param->max_scan_time);
520 
521 		/* Abort scan request */
522 		/* Based on [CN3AXSW-552]
523 		 * ex. max_scan_time = 4sec
524 		 * Usb dongle would abort scan_req in 29~33th chnl
525 		 * If chnllist insert op-chnl, scan_req would be aborted in 21~23th chnl.
526 		 * It means that usb dongle always can't do fully scan.
527 		 * So, abort scan_req or not, depend on core layer.
528 		*/
529 		/*_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
530 		return MDL_RET_FAIL; */
531 	}
532 	else {
533 		PHL_INFO("%s:: TimeIntvl: %u \n", __func__, diff_time);
534 	}
535 
536 	#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
537 	if (param->max_listen_time && diff_time >= param->max_listen_time) {
538 		PHL_WARN("%s:: Timeout! %d > max_listen_time %d\n",
539 				 __func__, diff_time, param->max_listen_time);
540 		#if 0
541 		_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
542 		return MDL_RET_FAIL;
543 		#endif
544 	}
545 	#endif
546 
547 	SET_MSG_MDL_ID_FIELD(nextmsg.msg_id, PHL_FG_MDL_SCAN);
548 	nextmsg.band_idx = idx;
549 
550 	switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
551 		case MSG_EVT_SCAN_START:
552 			_cmd_scan_start(phl_info, wifi_role, param);
553 			rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_START,
554 					     wifi_role->hw_band);
555 
556 			/* [scan start notify] */
557 			if (param->ops->scan_start)
558 				param->ops->scan_start(param->priv, param);
559 
560 			SET_STATUS_FLAG(param->state, CMD_SCAN_STARTED);
561 
562 			SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SWCH_START);
563 			nextmsg.rsvd[0] = (u8*)wifi_role;
564 			pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
565 			if(pstatus != RTW_PHL_STATUS_SUCCESS)
566 				PHL_ERR("%s :: [SCAN_START] phl_disp_eng_send_msg failed\n", __func__);
567 		break;
568 		case MSG_EVT_LISTEN_STATE_EXPIRE:
569 			if (_cmd_chk_ext_act_scan(param)) {
570 				_os_set_timer(d, &param->scan_timer, param->ext_act_scan_period);
571 				PHL_INFO("%s :: extend listen state of ch %d by %d ms, and reset timer\n",
572 					__func__, param->scan_ch->channel, param->ext_act_scan_period);
573 				break;
574 			}
575 			SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SWCH_START);
576 			nextmsg.rsvd[0] = (u8*)wifi_role;
577 
578 			pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
579 			if(pstatus != RTW_PHL_STATUS_SUCCESS)
580 				PHL_ERR("%s :: [LISTEN_STATE_EXPIRE] dispr_send_msg failed\n", __func__);
581 
582 		break;
583 
584 		case MSG_EVT_SWCH_START:
585 			/*	ycx++
586 				ycx > length(yclist) ? SCAN_EV_END : switch channel */
587 
588 			PHL_INFO("MSG_EVT_SWCH_START \n");
589 
590 			/* For the first time, param->scan_ch would be NULL */
591 			/* Current channel scan_mode */
592 			if (param->scan_ch && param->scan_ch->scan_mode == BACKOP_MODE) {
593 				tx_pause = false;
594 			}
595 
596 			scan_ch = _cmd_scan_select_chnl(d, param);
597 			if (scan_ch == NULL) {
598 				/* no more channel, we are done */
599 				SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SCAN_END);
600 				nextmsg.rsvd[0] = (u8*)param->wifi_role;
601 				#ifdef RTW_WKARD_MRC_ISSUE_NULL_WITH_SCAN_OPS
602 				nextmsg.rsvd[1] = (u8*)param->ops->scan_issue_null_data;
603 				#endif
604 				pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
605 				if(pstatus != RTW_PHL_STATUS_SUCCESS)
606 					PHL_ERR("%s :: [SWCH_START][1] dispr_send_msg failed\n", __func__);
607 				break;
608 			}
609 
610 			/* Next channel scan_mode */
611 			if ((scan_ch->scan_mode != BACKOP_MODE) && !tx_pause) {
612 				/* Tx pause */
613 				rtw_hal_scan_pause_tx_fifo(phl_info->hal, wifi_role->hw_band, true);
614 				tx_pause = true;
615 			}
616 			chdef.band = scan_ch->band;
617 			chdef.chan = (u8)scan_ch->channel;
618 			chdef.bw = scan_ch->bw;
619 			chdef.offset = scan_ch->offset;
620 
621 			phl_set_ch_bw(wifi_role, &chdef, false);
622 
623 			if ((scan_ch->scan_mode != BACKOP_MODE) &&
624 			    (scan_ch->type == RTW_PHL_SCAN_ACTIVE)) {
625 			    /* Notify RF to do tssi backup */
626 				rtw_hal_notification(phl_info->hal, MSG_EVT_SWCH_START, wifi_role->hw_band);
627 				if (param->ops->scan_issue_pbreq)
628 					param->ops->scan_issue_pbreq(param->priv, param);
629 			}
630 
631 			if ((scan_ch->scan_mode == BACKOP_MODE) && tx_pause) {
632 				/* Tx un-pause */
633 				rtw_hal_scan_pause_tx_fifo(phl_info->hal, wifi_role->hw_band, false);
634 			}
635 
636 			_os_set_timer(d, &param->scan_timer, scan_ch->duration);
637 			#ifdef DBG_SCAN_CHAN_DUMP
638 			PHL_INFO("[SCAN] band:%d chan:%d bw:%d offset:%d duration:%d (ms)\n",
639 				scan_ch->band, scan_ch->channel, scan_ch->bw,
640 					scan_ch->offset, scan_ch->duration);
641 			#endif
642 
643 			pstatus = _cmd_swch_done_notify(dispr, d, param);
644 		break;
645 
646 		case MSG_EVT_SWCH_DONE:
647 			if (param->ops->scan_ch_ready)
648 				param->ops->scan_ch_ready(param->priv, param);
649 
650 			PHL_INFO("MSG_EVT_SWCH_DONE :: duration=%d\n", param->scan_ch->duration);
651 		break;
652 
653 		case MSG_EVT_SCAN_END:
654 			PHL_INFO("MSG_EVT_SCAN_END \n");
655 			pstatus = phl_disp_eng_free_token(phl_info, idx, &param->token);
656 			if(pstatus == RTW_PHL_STATUS_SUCCESS) {
657 
658 				param->result = SCAN_REQ_COMPLETE;
659 
660 				_cmd_scan_end(d, param);
661 			}
662 			else
663 				PHL_WARN("%s :: [SCAN_END] Abort occurred, skip!\n", __func__);
664 
665 		break;
666 
667 		default:
668 			/* unknown state */
669 		break;
670 	}
671 
672 	return MDL_RET_SUCCESS;
673 }
674 
675 
_phl_cmd_scan_req_acquired(void * dispr,void * priv)676 enum phl_mdl_ret_code _phl_cmd_scan_req_acquired(
677 	void* dispr, void* priv)
678 {
679 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
680 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
681 	struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
682 	void *d = phlcom_to_drvpriv(phl_com);
683 	u32 diff_time = 0;
684 	struct phl_info_t *phl_info = phl_com->phl_priv;
685 	u8 idx = 0xff;
686 
687 	struct phl_msg msg = {0};
688 	struct phl_msg_attribute attr = {0};
689 
690 	FUNCIN();
691 
692 	param->start_time = _os_get_cur_time_ms();
693 
694 	/* check max scan time */
695 	if (param->max_scan_time > 0) {
696 		diff_time = phl_get_passing_time_ms(param->enqueue_time);
697 
698 		if (diff_time >= param->max_scan_time) {
699 			PHL_WARN("%s:: Timeout! %u > max_time %d\n",
700 				 __func__, diff_time, param->max_scan_time);
701 			goto error;
702 		}
703 	}
704 
705 	_os_init_timer(d, &param->scan_timer, _cmd_scan_timer,
706 		       param->wifi_role, "phl_cmd_scan_req_timer");
707 
708 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
709 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SCAN_START);
710 	msg.rsvd[0] = (u8*)param->wifi_role;
711 	phl_dispr_get_idx(dispr, &idx);
712 	msg.band_idx = idx;
713 	pstatus = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
714 
715 	if(pstatus != RTW_PHL_STATUS_SUCCESS) {
716 		_os_release_timer(d, &param->scan_timer);
717 		goto error;
718 	}
719 	else {
720 		SET_STATUS_FLAG(param->state, CMD_SCAN_ACQUIRE);
721 		return MDL_RET_SUCCESS;
722 	}
723 
724 error:
725 	_cmd_abort_notify(dispr, d, param, false);
726 	return MDL_RET_FAIL;
727 }
728 
_phl_cmd_scan_req_abort(void * dispr,void * priv)729 enum phl_mdl_ret_code _phl_cmd_scan_req_abort(
730 	void* dispr, void* priv)
731 {
732 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
733 	struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
734 	void *d = phlcom_to_drvpriv(phl_com);
735 
736 	PHL_INFO("_phl_cmd_scan_req_abort \n");
737 	_cmd_abort_notify(dispr, d, param, true);
738 	return MDL_RET_SUCCESS;
739 }
740 
_phl_cmd_scan_req_ev_hdlr(void * dispr,void * priv,struct phl_msg * msg)741 enum phl_mdl_ret_code _phl_cmd_scan_req_ev_hdlr(
742 	void* dispr, void* priv,
743 	struct phl_msg* msg)
744 {
745 	enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
746 
747 	if(IS_MSG_FAIL(msg->msg_id)) {
748 		PHL_INFO("%s :: MSG(%d)_FAIL - EVT_ID=%d \n", __func__,
749 			 MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
750 
751 		_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
752 		return MDL_RET_FAIL;
753 	}
754 
755 	switch(MSG_MDL_ID_FIELD(msg->msg_id)) {
756 		case PHL_FG_MDL_SCAN:
757 			ret = _cmd_scan_hdl_internal_evt(dispr, priv, msg);
758 			break;
759 
760 		default:
761 			ret = _cmd_scan_hdl_external_evt(dispr, priv, msg);
762 			break;
763 	}
764 	return ret;
765 }
766 
_phl_cmd_scan_req_set_info(void * dispr,void * priv,struct phl_module_op_info * info)767 enum phl_mdl_ret_code _phl_cmd_scan_req_set_info(
768 	void* dispr, void* priv, struct phl_module_op_info* info)
769 {
770 	enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
771 
772 #ifdef RTW_WKARD_CMD_SCAN_EXTEND_ACTIVE_SCAN
773 	switch(info->op_code) {
774 		case FG_REQ_OP_NOTIFY_BCN_RCV:
775 		{
776 			struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
777 			u16 channel = 0;
778 
779 			/* this workaround might have race condition with background thread*/
780 			channel = *(u8*)info->inbuf;
781 			if (param->scan_ch &&
782 			    param->scan_ch->channel == channel &&
783 			    param->scan_ch->ext_act_scan == EXT_ACT_SCAN_ENABLE) {
784 				param->scan_ch->ext_act_scan = EXT_ACT_SCAN_TRIGGER;
785 				PHL_INFO(" %s :: channel %d extend for active scan\n", __func__, channel);
786 			}
787 			if (param->scan_ch &&
788 			    param->scan_ch->channel != channel)
789 			    PHL_INFO(" %s :: channel %d mismatch from listen channel %d\n", __func__, channel, param->scan_ch->channel);
790 			ret = MDL_RET_SUCCESS;
791 		}
792 			break;
793 		default:
794 			break;
795 	}
796 #endif
797 	/* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
798 	return ret;
799 }
800 
_phl_cmd_scan_req_query_info(void * dispr,void * priv,struct phl_module_op_info * info)801 enum phl_mdl_ret_code _phl_cmd_scan_req_query_info(
802 	void* dispr, void* priv, struct phl_module_op_info* info)
803 {
804 	struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
805 	struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
806 	void *d = phlcom_to_drvpriv(phl_com);
807 	u8 ucInfo = 0;
808 	void* pInfo = NULL;
809 
810 	enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
811 	/* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
812 
813 	switch(info->op_code) {
814 		case FG_REQ_OP_GET_ROLE:
815 			info->outbuf = (u8*)param->wifi_role;
816 			ret = MDL_RET_SUCCESS;
817 			break;
818 
819 		case FG_REQ_OP_GET_MDL_ID:
820 			ucInfo= PHL_FG_MDL_SCAN;
821 			pInfo = (void*) &ucInfo;
822 			info->outlen=1;
823 			_os_mem_cpy(d, (void*)info->outbuf, pInfo, info->outlen);
824 			ret = MDL_RET_SUCCESS;
825 			break;
826 #ifdef RTW_WKARD_MRC_ISSUE_NULL_WITH_SCAN_OPS
827 		case FG_REQ_OP_GET_SCAN_PARAM:
828 			info->outbuf = (u8*)param;
829 			ret = MDL_RET_SUCCESS;
830 			break;
831 #endif
832 		default:
833 			break;
834 	}
835 
836 	return ret;
837 }
838 
839 #ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
840 static void
_cmd_scan_update_chparam(void * drv,struct rtw_phl_scan_param * param)841 _cmd_scan_update_chparam(void *drv, struct rtw_phl_scan_param *param)
842 {
843 	u8 idx = 0;
844 	u16 scan_section_ms = 0;
845 	u16 total_scan_ms = 0;
846 
847 	for(idx = 0; idx < param->ch_num; idx++) {
848 		if (param->ch[idx].scan_mode == P2P_LISTEN_MODE) {
849 			param->max_listen_time = param->ch[idx].duration;
850 			total_scan_ms = param->ch[idx].duration;
851 			break;
852 		}
853 	}
854 
855 	scan_section_ms = param->back_op_ch_dur_ms + param->back_op_off_ch_dur_ms;
856 	if (scan_section_ms)
857 		param->repeat = total_scan_ms / scan_section_ms;
858 }
859 #endif
860 
861 static void
_phl_cmd_scan_req_init(void * phl,struct phl_cmd_token_req * fgreq,struct rtw_phl_scan_param * param)862 _phl_cmd_scan_req_init(void *phl, struct phl_cmd_token_req *fgreq,
863 		       struct rtw_phl_scan_param *param)
864 {
865 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
866 	void *drv = phl_to_drvpriv(phl_info);
867 	struct rtw_chan_def chdef_list[MAX_WIFI_ROLE_NUMBER] = {0};
868 	u8 op_num = 0;
869 	u8 idx = 0;
870 
871 	pq_init(drv, &param->chlist);
872 	param->enqueue_time = _os_get_cur_time_ms();
873 
874 	_cmd_scan_update_chlist(drv, param);
875 	if (param->back_op_mode != SCAN_BKOP_NONE) {
876 		op_num = rtw_phl_mr_get_opch_list(phl_info, param->wifi_role,
877 						chdef_list, (u8)MAX_WIFI_ROLE_NUMBER);
878 		if(op_num) {
879 			for(idx = 0; idx < op_num; idx++) {
880 				if(chdef_list[idx].chan) {
881 					INIT_LIST_HEAD(&param->back_op_ch[idx].list);
882 					param->back_op_ch[idx].channel = chdef_list[idx].chan;
883 					param->back_op_ch[idx].bw = chdef_list[idx].bw;
884 					param->back_op_ch[idx].offset = chdef_list[idx].offset;
885 					param->back_op_ch[idx].duration = param->back_op_ch_dur_ms;
886 					param->back_op_ch[idx].scan_mode = BACKOP_MODE;
887 				}
888 			}
889 		}
890 		#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
891 		if (op_num && param->back_op_mode == SCAN_BKOP_TIMER)
892 			_cmd_scan_update_chparam(drv, param);
893 		#endif
894 	}
895 
896 	#ifdef DBG_SCAN_CHAN_DUMP
897 	/* debug information*/
898 	_cmd_estimated_swch_seq(param, op_num);
899 	#endif
900 
901 	/* Fill foreground command request */
902 	fgreq->module_id= PHL_FG_MDL_SCAN;
903 	fgreq->priv = param;
904 	fgreq->role = param->wifi_role;
905 
906 	fgreq->acquired = _phl_cmd_scan_req_acquired;
907 	fgreq->abort = _phl_cmd_scan_req_abort;
908 	fgreq->msg_hdlr = _phl_cmd_scan_req_ev_hdlr;
909 	fgreq->set_info = _phl_cmd_scan_req_set_info;
910 	fgreq->query_info = _phl_cmd_scan_req_query_info;
911 }
912 
913 
914 /* For EXTERNAL application to request scan (expose) */
915 /* @pscan: scan object
916  * @pbuf: scan parameter, will be freed by caller after retrun
917  * @order: queuing order
918  */
rtw_phl_cmd_scan_request(void * phl,struct rtw_phl_scan_param * param,enum PRECEDE order)919 enum rtw_phl_status rtw_phl_cmd_scan_request(void *phl,
920 	struct rtw_phl_scan_param *param, enum PRECEDE order)
921 {
922 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
923 	u8 band_idx = param->wifi_role->hw_band;
924 	struct phl_cmd_token_req fgreq={0};
925 
926 	_phl_cmd_scan_req_init(phl, &fgreq, param);
927 
928 	/* cmd_dispatcher would copy whole phl_cmd_token_req */
929 	pstatus = phl_disp_eng_add_token_req(phl, band_idx, &fgreq, &param->token);
930 	if((pstatus != RTW_PHL_STATUS_SUCCESS) &&
931 	   (pstatus != RTW_PHL_STATUS_PENDING))
932 		goto error;
933 
934 	pstatus = RTW_PHL_STATUS_SUCCESS;
935 
936 error:
937 	return pstatus;
938 }
rtw_phl_cmd_scan_cancel(void * phl,struct rtw_phl_scan_param * param)939 enum rtw_phl_status rtw_phl_cmd_scan_cancel(void *phl,
940 				struct rtw_phl_scan_param *param)
941 {
942 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
943 	u8 band_idx = param->wifi_role->hw_band;
944 
945 	return phl_disp_eng_cancel_token_req(phl_info, band_idx, &param->token);
946 }
947 
rtw_phl_cmd_scan_inprogress(void * phl,u8 band_idx)948 int rtw_phl_cmd_scan_inprogress(void *phl, u8 band_idx)
949 {
950 	struct phl_module_op_info op_info = {0};
951 	u32	mdl = 0;
952 
953 	op_info.op_code = FG_REQ_OP_GET_MDL_ID;
954 	op_info.outbuf = (u8*)&mdl;
955 	op_info.outlen = 4;
956 
957 	if(phl_disp_eng_query_cur_cmd_info(phl, band_idx,
958 				&op_info)== RTW_PHL_STATUS_SUCCESS ) {
959 
960 		if(mdl == PHL_FG_MDL_SCAN)
961 			return true;
962 	}
963 	return false;
964 }
965 
966 #endif /* CONFIG_PHL_CMD_SCAN */
967