xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_scan_fsm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2019 - 2020 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * Author: vincent_fann@realtek.com
15  *
16  *****************************************************************************/
17 #include "phl_headers.h"
18 
19 #ifdef CONFIG_FSM
20 #include "phl_scan.h"
21 
22 #ifdef FSM_DBG_MEM_OVERWRITE
23 #define _os_kmem_alloc(a, b) fsm_kmalloc(b)
24 #define _os_kmem_free(a, b, c) fsm_kfree(b, c)
25 #endif
26 
27 #define SCAN_PROBE_TIMES	3 /* issue max 3 probe_req per channel */
28 #define SCAN_PROBE_INTERVAL	10 /* preobe_req interval 10ms */
29 #define SCAN_NULL_PKT_TIME	50 /* 50ms */
30 #define ALL_TOKEN		0
31 #define MAX_POWER_ON_TIME	500
32 #define BACK_OP_CH_DUR_MS	100
33 
34 #define ALM_MAX_SCAN_TIME	1
35 #define ALM_PROBE_REQ		2
36 #define ALM_NEXT_CH		3
37 #define ALM_BKOP_OFF_CH		4
38 #ifndef pstr
39 #define pstr(s) (s + _os_strlen((u8 *)s))
40 #endif
41 #ifndef lstr
42 #define lstr(s, l) (size_t)(l - _os_strlen((u8 *)s))
43 #endif
44 
45 enum SCAN_EV_ID {
46 	SCAN_EV_START,
47 	SCAN_EV_REQ_PWR_OK,
48 	SCAN_EV_REQ_PWR_FAIL,
49 	SCAN_EV_REQ_PWR_TIMEOUT,
50 	SCAN_EV_NEXT_CH,
51 	SCAN_EV_NEXT_PROBE_REQ,
52 	SCAN_EV_PAUSE,
53 	SCAN_EV_RESUME,
54 	SCAN_EV_FORCE_ACTIVE,
55 	SCAN_EV_NOTIFY_PENDING_SCAN_REQ,
56 	SCAN_EV_PS_ANN_DONE,
57 	SCAN_EV_BKOP_OFF_CH_EXPIRE,
58 	SCAN_EV_BKOP_ON_CH_EXPIRE,
59 	SCAN_EV_NOTIFY_OFF_CH_CMD,
60 	SCAN_EV_MAX
61 };
62 
63 enum SCAN_STATE_ST {
64 	SCAN_ST_IDLE,
65 	SCAN_ST_REQ_PWR,
66 	SCAN_ST_OFF_CH,
67 	SCAN_ST_BACK_OP
68 };
69 
70 static int scan_idle_st_hdl(void *obj, u16 event, void *param);
71 static int scan_req_pwr_st_hdl(void *obj, u16 event, void *param);
72 static int scan_off_ch_st_hdl(void *obj, u16 event, void *param);
73 static int scan_back_op_st_hdl(void *obj, u16 event, void *param);
74 
75 /* STATE table */
76 static struct fsm_state_ent scan_state_tbl[] = {
77 	ST_ENT(SCAN_ST_IDLE, scan_idle_st_hdl),
78 	ST_ENT(SCAN_ST_REQ_PWR, scan_req_pwr_st_hdl),
79 	ST_ENT(SCAN_ST_OFF_CH, scan_off_ch_st_hdl),
80 	ST_ENT(SCAN_ST_BACK_OP, scan_back_op_st_hdl)
81 };
82 
83 /* EVENT table */
84 static struct fsm_event_ent scan_event_tbl[] = {
85 	EV_ENT(SCAN_EV_START),
86 	EV_ENT(SCAN_EV_REQ_PWR_OK),
87 	EV_ENT(SCAN_EV_REQ_PWR_FAIL),
88 	EV_ENT(SCAN_EV_REQ_PWR_TIMEOUT),
89 	EV_ENT(SCAN_EV_NEXT_CH),
90 	EV_ENT(SCAN_EV_NEXT_PROBE_REQ),
91 	EV_ENT(SCAN_EV_PAUSE),
92 	EV_ENT(SCAN_EV_RESUME),
93 	EV_ENT(SCAN_EV_FORCE_ACTIVE),
94 	EV_ENT(SCAN_EV_NOTIFY_PENDING_SCAN_REQ),
95 	EV_ENT(SCAN_EV_PS_ANN_DONE),
96 	EV_ENT(SCAN_EV_BKOP_OFF_CH_EXPIRE),
97 	EV_ENT(SCAN_EV_BKOP_ON_CH_EXPIRE),
98 	EV_ENT(SCAN_EV_NOTIFY_OFF_CH_CMD),
99 	EV_ENT(SCAN_EV_MAX)
100 };
101 
102 struct scan_obj {
103 	struct fsm_main *fsm;
104 	struct fsm_obj *fsm_obj;
105 
106 	struct rtw_phl_scan_param *param;
107 	struct phl_info_t *phl_info;
108 	struct phl_queue req_q;
109 	struct phl_queue off_ch_cmd_q;
110 
111 	u32 token; /* global increase when new scan request is comming */
112 	u32 token_running; /* token of running scan */
113 
114 	u8 fltr_mode; /* backup filter mode before off channel */
115 	u8 candidate; /* Guarantee we have one candidate */
116 	u8 probe_cnts;
117 	u8 off_ch_step;
118 
119 	/* back op */
120 	bool back_op_is_required;
121 	struct phl_scan_channel back_op_ch;
122 
123 	struct rtw_phl_scan_ops *ops;
124 };
125 
126 /*
127  * SCAN state sub function
128  */
129 #define OFF_CH_STEP_CLEAR	0x00
130 #define OFF_CH_SET_FILTER	0x01
131 #define OFF_CH_PAUSE_TX		0x02
132 
off_ch_set_step(struct scan_obj * pscan,u8 step)133 void off_ch_set_step(struct scan_obj *pscan, u8 step)
134 {
135 	pscan->off_ch_step |= step;
136 }
137 
off_ch_clr_step(struct scan_obj * pscan,u8 step)138 void off_ch_clr_step(struct scan_obj *pscan, u8 step)
139 {
140 	pscan->off_ch_step &= ~step;
141 }
142 
off_ch_chk_step(struct scan_obj * pscan,u8 step)143 bool off_ch_chk_step(struct scan_obj *pscan, u8 step)
144 {
145 	if (pscan->off_ch_step & step)
146 		return true;
147 	return false;
148 }
149 
150 /*
151  * stop netif queue
152  * notify the AP about us leaving the channel and stop all STA interfaces.
153  * Stop queues and transmit all frames queued by the driver before
154  * sending nullfunc to enable powersave at the AP.
155  */
drv_offchannel_stop_vifs(struct scan_obj * pscan)156 static int drv_offchannel_stop_vifs(struct scan_obj *pscan)
157 {
158 	// reference ieee80211_offchannel_stop_vifs();
159 
160 	/* TODO stop upper netif ac queues */
161 	/* stop lower macid */
162 	return 0;
163 }
164 
165 
166 /* return to OP channel */
off_ch_return_set_ch_bw(struct scan_obj * pscan)167 static int off_ch_return_set_ch_bw(struct scan_obj *pscan)
168 {
169 	enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;
170 	struct phl_info_t *phl_info = pscan->phl_info;
171 	struct rtw_wifi_role_t *wrole = pscan->param->wifi_role;
172 	struct rtw_chan_def chandef = {0};
173 
174 	if (wrole == NULL)
175 		return -1;
176 
177 	phl_sts = phl_mr_get_chandef(phl_info, wrole, false, &chandef);
178 	if (phl_sts != RTW_PHL_STATUS_SUCCESS) {
179 		PHL_ERR("%s phl_mr_get_chandef failed\n", __func__);
180 		return -2;
181 	}
182 
183 	PHL_DUMP_CHAN_DEF_EX(&chandef);
184 
185 	phl_set_ch_bw(wrole, &chandef, false);
186 
187 	FSM_INFO(pscan->fsm, "%s %s() channel=%d, bw=%d, offest=%d\n",
188 		phl_fsm_obj_name(pscan->fsm_obj), __func__,
189 		chandef.chan, chandef.bw, chandef.offset);
190 
191 	return 0;
192 }
193 
194 #ifdef CONFIG_RTW_ACS
scan_acs_mntr_trigger(struct scan_obj * pscan,struct phl_scan_channel * scan_ch)195 static void scan_acs_mntr_trigger(struct scan_obj *pscan,
196 	struct phl_scan_channel *scan_ch)
197 {
198 	u16 monitor_time = scan_ch->duration - MONITOR_TIME_TOLERANCE;
199 
200 	phl_acs_mntr_trigger(pscan->phl_info,
201 		(u8)pscan->param->ch_idx, scan_ch->channel, monitor_time);
202 }
203 
scan_acs_mntr_result(struct scan_obj * pscan)204 static void scan_acs_mntr_result(struct scan_obj *pscan)
205 {
206 	if (pscan->param->ch_idx < 0)
207 		return;
208 
209 	phl_acs_mntr_result(pscan->phl_info);
210 }
211 #endif /* CONFIG_RTW_ACS */
212 
213 /* inform CORE ahd HAL SCAN is complete */
scan_complete(struct scan_obj * pscan)214 static int scan_complete(struct scan_obj *pscan)
215 {
216 	struct phl_info_t *phl_info = (struct phl_info_t *)pscan->phl_info;
217 	struct rtw_phl_scan_param *param = pscan->param;
218 	u8 band_idx = 0;
219 	enum phl_phy_idx phy_idx = HW_PHY_0;
220 
221 	if (param->ch_num == (pscan->param->ch_idx + 1))
222 		param->result = SCAN_REQ_COMPLETE;
223 
224 	param->end_time = _os_get_cur_time_ms();
225 
226 	/* dump scan time */
227 	param->total_scan_time =
228 		phl_fsm_time_pass(param->enqueue_time);
229 
230 	FSM_INFO(pscan->fsm, "%s takes %d ms to scan %d/%d channels\n",
231 		phl_fsm_obj_name(pscan->fsm_obj),
232 		param->total_scan_time, param->ch_idx + 1, param->ch_num);
233 
234 	if (pscan->param->wifi_role)
235 		band_idx = pscan->param->wifi_role->hw_band;
236 	else
237 		band_idx = 0;
238 
239 	if (band_idx == HW_BAND_1)
240 		phy_idx = HW_PHY_1;
241 	rtw_hal_btc_scan_finish_ntfy(phl_info->hal, phy_idx);
242 	rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_END, band_idx);
243 
244 	phl_p2pps_noa_resume_all(phl_info, param->wifi_role);
245 #ifdef CONFIG_MCC_SUPPORT
246 	if (phl_mr_coex_handle(phl_info, param->wifi_role, 0,
247 			param->wifi_role->hw_band, MR_COEX_TRIG_BY_SCAN)
248 						!= RTW_PHL_STATUS_SUCCESS) {
249 		FSM_ERR(pscan->fsm,
250 			"%s enable MCC failed\n",
251 			phl_fsm_obj_name(pscan->fsm_obj));
252 		return -1;
253 	}
254 #endif /* CONFIG_MCC_SUPPORT */
255 	if (pscan->ops && pscan->ops->scan_complete)
256 		pscan->ops->scan_complete(pscan->param->priv, pscan->param);
257 
258 	return 0;
259 }
260 
scan_set_timer(struct scan_obj * pscan,u32 duration,u16 event)261 static void scan_set_timer(struct scan_obj *pscan, u32 duration, u16 event)
262 {
263 	FSM_DBG(pscan->fsm, "%s %s() duration=%d\n",
264 		phl_fsm_obj_name(pscan->fsm_obj), __func__, duration);
265 
266 	phl_fsm_set_alarm(pscan->fsm_obj, duration, event);
267 }
268 
269 /* Announce null data if needing
270  * @pscan: scan obj
271  * @off_ch:
272  *	true: go off channel (issue null-1)
273  *	false: back to OP channel (issue null-0)
274  *	need_wait:
275  *	  false: issue null packet is not necessary
276  *	  true: null packet issued (caller have to wait null data transmission)
277  *
278  * return: 0 success, negativ value: fail
279  */
scan_off_chan(struct scan_obj * pscan,bool off_ch,bool * need_wait)280 static int scan_off_chan(struct scan_obj *pscan, bool off_ch, bool *need_wait)
281 {
282 	struct rtw_phl_com_t *phl_com = pscan->phl_info->phl_com;
283 	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
284 	struct rtw_wifi_role_t *wrole = pscan->param->wifi_role;
285 	struct hw_band_ctl_t *band_ctl = &(mr_ctl->band_ctrl[wrole->hw_band]);
286 	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
287 
288 	*need_wait = false;
289 
290 	psts = phl_mr_offch_hdl(pscan->phl_info, pscan->param->wifi_role,
291 		off_ch, pscan->param->priv, pscan->ops->scan_issue_null_data);
292 
293 	/* call back fail */
294 	if (psts != RTW_PHL_STATUS_SUCCESS)
295 		return -1;
296 
297 	if ((band_ctl->cur_info.ld_sta_num) > 0)
298 		*need_wait = false;
299 
300 	/* ap is currently operating */
301 	if ((band_ctl->cur_info.ap_num) > 0)
302 		pscan->back_op_is_required = true;
303 
304 	if ((band_ctl->cur_info.ld_sta_num + band_ctl->cur_info.ld_ap_num) > 0)
305 		pscan->back_op_is_required = true;
306 
307 	FSM_INFO(pscan->fsm, "%s %s() off_ch=%d, back_op_is_requred=%d\n",
308 		phl_fsm_obj_name(pscan->fsm_obj), __func__,
309 		off_ch, pscan->back_op_is_required);
310 
311 	return 0;
312 }
313 
314 /* Move channel index and decide scan channel */
scan_select_channel(struct scan_obj * pscan)315 static struct phl_scan_channel *scan_select_channel(
316 	struct scan_obj *pscan)
317 {
318 	struct rtw_phl_scan_param *p = pscan->param;
319 
320 	if (p->ch_idx == -1)
321 		goto next_ch;
322 
323 	/* back_op acording to op_ch_count */
324 	if (p->back_op_mode == SCAN_BKOP_CNT &&
325 		pscan->back_op_is_required && p->scan_ch &&
326 		(p->scan_ch->scan_mode != BACKOP_MODE) &&
327 		((p->ch_idx + 1) % p->back_op_ch_cnt == 0)) {
328 
329 		/* goto back op channel */
330 		p->scan_ch = &pscan->back_op_ch;
331 		goto done; /* do back_op */
332 
333 	} else if (p->back_op_mode == SCAN_BKOP_TIMER && p->scan_ch &&
334 		(p->scan_ch->scan_mode == BACKOP_MODE)) {
335 		/* we just return form op ch;
336 		 * stay at the same channel for now
337 		 */
338 		p->scan_ch = &p->ch[p->ch_idx];
339 		goto done;
340 	}
341 
342 next_ch:
343 	p->ch_idx++;
344 
345 	if (p->ch_idx == p->ch_num) {
346 		/* no more channel for now */
347 		if (p->repeat > 0) {
348 
349 			/* go back to the first channel */
350 			p->ch_idx = 0;
351 			FSM_INFO(pscan->fsm, "%s repeat=%d\n",
352 				phl_fsm_obj_name(pscan->fsm_obj), p->repeat);
353 
354 			/* 255 means loop forever */
355 			if (p->repeat != 255)
356 				p->repeat--;
357 		} else {
358 			p->ch_idx--;
359 			return NULL; /* we are done */
360 		}
361 	}
362 	p->scan_ch = &p->ch[p->ch_idx];
363 
364 	if (p->scan_ch->scan_mode == BACKOP_MODE &&
365 		pscan->back_op_is_required == false)
366 		goto next_ch;
367 done:
368 	FSM_INFO(pscan->fsm, "%s ch_num = %d/%d, ch = %d\n",
369 		phl_fsm_obj_name(pscan->fsm_obj), (p->ch_idx + 1),
370 		p->ch_num, p->scan_ch->channel);
371 
372 	return p->scan_ch;
373 }
374 
375 /* Switch channel */
scan_set_channel_bw(struct scan_obj * pscan,u16 ch,enum channel_width bw,enum chan_offset offset,u8 phy_idx)376 static void scan_set_channel_bw(struct scan_obj *pscan, u16 ch,
377 	enum channel_width bw, enum chan_offset offset, u8 phy_idx)
378 {
379 	struct rtw_chan_def chdef = {0};
380 
381 	FSM_INFO(pscan->fsm,
382 		"%s %s() ch=%d, bw=%d, offest=%d, duration=%d\n",
383 		phl_fsm_obj_name(pscan->fsm_obj), __func__,
384 		ch, bw, offset, pscan->param->scan_ch->duration);
385 
386 	chdef.chan = (u8)ch;
387 	chdef.bw = bw;
388 	chdef.offset = offset;
389 
390 	phl_set_ch_bw(pscan->param->wifi_role, &chdef, false);
391 
392 	if (pscan->ops->scan_ch_ready)
393 		pscan->ops->scan_ch_ready(pscan->param->priv, pscan->param);
394 }
395 
396 /* call back caller to issue probe request */
scan_issue_probereq(struct scan_obj * pscan)397 static void scan_issue_probereq(struct scan_obj *pscan)
398 {
399 	if (pscan->param->scan_ch->type == RTW_PHL_SCAN_PASSIVE)
400 		return;
401 
402 	if (pscan->ops->scan_issue_pbreq)
403 		pscan->ops->scan_issue_pbreq(pscan->param->priv, pscan->param);
404 }
405 
406 /* flush NIC TX FIFO */
scan_flush_tx_queue(struct scan_obj * pscan)407 static int scan_flush_tx_queue(struct scan_obj *pscan)
408 {
409 	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
410 
411 	hal_status = rtw_hal_scan_flush_queue(pscan->phl_info->hal,
412 		pscan->param->wifi_role);
413 
414 	if (hal_status != RTW_HAL_STATUS_SUCCESS)
415 		FSM_WARN(pscan->fsm, "%s flush tx queue fail\n",
416 			phl_fsm_obj_name(pscan->fsm_obj));
417 	return hal_status;
418 }
419 
420 /* Pause NIC TX FIFO */
scan_pause_tx(struct scan_obj * pscan)421 static int scan_pause_tx(struct scan_obj *pscan)
422 {
423 	struct phl_info_t *phl_info = (struct phl_info_t *)pscan->phl_info;
424 	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
425 	bool off_ch = true;
426 
427 	/* we want to off-ch - pause TX */
428 	hal_status = rtw_hal_scan_pause_tx_fifo(phl_info->hal,
429 		pscan->param->wifi_role->hw_band, off_ch);
430 
431 	if (hal_status == RTW_HAL_STATUS_SUCCESS)
432 		off_ch_set_step(pscan, OFF_CH_PAUSE_TX);
433 	else
434 		FSM_WARN(pscan->fsm, "%s pause tx fifo fail\n",
435 			phl_fsm_obj_name(pscan->fsm_obj));
436 
437 	return hal_status;
438 }
439 
scan_resume_tx(struct scan_obj * pscan)440 static int scan_resume_tx(struct scan_obj *pscan)
441 {
442 	struct phl_info_t *phl_info = (struct phl_info_t *)pscan->phl_info;
443 	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
444 	bool off_ch = false;
445 
446 	/* we want to op-ch - resume TX */
447 	/* Do not resume un-paused TX */
448 	if (!off_ch_chk_step(pscan, OFF_CH_PAUSE_TX))
449 		return RTW_HAL_STATUS_SUCCESS;
450 
451 	hal_status = rtw_hal_scan_pause_tx_fifo(phl_info->hal,
452 		pscan->param->wifi_role->hw_band, off_ch);
453 
454 	off_ch_clr_step(pscan, OFF_CH_PAUSE_TX);
455 	if (hal_status != RTW_HAL_STATUS_SUCCESS)
456 		FSM_WARN(pscan->fsm, "%s resume tx fifo fail\n",
457 			phl_fsm_obj_name(pscan->fsm_obj));
458 
459 	return hal_status;
460 }
461 
scan_set_filter(struct scan_obj * pscan)462 static int scan_set_filter(struct scan_obj *pscan)
463 {
464 	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
465 	bool off_ch = true;
466 
467 	hal_status = rtw_hal_scan_set_rxfltr_by_mode(pscan->phl_info->hal,
468 		pscan->param->wifi_role->hw_band,
469 		off_ch, &pscan->fltr_mode);
470 
471 	if (hal_status == RTW_HAL_STATUS_SUCCESS)
472 		off_ch_set_step(pscan, OFF_CH_SET_FILTER);
473 
474 	return hal_status;
475 }
476 
scan_clr_filter(struct scan_obj * pscan)477 static int scan_clr_filter(struct scan_obj *pscan)
478 {
479 	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
480 	bool off_ch = false;
481 
482 	/* Do not clear clear filter */
483 	if (!off_ch_chk_step(pscan, OFF_CH_SET_FILTER))
484 		return hal_status;
485 
486 	hal_status = rtw_hal_scan_set_rxfltr_by_mode(pscan->phl_info->hal,
487 		pscan->param->wifi_role->hw_band,
488 		off_ch, &pscan->fltr_mode);
489 
490 	off_ch_clr_step(pscan, OFF_CH_SET_FILTER);
491 
492 	if (hal_status != RTW_HAL_STATUS_SUCCESS)
493 		FSM_WARN(pscan->fsm, "%s clear filter fail\n",
494 			phl_fsm_obj_name(pscan->fsm_obj));
495 
496 	return hal_status;
497 
498 }
499 
500 /* inform CORE and HAL SCAN is starting */
scan_start(struct scan_obj * pscan)501 static int scan_start(struct scan_obj *pscan)
502 {
503 	struct phl_info_t *phl_info = (struct phl_info_t *)pscan->phl_info;
504 	struct rtw_hal_com_t *hal_com = rtw_hal_get_halcom(phl_info->hal);
505 	struct rtw_phl_scan_param *param = pscan->param;
506 	u32 pass_time, remain_time, end_time;
507 	enum band_type band = BAND_ON_5G;
508 	u8 band_idx = 0;
509 	enum phl_phy_idx phy_idx = HW_PHY_0;
510 
511 	FSM_INFO(pscan->fsm, "%s %s()\n",
512 		phl_fsm_obj_name(pscan->fsm_obj), __func__);
513 #ifdef CONFIG_MCC_SUPPORT
514 	if (phl_mr_coex_disable(phl_info, param->wifi_role,
515 				param->wifi_role->hw_band, MR_COEX_TRIG_BY_SCAN)
516 				!= RTW_PHL_STATUS_SUCCESS) {
517 		FSM_ERR(pscan->fsm,
518 			"%s disable MCC failed\n",
519 			phl_fsm_obj_name(pscan->fsm_obj));
520 		return -1;
521 	}
522 #endif /* CONFIG_MCC_SUPPORT */
523 	phl_p2pps_noa_pause_all(phl_info, param->wifi_role);
524 	param->start_time = _os_get_cur_time_ms();
525 
526 	/* check max scan time */
527 	if (param->max_scan_time > 0) {
528 		end_time = param->enqueue_time + param->max_scan_time;
529 		pass_time = phl_fsm_time_pass(param->enqueue_time);
530 
531 		if (pass_time >= param->max_scan_time) {
532 			FSM_ERR(pscan->fsm,
533 				"%s Timeout! pass_time %d > max_time %d\n",
534 				phl_fsm_obj_name(pscan->fsm_obj),
535 				pass_time, param->max_scan_time);
536 			return -1;
537 		}
538 		remain_time = phl_fsm_time_left(param->enqueue_time, end_time);
539 
540 		FSM_INFO(pscan->fsm,
541 			"%s: max_time = %d ms, remain = %d ms\n",
542 			phl_fsm_obj_name(pscan->fsm_obj),
543 			param->max_scan_time, remain_time);
544 
545 		phl_fsm_set_alarm_ext(pscan->fsm_obj, remain_time,
546 			FSM_EV_CANCEL, ALM_MAX_SCAN_TIME, NULL);
547 	}
548 
549 	if (param->wifi_role)
550 		band_idx = param->wifi_role->hw_band;
551 	else
552 		band_idx = 0;
553 
554 	if (band_idx == HW_BAND_1)
555 		phy_idx = HW_PHY_1;
556 	band = hal_com->band[band_idx].cur_chandef.band;
557 	rtw_hal_btc_scan_start_ntfy(phl_info->hal, phy_idx, band);
558 	rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_START, band_idx);
559 
560 	/* [scan start notify] */
561 	if (pscan->ops->scan_start)
562 		pscan->ops->scan_start(pscan->param->priv, param);
563 
564 	pscan->token_running = param->token;
565 	pscan->param->result = SCAN_REQ_CANCEL;
566 	return 0;
567 }
568 
scan_free_req(struct scan_obj * pscan,struct fsm_msg * msg)569 static void scan_free_req(struct scan_obj *pscan, struct fsm_msg *msg)
570 {
571 	void *d = phl_to_drvpriv(pscan->phl_info);
572 	struct rtw_phl_scan_param *scan_param =
573 		(struct rtw_phl_scan_param *)msg->param;
574 
575 	if (msg->param != NULL) {
576 		if (scan_param->ch != NULL)
577 			_os_kmem_free(d, scan_param->ch, scan_param->ch_sz);
578 		_os_kmem_free(d, msg->param, msg->param_sz);
579 	}
580 	_os_kmem_free(d, (void *)msg, sizeof(*msg));
581 }
582 
scan_free_msg(struct scan_obj * pscan,struct fsm_msg * msg)583 static void scan_free_msg(struct scan_obj *pscan, struct fsm_msg *msg)
584 {
585 	void *d = phl_to_drvpriv(pscan->phl_info);
586 
587 	_os_kmem_free(d, msg->param, msg->param_sz);
588 	_os_kmem_free(d, msg, sizeof(*msg));
589 }
590 
scan_ps_cb(void * phl,void * hdl,void * ctx,enum rtw_phl_status stat)591 void scan_ps_cb(void *phl, void *hdl, void *ctx, enum rtw_phl_status stat)
592 {
593 	struct scan_obj *pscan = (struct scan_obj *)ctx;
594 
595 	if (stat == RTW_PHL_STATUS_SUCCESS)
596 		phl_fsm_gen_msg(phl,
597 			pscan->fsm_obj, NULL, 0, SCAN_EV_REQ_PWR_OK);
598 	else
599 		phl_fsm_gen_msg(phl, pscan->fsm_obj,
600 			NULL, 0, SCAN_EV_REQ_PWR_FAIL);
601 }
602 
chk_pending_req(struct scan_obj * pscan)603 static bool chk_pending_req(struct scan_obj *pscan)
604 {
605 	void *d = phl_to_drvpriv(pscan->phl_info);
606 	_os_list *obj;
607 
608 	/* Make sure we only have one candidate */
609 	if (pscan->candidate)
610 		return true;
611 
612 	/* Check pending scan request
613 	 * Dequeue extra_queue and enqueue back to msg_queue
614 	 */
615 	if (!pq_pop(d, &pscan->req_q, &obj, _first, _bh))
616 		return false;
617 
618 	pscan->candidate = 1;
619 	if (phl_fsm_sent_msg(pscan->fsm_obj, (struct fsm_msg *)obj) !=
620 		RTW_PHL_STATUS_SUCCESS) {
621 		scan_free_req(pscan, (struct fsm_msg *)obj);
622 		return false;
623 	}
624 	return true; /* has pending req */
625 }
626 
627 /*
628  * SCAN state handler
629  */
630 
631 /*
632  * scan idle handler
633  */
scan_idle_st_hdl(void * obj,u16 event,void * param)634 static int scan_idle_st_hdl(void *obj, u16 event, void *param)
635 {
636 	struct scan_obj *pscan = (struct scan_obj *)obj;
637 	struct rtw_phl_scan_param *scan_param;
638 	void *d = phl_to_drvpriv(pscan->phl_info);
639 	int rtn = FSM_FREE_PARAM;
640 
641 	switch (event) {
642 
643 	case FSM_EV_STATE_IN:
644 
645 		phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_MAX_SCAN_TIME);
646 		scan_complete(pscan);
647 
648 		/* clear all used data */
649 		_os_kmem_free(d, pscan->param->ch, pscan->param->ch_sz);
650 		_os_kmem_free(d, pscan->param, sizeof(*pscan->param));
651 		pscan->param = NULL;
652 		pscan->token_running = 0;
653 		pscan->back_op_is_required = false;
654 		pscan->back_op_ch.duration = BACK_OP_CH_DUR_MS;
655 
656 		if (chk_pending_req(pscan))
657 			break;
658 
659 		break;
660 
661 	case SCAN_EV_START:
662 
663 		/* save param from caller */
664 		scan_param = (struct rtw_phl_scan_param *)param;
665 		pscan->param = scan_param;
666 		pscan->ops = scan_param->ops;
667 
668 		if (scan_param->back_op_ch_dur_ms)
669 			pscan->back_op_ch.duration =
670 				scan_param->back_op_ch_dur_ms;
671 
672 		/* Tell FSM framework DON'T free param
673 		 * Scan fsm will free it when scan is done
674 		 */
675 		rtn = FSM_KEEP_PARAM;
676 
677 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_REQ_PWR);
678 		pscan->candidate = 0;
679 		break;
680 
681 	case SCAN_EV_NOTIFY_PENDING_SCAN_REQ:
682 
683 		chk_pending_req(pscan);
684 		break;
685 
686 	case FSM_EV_STATE_OUT:
687 		phl_fsm_cancel_alarm(pscan->fsm_obj);
688 		break;
689 
690 	default:
691 		break;
692 	}
693 
694 	return rtn;
695 }
696 
scan_req_pwr_st_hdl(void * obj,u16 event,void * param)697 static int scan_req_pwr_st_hdl(void *obj, u16 event, void *param)
698 {
699 	struct scan_obj *pscan = (struct scan_obj *)obj;
700 	int rtn = FSM_FREE_PARAM;
701 	enum rtw_phl_status phl_st = RTW_PHL_STATUS_SUCCESS;
702 
703 	switch (event) {
704 
705 	case FSM_EV_STATE_IN:
706 
707 		if (phl_st == RTW_PHL_STATUS_PENDING) {
708 			/* we have to wait SCAN_EV_REQ_PWR_OK */
709 			phl_fsm_set_alarm(pscan->fsm_obj,
710 				MAX_POWER_ON_TIME, SCAN_EV_REQ_PWR_TIMEOUT);
711 			break;
712 		}
713 
714 		if (phl_st != RTW_PHL_STATUS_SUCCESS) {
715 			FSM_ERR(pscan->fsm, "%s power on fail(%d)\n",
716 				phl_fsm_obj_name(pscan->fsm_obj), phl_st);
717 			phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
718 			break;
719 		}
720 		/* fall through */
721 
722 	case SCAN_EV_REQ_PWR_OK:
723 
724 		if (scan_start(pscan) < 0) {
725 			phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
726 			break;
727 		}
728 
729 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_OFF_CH);
730 		break;
731 
732 	case SCAN_EV_REQ_PWR_FAIL:
733 	case SCAN_EV_REQ_PWR_TIMEOUT:
734 
735 		FSM_ERR(pscan->fsm, "%s power on fail\n",
736 			phl_fsm_obj_name(pscan->fsm_obj));
737 		/* fall through */
738 
739 	case FSM_EV_CANCEL:
740 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
741 		break;
742 
743 	case FSM_EV_STATE_OUT:
744 		phl_fsm_cancel_alarm(pscan->fsm_obj);
745 		break;
746 
747 	default:
748 		break;
749 	}
750 
751 	return rtn;
752 }
753 
handle_off_ch_cmd(struct scan_obj * pscan)754 int handle_off_ch_cmd(struct scan_obj *pscan)
755 {
756 	struct rtw_phl_scan_param *param = pscan->param;
757 	void *d = phl_to_drvpriv(pscan->phl_info);
758 	int off_ch_tx_num = pscan->off_ch_cmd_q.cnt;
759 	struct fsm_msg *msg;
760 	_os_list *obj;
761 
762 
763 	while (pq_pop(d, &pscan->off_ch_cmd_q, &obj, _first, _bh)) {
764 		msg = (struct fsm_msg *)obj;
765 		if (param && param->ops && param->ops->scan_off_ch_tx)
766 			param->ops->scan_off_ch_tx(param->priv,
767 				param, msg->param);
768 		scan_free_msg(pscan, msg);
769 	}
770 	return off_ch_tx_num;
771 }
772 
773 /* swtich channel and scan
774  */
scan_off_ch_st_hdl(void * obj,u16 event,void * param)775 static int scan_off_ch_st_hdl(void *obj, u16 event, void *param)
776 {
777 	struct scan_obj *pscan = (struct scan_obj *)obj;
778 	struct rtw_phl_scan_param *p = pscan->param;
779 	struct phl_scan_channel *scan_ch;
780 	bool need_wait;
781 
782 	switch (event) {
783 	case FSM_EV_STATE_IN:
784 
785 		pscan->off_ch_step = OFF_CH_STEP_CLEAR;
786 		if (scan_off_chan(pscan, true, &need_wait) < 0) {
787 			/* issue Null-1 fail */
788 			phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
789 			break;
790 		}
791 
792 		if (need_wait == true) {
793 			/* TODO wait tx report */
794 			scan_set_timer(pscan,
795 				SCAN_NULL_PKT_TIME, SCAN_EV_PS_ANN_DONE);
796 			break;
797 		}
798 
799 	/* fall through */
800 	case SCAN_EV_PS_ANN_DONE:
801 		scan_flush_tx_queue(pscan);
802 		scan_pause_tx(pscan);
803 		scan_set_filter(pscan);
804 
805 		/* start back_op_off_ch_dur */
806 		if ((p->back_op_mode == SCAN_BKOP_TIMER) &&
807 			pscan->back_op_is_required)
808 			phl_fsm_set_alarm_ext(pscan->fsm_obj,
809 				p->back_op_off_ch_dur_ms,
810 				SCAN_EV_BKOP_OFF_CH_EXPIRE,
811 				ALM_BKOP_OFF_CH, NULL);
812 
813 		/* dequeue off_ch_cmd */
814 		if (handle_off_ch_cmd(pscan) > 0) {
815 			if (pscan->back_op_is_required == true)
816 				phl_fsm_extend_alarm_ext(pscan->fsm_obj,
817 					pscan->param->back_op_off_ch_ext_dur_ms,
818 					ALM_BKOP_OFF_CH);
819 			else
820 				phl_fsm_extend_alarm_ext(pscan->fsm_obj,
821 					pscan->param->back_op_off_ch_ext_dur_ms,
822 					ALM_NEXT_CH);
823 		}
824 
825 	/* fall through */
826 	case SCAN_EV_NEXT_CH:
827 
828 		phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_PROBE_REQ);
829 
830 		#ifdef CONFIG_RTW_ACS
831 		scan_acs_mntr_result(pscan);
832 		#endif
833 
834 		scan_ch = scan_select_channel(pscan);
835 		if (scan_ch == NULL) {
836 			/* no more channel, we are done */
837 			phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
838 			break;
839 		}
840 
841 		if (scan_ch->scan_mode == BACKOP_MODE) {
842 			phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_BACK_OP);
843 			break;
844 		}
845 
846 		pscan->probe_cnts = SCAN_PROBE_TIMES;
847 		scan_set_channel_bw(pscan, scan_ch->channel, CHANNEL_WIDTH_20,
848 					CHAN_OFFSET_NO_EXT, 0);
849 		#ifdef CONFIG_RTW_ACS
850 		scan_acs_mntr_trigger(pscan, scan_ch);
851 		#endif
852 
853 		if (phl_fsm_is_alarm_off_ext(
854 			pscan->fsm_obj, ALM_NEXT_CH)) {
855 			phl_fsm_set_alarm_ext(pscan->fsm_obj, scan_ch->duration,
856 				SCAN_EV_NEXT_CH, ALM_NEXT_CH, NULL);
857 		}
858 
859 	/* fall through */
860 	case SCAN_EV_NEXT_PROBE_REQ:
861 
862 		if (pscan->probe_cnts-- == 0)
863 			break;
864 
865 		if (pscan->ops->scan_issue_pbreq == NULL ||
866 			 p->scan_ch->type == RTW_PHL_SCAN_PASSIVE)
867 			break;
868 
869 		scan_issue_probereq(pscan);
870 		phl_fsm_set_alarm_ext(pscan->fsm_obj, SCAN_PROBE_INTERVAL,
871 			SCAN_EV_NEXT_PROBE_REQ, ALM_PROBE_REQ, NULL);
872 		break;
873 
874 	case SCAN_EV_BKOP_OFF_CH_EXPIRE:
875 		p->scan_ch = &pscan->back_op_ch;
876 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_BACK_OP);
877 		break;
878 
879 	case SCAN_EV_FORCE_ACTIVE:
880 
881 		/* Are we in active scan channel */
882 		if (p->scan_ch->type == RTW_PHL_SCAN_ACTIVE)
883 			break;
884 
885 		scan_ch = (struct phl_scan_channel *)param;
886 
887 		/* request ch mismaches current scan ch */
888 		if (scan_ch->channel != p->scan_ch->channel)
889 			break;
890 
891 #ifdef RTW_WKARD_PHL_FSM_SCAN_PASSIVE_TO_ACTIVE
892 		if (p->scan_ch->ext_act_scan == EXT_ACT_SCAN_ENABLE)
893 			p->scan_ch->ext_act_scan = EXT_ACT_SCAN_DONE;
894 		else {
895 			FSM_INFO(pscan->fsm, "ch(%d) scan type not changed, ext_act_scan(%d) \n",
896 					 scan_ch->channel, p->scan_ch->ext_act_scan);
897 			break;
898 		}
899 #endif
900 
901 		FSM_INFO(pscan->fsm, "ch(%d) PASSIVE->ACTIVE!\n", scan_ch->channel);
902 
903 		p->scan_ch->type = RTW_PHL_SCAN_ACTIVE;
904 		scan_issue_probereq(pscan);
905 		phl_fsm_set_alarm_ext(pscan->fsm_obj, SCAN_PROBE_INTERVAL,
906 			SCAN_EV_NEXT_PROBE_REQ, ALM_PROBE_REQ, NULL);
907 		break;
908 
909 	case SCAN_EV_NOTIFY_OFF_CH_CMD:
910 
911 		/* dequeue off_ch_cmd */
912 		if (handle_off_ch_cmd(pscan) > 0) {
913 			if (pscan->back_op_is_required == true)
914 				phl_fsm_extend_alarm_ext(pscan->fsm_obj,
915 					pscan->param->back_op_off_ch_ext_dur_ms,
916 					ALM_BKOP_OFF_CH);
917 			else
918 				phl_fsm_extend_alarm_ext(pscan->fsm_obj,
919 					pscan->param->back_op_off_ch_ext_dur_ms,
920 					ALM_NEXT_CH);
921 		}
922 		break;
923 
924 	case SCAN_EV_PAUSE:
925 		phl_fsm_pause_alarm(pscan->fsm_obj);
926 		phl_fsm_pause_alarm_ext(pscan->fsm_obj, ALM_NEXT_CH);
927 		phl_fsm_pause_alarm_ext(pscan->fsm_obj, ALM_PROBE_REQ);
928 		phl_fsm_pause_alarm_ext(pscan->fsm_obj, ALM_BKOP_OFF_CH);
929 		break;
930 
931 	case SCAN_EV_RESUME:
932 		phl_fsm_resume_alarm(pscan->fsm_obj);
933 		phl_fsm_resume_alarm_ext(pscan->fsm_obj, ALM_NEXT_CH);
934 		phl_fsm_resume_alarm_ext(pscan->fsm_obj, ALM_PROBE_REQ);
935 		phl_fsm_resume_alarm_ext(pscan->fsm_obj, ALM_BKOP_OFF_CH);
936 		break;
937 
938 	case FSM_EV_CANCEL:
939 		phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_NEXT_CH);
940 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
941 		break;
942 
943 	case FSM_EV_STATE_OUT:
944 		phl_fsm_cancel_alarm(pscan->fsm_obj);
945 		phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_PROBE_REQ);
946 		phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_BKOP_OFF_CH);
947 		scan_clr_filter(pscan);
948 		off_ch_return_set_ch_bw(pscan);
949 		scan_resume_tx(pscan);
950 		scan_off_chan(pscan, false, &need_wait);
951 
952 		if (p->scan_ch->scan_mode != BACKOP_MODE)
953 			phl_fsm_cancel_alarm_ext(pscan->fsm_obj, ALM_NEXT_CH);
954 		break;
955 
956 	default:
957 		break;
958 	}
959 	return 0;
960 }
961 
962 /* Stay in OP channel for a while
963  * OP channel normal data TRx
964  */
scan_back_op_st_hdl(void * obj,u16 event,void * param)965 static int scan_back_op_st_hdl(void *obj, u16 event, void *param)
966 {
967 	struct scan_obj *pscan = (struct scan_obj *)obj;
968 	u32 start_time = _os_get_cur_time_ms();
969 
970 
971 	switch (event) {
972 	case FSM_EV_STATE_IN:
973 
974 		scan_set_timer(pscan,
975 			pscan->param->scan_ch->duration,
976 			SCAN_EV_BKOP_ON_CH_EXPIRE);
977 
978 		break;
979 
980 	case SCAN_EV_BKOP_ON_CH_EXPIRE:
981 
982 		/* leve back_op channel */
983 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_OFF_CH);
984 		break;
985 
986 	case SCAN_EV_NEXT_CH:
987 		phl_fsm_set_alarm_ext(pscan->fsm_obj,
988 			phl_fsm_time_pass(start_time) + SCAN_NULL_PKT_TIME,
989 			SCAN_EV_NEXT_CH, ALM_NEXT_CH, NULL);
990 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_OFF_CH);
991 		break;
992 
993 	case SCAN_EV_NOTIFY_OFF_CH_CMD:
994 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_OFF_CH);
995 		break;
996 
997 	case SCAN_EV_PAUSE:
998 		phl_fsm_pause_alarm(pscan->fsm_obj);
999 		break;
1000 
1001 	case SCAN_EV_RESUME:
1002 		phl_fsm_resume_alarm(pscan->fsm_obj);
1003 		break;
1004 
1005 	case FSM_EV_CANCEL:
1006 		phl_fsm_state_goto(pscan->fsm_obj, SCAN_ST_IDLE);
1007 		break;
1008 
1009 	case FSM_EV_STATE_OUT:
1010 		phl_fsm_cancel_alarm(pscan->fsm_obj);
1011 		break;
1012 
1013 	default:
1014 		break;
1015 	}
1016 	return 0;
1017 }
1018 
scan_get_token(struct scan_obj * pscan)1019 static u32 scan_get_token(struct scan_obj *pscan)
1020 {
1021 	pscan->token++;
1022 	if (pscan->token == ALL_TOKEN)
1023 		pscan->token++;
1024 	return pscan->token;
1025 }
1026 
scan_dump_obj(void * obj,char * s,int * sz)1027 static void scan_dump_obj(void *obj, char *s, int *sz)
1028 {
1029 	/* nothing to do for now */
1030 }
1031 
scan_dump_fsm(void * fsm,char * s,int * sz)1032 static void scan_dump_fsm(void *fsm, char *s, int *sz)
1033 {
1034 	/* nothing to do for now */
1035 }
1036 
scan_dbg_help(struct scan_obj * pscan,char * p,int * sz)1037 static void scan_dbg_help(struct scan_obj *pscan, char *p, int *sz)
1038 {
1039 	int len = *sz;
1040 
1041 	_os_snprintf(pstr(p), lstr(p, len),
1042 		"usage:\n\t<%s> req del <0|token>\n\t<%s> req <pause|resume>\n",
1043 		phl_fsm_obj_name(pscan->fsm_obj),
1044 		phl_fsm_obj_name(pscan->fsm_obj));
1045 	*sz = len;
1046 }
1047 
scan_debug(void * obj,char input[][MAX_ARGV],u32 input_num,char * output,u32 * out_len)1048 static void scan_debug(void *obj, char input[][MAX_ARGV], u32 input_num,
1049 	char *output, u32 *out_len)
1050 {
1051 	struct scan_obj *pscan = (struct scan_obj *)obj;
1052 	char *ptr = output;
1053 	int len = *out_len;
1054 	int token;
1055 
1056 	if (input_num <  2) {
1057 		scan_dbg_help(pscan, ptr, &len);
1058 		goto done;
1059 	}
1060 
1061 	if (!_os_strcmp(input[0], "req")) {
1062 		if (!_os_strcmp(input[1], "del")) {
1063 
1064 			/* del scan request */
1065 			/* cmd: scan-1 req del <token> */
1066 
1067 			/* read token */
1068 			if (_os_sscanf(input[2], "%d", &token) != 1) {
1069 				_os_snprintf(pstr(ptr), lstr(ptr, len),
1070 					"%s Err missing token\n",
1071 					phl_fsm_obj_name(pscan->fsm_obj));
1072 				goto done;
1073 			}
1074 
1075 			_os_snprintf(pstr(ptr), lstr(ptr, len),
1076 				"%s del token %d\n",
1077 				phl_fsm_obj_name(pscan->fsm_obj), token);
1078 			rtw_phl_scan_del_request(pscan->phl_info, token);
1079 
1080 		} else if (!_os_strcmp(input[1], "pause")) {
1081 			/* cmd: scan-1 req pauase */
1082 			_os_snprintf(pstr(ptr), lstr(ptr, len),
1083 				"%s pause\n",
1084 				phl_fsm_obj_name(pscan->fsm_obj));
1085 			rtw_phl_scan_pause(pscan->phl_info);
1086 
1087 		} else if (!_os_strcmp(input[1], "resume")) {
1088 			/* cmd: scan-1 req resume */
1089 			_os_snprintf(pstr(ptr), lstr(ptr, len),
1090 				"%s resume\n",
1091 				phl_fsm_obj_name(pscan->fsm_obj));
1092 			rtw_phl_scan_resume(pscan->phl_info);
1093 		}
1094 	} else
1095 		scan_dbg_help(pscan, ptr, &len);
1096 done:
1097 	*out_len = len;
1098 }
1099 
1100 /* For EXTERNAL application to create a scan FSM */
1101 /* @root: FSM root structure
1102  * @phl: private data structure to invoke hal/phl function
1103  *
1104  * return
1105  * fsm_main: FSM main structure (Do NOT expose)
1106  */
phl_scan_new_fsm(struct fsm_root * root,struct phl_info_t * phl_info)1107 struct fsm_main *phl_scan_new_fsm(struct fsm_root *root,
1108 	struct phl_info_t *phl_info)
1109 {
1110 	void *d = phl_to_drvpriv(phl_info);
1111 	struct fsm_main *fsm = NULL;
1112 	struct rtw_phl_fsm_tb tb;
1113 
1114 
1115 	_os_mem_set(d, &tb, 0, sizeof(tb));
1116 	tb.max_state = sizeof(scan_state_tbl)/sizeof(scan_state_tbl[0]);
1117 	tb.max_event = sizeof(scan_event_tbl)/sizeof(scan_event_tbl[0]);
1118 	tb.state_tbl = scan_state_tbl;
1119 	tb.evt_tbl = scan_event_tbl;
1120 	tb.dump_obj = scan_dump_obj;
1121 	tb.dump_fsm = scan_dump_fsm;
1122 	tb.debug = scan_debug;
1123 	tb.dbg_level = FSM_DBG_INFO;
1124 	tb.evt_level = FSM_DBG_INFO;
1125 
1126 	fsm = phl_fsm_init_fsm(root, "scan", phl_info, &tb);
1127 
1128 	return fsm;
1129 }
1130 
1131 /* For EXTERNAL application to destory scan fsm */
1132 /* @fsm: see fsm_main
1133  */
phl_scan_destory_fsm(struct fsm_main * fsm)1134 void phl_scan_destory_fsm(struct fsm_main *fsm)
1135 {
1136 	if (fsm == NULL)
1137 		return;
1138 
1139 	/* deinit fsm local variable if has */
1140 
1141 	/* call FSM Framewro to deinit fsm */
1142 	phl_fsm_deinit_fsm(fsm);
1143 }
1144 
1145 /* For EXTERNAL application to create scan object */
1146 /* @fsm: FSM main structure which created by phl_scan_new_fsm()
1147  * @phl_info: private data structure of caller
1148  *
1149  * return
1150  * scan_obj: structure of scan object (Do NOT expose)
1151  */
phl_scan_new_obj(struct fsm_main * fsm,struct phl_info_t * phl_info)1152 struct scan_obj *phl_scan_new_obj(struct fsm_main *fsm,
1153 	struct phl_info_t *phl_info)
1154 {
1155 	void *d = phl_to_drvpriv(phl_info);
1156 	struct fsm_obj *obj;
1157 	struct scan_obj *pscan;
1158 
1159 
1160 	pscan = phl_fsm_new_obj(fsm, (void **)&obj, sizeof(*pscan));
1161 
1162 	if (pscan == NULL) {
1163 		/* TODO free fsm; currently will be freed in deinit process */
1164 		FSM_ERR(fsm, "scan: malloc obj fail\n");
1165 		return NULL;
1166 	}
1167 	pscan->fsm = fsm;
1168 	pscan->fsm_obj = obj;
1169 	pscan->phl_info = phl_info;
1170 
1171 	/* init obj local use variable */
1172 	pq_init(d, &pscan->req_q);
1173 	pq_init(d, &pscan->off_ch_cmd_q);
1174 
1175 	pscan->param = NULL;
1176 	pscan->token_running = 0;
1177 	pscan->off_ch_step = OFF_CH_STEP_CLEAR;
1178 
1179 	pscan->back_op_is_required = false;
1180 	pscan->back_op_ch.scan_mode = BACKOP_MODE;
1181 	pscan->back_op_ch.duration = BACK_OP_CH_DUR_MS;
1182 
1183 	return pscan;
1184 }
1185 
1186 /* For EXTERNAL application to destory scan object */
1187 /* @pscan: local created scan object
1188  */
phl_scan_destory_obj(struct scan_obj * pscan)1189 void phl_scan_destory_obj(struct scan_obj *pscan)
1190 {
1191 	void *d;
1192 	_os_list *obj;
1193 
1194 	if (pscan == NULL)
1195 		return;
1196 
1197 	d = phl_to_drvpriv(pscan->phl_info);
1198 
1199 	/* deinit and free all local variables */
1200 	while (pq_pop(d, &pscan->req_q, &obj, _first, _bh))
1201 		scan_free_req(pscan, (struct fsm_msg *)obj);
1202 	pq_deinit(d, &pscan->req_q);
1203 
1204 	while (pq_pop(d, &pscan->off_ch_cmd_q, &obj, _first, _bh))
1205 		scan_free_msg(pscan, (struct fsm_msg *)obj);
1206 	pq_deinit(d, &pscan->off_ch_cmd_q);
1207 
1208 	/* clear scan param */
1209 	if (pscan->param) {
1210 		if (pscan->param && pscan->param->ch && pscan->param->ch_sz)
1211 			_os_kmem_free(d, pscan->param->ch, pscan->param->ch_sz);
1212 		_os_kmem_free(d, pscan->param, sizeof(*pscan->param));
1213 		pscan->param = NULL;
1214 	}
1215 
1216 	/* inform FSM framewory to recycle fsm_obj */
1217 	phl_fsm_destory_obj(pscan->fsm_obj);
1218 }
1219 
1220 /* For EXTERNAL application to request scan (expose) */
1221 /* @pscan: scan object
1222  * @pbuf: scan parameter, will be freed by caller after retrun
1223  * @order: queuing order
1224  */
rtw_phl_scan_request(void * phl,struct rtw_phl_scan_param * pbuf,enum PRECEDE order)1225 enum rtw_phl_status rtw_phl_scan_request(void *phl,
1226 	struct rtw_phl_scan_param *pbuf, enum PRECEDE order)
1227 {
1228 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1229 	struct scan_obj *pscan = phl_info->scan_obj;
1230 	void *d = phl_to_drvpriv(pscan->phl_info);
1231 	struct rtw_phl_scan_param *param = NULL;
1232 	struct phl_scan_channel *pch = NULL;
1233 	struct fsm_msg *msg;
1234 
1235 	pch = (struct phl_scan_channel *)_os_kmem_alloc(d, pbuf->ch_sz);
1236 	if (pch == NULL)
1237 		goto pch_fail;
1238 
1239 	param = (struct rtw_phl_scan_param *)_os_kmem_alloc(d, sizeof(*pbuf));
1240 	if (param == NULL)
1241 		goto param_fail;
1242 
1243 	/* NEW message to start scan */
1244 	msg = phl_fsm_new_msg(pscan->fsm_obj, SCAN_EV_START);
1245 	if (msg == NULL)
1246 		goto msg_fail;
1247 
1248 	/* fill token */
1249 	pbuf->token = scan_get_token(pscan);
1250 	_os_mem_cpy(d, pch, pbuf->ch, pbuf->ch_sz);
1251 	_os_mem_cpy(d, param, pbuf, sizeof(*param));
1252 	param->ch = pch;
1253 	param->ch_idx = -1;
1254 	param->scan_ch = &param->ch[0];
1255 	param->result = SCAN_REQ_ABORT;
1256 
1257 	param->enqueue_time = _os_get_cur_time_ms();
1258 	msg->param = param;
1259 	msg->param_sz = sizeof(*param);
1260 
1261 	/*
1262 	 * Enqueue scan_request into extra queue (pending scan)
1263 	 */
1264 	switch (order) {
1265 	case IMMEDIATE:
1266 		pq_push(d, &pscan->req_q, (_os_list *)msg, _first, _bh);
1267 		/* Cancel running scan process */
1268 		phl_fsm_gen_msg(phl, pscan->fsm_obj, NULL, 0, FSM_EV_CANCEL);
1269 		/* fall through */
1270 		break;
1271 	case TO_HEAD:
1272 		pq_push(d, &pscan->req_q, (_os_list *)msg, _first, _bh);
1273 		break;
1274 	case TO_TAIL:
1275 	default:
1276 		pq_push(d, &pscan->req_q, (_os_list *)msg, _tail, _bh);
1277 		break;
1278 	}
1279 
1280 	/* notify scan-obj to dequeue from extra queue */
1281 	return phl_fsm_gen_msg(phl, pscan->fsm_obj,
1282 		NULL, 0, SCAN_EV_NOTIFY_PENDING_SCAN_REQ);
1283 
1284 msg_fail:
1285 	_os_kmem_free(d, param, sizeof(*param));
1286 param_fail:
1287 	_os_kmem_free(d, pch, sizeof(*pch));
1288 pch_fail:
1289 	FSM_ERR(pscan->fsm, "%s: %s() malloc fail\n",
1290 		phl_fsm_obj_name(pscan->fsm_obj), __func__);
1291 	return RTW_PHL_STATUS_RESOURCE;
1292 }
1293 
1294 /* For EXTERNAL application to del scan request (expose) */
1295 /* @phl: phl_info_t
1296  * @token: token to be deleted
1297  *	   0 means del all requests and cancel running scan
1298  */
rtw_phl_scan_del_request(void * phl,u32 token)1299 enum rtw_phl_status rtw_phl_scan_del_request(void *phl, u32 token)
1300 {
1301 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1302 	struct scan_obj *pscan = phl_info->scan_obj;
1303 	void *d = phl_to_drvpriv(phl_info);
1304 	struct fsm_msg *msg, *msg_t;
1305 	struct rtw_phl_scan_param *param = NULL;
1306 	_os_list *obj;
1307 
1308 	if (token == ALL_TOKEN) {
1309 		while (pq_pop(d, &pscan->req_q, &obj, _first, _bh)) {
1310 			msg = (struct fsm_msg *)obj;
1311 			param = msg->param;
1312 
1313 			FSM_INFO(pscan->fsm, "%s abort token %d\n",
1314 				phl_fsm_obj_name(pscan->fsm_obj), param->token);
1315 
1316 			if (param && param->ops && param->ops->scan_complete)
1317 				param->ops->scan_complete(param->priv, param);
1318 			scan_free_req(pscan, (struct fsm_msg *)obj);
1319 		}
1320 
1321 	} else {
1322 
1323 		/* search token in scan request queue */
1324 		_os_spinlock(d, &pscan->req_q.lock, _bh, NULL);
1325 		phl_list_for_loop_safe(msg, msg_t,
1326 			struct fsm_msg, &pscan->req_q.queue, list) {
1327 
1328 			param = (struct rtw_phl_scan_param *)msg->param;
1329 			if (param && param->token == token) {
1330 				list_del(&msg->list);
1331 				pscan->req_q.cnt--;
1332 				_os_spinunlock(d, &pscan->req_q.lock, _bh, NULL);
1333 
1334 				FSM_INFO(pscan->fsm, "%s abort token %d\n",
1335 					phl_fsm_obj_name(pscan->fsm_obj),
1336 					token);
1337 
1338 				/* callback to caller */
1339 				if (param->ops && param->ops->scan_complete)
1340 					param->ops->scan_complete(param->priv,
1341 						param);
1342 				scan_free_req(pscan, msg);
1343 				return RTW_PHL_STATUS_SUCCESS;
1344 			}
1345 		}
1346 		_os_spinunlock(d, &pscan->req_q.lock, _bh, NULL);
1347 
1348 		FSM_INFO(pscan->fsm, "%s del token %d not found\n",
1349 			phl_fsm_obj_name(pscan->fsm_obj), token);
1350 	}
1351 
1352 	if ((pscan->param) &&
1353 		((pscan->param->token == token) || ALL_TOKEN == token)) {
1354 		/* we have a running scan, cancel it */
1355 		FSM_INFO(pscan->fsm, "%s cancel running scan token %d\n",
1356 			phl_fsm_obj_name(pscan->fsm_obj), pscan->param->token);
1357 
1358 		phl_fsm_cancel_obj(pscan->fsm_obj);
1359 	}
1360 	return RTW_PHL_STATUS_SUCCESS;
1361 }
1362 
1363 /* For EXTERNAL application to cancel scan (expose) */
1364 /* @pscan: scan object will be cancelled
1365  */
rtw_phl_scan_cancel(void * phl)1366 enum rtw_phl_status rtw_phl_scan_cancel(void *phl)
1367 {
1368 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1369 	struct scan_obj *pscan = phl_info->scan_obj;
1370 
1371 	return phl_fsm_cancel_obj(pscan->fsm_obj);
1372 }
1373 
1374 /* For EXTERNAL application to pause scan (expose)
1375  * @phl: phl pirvate
1376  */
rtw_phl_scan_pause(void * phl)1377 enum rtw_phl_status rtw_phl_scan_pause(void *phl)
1378 {
1379 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1380 	struct scan_obj *pscan = phl_info->scan_obj;
1381 
1382 	return phl_fsm_gen_msg(phl, pscan->fsm_obj, NULL, 0, SCAN_EV_PAUSE);
1383 }
1384 
1385 /* For EXTERNAL application to resume scan (expose)
1386  * @phl: phl pirvate
1387  */
rtw_phl_scan_resume(void * phl)1388 enum rtw_phl_status rtw_phl_scan_resume(void *phl)
1389 {
1390 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1391 	struct scan_obj *pscan = phl_info->scan_obj;
1392 
1393 	return phl_fsm_gen_msg(phl, pscan->fsm_obj, NULL, 0, SCAN_EV_RESUME);
1394 }
1395 
1396 /* For EXTERNAL application to change passive scan to active scan (expose)
1397  * @phl: phl pirvate
1398  * @ch: channel to be changed to active scan
1399  * @duration: scan time for the channel; 0: half of original duration
1400  *
1401  * Usually triggered when receiving Beacon in a passive scan channel.
1402  * Changing current scan ch from passive to active scan.
1403  * (issue probe request in current scan channel)
1404  * More easy to find a hidden ssid AP in passive scan channel.
1405  */
rtw_phl_scan_force_active_scan(void * phl,u16 channel,u16 duration)1406 enum rtw_phl_status rtw_phl_scan_force_active_scan(void *phl,
1407 	u16 channel, u16 duration)
1408 {
1409 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1410 	struct scan_obj *pscan = phl_info->scan_obj;
1411 	struct phl_scan_channel ch;
1412 
1413 	_os_mem_set(phl_to_drvpriv(phl_info), &ch, 0, sizeof(ch));
1414 	ch.channel = channel;
1415 	ch.duration = duration;
1416 
1417 	return phl_fsm_gen_msg(phl, pscan->fsm_obj, &ch,
1418 		sizeof(ch), SCAN_EV_FORCE_ACTIVE);
1419 }
1420 
1421 /* For EXTERNAL application to get inprogress scan and requests num (expose)
1422  * @phl: phl pirvate
1423  *
1424  * return: 0: no scan is inprogressing
1425  * otherwise: number of queuing scan requests + inprogress scan
1426  */
rtw_phl_scan_inprogress_req_num(void * phl)1427 int rtw_phl_scan_inprogress_req_num(void *phl)
1428 {
1429 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1430 	struct scan_obj *pscan = phl_info->scan_obj;
1431 	u8 running = 0;
1432 
1433 	if (pscan->param != NULL)
1434 		running = 1;
1435 
1436 	return pscan->req_q.cnt + running;
1437 }
1438 
rtw_phl_scan_scanning_req(void * phl,u32 token,u32 * token_running)1439 bool rtw_phl_scan_scanning_req(void *phl, u32 token, u32 *token_running)
1440 {
1441 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1442 	struct scan_obj *pscan = phl_info->scan_obj;
1443 
1444 	*token_running = pscan->token_running;
1445 	return (token == *token_running);
1446 }
1447 
rtw_phl_scan_off_ch_tx(void * phl,void * data,int len)1448 enum rtw_phl_status rtw_phl_scan_off_ch_tx(void *phl, void *data, int len)
1449 {
1450 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1451 	struct scan_obj *pscan = phl_info->scan_obj;
1452 	struct rtw_phl_scan_param *param = pscan->param;
1453 	void *d = phl_to_drvpriv(pscan->phl_info);
1454 	struct fsm_msg *msg;
1455 	void *buf;
1456 
1457 	if (!param || !param->ops || !param->ops->scan_off_ch_tx)
1458 		return RTW_PHL_STATUS_FAILURE;
1459 
1460 	buf = _os_kmem_alloc(d, len);
1461 	if (buf == NULL)
1462 		goto buf_fail;
1463 
1464 	msg = phl_fsm_new_msg(pscan->fsm_obj, SCAN_EV_NOTIFY_OFF_CH_CMD);
1465 	if (msg == NULL)
1466 		goto msg_fail;
1467 
1468 	_os_mem_cpy(d, buf, data, len);
1469 	msg->param = buf;
1470 	msg->param_sz = len;
1471 	pq_push(d, &pscan->off_ch_cmd_q, (_os_list *)msg, _tail, _bh);
1472 
1473 	FSM_INFO(pscan->fsm, "%s %s(), q_cnt = %d\n",
1474 		phl_fsm_obj_name(pscan->fsm_obj), __func__,
1475 		pscan->off_ch_cmd_q.cnt);
1476 
1477 	/* notify scan-obj there is an off_ch_cmd */
1478 	return phl_fsm_gen_msg(phl, pscan->fsm_obj,
1479 		NULL, 0, SCAN_EV_NOTIFY_OFF_CH_CMD);
1480 msg_fail:
1481 	_os_kmem_free(d, buf, len);
1482 
1483 buf_fail:
1484 	FSM_ERR(pscan->fsm, "%s %s() malloc fail\n",
1485 		phl_fsm_obj_name(pscan->fsm_obj), __func__);
1486 	return RTW_PHL_STATUS_RESOURCE;
1487 }
1488 #endif /*CONFIG_FSM*/
1489 
1490