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 = ¶m->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