1 /******************************************************************************
2 *
3 * Copyright(c) 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 *****************************************************************************/
15 #define _PHL_ECSA_C_
16 #include "phl_headers.h"
17
18 #ifdef CONFIG_PHL_ECSA
19 void
_phl_ecsa_dump_param(struct rtw_phl_ecsa_param * param)20 _phl_ecsa_dump_param(
21 struct rtw_phl_ecsa_param *param
22 )
23 {
24 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Channel %d\n", __FUNCTION__,
25 param->ch);
26 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Op class %d\n", __FUNCTION__,
27 param->op_class);
28 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Count %d\n", __FUNCTION__,
29 param->count);
30 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Mode %d\n", __FUNCTION__,
31 param->mode);
32 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Delay time %d\n", __FUNCTION__,
33 param->delay_start_ms);
34 PHL_DUMP_CHAN_DEF(&(param->new_chan_def));
35 }
36
37 enum rtw_phl_status
_phl_ecsa_tx_pause(struct phl_ecsa_ctrl_t * ecsa_ctrl)38 _phl_ecsa_tx_pause(
39 struct phl_ecsa_ctrl_t *ecsa_ctrl
40 )
41 {
42 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
43 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
44 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
45 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
46
47 /* Pause SW Tx */
48 rtw_phl_tx_stop(phl_info);
49 rtw_phl_tx_req_notify(phl_info);
50
51 /* Disable hw tx all */
52 if (rtw_hal_dfs_pause_tx(phl_info->hal, wifi_role->hw_band, true) ==
53 RTW_HAL_STATUS_SUCCESS) {
54 status = RTW_PHL_STATUS_SUCCESS;
55 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "[ECSA] hw tx pause OK\n");
56 } else {
57 status = RTW_PHL_STATUS_FAILURE;
58 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "[ECSA] hw tx pause fail\n");
59 }
60
61 return status;
62 }
63
64 enum rtw_phl_status
_phl_ecsa_tx_resume(struct phl_ecsa_ctrl_t * ecsa_ctrl)65 _phl_ecsa_tx_resume(
66 struct phl_ecsa_ctrl_t *ecsa_ctrl
67 )
68 {
69 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
70 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
71 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
72 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
73
74 /* Enable hw tx all */
75 if (rtw_hal_dfs_pause_tx(phl_info->hal, wifi_role->hw_band, false) ==
76 RTW_HAL_STATUS_SUCCESS) {
77 status = RTW_PHL_STATUS_SUCCESS;
78 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "[ECSA] hw tx unpause OK\n");
79 } else {
80 status = RTW_PHL_STATUS_FAILURE;
81 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "[ECSA] hw tx unpause fail\n");
82 }
83
84 rtw_phl_tx_resume(phl_info);
85
86 return status;
87 }
88
89 u32
_phl_ecsa_calculate_next_timer_ap(struct phl_ecsa_ctrl_t * ecsa_ctrl)90 _phl_ecsa_calculate_next_timer_ap(
91 struct phl_ecsa_ctrl_t *ecsa_ctrl
92 )
93 {
94 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
95 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
96 struct rtw_bcn_info_cmn *bcn_cmn = NULL;
97 u32 tsf_h = 0, tsf_l = 0;
98 u64 tsf = 0;
99 u32 beacon_period_us = 0, timeslot_us = 0, next_timeslot_us = 0;
100 u32 current_time_ms = _os_get_cur_time_ms();
101
102 if (RTW_HAL_STATUS_SUCCESS != rtw_hal_get_tsf(phl_info->hal,
103 ecsa_ctrl->role->hw_port,
104 &tsf_h,
105 &tsf_l)) {
106 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "_phl_ecsa_timer_callback(): Get tsf fail\n");
107 return 0;
108 }
109 tsf = tsf_h;
110 tsf = tsf << 32;
111 tsf |= tsf_l;
112
113 bcn_cmn = &ecsa_ctrl->role->bcn_cmn;
114 beacon_period_us = bcn_cmn->bcn_interval * TU;
115
116 timeslot_us = (u32)_os_modular64(tsf, beacon_period_us);
117
118 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: CurTimeMs = %d State = %x timeslot = %d\n",
119 __FUNCTION__, current_time_ms, ecsa_ctrl->state, timeslot_us);
120
121 if(ecsa_ctrl->state == ECSA_STATE_START){
122 next_timeslot_us = beacon_period_us - timeslot_us + (2 * TU);
123 }
124 /* To make sure first ECSA IE show in Beacon */
125 else if(ecsa_ctrl->state == ECSA_STATE_UPDATE_FIRST_BCN_DONE){
126 next_timeslot_us = (beacon_period_us - timeslot_us -
127 ECSA_UPDATE_BCN_BEFORE_TBTT_US);
128 ecsa_ctrl->expected_tbtt_ms = current_time_ms +
129 (beacon_period_us - timeslot_us)/1000;
130 }
131 else if(ecsa_ctrl->state == ECSA_STATE_COUNT_DOWN){
132 if(ecsa_ctrl->ecsa_param.count == 1){
133 next_timeslot_us = (beacon_period_us - timeslot_us) +
134 ECSA_SWITCH_TIME_AFTER_LAST_COUNT_DOWN;
135 }
136 else{
137 next_timeslot_us = (beacon_period_us - timeslot_us) +
138 (beacon_period_us - ECSA_UPDATE_BCN_BEFORE_TBTT_US);
139
140 ecsa_ctrl->expected_tbtt_ms = current_time_ms +
141 (2 * beacon_period_us - timeslot_us)/1000;
142 }
143 }
144
145 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Expected tbtt %d!\n", __FUNCTION__, ecsa_ctrl->expected_tbtt_ms);
146 return next_timeslot_us/1000;
147 }
148
149 u32
_phl_ecsa_calculate_next_timer_sta(struct phl_ecsa_ctrl_t * ecsa_ctrl)150 _phl_ecsa_calculate_next_timer_sta(
151 struct phl_ecsa_ctrl_t *ecsa_ctrl
152 )
153 {
154 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
155 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
156 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
157 struct rtw_phl_stainfo_t *sta = NULL;
158 u32 beacon_period_us = 0, next_timeslot = 0;
159 u32 current_time_ms = 0;
160
161 current_time_ms = _os_get_cur_time_ms();
162 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: CurTimeMs = %d State = %x\n",
163 __FUNCTION__, current_time_ms, ecsa_ctrl->state);
164
165 sta = rtw_phl_get_stainfo_self(phl_info, wifi_role);
166 if(sta == NULL){
167 PHL_TRACE(COMP_PHL_ECSA, _PHL_ERR_, "%s: Get sta info fail!\n",
168 __FUNCTION__);
169 return 0;
170 }
171
172 beacon_period_us = sta->asoc_cap.bcn_interval * TU;
173
174 if(ecsa_ctrl->state == ECSA_STATE_START){
175 next_timeslot = 0;
176 }
177 else if(ecsa_ctrl->state == ECSA_STATE_COUNT_DOWN){
178 u8 count = ecsa_ctrl->ecsa_param.count;
179 next_timeslot = (beacon_period_us * count) / 1000; /* ms */
180 }
181 else if(ecsa_ctrl->state == ECSA_STATE_SWITCH){
182 next_timeslot = 1000; /* 1s */
183 }
184
185 return next_timeslot;
186 }
187
188 void
_phl_ecsa_calculate_next_timer(struct phl_ecsa_ctrl_t * ecsa_ctrl)189 _phl_ecsa_calculate_next_timer(
190 struct phl_ecsa_ctrl_t *ecsa_ctrl
191 )
192 {
193 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
194 void *d = phlcom_to_drvpriv(phl_com);
195 u32 next_timeslot = 0; /* ms */
196
197 if(IS_ECSA_TYPE_AP(ecsa_ctrl))
198 next_timeslot = _phl_ecsa_calculate_next_timer_ap(ecsa_ctrl);
199
200 if(IS_ECSA_TYPE_STA(ecsa_ctrl))
201 next_timeslot = _phl_ecsa_calculate_next_timer_sta(ecsa_ctrl);;
202 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: Next time slot %d!\n", __FUNCTION__, next_timeslot);
203 _os_set_timer(d, &ecsa_ctrl->timer, next_timeslot);
204
205 }
206
_phl_ecsa_state_change_ap(struct phl_ecsa_ctrl_t * ecsa_ctrl)207 void _phl_ecsa_state_change_ap(
208 struct phl_ecsa_ctrl_t *ecsa_ctrl
209 )
210 {
211 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
212 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
213 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
214 struct phl_msg msg = {0};
215 struct phl_msg_attribute attr = {0};
216 void *d = phlcom_to_drvpriv(phl_com);
217
218 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_ECSA);
219
220 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: CurTimeMs = %d State = %x\n",
221 __FUNCTION__, _os_get_cur_time_ms(), ecsa_ctrl->state);
222
223 /* Protect ECSA state change to prevent timer callback racing */
224 _os_spinlock(d, &(ecsa_ctrl->lock), _bh, NULL);
225
226 if(ecsa_ctrl->state == ECSA_STATE_WAIT_DELAY){
227 status = rtw_phl_ecsa_cmd_request(phl_info, ecsa_ctrl->role);
228 if(status != RTW_PHL_STATUS_SUCCESS){
229 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
230 "%s: ECSA command fail!\n", __FUNCTION__);
231 ecsa_ctrl->state = ECSA_STATE_NONE;
232 }
233 else{
234 ecsa_ctrl->state = ECSA_STATE_START;
235 }
236
237 }
238 else if(ecsa_ctrl->state == ECSA_STATE_START){
239 ecsa_ctrl->state = ECSA_STATE_UPDATE_FIRST_BCN_DONE;
240 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_UPDATE_FIRST_BCN_DONE);
241
242 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
243 if(status != RTW_PHL_STATUS_SUCCESS)
244 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
245 }
246 /* To make sure first ECSA IE show in Beacon */
247 else if(ecsa_ctrl->state == ECSA_STATE_UPDATE_FIRST_BCN_DONE){
248 ecsa_ctrl->state = ECSA_STATE_COUNT_DOWN;
249 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_COUNT_DOWN);
250
251 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
252 if(status != RTW_PHL_STATUS_SUCCESS)
253 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
254 }
255 else if(ecsa_ctrl->state == ECSA_STATE_COUNT_DOWN){
256 if(ecsa_ctrl->ecsa_param.count == 1){
257 ecsa_ctrl->state = ECSA_STATE_SWITCH;
258 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_SWITCH_START);
259 msg.rsvd[0] = (u8*)ecsa_ctrl->role;
260 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
261 if(status != RTW_PHL_STATUS_SUCCESS)
262 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
263 }
264 else{
265 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_COUNT_DOWN);
266
267 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
268 if(status != RTW_PHL_STATUS_SUCCESS)
269 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
270 }
271 }
272 _os_spinunlock(d, &(ecsa_ctrl->lock), _bh, NULL);
273 }
274
_phl_ecsa_state_change_sta(struct phl_ecsa_ctrl_t * ecsa_ctrl)275 void _phl_ecsa_state_change_sta(
276 struct phl_ecsa_ctrl_t *ecsa_ctrl
277 )
278 {
279 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
280 struct rtw_phl_com_t *phl_com = ecsa_ctrl->phl_com;
281 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
282 struct phl_msg msg = {0};
283 struct phl_msg_attribute attr = {0};
284 void *d = phlcom_to_drvpriv(phl_com);
285
286 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_ECSA);
287
288 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: CurTimeMs = %d State = %x\n",
289 __FUNCTION__, _os_get_cur_time_ms(), ecsa_ctrl->state);
290
291 /* Protect ECSA state change to prevent timer callback racing */
292 _os_spinlock(d, &(ecsa_ctrl->lock), _bh, NULL);
293
294 if(ecsa_ctrl->state == ECSA_STATE_WAIT_DELAY){
295 status = rtw_phl_ecsa_cmd_request(phl_info, ecsa_ctrl->role);
296 if(status != RTW_PHL_STATUS_SUCCESS){
297 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
298 "%s: ECSA command fail!\n", __FUNCTION__);
299 ecsa_ctrl->state = ECSA_STATE_NONE;
300 }
301 else{
302 ecsa_ctrl->state = ECSA_STATE_START;
303 }
304 }
305 else if(ecsa_ctrl->state == ECSA_STATE_START){
306 ecsa_ctrl->state = ECSA_STATE_COUNT_DOWN;
307 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_COUNT_DOWN);
308
309 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
310 if(status != RTW_PHL_STATUS_SUCCESS)
311 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
312 }
313 else if(ecsa_ctrl->state == ECSA_STATE_COUNT_DOWN){
314 ecsa_ctrl->state = ECSA_STATE_SWITCH;
315 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_SWITCH_START);
316 msg.rsvd[0] = (u8*)ecsa_ctrl->role;
317 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
318 if(status != RTW_PHL_STATUS_SUCCESS)
319 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
320 }
321 else if(ecsa_ctrl->state == ECSA_STATE_SWITCH){
322 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_CHECK_TX_RESUME);
323 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
324 if(status != RTW_PHL_STATUS_SUCCESS)
325 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
326 }
327 _os_spinunlock(d, &(ecsa_ctrl->lock), _bh, NULL);
328 }
329
330 void
_phl_ecsa_timer_callback(void * context)331 _phl_ecsa_timer_callback(
332 void *context
333 )
334 {
335 struct phl_ecsa_ctrl_t *ecsa_ctrl = (struct phl_ecsa_ctrl_t *)context;
336
337 if(IS_ECSA_TYPE_AP(ecsa_ctrl))
338 _phl_ecsa_state_change_ap(ecsa_ctrl);
339
340 if(IS_ECSA_TYPE_STA(ecsa_ctrl))
341 _phl_ecsa_state_change_sta(ecsa_ctrl);
342 }
343
344 void
_phl_ecsa_cmd_abort_hdlr(void * dispr,void * priv,bool abort)345 _phl_ecsa_cmd_abort_hdlr(
346 void* dispr,
347 void* priv,
348 bool abort
349 )
350 {
351 struct phl_ecsa_ctrl_t *ecsa_ctrl = (struct phl_ecsa_ctrl_t *)priv;
352 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
353 struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
354 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
355 struct rtw_phl_ecsa_ops *ops = &ecsa_ctrl->ops;
356 struct phl_msg msg = {0};
357 struct phl_msg_attribute attr = {0};
358 enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
359 void *d = phlcom_to_drvpriv(phl_com);
360
361 _os_cancel_timer(d, &ecsa_ctrl->timer);
362
363 /* ECSA AP abort handle */
364 if(IS_ECSA_TYPE_AP(ecsa_ctrl) &&
365 ecsa_ctrl->ecsa_param.flag != 0){
366 ecsa_ctrl->state = ECSA_STATE_NONE;
367 CLEAR_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
368 ECSA_PARAM_FLAG_APPEND_BCN);
369 CLEAR_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
370 ECSA_PARAM_FLAG_APPEND_PROBERSP);
371 /* Update Bcn */
372 if(ops->update_beacon)
373 ops->update_beacon(ops->priv, wifi_role);
374 }
375
376 /* ECSA STA abort handle */
377 if(IS_ECSA_TYPE_STA(ecsa_ctrl)){
378 if(ecsa_ctrl->ecsa_param.mode == true)
379 _phl_ecsa_tx_resume(ecsa_ctrl);
380
381 if(ops->ecsa_complete)
382 ops->ecsa_complete(ops->priv, wifi_role);
383 }
384
385 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_ECSA);
386 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_DONE);
387
388 if(abort)
389 attr.opt = MSG_OPT_SEND_IN_ABORT;
390
391 pstatus = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
392
393 if(pstatus != RTW_PHL_STATUS_SUCCESS) {
394 PHL_ERR("%s:[ECSA] dispr_send_msg failed (0x%X)\n",
395 __FUNCTION__, pstatus);
396 }
397 }
398
399 enum phl_mdl_ret_code
_phl_ecsa_cmd_acquired(void * dispr,void * priv)400 _phl_ecsa_cmd_acquired(
401 void* dispr,
402 void* priv)
403 {
404 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
405 enum phl_mdl_ret_code ret = MDL_RET_FAIL;
406 struct phl_ecsa_ctrl_t *ecsa_ctrl = (struct phl_ecsa_ctrl_t *)priv;
407 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
408 struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
409 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
410 struct phl_msg msg = {0};
411 struct phl_msg_attribute attr = {0};
412
413 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_ECSA);
414 SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ECSA_START);
415
416 status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
417 if(status != RTW_PHL_STATUS_SUCCESS){
418 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
419 goto exit;
420 }
421
422 ret = MDL_RET_SUCCESS;
423 exit:
424 return ret;
425 }
426
427 enum phl_mdl_ret_code
_phl_ecsa_cmd_abort(void * dispr,void * priv)428 _phl_ecsa_cmd_abort(
429 void* dispr,
430 void* priv)
431 {
432 _phl_ecsa_cmd_abort_hdlr(dispr, priv, true);
433 return MDL_RET_SUCCESS;
434 }
435
436 enum phl_mdl_ret_code
_phl_ecsa_cmd_msg_hdlr(void * dispr,void * priv,struct phl_msg * msg)437 _phl_ecsa_cmd_msg_hdlr(
438 void* dispr,
439 void* priv,
440 struct phl_msg* msg)
441 {
442 struct phl_ecsa_ctrl_t *ecsa_ctrl = (struct phl_ecsa_ctrl_t *)priv;
443 struct rtw_wifi_role_t *wifi_role = ecsa_ctrl->role;
444 struct rtw_phl_com_t *phl_com = wifi_role->phl_com;
445 struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
446 void *d = phlcom_to_drvpriv(phl_com);
447 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
448 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
449 struct phl_msg nextmsg = {0};
450 struct phl_msg_attribute attr = {0};
451 struct rtw_phl_ecsa_ops *ops = &ecsa_ctrl->ops;
452 u32 current_time_ms = _os_get_cur_time_ms();
453 struct rtw_bcn_info_cmn *bcn_cmn = &ecsa_ctrl->role->bcn_cmn;
454 u32 beacon_period_ms = bcn_cmn->bcn_interval * TU / 1000;
455 u8 countdown_n = 1;
456 struct rtw_chan_def chdef_to_switch = {0};
457
458 if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_ECSA) {
459 return MDL_RET_IGNORE;
460 }
461
462 if(IS_MSG_FAIL(msg->msg_id)) {
463 _phl_ecsa_cmd_abort_hdlr(dispr, priv, false);
464 status = phl_disp_eng_free_token(phl_info,
465 wifi_role->hw_band,
466 &ecsa_ctrl->req_hdl);
467 if(status != RTW_PHL_STATUS_SUCCESS)
468 PHL_WARN("%s: Free token fail!\n", __FUNCTION__);
469 return MDL_RET_SUCCESS;
470 }
471
472 SET_MSG_MDL_ID_FIELD(nextmsg.msg_id, PHL_FG_MDL_ECSA);
473
474 switch(MSG_EVT_ID_FIELD(msg->msg_id)){
475 case MSG_EVT_ECSA_START:
476 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
477 "%s: MSG_EVT_ECSA_START\n", __FUNCTION__);
478 if(IS_ECSA_TYPE_AP(ecsa_ctrl)){
479 SET_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
480 ECSA_PARAM_FLAG_APPEND_BCN);
481 /* Update Bcn */
482 if(ops->update_beacon)
483 ops->update_beacon(ops->priv, wifi_role);
484 }
485
486 if(IS_ECSA_TYPE_STA(ecsa_ctrl) &&
487 ecsa_ctrl->ecsa_param.mode == true){
488 _phl_ecsa_tx_pause(ecsa_ctrl);
489 }
490 _phl_ecsa_calculate_next_timer(ecsa_ctrl);
491 break;
492 case MSG_EVT_ECSA_UPDATE_FIRST_BCN_DONE:
493 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
494 "%s: MSG_EVT_ECSA_UPDATE_FIRST_BCN_DONE\n", __FUNCTION__);
495 SET_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
496 ECSA_PARAM_FLAG_APPEND_PROBERSP);
497 _phl_ecsa_calculate_next_timer(ecsa_ctrl);
498 break;
499 case MSG_EVT_ECSA_COUNT_DOWN:
500 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
501 "%s: MSG_EVT_ECSA_COUNT_DOWN\n", __FUNCTION__);
502
503 /* Count down mode of STA ECSA only calculate the switch time */
504 if(IS_ECSA_TYPE_STA(ecsa_ctrl)){
505 _phl_ecsa_calculate_next_timer(ecsa_ctrl);
506 break;
507 }
508
509 /* Count down mode of AP ECSA calculate the update beacon time */
510 if(ecsa_ctrl->expected_tbtt_ms > current_time_ms){
511 countdown_n = 1;
512 }
513 else{
514 /*
515 * There may be delay time during msg delivery,
516 * calulate the actual countdown value
517 */
518 countdown_n = (u8)((current_time_ms-(ecsa_ctrl->expected_tbtt_ms))%beacon_period_ms+1);
519
520 }
521
522 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
523 "%s: count down %d\n", __FUNCTION__, countdown_n);
524
525 if(ecsa_ctrl->ecsa_param.count > countdown_n){
526 ecsa_ctrl->ecsa_param.count -= countdown_n;
527 /* Update Bcn */
528 if(ops->update_beacon)
529 ops->update_beacon(ops->priv, wifi_role);
530 _phl_ecsa_calculate_next_timer(ecsa_ctrl);
531 }
532 else{
533 /*
534 * If the countdown value is less than 1,
535 * we have to switch channel immediately
536 */
537 ecsa_ctrl->ecsa_param.count = 0;
538 ecsa_ctrl->state = ECSA_STATE_SWITCH;
539 SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_ECSA_SWITCH_START);
540 nextmsg.rsvd[0] = (u8*)ecsa_ctrl->role;
541 status = phl_disp_eng_send_msg(phl_info,
542 &nextmsg,
543 &attr,
544 NULL);
545 if(status != RTW_PHL_STATUS_SUCCESS)
546 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: Send msg fail!\n", __FUNCTION__);
547 }
548 break;
549 case MSG_EVT_ECSA_SWITCH_START:
550 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
551 "%s: MSG_EVT_ECSA_SWITCH_START\n", __FUNCTION__);
552
553 /* Update channel info */
554 if(ops->update_chan_info){
555 ops->update_chan_info(ops->priv,
556 wifi_role,
557 ecsa_ctrl->ecsa_param.new_chan_def);
558 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
559 "%s: update_chan_info done!\n", __FUNCTION__);
560 }
561 else{
562 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
563 "%s: update_chan_info is NULL!\n", __FUNCTION__);
564 }
565
566 /* AP mode ECSA should update beacon to remove ECSA IE and update the channel info */
567 if(IS_ECSA_TYPE_AP(ecsa_ctrl)){
568 CLEAR_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
569 ECSA_PARAM_FLAG_APPEND_BCN);
570 CLEAR_STATUS_FLAG(ecsa_ctrl->ecsa_param.flag,
571 ECSA_PARAM_FLAG_APPEND_PROBERSP);
572 /* Update Bcn */
573 if(ops->update_beacon)
574 ops->update_beacon(ops->priv, wifi_role);
575 }
576
577 /*
578 * We should use chandef of the chanctx to switch,
579 * the bw may not be same as the ECSA operating class
580 * because of the SCC mode with different bandwidth.
581 */
582 if(wifi_role->chanctx != NULL){
583 _os_mem_cpy(d, &chdef_to_switch, &(wifi_role->chanctx->chan_def),
584 sizeof(struct rtw_chan_def));
585 if(wifi_role->chanctx->chan_def.chan !=
586 ecsa_ctrl->ecsa_param.new_chan_def.chan)
587 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
588 "%s: channel is not same as ECSA parameter!\n",
589 __FUNCTION__);
590 }
591 else{
592 _os_mem_cpy(d, &chdef_to_switch, &(ecsa_ctrl->ecsa_param.new_chan_def),
593 sizeof(struct rtw_chan_def));
594 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
595 "%s: chanctx of role is NULL use ECSA parameter!\n",
596 __FUNCTION__);
597 }
598
599 /* Switch channel */
600 phl_set_ch_bw(wifi_role, &chdef_to_switch, true);
601
602 SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_ECSA_SWITCH_DONE);
603 nextmsg.rsvd[0] = (u8*)ecsa_ctrl->role;
604 status = phl_disp_eng_send_msg(phl_info,
605 &nextmsg,
606 &attr,
607 NULL);
608 if(status != RTW_PHL_STATUS_SUCCESS)
609 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
610 "%s: Send msg fail!\n", __FUNCTION__);
611 break;
612 case MSG_EVT_ECSA_SWITCH_DONE:
613 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
614 "%s: MSG_EVT_ECSA_SWITCH_DONE\n", __FUNCTION__);
615 if(IS_ECSA_TYPE_STA(ecsa_ctrl) &&
616 ecsa_ctrl->ecsa_param.mode == true){
617 SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_ECSA_CHECK_TX_RESUME);
618 status = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
619 if(status != RTW_PHL_STATUS_SUCCESS)
620 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
621 "%s: Send msg fail!\n", __FUNCTION__);
622 break;
623 }
624
625 SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_ECSA_DONE);
626 status = phl_disp_eng_send_msg(phl_info,
627 &nextmsg,
628 &attr,
629 NULL);
630 if(status != RTW_PHL_STATUS_SUCCESS)
631 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
632 "%s: Send msg fail!\n", __FUNCTION__);
633 break;
634 case MSG_EVT_ECSA_CHECK_TX_RESUME:
635 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
636 "%s: MSG_EVT_ECSA_CHECK_TX_RESUME\n", __FUNCTION__);
637 if(IS_ECSA_TYPE_STA(ecsa_ctrl) &&
638 ecsa_ctrl->ecsa_param.mode == true){
639 /*
640 * TODO: If driver support DFS-slave with radar
641 * detection, ECSA should tx un-pause directly
642 * and the tx pause should be handled by DFS-slave.
643 */
644 if(ops->check_tx_resume_allow){
645 if(!ops->check_tx_resume_allow(ops->priv, wifi_role)){
646 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
647 "%s: Keep Tx pause...\n", __FUNCTION__);
648 _phl_ecsa_calculate_next_timer(ecsa_ctrl);
649 break;
650 }
651 }
652 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
653 "%s: Tx resume!\n", __FUNCTION__);
654 _phl_ecsa_tx_resume(ecsa_ctrl);
655 }
656
657 SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_ECSA_DONE);
658 status = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
659 if(status != RTW_PHL_STATUS_SUCCESS)
660 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
661 "%s: Send msg fail!\n", __FUNCTION__);
662
663 break;
664 case MSG_EVT_ECSA_DONE:
665 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_,
666 "%s: MSG_EVT_ECSA_DONE\n", __FUNCTION__);
667 ecsa_ctrl->state = ECSA_STATE_NONE;
668
669 if(ops->ecsa_complete){
670 ops->ecsa_complete(ops->priv, wifi_role);
671 }
672 else{
673 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
674 "%s: ecsa_complete is NULL!\n", __FUNCTION__);
675 }
676
677 status = phl_disp_eng_free_token(phl_info,
678 wifi_role->hw_band,
679 &ecsa_ctrl->req_hdl);
680 if(status != RTW_PHL_STATUS_SUCCESS)
681 PHL_WARN("%s: Free token fail!\n", __FUNCTION__);
682 break;
683 default:
684 break;
685 }
686 return ret;
687 }
688
689 enum phl_mdl_ret_code
_phl_ecsa_cmd_set_info(void * dispr,void * priv,struct phl_module_op_info * info)690 _phl_ecsa_cmd_set_info(
691 void* dispr,
692 void* priv,
693 struct phl_module_op_info* info)
694 {
695 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
696
697 /* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
698 return ret;
699 }
700
701 enum phl_mdl_ret_code
_phl_ecsa_cmd_query_info(void * dispr,void * priv,struct phl_module_op_info * info)702 _phl_ecsa_cmd_query_info(
703 void* dispr,
704 void* priv,
705 struct phl_module_op_info* info)
706 {
707 struct phl_ecsa_ctrl_t *ecsa_ctrl = (struct phl_ecsa_ctrl_t *)priv;
708 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
709 /* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
710
711 switch(info->op_code) {
712 case FG_REQ_OP_GET_ROLE:
713 info->outbuf = (u8*)ecsa_ctrl->role;
714 ret = MDL_RET_SUCCESS;
715 break;
716 default:
717 break;
718 }
719
720 return ret;
721 }
722
723 enum rtw_phl_status
rtw_phl_ecsa_cmd_request(void * phl,struct rtw_wifi_role_t * role)724 rtw_phl_ecsa_cmd_request(
725 void *phl,
726 struct rtw_wifi_role_t *role
727 )
728 {
729 enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
730 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
731 struct phl_ecsa_ctrl_t *ecsa_ctrl =
732 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
733 struct phl_cmd_token_req req={0};
734
735 if(ecsa_ctrl == NULL)
736 goto exit;
737
738 /* Fill foreground command request */
739 req.module_id= PHL_FG_MDL_ECSA;
740 req.priv = ecsa_ctrl;
741 req.role = role;
742
743 req.acquired = _phl_ecsa_cmd_acquired;
744 req.abort = _phl_ecsa_cmd_abort;
745 req.msg_hdlr = _phl_ecsa_cmd_msg_hdlr;
746 req.set_info = _phl_ecsa_cmd_set_info;
747 req.query_info = _phl_ecsa_cmd_query_info;
748
749 status = phl_disp_eng_add_token_req(phl, role->hw_band, &req,
750 &ecsa_ctrl->req_hdl);
751 if((status != RTW_PHL_STATUS_SUCCESS) &&
752 (status != RTW_PHL_STATUS_PENDING))
753 goto exit;
754
755 status = RTW_PHL_STATUS_SUCCESS;
756
757 exit:
758 return status;
759 }
760
761 enum rtw_phl_status
rtw_phl_ecsa_start(void * phl,struct rtw_wifi_role_t * role,struct rtw_phl_ecsa_param * param)762 rtw_phl_ecsa_start(
763 void *phl,
764 struct rtw_wifi_role_t *role,
765 struct rtw_phl_ecsa_param *param
766 )
767 {
768 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
769 void *d = phlcom_to_drvpriv(phl_info->phl_com);
770 struct phl_ecsa_ctrl_t *ecsa_ctrl =
771 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
772 struct rtw_phl_ecsa_param *ecsa_param = &(ecsa_ctrl->ecsa_param);
773
774 if(ecsa_ctrl == NULL)
775 return RTW_PHL_STATUS_FAILURE;
776 if(ecsa_ctrl->state != ECSA_STATE_NONE){
777 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_, "%s: ECSA already started!\n",
778 __FUNCTION__);
779 return RTW_PHL_STATUS_FAILURE;
780 }
781
782 ecsa_ctrl->role = role;
783 _os_mem_cpy(d, ecsa_param, param, sizeof(struct rtw_phl_ecsa_param));
784 _phl_ecsa_dump_param(ecsa_param);
785 ecsa_ctrl->state = ECSA_STATE_WAIT_DELAY;
786 PHL_TRACE(COMP_PHL_ECSA, _PHL_INFO_, "%s: ECSA start after %dms !\n",
787 __FUNCTION__, ecsa_ctrl->ecsa_param.delay_start_ms);
788 _os_set_timer(d, &ecsa_ctrl->timer, ecsa_ctrl->ecsa_param.delay_start_ms);
789
790 return RTW_PHL_STATUS_SUCCESS;
791 }
792
793 enum rtw_phl_status
rtw_phl_ecsa_cancel(void * phl,struct rtw_wifi_role_t * role)794 rtw_phl_ecsa_cancel(
795 void *phl,
796 struct rtw_wifi_role_t *role
797 )
798 {
799 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
800 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
801 void *d = phlcom_to_drvpriv(phl_info->phl_com);
802 struct phl_ecsa_ctrl_t *ecsa_ctrl =
803 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
804
805 if(ecsa_ctrl == NULL){
806 status = RTW_PHL_STATUS_FAILURE;
807 goto exit;
808 }
809
810 if(ecsa_ctrl->state == ECSA_STATE_NONE)
811 goto exit;
812
813 _os_cancel_timer(d, &ecsa_ctrl->timer);
814
815 _os_spinlock(d, &(ecsa_ctrl->lock), _bh, NULL);
816 if(ecsa_ctrl->state > ECSA_STATE_WAIT_DELAY){
817 status = phl_disp_eng_cancel_token_req(phl_info,
818 role->hw_band,
819 &ecsa_ctrl->req_hdl);
820
821 if(status != RTW_PHL_STATUS_SUCCESS){
822 PHL_TRACE(COMP_PHL_ECSA, _PHL_WARNING_,
823 "%s: ECSA cancel req fail!\n", __FUNCTION__);
824 }
825
826 }
827 else{
828 ecsa_ctrl->state = ECSA_STATE_NONE;
829 }
830 _os_spinunlock(d, &(ecsa_ctrl->lock), _bh, NULL);
831
832 exit:
833 return status;
834 }
835
836 enum rtw_phl_status
rtw_phl_ecsa_get_param(void * phl,struct rtw_phl_ecsa_param ** param)837 rtw_phl_ecsa_get_param(
838 void *phl,
839 struct rtw_phl_ecsa_param **param
840 )
841 {
842 enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
843 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
844 struct phl_ecsa_ctrl_t *ecsa_ctrl =
845 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
846
847 if(ecsa_ctrl == NULL)
848 goto exit;
849
850 *param = &ecsa_ctrl->ecsa_param;
851 exit:
852 return status;
853 }
854
855 enum rtw_phl_status
phl_ecsa_ctrl_init(struct phl_info_t * phl_info)856 phl_ecsa_ctrl_init(
857 struct phl_info_t *phl_info
858 )
859 {
860 void *drv_priv = phl_to_drvpriv(phl_info);
861 struct phl_ecsa_ctrl_t *ecsa_ctrl = NULL;
862
863 ecsa_ctrl = _os_mem_alloc(drv_priv, sizeof(struct phl_ecsa_ctrl_t));
864 if (ecsa_ctrl == NULL) {
865 phl_info->ecsa_ctrl = NULL;
866 return RTW_PHL_STATUS_FAILURE;
867 }
868
869 phl_info->ecsa_ctrl = ecsa_ctrl;
870
871 /* set default value */
872 ecsa_ctrl->state = ECSA_STATE_NONE;
873 ecsa_ctrl->phl_com = phl_info->phl_com;
874 ecsa_ctrl->role = NULL;
875 ecsa_ctrl->expected_tbtt_ms = 0;
876
877 _os_init_timer(drv_priv, &ecsa_ctrl->timer, _phl_ecsa_timer_callback,
878 ecsa_ctrl, "phl_ecsa_timer");
879
880 _os_spinlock_init(drv_priv, &(ecsa_ctrl->lock));
881
882 return RTW_PHL_STATUS_SUCCESS;
883 }
884
885 void
phl_ecsa_ctrl_deinit(struct phl_info_t * phl_info)886 phl_ecsa_ctrl_deinit(
887 struct phl_info_t *phl_info
888 )
889 {
890 void *drv_priv = phl_to_drvpriv(phl_info);
891 struct phl_ecsa_ctrl_t *ecsa_ctrl =
892 (struct phl_ecsa_ctrl_t *)(phl_info->ecsa_ctrl);
893
894 if (ecsa_ctrl == NULL)
895 return;
896 _os_spinlock_free(drv_priv, &(ecsa_ctrl->lock));
897 _os_release_timer(drv_priv, &ecsa_ctrl->timer);
898 _os_mem_free(drv_priv, ecsa_ctrl, sizeof(struct phl_ecsa_ctrl_t));
899
900 phl_info->ecsa_ctrl = NULL;
901 }
902
903 enum rtw_phl_status
rtw_phl_ecsa_init_ops(void * phl,struct rtw_phl_ecsa_ops * ops)904 rtw_phl_ecsa_init_ops(
905 void *phl,
906 struct rtw_phl_ecsa_ops *ops)
907 {
908 enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
909 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
910 struct phl_ecsa_ctrl_t *ecsa_ctrl =
911 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
912
913 if(ecsa_ctrl == NULL)
914 goto exit;
915
916 ecsa_ctrl->ops.priv = ops->priv;
917 ecsa_ctrl->ops.update_beacon = ops->update_beacon;
918 ecsa_ctrl->ops.update_chan_info = ops->update_chan_info;
919 ecsa_ctrl->ops.check_ecsa_allow = ops->check_ecsa_allow;
920 ecsa_ctrl->ops.ecsa_complete = ops->ecsa_complete;
921 ecsa_ctrl->ops.check_tx_resume_allow = ops->check_tx_resume_allow;
922 status = RTW_PHL_STATUS_SUCCESS;
923 exit:
924 return status;
925 }
926
927 #ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
928 void
rtw_phl_ecsa_extend_option_hdlr(u32 extend_option,struct rtw_phl_ecsa_param * param)929 rtw_phl_ecsa_extend_option_hdlr(
930 u32 extend_option,
931 struct rtw_phl_ecsa_param *param
932 )
933 {
934 if ((extend_option & ECSA_EX_OPTION_FORCE_BW20) &&
935 (param->new_chan_def.bw != CHANNEL_WIDTH_20)) {
936 /* force 20M mode, set attributes accordingly */
937 param->new_chan_def.bw = CHANNEL_WIDTH_20;
938 param->new_chan_def.center_ch = param->new_chan_def.chan;
939 param->new_chan_def.offset = CHAN_OFFSET_NO_EXT;
940 param->op_class = rtw_phl_get_operating_class(param->new_chan_def);
941 }
942 }
943 #endif
944
945 bool
rtw_phl_ecsa_check_allow(void * phl,struct rtw_wifi_role_t * role,struct rtw_chan_def chan_def,enum phl_ecsa_start_reason reason,u32 * extend_option,u32 * delay_start_ms)946 rtw_phl_ecsa_check_allow(
947 void *phl,
948 struct rtw_wifi_role_t *role,
949 struct rtw_chan_def chan_def,
950 enum phl_ecsa_start_reason reason,
951 #ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
952 u32 *extend_option,
953 #endif
954 u32 *delay_start_ms
955 )
956 {
957 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
958 struct phl_ecsa_ctrl_t *ecsa_ctrl =
959 (struct phl_ecsa_ctrl_t *)phl_info->ecsa_ctrl;
960 struct rtw_phl_ecsa_ops *ops = &(ecsa_ctrl->ops);
961 bool ecsa_allow = false;
962
963 if(ops->check_ecsa_allow)
964 ecsa_allow = ops->check_ecsa_allow(ops->priv,
965 role,
966 chan_def,
967 reason,
968 #ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
969 extend_option,
970 #endif
971 delay_start_ms);
972 return ecsa_allow;
973 }
974 #endif /* CONFIG_PHL_ECSA */