xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_ecsa.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 */