xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_twt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2019 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_TWT_C_
16 #include "phl_headers.h"
17 
18 #ifdef CONFIG_PHL_TWT
19 #include "phl_twt.h"
_twt_transfer_config_state(enum phl_twt_action action,enum twt_config_state * state)20 void _twt_transfer_config_state(enum phl_twt_action action,
21 				enum twt_config_state *state)
22 {
23 	if (PHL_TWT_ACTION_FREE == action)
24 		*state = twt_config_state_free;
25 	else if (PHL_TWT_ACTION_ALLOC == action)
26 		*state = twt_config_state_idle;
27 	else if (PHL_TWT_ACTION_ENABLE == action)
28 		*state = twt_config_state_enable;
29 	else if (PHL_TWT_ACTION_DISABLE == action)
30 		*state = twt_config_state_idle;
31 	else if (PHL_TWT_ACTION_UP_ERROR == action)
32 		*state = twt_config_state_error;
33 }
34 
35 /*
36  * Calculate map of macid
37  * @map_offset: number of offset for wait_macid_map
38  * @macid_map: map of macid
39  * Ex: macid_map = 0x80(bit7), offset = 2, macid 71(7 + 2*32) wait announce
40  */
_twt_calc_macid_map_info(u16 macid,u8 * map_offset,u32 * macid_map)41 void _twt_calc_macid_map_info(u16 macid, u8 *map_offset, u32 *macid_map)
42 {
43 	*map_offset = (u8)(macid / 32);
44 	*macid_map = BIT(macid % 32);
45 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_calc_macid_map_info(): macid:%d, map_offset:%d, macid_map:0x%x\n",
46 		macid, *map_offset, *macid_map);
47 }
48 
_twt_calc_intvl(u8 exp,u16 mantissa)49 u32 _twt_calc_intvl(u8 exp, u16 mantissa)
50 {
51 	u32 intvl = 0;
52 
53 	intvl = mantissa * (1 << exp);
54 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_calc_intvl(): exp:%u, mantissa:%u, intvl=%u\n",
55 		exp, mantissa, intvl);
56 	return intvl;
57 }
58 
_twt_calc_wakeup_dur(u8 dur,enum rtw_phl_wake_dur_unit dur_unit)59 u32 _twt_calc_wakeup_dur(u8 dur, enum rtw_phl_wake_dur_unit dur_unit)
60 {
61 	u32 dur_t = 0;
62 
63 	if (RTW_PHL_WAKE_256US == dur_unit)
64 		dur_t = dur * 256;
65 	else if (RTW_PHL_WAKE_1TU == dur_unit)
66 		dur_t = dur * 1024;
67 	return dur_t;
68 }
69 
_twt_fill_individual_twt_para_set(struct rtw_phl_indiv_twt_para_set * para,bool ndp_paging,u8 * buf,u8 * length)70 enum rtw_phl_status _twt_fill_individual_twt_para_set(
71 				struct rtw_phl_indiv_twt_para_set *para,
72 				bool ndp_paging, u8 *buf, u8 *length)
73 {
74 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
75 	struct rtw_phl_req_type_indiv *req_type = &para->req_type;
76 
77 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_fill_individual_twt_para_set(): twt_request(%d), twt_setup_cmd(%d), trigger(%d), implicit(%d), flow_type(%d), twt_flow_id(%d), twt_wake_int_exp(%d), twt_protection(%d)\n",
78 		req_type->twt_request, req_type->twt_setup_cmd,
79 		req_type->trigger, req_type->implicit,
80 		req_type->flow_type, req_type->twt_flow_id,
81 		req_type->twt_wake_int_exp, req_type->twt_protection);
82 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_fill_individual_twt_para_set(): target_wake_t_h(0x%08x), target_wake_t_l(0x%08x), nom_min_twt_wake_dur(%d), twt_wake_int_mantissa(%d), twt_channel(%d)\n",
83 		para->target_wake_t_h, para->target_wake_t_l,
84 		para->nom_min_twt_wake_dur, para->twt_wake_int_mantissa,
85 		para->twt_channel);
86 	*length = 0;
87 	/*Request Type*/
88 	SET_TWT_REQ_TYPE_TWT_REQUEST(buf, req_type->twt_request);
89 	SET_TWT_REQ_TYPE_TWT_SETUP_COMMAND(buf, req_type->twt_setup_cmd);
90 	SET_TWT_REQ_TYPE_TRIGGER(buf, req_type->trigger);
91 	SET_TWT_REQ_TYPE_IMPLICIT(buf, req_type->implicit);
92 	SET_TWT_REQ_TYPE_FLOW_TYPE(buf, req_type->flow_type);
93 	SET_TWT_REQ_TYPE_TWT_FLOW_IDENTIFER(buf, req_type->twt_flow_id);
94 	SET_TWT_REQ_TYPE_TWT_WAKE_INTERVAL_EXPONENT(buf,
95 					req_type->twt_wake_int_exp);
96 	SET_TWT_REQ_TYPE_TWT_PROTECTION(buf, req_type->twt_protection);
97 	*length += REQUEST_TYPE_LENGTH;
98 	if (RTW_PHL_TWT_GROUPING == req_type->twt_setup_cmd) {
99 		/*TODO*/
100 	} else {
101 		SET_TWT_TARGET_WAKE_TIME_L(buf, para->target_wake_t_l);
102 		SET_TWT_TARGET_WAKE_TIME_H(buf, para->target_wake_t_h);
103 		*length += TARGET_WAKE_TIME_LENGTH;
104 	}
105 	SET_TWT_NOMINAL_MINIMUM_TWT_WAKE_DURATION(buf, *length,
106 						para->nom_min_twt_wake_dur);
107 	*length += NOMINAL_MINIMUM_TWT_WAKE_DURATION_LENGTH;
108 
109 	SET_TWT_TWT_WAKE_INTERVAL_MANTISSA(buf, *length,
110 					para->twt_wake_int_mantissa);
111 	*length += TWT_WAKE_INTERVAL_MANTISSA_LENGTH;
112 	SET_TWT_TWT_CHANNEL(buf, *length, para->twt_channel);
113 	*length += TWT_CHANNEL_LENGTH;
114 	if (true == ndp_paging) {
115 		/*TODO*/
116 	}
117 	pstatus = RTW_PHL_STATUS_SUCCESS;
118 	return pstatus;
119 }
120 
_twt_parse_individual_twt_para(u8 * twt_ele,u16 length,struct rtw_phl_twt_element * element)121 enum rtw_phl_status _twt_parse_individual_twt_para(u8 *twt_ele, u16 length,
122 				struct rtw_phl_twt_element *element)
123 {
124 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
125 	struct rtw_phl_indiv_twt_para_set *para = &element->info.i_twt_para_set;
126 	struct rtw_phl_req_type_indiv *req_type = &para->req_type;
127 
128 	u8 *next_buf = twt_ele + ELEM_ID_LEN + ELEM_LEN_LEN + CONTROL_LENGTH;
129 	req_type->twt_request = GET_TWT_REQ_TYPE_TWT_REQUEST(next_buf);
130 	req_type->twt_setup_cmd = GET_TWT_REQ_TYPE_TWT_SETUP_COMMAND(next_buf);
131 	req_type->trigger = GET_TWT_REQ_TYPE_TRIGGER(next_buf);
132 	req_type->implicit = GET_TWT_REQ_TYPE_IMPLICIT(next_buf);
133 	req_type->flow_type = GET_TWT_REQ_TYPE_FLOW_TYPE(next_buf);
134 	req_type->twt_flow_id = GET_TWT_REQ_TYPE_TWT_FLOW_IDENTIFER(next_buf);
135 	req_type->twt_wake_int_exp =
136 			GET_TWT_REQ_TYPE_TWT_WAKE_INTERVAL_EXPONENT(next_buf);
137 	req_type->twt_protection = GET_TWT_REQ_TYPE_TWT_PROTECTION(next_buf);
138 	next_buf += REQUEST_TYPE_LENGTH;
139 	if (RTW_PHL_TWT_GROUPING == req_type->twt_setup_cmd) {
140 		//Todo
141 	} else {
142 		para->target_wake_t_l = GET_TWT_TARGET_WAKE_TIME_L(next_buf);
143 		para->target_wake_t_h = GET_TWT_TARGET_WAKE_TIME_H(next_buf);
144 		next_buf += TARGET_WAKE_TIME_LENGTH;
145 	}
146 	para->nom_min_twt_wake_dur =
147 			GET_TWT_NOMINAL_MINIMUM_TWT_WAKE_DURATION(next_buf);
148 	next_buf += NOMINAL_MIN_TWT_WAKE_DURATION_LENGTH;
149 	para->twt_wake_int_mantissa =
150 				GET_TWT_TWT_WAKE_INTERVAL_MANTISSA(next_buf);
151 	next_buf += TWT_WAKE_INTERVAL_MANTISSA_LENGTH;
152 	para->twt_channel = GET_TWT_TWT_CHANNEL(next_buf);
153 	next_buf += TWT_CHANNEL_LENGTH;
154 	if (element->twt_ctrl.ndp_paging_indic) {
155 		/*TODO*/
156 	}
157 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_parse_individual_twt_para(): twt_request:%d, twt_setup_cmd:%d, trigger:%d, implicit:%d, flow_type:%d, twt_flow_id:%d, twt_wake_int_exp:%d, twt_protection:%d\n",
158 		req_type->twt_request, req_type->twt_setup_cmd,
159 		req_type->trigger, req_type->implicit,
160 		req_type->flow_type, req_type->twt_flow_id,
161 		req_type->twt_wake_int_exp, req_type->twt_protection);
162 
163 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_parse_individual_twt_para(): target_wake_t_h:0x%08X, target_wake_t_l:0x%08X, nom_min_twt_wake_dur:%d, twt_wake_int_mantissa:%d, twt_channel:%d\n",
164 		para->target_wake_t_h, para->target_wake_t_l,
165 		para->nom_min_twt_wake_dur, para->twt_wake_int_mantissa,
166 		para->twt_channel);
167 	pstatus = RTW_PHL_STATUS_SUCCESS;
168 	return pstatus;
169 }
170 
_twt_announce_info_enqueue(struct phl_info_t * phl_info,struct phl_queue * twt_annc_q,struct _twt_announce_info * twt_annc)171 enum rtw_phl_status _twt_announce_info_enqueue(struct phl_info_t *phl_info,
172 				struct phl_queue *twt_annc_q,
173 				struct _twt_announce_info *twt_annc)
174 {
175 	void *drv = phl_to_drvpriv(phl_info);
176 	_os_spinlockfg sp_flags;
177 
178 	if (!twt_annc)
179 		return RTW_PHL_STATUS_FAILURE;
180 	_os_spinlock(drv, &twt_annc_q->lock, _irq, &sp_flags);
181 	list_add_tail(&twt_annc->list, &twt_annc_q->queue);
182 	twt_annc_q->cnt++;
183 	_os_spinunlock(drv, &twt_annc_q->lock, _irq, &sp_flags);
184 	return RTW_PHL_STATUS_SUCCESS;
185 }
186 
_twt_announce_info_dequeue(struct phl_info_t * phl_info,struct phl_queue * twt_annc_q)187 struct _twt_announce_info * _twt_announce_info_dequeue(
188 				struct phl_info_t *phl_info,
189 				struct phl_queue *twt_annc_q)
190 {
191 	struct _twt_announce_info *twt_annc = NULL;
192 	void *drv = phl_to_drvpriv(phl_info);
193 	_os_spinlockfg sp_flags;
194 
195 	_os_spinlock(drv, &twt_annc_q->lock, _irq, &sp_flags);
196 	if (list_empty(&twt_annc_q->queue)) {
197 		twt_annc = NULL;
198 	} else {
199 		twt_annc = list_first_entry(&twt_annc_q->queue,
200 					struct _twt_announce_info, list);
201 		list_del(&twt_annc->list);
202 		twt_annc_q->cnt--;
203 	}
204 	_os_spinunlock(drv, &twt_annc_q->lock, _irq, &sp_flags);
205 	return twt_annc;
206 }
207 
_twt_sta_announce(struct phl_info_t * phl_info,struct phl_queue * annc_queue,u16 macid)208 enum rtw_phl_status _twt_sta_announce(struct phl_info_t *phl_info,
209 				struct phl_queue *annc_queue, u16 macid)
210 {
211 	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
212 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
213 	void *drv = phl_to_drvpriv(phl_info);
214 	_os_spinlockfg sp_flags;
215 	struct _twt_announce_info *info = NULL;
216 	_os_list *annc_list = &annc_queue->queue;
217 	u8 offset = 0;
218 	u32 macid_map = 0;
219 
220 	_twt_calc_macid_map_info(macid, &offset, &macid_map);
221 	_os_spinlock(drv, &annc_queue->lock, _irq, &sp_flags);
222 	phl_list_for_loop(info, struct _twt_announce_info, annc_list, list) {
223 		if (NULL == info)
224 			break;
225 		if (info->map_offset != offset)
226 			continue;
227 		if (!(info->wait_macid_map & macid_map))
228 			continue;
229 		hstatus = rtw_hal_twt_sta_announce(phl_info->hal, (u8)macid);
230 		if (RTW_HAL_STATUS_SUCCESS == hstatus) {
231 			info->wait_macid_map &= (~macid_map);
232 			pstatus = RTW_PHL_STATUS_SUCCESS;
233 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_sta_announce(): rtw_hal_twt_sta_announce success, macid:%d, map_offset:%d, wait_macid_map:0x%x\n",
234 				macid, info->map_offset, info->wait_macid_map);
235 		} else {
236 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_twt_sta_announce(): rtw_hal_twt_sta_announce fail, macid:%d, map_offset:%d, wait_macid_map:0x%x\n",
237 				macid, info->map_offset, info->wait_macid_map);
238 		}
239 		break;
240 	}
241 	_os_spinunlock(drv, &annc_queue->lock, _irq, &sp_flags);
242 	return pstatus;
243 }
244 
_twt_set_sta_announce_state(struct phl_info_t * phl_info,struct phl_queue * annc_q,u16 macid,enum phl_wait_annc_type type)245 enum rtw_phl_status _twt_set_sta_announce_state(struct phl_info_t *phl_info,
246 				struct phl_queue *annc_q, u16 macid,
247 				enum phl_wait_annc_type type)
248 {
249 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
250 	void *drv = phl_to_drvpriv(phl_info);
251 	_os_spinlockfg sp_flags;
252 	struct _twt_announce_info *info = NULL;
253 	_os_list *annc_list = &annc_q->queue;
254 	u8 offset = 0;
255 	u32 macid_map = 0;
256 	u8 bset = false;
257 
258 	_twt_calc_macid_map_info(macid, &offset, &macid_map);
259 	_os_spinlock(drv, &annc_q->lock, _irq, &sp_flags);
260 	phl_list_for_loop(info, struct _twt_announce_info, annc_list, list) {
261 		if (NULL == info)
262 			break;
263 		if (info->map_offset != offset)
264 			continue;
265 		if (PHL_WAIT_ANNC_ENABLE == type) {
266 			info->wait_macid_map |= macid_map;
267 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_set_sta_announce_state(): set macid:%d to wait annc state, map_offset:%d, wait_macid_map:0x%x\n",
268 				macid, info->map_offset, info->wait_macid_map);
269 		} else if (PHL_WAIT_ANNC_DISABLE == type) {
270 			info->wait_macid_map &= (~macid_map);
271 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_set_sta_announce_state(): set macid:%d to annc state, map_offset:%d, wait_macid_map:0x%x\n",
272 				macid, info->map_offset, info->wait_macid_map);
273 		} else {
274 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_twt_set_sta_announce_state(): Unknown type:%d\n",
275 				type);
276 			break;
277 		}
278 		pstatus = RTW_PHL_STATUS_SUCCESS;
279 		bset = true;
280 		break;
281 	}
282 	_os_spinunlock(drv, &annc_q->lock, _irq, &sp_flags);
283 	if (true == bset)
284 		goto exit;
285 	if (PHL_WAIT_ANNC_ENABLE == type) {
286 		info = _os_mem_alloc(drv, sizeof(struct _twt_announce_info));
287 		if (NULL == info) {
288 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_twt_sta_wait_announce(): Fail to alloc new annc info\n");
289 		} else {
290 			info->map_offset = offset;
291 			info->wait_macid_map = macid_map;
292 			_twt_announce_info_enqueue(phl_info, annc_q, info);
293 			pstatus = RTW_PHL_STATUS_SUCCESS;
294 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_set_sta_announce_state(): add new Q and set macid:%d to annc state, map_offset:%d, wait_macid_map:0x%x\n",
295 				macid, info->map_offset, info->wait_macid_map);
296 		}
297 	} else if (PHL_WAIT_ANNC_DISABLE == type) {
298 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_twt_set_sta_announce_state(): macid:%d is not in wait annc state\n",
299 				macid);
300 	} else {
301 		/*nothing*/
302 	}
303 exit:
304 	return pstatus;
305 }
306 
307 #if 0
308 /*
309  * Get macid of sta wait for announce form FW
310  * @wait_case: C2HTWT_ANNOUNCE_WAIT_DISABLE_MACID = 0, C2HTWT_ANNOUNCE_WAIT_ENABLE_MACID = 1
311  * @macid0: macid of sta
312  * @macid1: macid of sta
313  * @macid2: macid of sta
314  */
315 enum rtw_phl_status _twt_handle_c2h_wait_annc(struct phl_info_t *phl_info,
316 				u8 *content)
317 {
318 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
319 	struct phl_twt_info *phl_twt_info = get_twt_info(phl_info);
320 	struct phl_queue *annc_q = &phl_twt_info->twt_annc_queue;
321 	u8 wait_case = 0, macid = 0;
322 	u8 i = 0;
323 	bool error = false;
324 
325 	wait_case = (*((u8*)content)) & 0xf; /*BIT0-3*/
326 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_handle_c2h_wait_annc(): content:0x%X, wait_case:%d, macid0:%d, macid1:%d, macid2:%d\n",
327 		*content, wait_case, *((u8*)content + 1), *((u8*)content + 2),
328 		*((u8*)content + 3));
329 	for (i = 1; i < 4; i++) {
330 		macid = *((u8*)content + i);
331 		if (IGNORE_MACID == macid)
332 			continue;
333 		pstatus = _twt_set_sta_announce_state(phl_info, annc_q, macid,
334 							wait_case);
335 		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
336 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_handle_c2h_wait_annc(): pstatus:%d, macid: %d, fail to set sta wait announce state\n",
337 				pstatus, macid);
338 			error = true;
339 		}
340 	}
341 	if (true == error)
342 		pstatus = RTW_PHL_STATUS_FAILURE;
343 	return pstatus;
344 }
345 #endif
346 
347 /*
348 struct rtw_twt_sta_info *
349 _twt_get_twt_sta(
350 	struct phl_info_t *phl_info,
351 	struct phl_queue *sta_queue,
352 	struct rtw_phl_stainfo_t *phl_sta,
353 	u8 id
354 )
355 {
356 	void *drv = phl_to_drvpriv(phl_info);
357 	struct rtw_twt_sta_info *twt_sta = NULL, *ret_twt_sta = NULL;
358 	_os_list *sta_list = &sta_queue->queue;
359 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_get_twt_sta()\n");
360 	_os_spinlock(drv, &sta_queue->lock, _bh, NULL);
361 	phl_list_for_loop(twt_sta, struct rtw_twt_sta_info, sta_list, list) {
362 		if (twt_sta == NULL)
363 			break;
364 		if (phl_sta != twt_sta->phl_sta)
365 			continue;
366 		if (DELETE_ALL != id && id != twt_sta->id)
367 			continue;
368 		ret_twt_sta = twt_sta;
369 	}
370 	_os_spinunlock(drv, &sta_queue->lock, _bh, NULL);
371 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== _twt_get_twt_sta()\n");
372 	return ret_twt_sta;
373 }
374 */
375 
_twt_fill_config_info_indiv(struct rtw_phl_twt_info * twt_info,struct rtw_phl_indiv_twt_para_set * para_set)376 void _twt_fill_config_info_indiv(struct rtw_phl_twt_info *twt_info,
377 				struct rtw_phl_indiv_twt_para_set *para_set)
378 {
379 	struct rtw_phl_req_type_indiv *req_type = &para_set->req_type;
380 
381 	twt_info->trigger = req_type->trigger;
382 	twt_info->flow_type = req_type->flow_type;
383 	twt_info->implicit_lastbcast = req_type->implicit;
384 	twt_info->twt_protection = req_type->twt_protection;
385 	twt_info->twt_wake_int_exp = req_type->twt_wake_int_exp;
386 	twt_info->twt_wake_int_mantissa = para_set->twt_wake_int_mantissa;
387 	twt_info->nom_min_twt_wake_dur = para_set->nom_min_twt_wake_dur;
388 	twt_info->target_wake_time_h = para_set->target_wake_t_h;
389 	twt_info->target_wake_time_l = para_set->target_wake_t_l;
390 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_fill_config_info_indiv(): twt_info: trigger:%d, flow_type:%d, implicit_lastbcast:%d, twt_protection:%d, twt_wake_int_exp:%d, twt_wake_int_mantissa:%d, nom_min_twt_wake_dur:%d, target_wake_time_h:0x%08X, target_wake_time_l:0x%08X\n",
391 		twt_info->trigger, twt_info->flow_type,
392 		twt_info->implicit_lastbcast, twt_info->twt_protection,
393 		twt_info->twt_wake_int_exp, twt_info->twt_wake_int_mantissa,
394 		twt_info->nom_min_twt_wake_dur, twt_info->target_wake_time_h,
395 		twt_info->target_wake_time_l);
396 }
397 
_twt_fill_config_info(struct rtw_phl_twt_info * twt_info,struct rtw_phl_twt_setup_info * setup_info)398 void _twt_fill_config_info(struct rtw_phl_twt_info *twt_info,
399 				struct rtw_phl_twt_setup_info *setup_info)
400 {
401 	struct rtw_phl_twt_element *twt_ele = &setup_info->twt_element;
402 	struct rtw_phl_twt_control *twt_ctrl = &twt_ele->twt_ctrl;
403 
404 	twt_info->responder_pm_mode = twt_ctrl->responder_pm_mode;
405 	twt_info->nego_type = twt_ctrl->nego_type;
406 	twt_info->wake_dur_unit = twt_ctrl->wake_dur_unit;
407 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_fill_config_info(): twt_info: responder_pm_mode:%d, nego_type:%d, wake_dur_unit:%d\n",
408 		twt_info->responder_pm_mode, twt_info->nego_type,
409 		twt_info->wake_dur_unit);
410 	if (RTW_PHL_INDIV_TWT == twt_info->nego_type) {
411 		_twt_fill_config_info_indiv(twt_info,
412 						&twt_ele->info.i_twt_para_set);
413 	} else {
414 		/*todo*/
415 	}
416 }
417 
_twt_reset_config_info(struct phl_info_t * phl,struct phl_twt_config * config)418 void _twt_reset_config_info(struct phl_info_t *phl,
419 				struct phl_twt_config *config)
420 {
421 	config->role = NULL;
422 	_os_mem_set(phl_to_drvpriv(phl), &config->twt_info, 0,
423 			sizeof(struct rtw_phl_twt_info));
424 }
425 
_twt_compare_twt_para(struct rtw_phl_twt_info * twt_info,struct rtw_phl_twt_setup_info * twt_setup)426 u8 _twt_compare_twt_para(struct rtw_phl_twt_info *twt_info,
427 				struct rtw_phl_twt_setup_info *twt_setup)
428 {
429 	u8 ret = false;
430 	u64 twt1 = 0, twt2 = 0, diff_t = 0;
431 	u32 intvl = 0;
432 	struct rtw_phl_twt_info cmp_info = {0};
433 
434 	_twt_fill_config_info(&cmp_info, twt_setup);
435 	do {
436 		if (cmp_info.responder_pm_mode != twt_info->responder_pm_mode)
437 			break;
438 		if (cmp_info.nego_type != twt_info->nego_type)
439 			break;
440 		if (cmp_info.trigger != twt_info->trigger)
441 			break;
442 		if (cmp_info.flow_type != twt_info->flow_type)
443 			break;
444 		if (cmp_info.implicit_lastbcast != twt_info->implicit_lastbcast)
445 			break;
446 		if (cmp_info.twt_protection != twt_info->twt_protection)
447 			break;
448 		if ((_twt_calc_wakeup_dur(cmp_info.nom_min_twt_wake_dur
449 			, cmp_info.wake_dur_unit)) !=
450 			(_twt_calc_wakeup_dur(twt_info->nom_min_twt_wake_dur,
451 			twt_info->wake_dur_unit)))
452 			break;
453 		if ((_twt_calc_intvl(cmp_info.twt_wake_int_exp,
454 			cmp_info.twt_wake_int_mantissa)) !=
455 			(_twt_calc_intvl(twt_info->twt_wake_int_exp,
456 			twt_info->twt_wake_int_mantissa)))
457 			break;
458 		/*compare target wake time*/
459 		intvl = _twt_calc_intvl(twt_info->twt_wake_int_exp,
460 					twt_info->twt_wake_int_mantissa);
461 		twt1 = cmp_info.target_wake_time_h;
462 		twt1 = twt1 << 32;
463 		twt1 |= cmp_info.target_wake_time_l;
464 		twt2 = twt_info->target_wake_time_h;
465 		twt2 = twt2 << 32;
466 		twt2 |= twt_info->target_wake_time_l;
467 		if (twt1 > twt2) {
468 			/*cmp_info target_wake_time > twt_info target_wake_time*/
469 			diff_t = _os_minus64(twt1, twt2);
470 		} else {
471 			diff_t = _os_minus64(twt2, twt1);
472 		}
473 		if (_os_modular64(diff_t, intvl) != 0)
474 			break;
475 		ret = true;
476 	} while(false);
477 	return ret;
478 }
479 
_twt_is_same_config(struct phl_twt_config * config,struct _twt_compare * compare_info)480 u8 _twt_is_same_config(struct phl_twt_config *config,
481 				struct _twt_compare *compare_info)
482 {
483 	bool found = false;
484 
485 	do {
486 		if (config->role != compare_info->role)
487 			break;
488 		if (!(twt_config_state_idle == config->state ||
489 			twt_config_state_enable == config->state))
490 			break;
491 		if (_twt_compare_twt_para(&config->twt_info,
492 				&compare_info->twt_setup))
493 			found = true;
494 	} while(false);
495 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== _twt_is_same_config(): found(%d)\n",
496 		found);
497 	return found;
498 }
499 
_twt_dump_twt_cfg_info(struct phl_twt_cfg_info * twt_cfg_i)500 void _twt_dump_twt_cfg_info(struct phl_twt_cfg_info *twt_cfg_i)
501 {
502 	struct phl_twt_config *config = NULL;
503 	u8 i = 0;
504 
505 	config = (struct phl_twt_config *)twt_cfg_i->twt_cfg_ring;
506 
507 	for (i = 0; i < twt_cfg_i->twt_cfg_num; i++) {
508 		PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "_twt_dump_twt_cfg_info(): loop i(%d), cfg id(%d), state(%d)\n",
509 			i, config[i].idx, config[i].state);
510 	}
511 }
512 
_twt_operate_twt_config(struct phl_info_t * phl_info,struct phl_twt_cfg_info * twt_cfg_i,enum phl_operate_config_type type,u8 * para,struct phl_twt_config ** ret_config)513 enum rtw_phl_status _twt_operate_twt_config(struct phl_info_t *phl_info,
514 		struct phl_twt_cfg_info *twt_cfg_i, enum phl_operate_config_type type,
515 		u8 *para, struct phl_twt_config **ret_config)
516 {
517 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
518 	struct phl_twt_config *config =
519 			(struct phl_twt_config *)twt_cfg_i->twt_cfg_ring;
520 	u8 i = 0;
521 
522 	PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "==> _twt_operate_twt_config(): type(%d)\n",
523 		type);
524 	if (type == PHL_GET_CONFIG_BY_ID) {
525 		if (*para >= twt_cfg_i->twt_cfg_num) {
526 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_operate_twt_config(): get cfg by id(%d) fail, out of range(%d)\n",
527 				*para, twt_cfg_i->twt_cfg_num);
528 			goto exit;
529 		}
530 		if (twt_config_state_free == config[*para].state){
531 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_operate_twt_config(): get cfg by id(%d) fail, cfg state is in twt_config_state_free\n",
532 				*para);
533 			goto exit;
534 		}
535 		*ret_config = &config[*para];
536 		pstatus = RTW_PHL_STATUS_SUCCESS;
537 		goto exit;
538 	} else if (type == PHL_FREE_CONFIG) {
539 		if (*para >= twt_cfg_i->twt_cfg_num) {
540 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_operate_twt_config(): free cfg by id(%d) fail, out of range(%d)\n",
541 				*para, twt_cfg_i->twt_cfg_num);
542 			goto exit;
543 		}
544 		if (twt_config_state_free == config[*para].state){
545 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_operate_twt_config(): free cfg by id(%d) fail, cfg state is in twt_config_state_free\n",
546 				*para);
547 			goto exit;
548 		}
549 		_twt_transfer_config_state(PHL_TWT_ACTION_FREE, &config[*para].state);
550 		pstatus = RTW_PHL_STATUS_SUCCESS;
551 		goto exit;
552 	} else if (type == PHL_GET_HEAD_CONFIG) {
553 		*ret_config = config;
554 		pstatus = RTW_PHL_STATUS_SUCCESS;
555 		goto exit;
556 	} else if (type == PHL_GET_NEXT_CONFIG) {
557 		u8 next_id = 0;
558 		if (*para >= twt_cfg_i->twt_cfg_num) {
559 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_operate_twt_config(): get cfg by id(%d) fail, out of range(%d)\n",
560 				*para, twt_cfg_i->twt_cfg_num);
561 			goto exit;
562 		}
563 		next_id = *para + 1;
564 		if (next_id == twt_cfg_i->twt_cfg_num)
565 			next_id = 0;
566 		*ret_config = &config[next_id];
567 		pstatus = RTW_PHL_STATUS_SUCCESS;
568 		goto exit;
569 	}
570 	for (i = 0; i < twt_cfg_i->twt_cfg_num; i++) {
571 		PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "_twt_operate_twt_config(): loop i(%d), cfg id(%d), state(%d)\n",
572 		i, config[i].idx, config[i].state);
573 		if (type == PHL_GET_NEW_CONFIG) {
574 			if (twt_config_state_free != config[i].state)
575 				continue;
576 			_twt_reset_config_info(phl_info, &config[i]);
577 			_twt_transfer_config_state(PHL_TWT_ACTION_ALLOC,
578 							&config[i].state);
579 			config[i].twt_info.twt_id = config[i].idx;
580 			*ret_config = &config[i];
581 			pstatus = RTW_PHL_STATUS_SUCCESS;
582 			break;
583 		} else if (type == PHL_GET_CONFIG_BY_ROLE) {
584 			if (twt_config_state_free == config[i].state)
585 				continue;
586 			if ((struct rtw_wifi_role_t *)para != config[i].role)
587 				continue;
588 			*ret_config = &config[i];
589 			pstatus = RTW_PHL_STATUS_SUCCESS;
590 			break;
591 		} else if (type == PHL_GET_CONFIG_BY_PARA) {
592 			if (twt_config_state_free == config[i].state)
593 				continue;
594 			if (!_twt_is_same_config(&config[i],
595 						(struct _twt_compare *)para))
596 				continue;
597 			*ret_config = &config[i];
598 			pstatus = RTW_PHL_STATUS_SUCCESS;
599 			break;
600 		}
601 	}
602 exit:
603 	_twt_dump_twt_cfg_info(twt_cfg_i);
604 	PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "<== _twt_operate_twt_config(): pstatus:%d\n",
605 		pstatus);
606 	return pstatus;
607 }
608 
_twt_sta_update(void * hal,u16 macid,u8 twt_id,enum rtw_phl_twt_sta_action action)609 enum rtw_phl_status _twt_sta_update(void *hal, u16 macid, u8 twt_id,
610 				enum rtw_phl_twt_sta_action action)
611 {
612 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
613 	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
614 
615 	hstatus = rtw_hal_twt_sta_update(hal, (u8)macid, twt_id, action);
616 	if (hstatus != RTW_HAL_STATUS_SUCCESS) {
617 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "twt sta update fail: hstatus:%d, macid:%d, twt_id:%d, action:%d\n",
618 			hstatus, macid, twt_id, action);
619 	} else {
620 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "twt sta update ok: macid:%d, twt_id:%d, action:%d\n",
621 			macid, twt_id, action);
622 		pstatus = RTW_PHL_STATUS_SUCCESS;
623 	}
624 	return pstatus;
625 }
626 
_twt_all_sta_update(struct phl_info_t * phl_info,u8 config_id,struct phl_queue * sta_queue,enum rtw_phl_twt_sta_action action)627 enum rtw_phl_status _twt_all_sta_update(struct phl_info_t *phl_info,
628 				u8 config_id, struct phl_queue *sta_queue,
629 				enum rtw_phl_twt_sta_action action)
630 {
631 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
632 	void *drv = phl_to_drvpriv(phl_info);
633 	_os_list *sta_list = &sta_queue->queue;
634 	struct rtw_twt_sta_info *psta = NULL;
635 
636 	_os_spinlock(drv, &sta_queue->lock, _bh, NULL);
637 	phl_list_for_loop(psta, struct rtw_twt_sta_info, sta_list, list) {
638 		if (NULL == psta)
639 			break;
640 		pstatus = _twt_sta_update(phl_info->hal, psta->phl_sta->macid,
641 						config_id, action);
642 		if (RTW_PHL_STATUS_SUCCESS != pstatus)
643 			break;
644 	}
645 	_os_spinunlock(drv, &sta_queue->lock, _bh, NULL);
646 	return pstatus;
647 }
648 
_twt_get_sta_info(struct phl_info_t * phl_info,struct phl_queue * sta_queue,struct rtw_phl_stainfo_t * phl_sta)649 struct rtw_twt_sta_info * _twt_get_sta_info(struct phl_info_t *phl_info,
650 		struct phl_queue *sta_queue, struct rtw_phl_stainfo_t *phl_sta)
651 {
652 	void *drv = phl_to_drvpriv(phl_info);
653 	_os_list *sta_list = &sta_queue->queue;
654 	struct rtw_twt_sta_info *psta = NULL, *ret_sta = NULL;
655 
656 	_os_spinlock(drv, &sta_queue->lock, _bh, NULL);
657 	phl_list_for_loop(psta, struct rtw_twt_sta_info, sta_list, list) {
658 		if (NULL == psta)
659 			break;
660 		if (phl_sta == psta->phl_sta) {
661 			ret_sta = psta;
662 			break;
663 		}
664 	}
665 	_os_spinunlock(drv, &sta_queue->lock, _bh, NULL);
666 	return ret_sta;
667 }
668 
_twt_sta_enqueue(struct phl_info_t * phl_info,struct phl_queue * sta_q,struct rtw_twt_sta_info * psta)669 enum rtw_phl_status _twt_sta_enqueue(struct phl_info_t *phl_info,
670 		struct phl_queue *sta_q, struct rtw_twt_sta_info *psta)
671 {
672 	void *drv = phl_to_drvpriv(phl_info);
673 
674 	if (!psta)
675 		return RTW_PHL_STATUS_FAILURE;
676 	_os_spinlock(drv, &sta_q->lock, _bh, NULL);
677 	list_add_tail(&psta->list, &sta_q->queue);
678 	sta_q->cnt++;
679 	_os_spinunlock(drv, &sta_q->lock, _bh, NULL);
680 	return RTW_PHL_STATUS_SUCCESS;
681 }
682 
_twt_sta_dequeue(struct phl_info_t * phl_info,struct phl_queue * sta_q,u16 * cnt)683 struct rtw_twt_sta_info * _twt_sta_dequeue(struct phl_info_t *phl_info,
684 				struct phl_queue *sta_q, u16 *cnt)
685 {
686 	struct rtw_twt_sta_info *psta = NULL;
687 	void *drv = phl_to_drvpriv(phl_info);
688 
689 	_os_spinlock(drv, &sta_q->lock, _bh, NULL);
690 	if (list_empty(&sta_q->queue)) {
691 		psta = NULL;
692 	} else {
693 		psta = list_first_entry(&sta_q->queue,
694 					struct rtw_twt_sta_info, list);
695 		list_del(&psta->list);
696 		sta_q->cnt--;
697 		*cnt = (u16)sta_q->cnt;
698 	}
699 	_os_spinunlock(drv, &sta_q->lock, _bh, NULL);
700 	return psta;
701 }
702 
703 /*
704  * Delete all sta entry from queue
705  * @sta_queue: twt sta Q
706  */
_twt_delete_all_sta(struct phl_info_t * phl_info,struct phl_queue * sta_queue)707 void _twt_delete_all_sta(struct phl_info_t *phl_info,
708 				struct phl_queue *sta_queue)
709 {
710 	struct rtw_twt_sta_info *twt_sta;
711 	void *drv = phl_to_drvpriv(phl_info);
712 	u16 cnt;
713 
714 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_delete_all_sta()\n");
715 	do {
716 		twt_sta = _twt_sta_dequeue(phl_info, sta_queue, &cnt);
717 		if (NULL != twt_sta)
718 			_os_mem_free(drv, twt_sta,
719 					sizeof(struct rtw_twt_sta_info));
720 	} while (twt_sta != NULL);
721 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== _twt_delete_all_sta()\n");
722 }
723 
724 /*
725  * Delete twt sta entry by specific sta and id from queue
726  * @sta_queue: twt sta Q
727  * @phl_sta: specific sta
728  * @id: specific twt folw id/broadcast twt id or delete all
729  * @cnt: total num of sta entery in Q
730  */
_twt_delete_sta(struct phl_info_t * phl_info,struct phl_queue * sta_q,struct rtw_phl_stainfo_t * phl_sta,u8 id,u16 * cnt)731 enum rtw_phl_status _twt_delete_sta(struct phl_info_t *phl_info,
732 			struct phl_queue *sta_q,
733 			struct rtw_phl_stainfo_t *phl_sta, u8 id, u16 *cnt)
734 {
735 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
736 	struct rtw_twt_sta_info *twt_sta, *f_sta;
737 	void *drv = phl_to_drvpriv(phl_info);
738 
739 	f_sta = _twt_sta_dequeue(phl_info, sta_q, cnt);
740 	twt_sta = f_sta;
741 	do {
742 		if (twt_sta == NULL)
743 			break;
744 		if ((phl_sta == twt_sta->phl_sta) &&
745 			(DELETE_ALL == id || id == twt_sta->id)) {
746 			_os_mem_free(drv, twt_sta,
747 					sizeof(struct rtw_twt_sta_info));
748 			pstatus = RTW_PHL_STATUS_SUCCESS;
749 			break;
750 		}
751 		_twt_sta_enqueue(phl_info, sta_q, twt_sta);
752 		twt_sta = _twt_sta_dequeue(phl_info, sta_q, cnt);
753 		if (NULL != twt_sta && twt_sta == f_sta) {
754 			_twt_sta_enqueue(phl_info, sta_q, twt_sta);
755 			break;
756 		}
757 	} while (true);
758 	return pstatus;
759 }
760 
761 /*
762  * Does sta exist in twt sta entry by specific sta and id
763  * @sta_queue: twt sta Q
764  * @phl_sta: specific sta
765  * @id: specific twt folw id/broadcast twt id or delete all
766  */
_twt_sta_exist(struct phl_info_t * phl_info,struct phl_queue * sta_q,struct rtw_phl_stainfo_t * phl_sta,u8 id)767 enum rtw_phl_status _twt_sta_exist(struct phl_info_t *phl_info,
768 			struct phl_queue *sta_q,
769 			struct rtw_phl_stainfo_t *phl_sta, u8 id)
770 {
771 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
772 	struct rtw_twt_sta_info *twt_sta = NULL;
773 	void *drv = phl_to_drvpriv(phl_info);
774 	_os_list *q_list = &sta_q->queue;
775 
776 	_os_spinlock(drv, &sta_q->lock, _bh, NULL);
777 	phl_list_for_loop(twt_sta, struct rtw_twt_sta_info, q_list, list) {
778 		if (NULL == twt_sta)
779 			break;
780 		if ((phl_sta == twt_sta->phl_sta) &&
781 			(DELETE_ALL == id || id == twt_sta->id)) {
782 			pstatus = RTW_PHL_STATUS_SUCCESS;
783 			break;
784 		}
785 	}
786 	_os_spinunlock(drv, &sta_q->lock, _bh, NULL);
787 	return pstatus;
788 }
789 
790 
_twt_add_sta(struct phl_info_t * phl_info,struct rtw_phl_stainfo_t * phl_sta,struct phl_queue * sta_q,u8 id)791 enum rtw_phl_status _twt_add_sta(struct phl_info_t *phl_info,
792 			struct rtw_phl_stainfo_t *phl_sta,
793 			struct phl_queue *sta_q, u8 id)
794 {
795 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
796 	struct rtw_twt_sta_info *twt_sta;
797 	void *drv = phl_to_drvpriv(phl_info);
798 
799 	twt_sta = _os_mem_alloc(drv, sizeof(struct rtw_twt_sta_info));
800 	if (NULL == twt_sta) {
801 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_phl_twt_add_sta(): alloc rtw_twt_sta_info failed\n");
802 	} else {
803 		twt_sta->phl_sta = phl_sta;
804 		twt_sta->id = id;
805 		_twt_sta_enqueue(phl_info, sta_q, twt_sta);
806 		pstatus = RTW_PHL_STATUS_SUCCESS;
807 	}
808 	return pstatus;
809 }
810 
_twt_delete_sta_info(struct phl_info_t * phl_info,struct rtw_phl_stainfo_t * phl_sta,u8 ignore_type,enum rtw_phl_nego_type nego_type,u8 id,u8 * bitmap)811 enum rtw_phl_status _twt_delete_sta_info(struct phl_info_t *phl_info,
812 			struct rtw_phl_stainfo_t *phl_sta,
813 			u8 ignore_type, enum rtw_phl_nego_type nego_type,
814 			u8 id, u8 *bitmap)
815 {
816 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
817 	struct phl_twt_info *phl_twt_info = get_twt_info(phl_info);
818 	struct phl_twt_cfg_info *twt_cfg_i = &phl_twt_info->twt_cfg_info;
819 	struct phl_twt_config *config = NULL, *f_config = NULL;
820 	enum rtw_phl_nego_type type = nego_type;
821 	bool delete_error = false;
822 	u16 cnt;
823 	u8 delete_id = ignore_type ? DELETE_ALL : id;
824 
825 	*bitmap = 0;
826 	if (RTW_PHL_MANAGE_BCAST_TWT == nego_type)
827 		type = RTW_PHL_BCAST_TWT;
828 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl_info, twt_cfg_i,
829 				PHL_GET_HEAD_CONFIG, NULL, &config)) {
830 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_delete_sta_info(): Fail to get first allocate config\n");
831 		goto exit;
832 	}
833 	f_config = config;
834 	do {
835 		PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "_twt_delete_sta_info(): while loop, twt_id:%d\n",
836 			config->twt_info.twt_id);
837 		if (twt_config_state_free == config->state)
838 			goto next_cfg;
839 		if (config->role != phl_sta->wrole)
840 			goto next_cfg;
841 		if (false == ignore_type && config->twt_info.nego_type != type)
842 			goto next_cfg;
843 		if (RTW_PHL_STATUS_SUCCESS != _twt_sta_exist(phl_info,
844 							&config->twt_sta_queue,
845 							phl_sta, delete_id))
846 			goto next_cfg;
847 		if (RTW_PHL_STATUS_SUCCESS != _twt_sta_update(phl_info->hal,
848 							phl_sta->macid,
849 							config->twt_info.twt_id,
850 							TWT_STA_DEL_MACID)) {
851 			delete_error = true;
852 			goto next_cfg;
853 		}
854 		if (RTW_PHL_STATUS_SUCCESS != _twt_delete_sta(phl_info,
855 							&config->twt_sta_queue,
856 							phl_sta, delete_id,
857 							&cnt)) {
858 			PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_delete_sta_info(): Fail to delete sta from twt_sta Q, macid(0x%x), delete_id(%d)\n",
859 				phl_sta->macid, delete_id);
860 			delete_error = true;
861 			goto next_cfg;
862 		}
863 		if (0 == cnt)
864 			*bitmap |= (1 << config->twt_info.twt_id);
865 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_delete_sta_info(): Delete sta success, config id = %d, twt_sta_queue cnt:%d, bitmap:0x%X\n",
866 			config->twt_info.twt_id, cnt, *bitmap);
867 		if (DELETE_ALL != delete_id)
868 			break;
869 next_cfg:
870 		if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl_info,
871 						twt_cfg_i, PHL_GET_NEXT_CONFIG,
872 						(u8 *)&config->idx, &config)) {
873 			delete_error = true;
874 			break;
875 		}
876 	} while (config != f_config);
877 	if (false == delete_error)
878 		pstatus = RTW_PHL_STATUS_SUCCESS;
879 	else
880 		pstatus = RTW_PHL_STATUS_FAILURE;
881 exit:
882 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_delete_sta_info(): pstatus:%d, nego_type = %d, id:%d, bitmap:0x%x\n",
883 		pstatus, nego_type, id, *bitmap);
884 	return pstatus;
885 }
886 
_twt_info_update(struct phl_info_t * phl_info,struct phl_twt_config * config,enum phl_twt_action action)887 enum rtw_phl_status _twt_info_update(struct phl_info_t *phl_info,
888 				struct phl_twt_config *config,
889 				enum phl_twt_action action)
890 {
891 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
892 	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
893 	enum rtw_phl_twt_cfg_action config_action;
894 
895 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_info_update()\n");
896 	if (PHL_TWT_ACTION_ENABLE == action) {
897 		config_action = TWT_CFG_ADD;
898 	} else if (PHL_TWT_ACTION_DISABLE == action) {
899 		config_action = TWT_CFG_DELETE;
900 	} else {
901 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_info_update(): Unexpected action:%d\n",
902 			action);
903 		goto exit;
904 	}
905 	hstatus = rtw_hal_twt_info_update(phl_info, config->twt_info, config->role,
906 						config_action);
907 	if (hstatus == RTW_HAL_STATUS_SUCCESS) {
908 		_twt_transfer_config_state(action, &config->state);
909 		pstatus = RTW_PHL_STATUS_SUCCESS;
910 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "_twt_info_update(): update ok\n");
911 	} else {
912 		_twt_transfer_config_state(PHL_TWT_ACTION_UP_ERROR,
913 								&config->state);
914 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_info_update(): update fail, hstatus:%d\n",
915 			hstatus);
916 	}
917 exit:
918 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<==_twt_info_update(): hstatus:%d, twt_id:%d, action:%d\n",
919 		pstatus, config->twt_info.twt_id, action);
920 	return pstatus;
921 }
922 
923 /*
924 void
925 _twt_free_config(
926 	void *phl,
927 	struct phl_twt_config *config
928 )
929 {
930 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
931 	_twt_info_update(phl_info->hal, config, PHL_TWT_ACTION_DISABLE);
932 	_twt_delete_all_sta(phl_info, &config->twt_sta_queue);
933 	_twt_reset_config_info(config);
934 	_twt_transfer_config_state(PHL_TWT_ACTION_FREE, &config->state);
935 }
936 */
937 
_twt_exist_same_twt_config(struct phl_info_t * phl,struct phl_twt_cfg_info * twt_cfg_i,struct rtw_wifi_role_t * role,struct rtw_phl_twt_setup_info setup_info,struct phl_twt_config ** ret_config)938 bool _twt_exist_same_twt_config(struct phl_info_t *phl,
939 		struct phl_twt_cfg_info *twt_cfg_i, struct rtw_wifi_role_t *role,
940 		struct rtw_phl_twt_setup_info setup_info,
941 		struct phl_twt_config **ret_config)
942 {
943 	bool exist = false;
944 	struct _twt_compare compare_info = {0};
945 	struct phl_twt_config *config = NULL;
946 
947 	compare_info.role = role;
948 	compare_info.twt_setup = setup_info;
949 	if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl, twt_cfg_i,
950 		PHL_GET_CONFIG_BY_PARA, (u8 *)&compare_info, &config)) {
951 		*ret_config = config;
952 		exist = true;
953 	}
954 	return exist;
955 }
956 
957 /*
958 u8
959 _twt_get_new_config_entry(
960 	struct phl_info_t *phl,
961 	struct phl_queue *twt_queue,
962 	struct phl_twt_config **ret_config
963 )
964 {
965 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
966 	struct phl_twt_config *config = NULL;
967 	u8 bget = false;
968 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_get_new_config_entry()\n");
969 	if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl, twt_queue,
970 				PHL_GET_NEW_CONFIG, NULL, &config)) {
971 		*ret_config = config;
972 		bget = true;
973 	}
974 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== _twt_get_new_config_entry(): bget:%d\n",
975 		bget);
976 	return bget;
977 }
978 */
979 
_twt_new_config_is_available(struct phl_info_t * phl_i)980 bool _twt_new_config_is_available(struct phl_info_t *phl_i)
981 {
982 	struct phl_twt_info *phl_twt_info = get_twt_info(phl_i);
983 	struct phl_twt_cfg_info *twt_cfg_i = &phl_twt_info->twt_cfg_info;
984 	struct phl_twt_config *config = NULL;
985 	u8 available = false;
986 
987 	if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl_i, twt_cfg_i,
988 				PHL_GET_NEW_CONFIG, NULL, &config)) {
989 		_twt_operate_twt_config(phl_i, twt_cfg_i, PHL_FREE_CONFIG,
990 					&config->twt_info.twt_id, NULL);
991 		available = true;
992 	}
993 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_new_config_is_available(): bavailable:%d\n", available);
994 	return available;
995 }
996 
997 /*
998  * Whether the twt flow id of sta exist in any twt config entry.
999  * @phl_sta: the specific sta
1000  * @role: specific role for search twt config entry
1001  * @id: twt flow id
1002  * Note: for sta mode.
1003 */
_twt_flow_id_exist(void * phl,struct rtw_phl_stainfo_t * phl_sta,struct rtw_wifi_role_t * role,u8 id)1004 u8 _twt_flow_id_exist(void *phl, struct rtw_phl_stainfo_t *phl_sta,
1005 				struct rtw_wifi_role_t *role, u8 id)
1006 {
1007 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1008 	struct phl_twt_info *phl_twt_info = get_twt_info(phl_info);
1009 	struct phl_twt_cfg_info *twt_cfg_i = &phl_twt_info->twt_cfg_info;
1010 	struct phl_twt_config *config = NULL, *f_config = NULL;
1011 	struct rtw_twt_sta_info *twt_sta = NULL;
1012 	bool exist = false;
1013 
1014 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_flow_id_exist()\n");
1015 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl, twt_cfg_i,
1016 				PHL_GET_HEAD_CONFIG, NULL, &config)) {
1017 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_flow_id_exist(): Fail to get first allocate config\n");
1018 		goto exit;
1019 	}
1020 	f_config = config;
1021 	do {
1022 		PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "_twt_flow_id_exist(): while loop\n");
1023 		if (twt_config_state_free == config->state)
1024 			goto next_cfg;
1025 		if (config->role != phl_sta->wrole ||
1026 			RTW_PHL_INDIV_TWT != config->twt_info.nego_type)
1027 			goto next_cfg;
1028 		twt_sta = _twt_get_sta_info(phl_info, &config->twt_sta_queue,
1029 						phl_sta);
1030 		if (NULL != twt_sta && id == twt_sta->id) {
1031 			exist = true;
1032 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_flow_id_exist(): exist the twt_flow_id:%d\n",
1033 				id);
1034 			break;
1035 		}
1036 next_cfg:
1037 		if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl,
1038 						twt_cfg_i, PHL_GET_NEXT_CONFIG,
1039 						(u8 *)&config->idx, &config))
1040 			break;
1041 	} while(config != f_config);
1042 exit:
1043 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== _twt_flow_id_exist(): twt flow id:%d, bexist:%d\n",
1044 		id, exist);
1045 	return exist;
1046 }
1047 
_twt_accept_bcast_by_sta(struct phl_info_t * phl,struct rtw_phl_twt_setup_info * setup_info,struct rtw_phl_stainfo_t * phl_sta,u8 * config_id)1048 enum rtw_phl_status _twt_accept_bcast_by_sta(struct phl_info_t *phl,
1049 			struct rtw_phl_twt_setup_info *setup_info,
1050 			struct rtw_phl_stainfo_t *phl_sta, u8 *config_id)
1051 {
1052 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1053 
1054 	/*TODO*/
1055 	PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "==> _twt_accept_bcast_by_sta(): not support, todo\n");
1056 	pstatus = RTW_PHL_STATUS_FAILURE;
1057 	return pstatus;
1058 }
1059 
_twt_accept_indiv_by_sta(struct phl_info_t * phl,struct rtw_phl_twt_setup_info * setup_info,struct rtw_phl_stainfo_t * phl_sta,u8 * config_id)1060 enum rtw_phl_status _twt_accept_indiv_by_sta(struct phl_info_t *phl,
1061 			struct rtw_phl_twt_setup_info *setup_info,
1062 			struct rtw_phl_stainfo_t *phl_sta, u8 *config_id)
1063 {
1064 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1065 	struct rtw_phl_twt_element *twt_ele = &setup_info->twt_element;
1066 	struct rtw_phl_twt_control *twt_ctrl = &twt_ele->twt_ctrl;
1067 	struct rtw_phl_indiv_twt_para_set *para = &twt_ele->info.i_twt_para_set;
1068 	struct rtw_phl_req_type_indiv *req_type = &para->req_type;
1069 	u8 bitmap = 0, id = 0, i = 0;
1070 
1071 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> _twt_accept_indiv_by_sta()\n");
1072 	if (_twt_flow_id_exist(phl, phl_sta, phl_sta->wrole,
1073 				req_type->twt_flow_id)) {
1074 		pstatus = _twt_delete_sta_info(phl, phl_sta, false,
1075 						twt_ctrl->nego_type,
1076 						req_type->twt_flow_id, &bitmap);
1077 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_accept_indiv_by_sta(): twt flow id(%d) exist, first, delete twt sta, pstatus:%d, bitmap:0x%x\n",
1078 			req_type->twt_flow_id, pstatus, bitmap);
1079 		if (RTW_PHL_STATUS_SUCCESS == pstatus && bitmap != 0) {
1080 			id = 0;
1081 			do {
1082 				i = ((bitmap >> id) & BIT0);
1083 				if (i != 0) {
1084 					bitmap &= ~(BIT(id));
1085 					break;
1086 				}
1087 				id++;
1088 			} while (true);
1089 			pstatus = rtw_phl_twt_free_twt_config(phl, id);
1090 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_accept_indiv_by_sta():sta Q is empty in twt config entry(%d), we free it, pstatus:%d \n",
1091 				id, pstatus);
1092 			if (bitmap !=0) {
1093 				PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "_twt_accept_indiv_by_sta():  TWT config entry bitmap(0x%x) != 0, some twt config entry not free. please check code\n",
1094 						bitmap);
1095 			}
1096 		}
1097 	}
1098 	pstatus = rtw_phl_twt_alloc_twt_config(phl, phl_sta->wrole, *setup_info,
1099 						true, &id);
1100 	if (RTW_PHL_STATUS_SUCCESS == pstatus) {
1101 		pstatus = rtw_phl_twt_add_sta_info(phl, phl_sta, id,
1102 							req_type->twt_flow_id);
1103 		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
1104 			rtw_phl_twt_free_twt_config(phl, id);
1105 		} else {
1106 			*config_id = id;
1107 		}
1108 	}
1109 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "_twt_accept_indiv_by_sta(): pstatus:%d, config_id:%d\n",
1110 		pstatus, *config_id);
1111 	return pstatus;
1112 }
1113 
1114 /*
1115  * Initialize twt
1116  */
phl_twt_init(void * phl)1117 enum rtw_phl_status phl_twt_init(void *phl)
1118 {
1119 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1120 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1121 	void *drv = phl_to_drvpriv(phl_info);
1122 	struct phl_twt_info *phl_twt_i = NULL;
1123 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1124 	struct phl_twt_config *config = NULL;
1125 	u16 len = 0;
1126 	u8 i = 0;
1127 
1128 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> phl_twt_init()\n");
1129 	if (NULL == phl_info->phl_twt_info) {
1130 		phl_info->phl_twt_info = _os_mem_alloc(drv,
1131 					sizeof(struct phl_twt_info));
1132 		if (NULL == phl_info->phl_twt_info) {
1133 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "phl_twt_init(): Failed to allocate phl_twt_info\n");
1134 			goto exit;
1135 		}
1136 		_os_mem_set(phl_to_drvpriv(phl_info), phl_info->phl_twt_info,
1137 				0, sizeof(struct phl_twt_info));
1138 	} else {
1139 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "phl_twt_init(): Duplicate init1, please check code\n");
1140 	}
1141 	phl_twt_i = get_twt_info(phl_info);
1142 	twt_cfg_i = &phl_twt_i->twt_cfg_info;
1143 	if (NULL == twt_cfg_i->twt_cfg_ring) {
1144 		twt_cfg_i->twt_cfg_num = MAX_NUM_HW_TWT_CONFIG;
1145 		len = sizeof(struct phl_twt_config) * twt_cfg_i->twt_cfg_num;
1146 		twt_cfg_i->twt_cfg_ring = _os_mem_alloc(drv, len);
1147 		if (NULL == twt_cfg_i->twt_cfg_ring) {
1148 			twt_cfg_i->twt_cfg_num = 0;
1149 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "phl_twt_init(): Failed to allocate twt_cfg_ring\n");
1150 			goto exit;
1151 		}
1152 		config = (struct phl_twt_config *)twt_cfg_i->twt_cfg_ring;
1153 		for (i = 0; i < twt_cfg_i->twt_cfg_num; i++) {
1154 			_os_mem_set(phl_to_drvpriv(phl_info), config, 0,
1155 					sizeof(struct phl_twt_config));
1156 			config->idx = i;
1157 			pq_init(drv, &config->twt_sta_queue);
1158 			config++;
1159 		}
1160 	} else {
1161 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "phl_twt_init(): Duplicate init2, please check code\n");
1162 	}
1163 	/* init for twt_annc_queue */
1164 	pq_init(drv, &phl_twt_i->twt_annc_queue);
1165 	pstatus = RTW_PHL_STATUS_SUCCESS;
1166 exit:
1167 	PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "<== phl_twt_init(): pstatus:%d\n",
1168 		pstatus);
1169 	return pstatus;
1170 }
1171 
1172 /*
1173  * Deinitialize twt
1174  */
phl_twt_deinit(void * phl)1175 void phl_twt_deinit(void *phl)
1176 {
1177 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1178 	void *drv = phl_to_drvpriv(phl_info);
1179 	struct phl_twt_info *phl_twt_i = get_twt_info(phl_info);
1180 	struct phl_twt_config *config = NULL;
1181 	struct _twt_announce_info *annc_info = NULL;
1182 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1183 	u8 i = 0;
1184 	u16 len = 0;
1185 
1186 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> phl_twt_deinit()\n");
1187 	if (NULL == phl_twt_i)
1188 		goto exit;
1189 	twt_cfg_i = &phl_twt_i->twt_cfg_info;
1190 	if (NULL == twt_cfg_i->twt_cfg_ring)
1191 		goto free_twt_info;
1192 	config = (struct phl_twt_config *)(twt_cfg_i->twt_cfg_ring);
1193 	for (i = 0; i < twt_cfg_i->twt_cfg_num; i++) {
1194 		if (config->twt_sta_queue.cnt > 0) {
1195 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_deinit(): config_id: %d, twt_sta_queue.cnt(%d) >0, force delete all\n",
1196 				config->idx ,config->twt_sta_queue.cnt);
1197 			_twt_delete_all_sta(phl_info, &config->twt_sta_queue);
1198 		}
1199 		pq_deinit(drv, &config->twt_sta_queue);
1200 		config++;
1201 	}
1202 	len = sizeof(struct phl_twt_config) * twt_cfg_i->twt_cfg_num;
1203 	_os_mem_free(drv, twt_cfg_i->twt_cfg_ring, len);
1204 	do {
1205 		annc_info = _twt_announce_info_dequeue(phl_info,
1206 						&phl_twt_i->twt_annc_queue);
1207 		if (NULL == annc_info)
1208 			break;
1209 		_os_mem_free(drv, annc_info, sizeof(struct _twt_announce_info));
1210 	} while(true);
1211 	pq_deinit(drv, &phl_twt_i->twt_annc_queue);
1212 free_twt_info:
1213 	_os_mem_free(drv, phl_info->phl_twt_info, sizeof(struct phl_twt_info));
1214 exit:
1215 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_deinit()\n");
1216 }
1217 
1218 /*
1219  * Allocate new twt config
1220  * @role: the user of twt config
1221  * @setup_info: twt setup info
1222  * @benable: whether to enable the twt config to fw,
1223  * if benable is equal to false, only allocate twt config entry
1224  * @id: Output the id of twt confi entry
1225  */
rtw_phl_twt_alloc_twt_config(void * phl,struct rtw_wifi_role_t * role,struct rtw_phl_twt_setup_info setup_info,u8 benable,u8 * id)1226 enum rtw_phl_status rtw_phl_twt_alloc_twt_config(void *phl,
1227 				struct rtw_wifi_role_t *role,
1228 				struct rtw_phl_twt_setup_info setup_info,
1229 				u8 benable, u8 *id)
1230 {
1231 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1232 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1233 	struct phl_twt_info *phl_twt_info = NULL;
1234 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1235 	struct phl_twt_config *config = NULL;
1236 	bool alloc = false;
1237 
1238 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_alloc_twt_config()\n");
1239 	if (false == twt_sup(phl_info)) {
1240 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_alloc_twt_config(): twt_sup == false\n");
1241 		return pstatus;
1242 	}
1243 	if (false == twt_init(phl_info)) {
1244 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_alloc_twt_config(): twt_init == false\n");
1245 		return pstatus;
1246 	}
1247 	phl_twt_info = get_twt_info(phl_info);
1248 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1249 /*	if (true == _twt_exist_same_twt_config(phl_info, twt_cfg_i, role,
1250 						setup_info, &config)) {
1251 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "[TWT]alloc from existing config, id = %d\n",
1252 			config->twt_info.twt_id);
1253 		alloc = true;
1254 	} else */{
1255 		if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl_info,
1256 				twt_cfg_i, PHL_GET_NEW_CONFIG, NULL, &config)) {
1257 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "[TWT]alloc from new config, id = %d\n",
1258 				config->twt_info.twt_id);
1259 			alloc = true;
1260 		} else {
1261 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "[TWT]fail to alloc new config\n");
1262 			pstatus = RTW_PHL_STATUS_RESOURCE;
1263 		}
1264 	}
1265 	if (true == alloc) {
1266 		*id = config->twt_info.twt_id;
1267 		config->role = role;
1268 		_twt_fill_config_info(&config->twt_info, &setup_info);
1269 		if (benable) {
1270 			pstatus = _twt_info_update(phl_info->hal, config,
1271 							PHL_TWT_ACTION_ENABLE);
1272 			if (RTW_PHL_STATUS_SUCCESS != pstatus) {
1273 				/*todo*/
1274 			}
1275 		} else {
1276 			pstatus = RTW_PHL_STATUS_SUCCESS;
1277 		}
1278 	}
1279 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_alloc_twt_config(): pstatus:%d\n",
1280 		pstatus);
1281 	return pstatus;
1282 }
1283 
1284 /*
1285  * Free twt config entry by specific config ID
1286  * @id: id of twt config entry
1287  */
rtw_phl_twt_free_twt_config(void * phl,u8 id)1288 enum rtw_phl_status rtw_phl_twt_free_twt_config(void *phl, u8 id)
1289 {
1290 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1291 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1292 	struct phl_twt_info *phl_twt_info = NULL;
1293 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1294 	struct phl_twt_config *config = NULL;
1295 
1296 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_free_twt_config()\n");
1297 	if (false == twt_sup(phl_info)) {
1298 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_free_twt_config(): twt_sup == false\n");
1299 		return pstatus;
1300 	}
1301 	if (false == twt_init(phl_info)) {
1302 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_free_twt_config(): twt_init == false\n");
1303 		return pstatus;
1304 	}
1305 	phl_twt_info = get_twt_info(phl_info);
1306 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1307 	if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl, twt_cfg_i,
1308 							PHL_GET_CONFIG_BY_ID,
1309 							&id, &config)) {
1310 		_twt_info_update(phl_info->hal, config, PHL_TWT_ACTION_DISABLE);
1311 		_twt_delete_all_sta(phl_info, &config->twt_sta_queue);
1312 		_twt_operate_twt_config(phl, twt_cfg_i, PHL_FREE_CONFIG, &id,
1313 									NULL);
1314 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "[TWT]Free twt config success, id = %d\n",
1315 			id);
1316 		pstatus = RTW_PHL_STATUS_SUCCESS;
1317 	}
1318 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_free_twt_config(): pstatus:%d\n",
1319 		pstatus);
1320 	return pstatus;
1321 }
1322 
1323 /*
1324  * Enable twt config by specific config id
1325  * @id: id of twt confi entry
1326  */
rtw_phl_twt_enable_twt_config(void * phl,u8 id)1327 enum rtw_phl_status rtw_phl_twt_enable_twt_config(void *phl, u8 id)
1328 {
1329 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1330 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1331 	struct phl_twt_info *phl_twt_info = NULL;
1332 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1333 	struct phl_twt_config *config = NULL;
1334 
1335 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_enable_twt_config()\n");
1336 	if (false == twt_sup(phl_info)) {
1337 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_enable_twt_config(): twt_sup == false\n");
1338 		return pstatus;
1339 	}
1340 	if (false == twt_init(phl_info)) {
1341 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_enable_twt_config(): twt_init == false\n");
1342 		return pstatus;
1343 	}
1344 	phl_twt_info = get_twt_info(phl_info);
1345 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1346 	if (RTW_PHL_STATUS_SUCCESS == _twt_operate_twt_config(phl, twt_cfg_i,
1347 					PHL_GET_CONFIG_BY_ID, &id, &config)) {
1348 		pstatus = _twt_info_update(phl_info->hal, config,
1349 							PHL_TWT_ACTION_ENABLE);
1350 		if (RTW_PHL_STATUS_SUCCESS == pstatus) {
1351 			_twt_all_sta_update(phl_info, id, &config->twt_sta_queue,
1352 						TWT_STA_ADD_MACID);
1353 		}
1354 	}
1355 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_enable_twt_config(): pstatus:%d, id = %d\n",
1356 		pstatus, id);
1357 	return pstatus;
1358 }
1359 
1360 /*
1361  * Free all twt config by specific role
1362  * @role: specific role for search twt config entry
1363  */
rtw_phl_twt_free_all_twt_by_role(void * phl,struct rtw_wifi_role_t * role)1364 enum rtw_phl_status rtw_phl_twt_free_all_twt_by_role(void *phl,
1365 				struct rtw_wifi_role_t *role)
1366 {
1367 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1368 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1369 	struct phl_twt_info *phl_twt_info = NULL;
1370 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1371 	struct phl_twt_config *config;
1372 	u8 id;
1373 	bool free = false;
1374 
1375 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_free_all_twt_by_role()\n");
1376 	if (false == twt_sup(phl_info)) {
1377 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_free_all_twt_by_role(): twt_sup == false\n");
1378 		return pstatus;
1379 	}
1380 	if (false == twt_init(phl_info)) {
1381 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_free_all_twt_by_role(): twt_init == false\n");
1382 		return pstatus;
1383 	}
1384 	phl_twt_info = get_twt_info(phl_info);
1385 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1386 	do {
1387 		pstatus = _twt_operate_twt_config(phl, twt_cfg_i,
1388 				PHL_GET_CONFIG_BY_ROLE, (u8 *)role, &config);
1389 		if (RTW_PHL_STATUS_SUCCESS != pstatus)
1390 			break;
1391 		id = config->twt_info.twt_id;
1392 		_twt_info_update(phl_info->hal, config, PHL_TWT_ACTION_DISABLE);
1393 		_twt_delete_all_sta(phl_info, &config->twt_sta_queue);
1394 		_twt_operate_twt_config(phl, twt_cfg_i, PHL_FREE_CONFIG, &id,
1395 									NULL);
1396 		free = true;
1397 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "Free twt config success, id = %d\n",
1398 			id);
1399 	} while(true);
1400 	if (true == free)
1401 		pstatus = RTW_PHL_STATUS_SUCCESS;
1402 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_free_all_twt_by_role(): pstatus:%d\n",
1403 		pstatus);
1404 	return pstatus;
1405 }
1406 
1407 /*
1408  * Pause all twt config by specific role
1409  * @role: specific role for search twt config entry
1410  */
rtw_phl_twt_disable_all_twt_by_role(void * phl,struct rtw_wifi_role_t * role)1411 enum rtw_phl_status rtw_phl_twt_disable_all_twt_by_role(void *phl,
1412 				struct rtw_wifi_role_t *role)
1413 {
1414 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1415 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1416 	struct phl_twt_info *phl_twt_info = NULL;
1417 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1418 	struct phl_twt_config *config = NULL, *f_config = NULL;
1419 
1420 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_disable_all_twt_by_role()\n");
1421 	if (false == twt_sup(phl_info)) {
1422 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_disable_all_twt_by_role(): twt_sup == false\n");
1423 		goto exit;
1424 	}
1425 	if (false == twt_init(phl_info)) {
1426 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_disable_all_twt_by_role(): twt_init == false\n");
1427 		goto exit;
1428 	}
1429 	phl_twt_info = get_twt_info(phl_info);
1430 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1431 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl, twt_cfg_i,
1432 				PHL_GET_HEAD_CONFIG, NULL, &config)) {
1433 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_disable_all_twt_by_role(): Fail to get first allocate config\n");
1434 		goto exit;
1435 	}
1436 	f_config = config;
1437 	do {
1438 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_disable_all_twt_by_role(): while loop, twt_id:%d\n",
1439 			config->twt_info.twt_id);
1440 		if (twt_config_state_free == config->state)
1441 			goto next_cfg;
1442 		if (config->role == role)
1443 			_twt_info_update(phl_info->hal, config,
1444 					PHL_TWT_ACTION_DISABLE);
1445 next_cfg:
1446 		if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl,
1447 						twt_cfg_i, PHL_GET_NEXT_CONFIG,
1448 						(u8 *)&config->idx, &config))
1449 			goto exit;
1450 	} while(config != f_config);
1451 	pstatus = RTW_PHL_STATUS_SUCCESS;
1452 exit:
1453 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_disable_all_twt_by_role(): pstatus:%d\n",
1454 		pstatus);
1455 	return pstatus;
1456 }
1457 
1458 /*
1459  * Enable all twt config by specific role
1460  * @role: specific role for search twt config entry
1461  */
rtw_phl_twt_enable_all_twt_by_role(void * phl,struct rtw_wifi_role_t * role)1462 enum rtw_phl_status rtw_phl_twt_enable_all_twt_by_role(void *phl,
1463 				struct rtw_wifi_role_t *role)
1464 {
1465 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1466 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1467 	struct phl_twt_info *phl_twt_info = NULL;
1468 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1469 	struct phl_twt_config *config = NULL, *f_config = NULL;
1470 	bool error = false;
1471 
1472 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_enable_all_twt_by_role()\n");
1473 	if (false == twt_sup(phl_info)) {
1474 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_enable_all_twt_by_role(): twt_sup == false\n");
1475 		goto exit;
1476 	}
1477 	if (false == twt_init(phl_info)) {
1478 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_enable_all_twt_by_role(): twt_init == false\n");
1479 		goto exit;
1480 	}
1481 	phl_twt_info = get_twt_info(phl_info);
1482 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1483 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl, twt_cfg_i,
1484 				PHL_GET_HEAD_CONFIG, NULL, &config)) {
1485 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_enable_all_twt_by_role(): Fail to get first allocate config\n");
1486 		goto exit;
1487 	}
1488 	f_config = config;
1489 	do {
1490 		PHL_TRACE(COMP_PHL_TWT, _PHL_DEBUG_, "rtw_phl_twt_enable_all_twt_by_role(): while loop, twt_id:%d\n",
1491 			config->twt_info.twt_id);
1492 		if (twt_config_state_free == config->state)
1493 			goto next_cfg;
1494 		if (config->role != role)
1495 			goto next_cfg;
1496 		pstatus = _twt_info_update(phl_info->hal, config,
1497 						PHL_TWT_ACTION_ENABLE);
1498 		if (RTW_PHL_STATUS_SUCCESS == pstatus) {
1499 			pstatus = _twt_all_sta_update(phl_info,
1500 							config->twt_info.twt_id,
1501 							&config->twt_sta_queue,
1502 							TWT_STA_ADD_MACID);
1503 			if (RTW_PHL_STATUS_SUCCESS != pstatus) {
1504 				error = true;
1505 				PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_enable_all_twt_by_role(): Fail to update all twt sta, twt_id:%d\n",
1506 						config->twt_info.twt_id);
1507 			}
1508 		} else {
1509 			error = true;
1510 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_enable_all_twt_by_role(): Fail to enable twt config, twt_id:%d\n",
1511 				config->twt_info.twt_id);
1512 		}
1513 next_cfg:
1514 		if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl,
1515 						twt_cfg_i, PHL_GET_NEXT_CONFIG,
1516 						(u8 *)&config->idx, &config)) {
1517 			error = true;
1518 			break;
1519 		}
1520 	} while(config != f_config);
1521 	if (true == error)
1522 		pstatus = RTW_PHL_STATUS_FAILURE;
1523 exit:
1524 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_enable_all_twt_by_role(): pstatus:%d\n",
1525 		pstatus);
1526 	return pstatus;
1527 }
1528 
1529 /*
1530  *  Add twt sta to specifi twt conig entry
1531  * @phl_sta: sta entry that you wnat to add in specifi twt conig entry
1532  * @config_id: id of target twt config entry
1533  * @id: twt flow id/ broadcast twt id
1534  */
rtw_phl_twt_add_sta_info(void * phl,struct rtw_phl_stainfo_t * phl_sta,u8 config_id,u8 id)1535 enum rtw_phl_status rtw_phl_twt_add_sta_info(void *phl,
1536 			struct rtw_phl_stainfo_t *phl_sta, u8 config_id, u8 id)
1537 {
1538 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1539 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1540 	struct phl_twt_info *phl_twt_info = NULL;
1541 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1542 	struct phl_twt_config *config = NULL;
1543 	struct phl_queue *sta_q = NULL;
1544 	u16 cnt = 0;
1545 
1546 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_add_sta_info()\n");
1547 	if (false == twt_sup(phl_info)) {
1548 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_add_sta_info(): twt_sup == false\n");
1549 		goto fail;
1550 	}
1551 	if (false == twt_init(phl_info)) {
1552 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_add_sta_info(): twt_init == false\n");
1553 		goto fail;
1554 	}
1555 	phl_twt_info = get_twt_info(phl_info);
1556 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1557 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl, twt_cfg_i,
1558 							PHL_GET_CONFIG_BY_ID,
1559 							&config_id, &config)) {
1560 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "Fail to get TWT config by id(%d)\n",
1561 			config_id);
1562 		goto fail;
1563 	}
1564 	sta_q = &config->twt_sta_queue;
1565 	if (RTW_PHL_STATUS_SUCCESS != _twt_add_sta(phl, phl_sta, sta_q, id)) {
1566 		goto fail;
1567 	}
1568 	if (RTW_PHL_STATUS_SUCCESS != _twt_sta_update(phl_info->hal,
1569 				phl_sta->macid, config_id, TWT_STA_ADD_MACID)) {
1570 		_twt_delete_sta(phl, sta_q, phl_sta, id, &cnt);
1571 		goto fail;
1572 	}
1573 	pstatus = RTW_PHL_STATUS_SUCCESS;
1574 fail:
1575 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_add_sta_info(): pstatus:%d\n",
1576 		pstatus);
1577 	return pstatus;
1578 }
1579 
1580 /*
1581  *  Remove all twt sta from twt config entry by specific sta entry
1582  * @phl_sta: sta entry that you wnat to remove
1583  * @bitmap: Output the bitmap. Indicate the statue that twt sta don't exist in the twt config entry that twt sta removed from it.
1584  * ex: Bitmap=10: We remove the twt sta from id 1, id 3 and other id of twt config entry,
1585  * but after remove, there are no twt sta existing in the twt config entry of id 1 and id 3.
1586  * ex: Bitmap=0: We remove the twt sta, after remove, there are at least one twt sta existing in the twt config entry that twt sta removed from it.
1587  */
rtw_phl_twt_delete_all_sta_info(void * phl,struct rtw_phl_stainfo_t * phl_sta,u8 * bitmap)1588 enum rtw_phl_status rtw_phl_twt_delete_all_sta_info(void *phl,
1589 				struct rtw_phl_stainfo_t *phl_sta, u8 *bitmap)
1590 {
1591 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1592 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1593 
1594 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_delete_all_sta_info()\n");
1595 	if (false == twt_sup(phl_info)) {
1596 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_delete_all_sta_info(): twt_sup == false\n");
1597 		return pstatus;
1598 	}
1599 	if (false == twt_init(phl_info)) {
1600 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_delete_all_sta_info(): twt_init == false\n");
1601 		return pstatus;
1602 	}
1603 	pstatus = _twt_delete_sta_info(phl, phl_sta, true, 0, 0, bitmap);
1604 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_delete_all_sta_info(): pstatus:%d, bitmap:0x%x\n",
1605 		pstatus, *bitmap);
1606 	return pstatus;
1607 }
1608 
1609 /*
1610  * Remove twt sta when tx/rx twt teardown frame
1611  * @phl_sta: sta entry that you wnat to remove
1612  * @twt_flow: twt flow field info
1613  * @bitmap: Output the bitmap. Indicate the statue that twt sta don't exist in the twt config entry that twt sta removed from it.
1614  * ex: Bitmap=10: We remove the twt sta from id 1, id 3 and other id of twt config entry,
1615  * but after remove, there are no twt sta existing in the twt config entry of id 1 and id 3.
1616  * ex: Bitmap=0: We remove the twt sta, after remove, there are at least one twt sta existing in the twt config entry that twt sta removed from it.
1617  */
rtw_phl_twt_teardown_sta(void * phl,struct rtw_phl_stainfo_t * phl_sta,struct rtw_phl_twt_flow_field * twt_flow,u8 * bitmap)1618 enum rtw_phl_status rtw_phl_twt_teardown_sta(void *phl,
1619 			struct rtw_phl_stainfo_t *phl_sta,
1620 			struct rtw_phl_twt_flow_field *twt_flow, u8 *bitmap)
1621 {
1622 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1623 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1624 	u8 id = 0;
1625 
1626 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_teardown_sta()\n");
1627 	if (false == twt_sup(phl_info)) {
1628 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_teardown_sta(): twt_sup == false\n");
1629 		return pstatus;
1630 	}
1631 	if (false == twt_init(phl_info)) {
1632 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_teardown_sta(): twt_init == false\n");
1633 		return pstatus;
1634 	}
1635 	if (RTW_PHL_INDIV_TWT == twt_flow->nego_type ||
1636 		RTW_PHL_WAKE_TBTT_INR == twt_flow->nego_type) {
1637 		if (twt_flow->info.twt_flow01.teardown_all)
1638 			id = DELETE_ALL;
1639 		else
1640 			id = twt_flow->info.twt_flow01.twt_flow_id;
1641 		pstatus = RTW_PHL_STATUS_SUCCESS;
1642 	} else if (RTW_PHL_BCAST_TWT == twt_flow->nego_type ) {
1643 		/*Todo*/
1644 	} else if (RTW_PHL_MANAGE_BCAST_TWT == twt_flow->nego_type) {
1645 		if (twt_flow->info.twt_flow3.teardown_all)
1646 			id = DELETE_ALL;
1647 		else
1648 			id = twt_flow->info.twt_flow3.bcast_twt_id;
1649 		pstatus = RTW_PHL_STATUS_SUCCESS;
1650 	} else {
1651 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_teardown_sta(): Unknown nego_type:%d\n",
1652 			twt_flow->nego_type);
1653 	}
1654 	if (RTW_PHL_STATUS_SUCCESS == pstatus) {
1655 		pstatus = _twt_delete_sta_info(phl, phl_sta, false,
1656 					twt_flow->nego_type, id, bitmap);
1657 	}
1658 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_teardown_sta(): pstatus:%d, twt_flow->nego_type:%d, id:%d, bitmap:0x%x\n",
1659 		pstatus, twt_flow->nego_type, id, *bitmap);
1660 	return pstatus;
1661 }
1662 
1663 /*
1664  * Assign new flow id for twt setup of sta.
1665  * @phl_sta: the specific sta
1666  * @role: specific role for search twt config entry
1667  * @id: Output: twt flow id
1668  * Note: for sta mode.
1669  */
rtw_phl_twt_get_new_flow_id(void * phl,struct rtw_phl_stainfo_t * phl_sta,u8 * id)1670 enum rtw_phl_status rtw_phl_twt_get_new_flow_id(void *phl,
1671 				struct rtw_phl_stainfo_t *phl_sta, u8 *id)
1672 {
1673 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_RESOURCE;
1674 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1675 	struct phl_twt_info *phl_twt_info = NULL;
1676 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1677 	struct phl_twt_config *config = NULL, *f_config = NULL;
1678 	struct rtw_twt_sta_info *twt_sta = NULL;
1679 	u8 use_map = 0, unuse_map = 0;
1680 	u8 i = 0;
1681 
1682 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_get_new_flow_id()\n");
1683 	if (false == twt_sup(phl_info)) {
1684 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_get_new_flow_id(): twt_sup == false\n");
1685 		goto exit;
1686 	}
1687 	if (false == twt_init(phl_info)) {
1688 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_get_new_flow_id(): twt_init == false\n");
1689 		goto exit;
1690 	}
1691 	phl_twt_info = get_twt_info(phl_info);
1692 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1693 	if (false == _twt_new_config_is_available(phl_info))
1694 		goto exit;
1695 	if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl, twt_cfg_i,
1696 				PHL_GET_HEAD_CONFIG, NULL, &config)) {
1697 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_get_new_flow_id(): Fail to get first allocate config\n");
1698 		goto exit;
1699 	}
1700 	f_config = config;
1701 	do {
1702 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_get_new_flow_id(): while loop\n");
1703 		if (twt_config_state_free == config->state)
1704 			goto next_cfg;
1705 		if (config->role != phl_sta->wrole ||
1706 			RTW_PHL_INDIV_TWT != config->twt_info.nego_type)
1707 			goto next_cfg;
1708 		twt_sta = _twt_get_sta_info(phl_info, &config->twt_sta_queue,
1709 						phl_sta);
1710 		if (NULL != twt_sta) {
1711 			use_map |= (1 << twt_sta->id);
1712 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_get_new_flow_id(): config_ID:%d, get match sta, twt_sta->id:%d\n",
1713 				config->twt_info.twt_id, twt_sta->id);
1714 		}
1715 next_cfg:
1716 		if (RTW_PHL_STATUS_SUCCESS != _twt_operate_twt_config(phl,
1717 						twt_cfg_i, PHL_GET_NEXT_CONFIG,
1718 						(u8 *)&config->idx, &config))
1719 			goto exit;
1720 	} while(config != f_config);
1721 	unuse_map = (~use_map) & 0xFF;
1722 	i = 0;
1723 	while ((unuse_map >> i) > 0) {
1724 		if ((unuse_map >> i) & BIT0) {
1725 			*id = i;
1726 			pstatus = RTW_PHL_STATUS_SUCCESS;
1727 			break;
1728 		}
1729 		i++;
1730 	}
1731 exit:
1732 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_get_new_flow_id(): pstatus:%d, use_map:%d, unuse_map:%d, new_flow_id:%d\n",
1733 		pstatus, use_map, unuse_map, *id);
1734 	return pstatus;
1735 }
1736 
1737 /*
1738  * get target wake time
1739  * @port: port num of role
1740  * @id: reference id of twt configuration
1741  * @offset: unit: ms. An amount of time that you will start TWT from now
1742  * @tsf_h: return high 4-byte value of target wake time
1743  * @tsf_l: return low 4-byte value of target wake time
1744  */
rtw_phl_twt_get_target_wake_time(void * phl,u8 port,u8 id,u16 offset,u32 * tsf_h,u32 * tsf_l)1745 enum rtw_phl_status rtw_phl_twt_get_target_wake_time(void *phl,
1746 			u8 port, u8 id, u16 offset, u32 *tsf_h, u32 *tsf_l)
1747 {
1748 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1749 	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
1750 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1751 	struct phl_twt_info *phl_twt_info = NULL;
1752 	struct phl_twt_cfg_info *twt_cfg_i = NULL;
1753 	struct phl_twt_config *config = NULL;
1754 	u32 c_tsf_l = 0, c_tsf_h = 0, intvl = 0;
1755 	u64 cur_tsf = 0, tgt_tsf = 0, ref_tsf = 0, dif_tsf = 0;
1756 
1757 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_get_target_wake_time()\n");
1758 	if (false == twt_sup(phl_info)) {
1759 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_get_target_wake_time(): twt_sup == false\n");
1760 		goto exit;
1761 	}
1762 	if (false == twt_init(phl_info)) {
1763 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_get_target_wake_time(): twt_init == false\n");
1764 		goto exit;
1765 	}
1766 	phl_twt_info = get_twt_info(phl_info);
1767 	twt_cfg_i = &phl_twt_info->twt_cfg_info;
1768 	hstatus = rtw_hal_get_tsf(phl_info->hal, port, &c_tsf_h, &c_tsf_l);
1769 	if (RTW_HAL_STATUS_FAILURE == hstatus) {
1770 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_get_target_wake_time(): Fail to get tsf, hstatus:%d, port:%d\n",
1771 		hstatus, port);
1772 		goto exit;
1773 	}
1774 	cur_tsf = c_tsf_h;
1775 	cur_tsf = cur_tsf << 32;
1776 	cur_tsf |= c_tsf_l;
1777 	if (IGNORE_CFG_ID == id) {
1778 		tgt_tsf = _os_add64(cur_tsf, offset * 1000);
1779 	} else {
1780 		pstatus = _twt_operate_twt_config(phl, twt_cfg_i,
1781 					PHL_GET_CONFIG_BY_ID, &id, &config);
1782 		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
1783 			PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_get_target_wake_time(): Fail to get twt entry by id, pstatus:%d, id:%d\n",
1784 				pstatus, id);
1785 			goto exit;
1786 		}
1787 		ref_tsf = config->twt_info.target_wake_time_h;
1788 		ref_tsf = ref_tsf << 32;
1789 		ref_tsf |= config->twt_info.target_wake_time_l;
1790 		intvl = _twt_calc_intvl(config->twt_info.twt_wake_int_exp,
1791 					config->twt_info.twt_wake_int_mantissa);
1792 		tgt_tsf = _os_add64(cur_tsf, offset * 1000);
1793 		dif_tsf = _os_minus64(tgt_tsf, ref_tsf);
1794 		tgt_tsf = _os_minus64(tgt_tsf, _os_modular64(dif_tsf, intvl));
1795 		tgt_tsf = _os_add64(tgt_tsf, intvl);
1796 	}
1797 	*tsf_h = (u32)(tgt_tsf >> 32);
1798 	*tsf_l = (u32)(tgt_tsf);
1799 	pstatus = RTW_PHL_STATUS_SUCCESS;
1800 exit:
1801 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_get_target_wake_time(): pstatus(%d), port:%d, twt_id:%d, offset:0x%08x, tsf_h: 0x%08X, tsf_l: 0x%08X\n",
1802 		pstatus, port, id, offset, *tsf_h, *tsf_l);
1803 	return pstatus;
1804 }
1805 
1806 /*
1807  * Fill twt element
1808  * @twt_ele: twt element info
1809  * @buf: fill memory
1810  * @len: the length of twt element
1811  */
rtw_phl_twt_fill_twt_element(struct rtw_phl_twt_element * twt_ele,u8 * buf,u8 * len)1812 enum rtw_phl_status rtw_phl_twt_fill_twt_element(
1813 			struct rtw_phl_twt_element *twt_ele, u8 *buf, u8 *len)
1814 {
1815 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1816 	u8 twt_para_length = 0;
1817 	struct rtw_phl_twt_control *twt_ctrl = NULL;
1818 
1819 	if (twt_ele == NULL || buf == NULL || len == NULL) {
1820 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_fill_twt_element(): twt_ele or buf or len = NULL\n");
1821 		return pstatus;
1822 	}
1823 	twt_ctrl = &twt_ele->twt_ctrl;
1824 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_fill_twt_element(): twt_ctrl: ndp_paging_indic(%d), responder_pm_mode(%d), nego_type(%d), twt_info_frame_disable(%d), wake_dur_unit(%d)\n",
1825 		twt_ctrl->ndp_paging_indic, twt_ctrl->responder_pm_mode,
1826 		twt_ctrl->nego_type, twt_ctrl->twt_info_frame_disable,
1827 		twt_ctrl->wake_dur_unit);
1828 	*len = 0;
1829 /*Control filed*/
1830 	SET_TWT_CONTROL_NDP_PAGING_INDICATOR(buf, twt_ctrl->ndp_paging_indic);
1831 	SET_TWT_CONTROL_RESPONDER_PM_MODE(buf, twt_ctrl->responder_pm_mode);
1832 	SET_TWT_CONTROL_NEGOTIATION_TYPE(buf, twt_ctrl->nego_type);
1833 	SET_TWT_CONTROL_TWT_INFORMATION_FRAME_DISABLE(buf,
1834 					twt_ctrl->twt_info_frame_disable);
1835 	SET_TWT_CONTROL_WAKE_DURATION_UNIT(buf, twt_ctrl->wake_dur_unit);
1836 	*len += CONTROL_LENGTH;
1837 /*TWT Parameter Information*/
1838 	if (RTW_PHL_INDIV_TWT == twt_ctrl->nego_type) {
1839 		pstatus = _twt_fill_individual_twt_para_set(
1840 					&twt_ele->info.i_twt_para_set,
1841 					twt_ctrl->ndp_paging_indic,
1842 					buf + *len, &twt_para_length);
1843 		*len += twt_para_length;
1844 	} else {
1845 		/*todo*/
1846 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_fill_twt_element(): not support, todo, twt_ctrl->nego_type(%d)\n",
1847 			twt_ctrl->nego_type);
1848 	}
1849 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_fill_twt_element()\n");
1850 	return pstatus;
1851 }
1852 
1853 /*
1854  * Fill twt flow field of TWT teardown frame
1855  * @twt_flow: twt flow field info
1856  * @buf: fill memory
1857  * @length: the length of twt flow field
1858  */
rtw_phl_twt_fill_flow_field(struct rtw_phl_twt_flow_field * twt_flow,u8 * buf,u16 * length)1859 enum rtw_phl_status rtw_phl_twt_fill_flow_field(
1860 		struct rtw_phl_twt_flow_field *twt_flow, u8 *buf, u16 *length)
1861 {
1862 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1863 
1864 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_fill_flow_field()\n");
1865 	if (twt_flow == NULL || buf == NULL || length == NULL) {
1866 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_fill_flow_field(): twt_flow or buf or length = NULL\n");
1867 		return pstatus;
1868 	}
1869 	*length = 0;
1870 	if (RTW_PHL_INDIV_TWT == twt_flow->nego_type ||
1871 		RTW_PHL_WAKE_TBTT_INR == twt_flow->nego_type) {
1872 		struct rtw_phl_twt_flow_type01 *flow_info =
1873 						&twt_flow->info.twt_flow01;
1874 		SET_TWT_FLOW_ID(buf, flow_info->twt_flow_id);
1875 		SET_NEGOTIATION_TYPE(buf, twt_flow->nego_type);
1876 		SET_TEARDOWN_ALL_TWT(buf, flow_info->teardown_all);
1877 		*length = TWT_FLOW_FIELD_LENGTH;
1878 		pstatus = RTW_PHL_STATUS_SUCCESS;
1879 	} else if (RTW_PHL_BCAST_TWT  == twt_flow->nego_type) {
1880 		SET_NEGOTIATION_TYPE(buf, twt_flow->nego_type);
1881 		*length = TWT_FLOW_FIELD_LENGTH;
1882 		pstatus = RTW_PHL_STATUS_SUCCESS;
1883 	} else if (RTW_PHL_MANAGE_BCAST_TWT == twt_flow->nego_type) {
1884 		struct rtw_phl_twt_flow_type3 *flow_info =
1885 						&twt_flow->info.twt_flow3;
1886 		SET_BROADCAST_TWT_ID(buf, flow_info->bcast_twt_id);
1887 		SET_NEGOTIATION_TYPE(buf, twt_flow->nego_type);
1888 		SET_TEARDOWN_ALL_TWT(buf, flow_info->teardown_all);
1889 		*length = TWT_FLOW_FIELD_LENGTH;
1890 		pstatus = RTW_PHL_STATUS_SUCCESS;
1891 	} else {
1892 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_fill_flow_field(): Unknown type(%d)\n",
1893 			twt_flow->nego_type);
1894 	}
1895 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_fill_flow_field()\n");
1896 	return pstatus;
1897 }
1898 
1899 /*
1900  * Parse twt element from pkt
1901  * @twt_ele: the address of twt elemant
1902  * @length: length of pkt
1903  * @twt_element: Parse info
1904  */
rtw_phl_twt_parse_element(u8 * twt_ele,u16 length,struct rtw_phl_twt_element * twt_element)1905 enum rtw_phl_status rtw_phl_twt_parse_element(u8 *twt_ele, u16 length,
1906 				struct rtw_phl_twt_element *twt_element)
1907 {
1908 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1909 	struct rtw_phl_twt_control *twt_ctrl = NULL;
1910 	u8 ele_len = 0, ele_id = 0;
1911 	u8 *next_buf = twt_ele;
1912 
1913 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_parse_element()\n");
1914 	if (twt_ele == NULL || twt_element == NULL) {
1915 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_element(): twt_ele or twt_element = NULL\n");
1916 		return pstatus;
1917 	}
1918 	twt_ctrl = &twt_element->twt_ctrl;
1919 	if (length < (MIN_TWT_ELE_LEN + ELEM_ID_LEN + ELEM_LEN_LEN)) {
1920 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_parse_element(): error buffer length(%d) < %d\n",
1921 			length, (MIN_TWT_ELE_LEN + ELEM_ID_LEN + ELEM_LEN_LEN));
1922 		goto exit;
1923 	}
1924 	ele_id = GET_ELE_ID(next_buf);
1925 	next_buf += ELEM_ID_LEN;
1926 	ele_len = GET_ELE_LEN(next_buf);
1927 	next_buf += ELEM_LEN_LEN;
1928 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_parse_element(): ele_id:%d, ele_len:%d, length:%d\n",
1929 		ele_id, ele_len, length);
1930 	if (ele_len < MIN_TWT_ELE_LEN) {
1931 		PHL_TRACE(COMP_PHL_TWT, _PHL_WARNING_, "rtw_phl_twt_parse_element(): error ele length(%d) < %d\n",
1932 			ele_len, MIN_TWT_ELE_LEN);
1933 		goto exit;
1934 	}
1935 	twt_ctrl->ndp_paging_indic =
1936 				GET_TWT_CONTROL_NDP_PAGING_INDICATOR(next_buf);
1937 	twt_ctrl->responder_pm_mode =
1938 				GET_TWT_CONTROL_RESPONDER_PM_MODE(next_buf);
1939 	twt_ctrl->nego_type = GET_TWT_CONTROL_NEGOTIATION_TYPE(next_buf);
1940 	twt_ctrl->twt_info_frame_disable =
1941 			GET_TWT_CONTROL_TWT_INFORMATION_FRAME_DISABLE(next_buf);
1942 	twt_ctrl->wake_dur_unit = GET_TWT_CONTROL_WAKE_DURATION_UNIT(next_buf);
1943 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_parse_element(): twt_ctrl: ndp_paging_indic(%d), responder_pm_mode(%d), nego_type(%d), twt_info_frame_disable(%d), wake_dur_unit(%d)\n",
1944 		twt_ctrl->ndp_paging_indic, twt_ctrl->responder_pm_mode,
1945 		twt_ctrl->nego_type, twt_ctrl->twt_info_frame_disable,
1946 		twt_ctrl->wake_dur_unit);
1947 	if (RTW_PHL_INDIV_TWT == twt_ctrl->nego_type) {
1948 		pstatus = _twt_parse_individual_twt_para(twt_ele, length,
1949 							twt_element);
1950 	} else {
1951 		/*todo*/
1952 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_element(): not support, todo, twt_ctrl->nego_type(%d)\n",
1953 			twt_ctrl->nego_type);
1954 	}
1955 exit:
1956 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_parse_element(): pstatus(%d)\n",
1957 		pstatus);
1958 	return pstatus;
1959 }
1960 
1961 /*
1962  * Parse twt setup info from pkt
1963  * @pkt: the address of Category of twt setup info frame
1964  * @length: length of pkt
1965  * @twt_setup_info: Parse info
1966  */
rtw_phl_twt_parse_setup_info(u8 * pkt,u16 length,struct rtw_phl_twt_setup_info * setup_info)1967 enum rtw_phl_status rtw_phl_twt_parse_setup_info(u8 *pkt, u16 length,
1968 				struct rtw_phl_twt_setup_info *setup_info)
1969 {
1970 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1971 	u8 *twt_ele = NULL;
1972 	u16 ele_length = length - TOKEN_OFFSET- TOKEN_LENGTH;
1973 
1974 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_parse_setup_info()\n");
1975 	if (pkt == NULL || setup_info == NULL) {
1976 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_setup_info(): pkt or setup_info = NULL\n");
1977 		return pstatus;
1978 	}
1979 	twt_ele = pkt + TOKEN_OFFSET + TOKEN_LENGTH;
1980 	setup_info->dialog_token = GET_DIALOG_TOKEN(pkt + TOKEN_OFFSET);
1981 	pstatus = rtw_phl_twt_parse_element(twt_ele, ele_length,
1982 						&setup_info->twt_element);
1983 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_parse_setup_info(): pstatus(%d)\n",
1984 		pstatus);
1985 	return pstatus;
1986 }
1987 
1988 /*
1989  * Parse twt twt flow field from twt teardown frame
1990  * @pkt: the address of twt flow field
1991  * @length: length of pkt
1992  * @twt_flow_info: Parse info
1993  */
rtw_phl_twt_parse_flow_field(u8 * pkt,u16 length,struct rtw_phl_twt_flow_field * twt_flow)1994 enum rtw_phl_status rtw_phl_twt_parse_flow_field(u8 *pkt, u16 length,
1995 				struct rtw_phl_twt_flow_field *twt_flow)
1996 {
1997 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
1998 
1999 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_parse_flow_field()\n");
2000 	if (pkt == NULL || twt_flow == NULL) {
2001 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_flow_field(): pkt or twt_flow = NULL\n");
2002 		return pstatus;
2003 	}
2004 	twt_flow->nego_type = GET_NEGOTIATION_TYPE(pkt);
2005 	if (RTW_PHL_INDIV_TWT == twt_flow->nego_type ||
2006 		RTW_PHL_WAKE_TBTT_INR == twt_flow->nego_type) {
2007 		struct rtw_phl_twt_flow_type01 *flow_info =
2008 						&twt_flow->info.twt_flow01;
2009 		flow_info->twt_flow_id = GET_TWT_FLOW_ID(pkt);
2010 		flow_info->teardown_all = GET_TEARDOWN_ALL_TWT(pkt);
2011 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_parse_flow_field(): nego_type:%d, twt_flow_id:%d, teardown_all:%d\n",
2012 			twt_flow->nego_type, flow_info->twt_flow_id,
2013 			flow_info->teardown_all);
2014 		pstatus = RTW_PHL_STATUS_SUCCESS;
2015 	} else if (RTW_PHL_BCAST_TWT == twt_flow->nego_type) {
2016 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_flow_field(): not support, todo, twt_flow->nego_type(%d)\n",
2017 			twt_flow->nego_type);
2018 	} else if (RTW_PHL_MANAGE_BCAST_TWT == twt_flow->nego_type) {
2019 		struct rtw_phl_twt_flow_type3 *flow_info =
2020 						&twt_flow->info.twt_flow3;
2021 		flow_info->bcast_twt_id = GET_BROADCAST_TWT_ID(pkt);
2022 		flow_info->teardown_all = GET_TEARDOWN_ALL_TWT(pkt);
2023 		PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_parse_flow_field(): nego_type:%d, bcast_twt_id:%d, teardown_all:%d\n",
2024 			twt_flow->nego_type, flow_info->bcast_twt_id,
2025 			flow_info->teardown_all);
2026 		pstatus = RTW_PHL_STATUS_SUCCESS;
2027 	} else {
2028 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_parse_flow_field(): Unknown type, twt_flow->nego_type(%d)\n",
2029 			twt_flow->nego_type);
2030 	}
2031 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_parse_flow_field(): pstatus(%d)\n",
2032 		pstatus);
2033 	return pstatus;
2034 }
2035 
2036 /*
2037  * Tell fw which macid is announced in awake state
2038  * @macid: macid of sta that is in awake state
2039  */
rtw_phl_twt_sta_announce_to_fw(void * phl,u16 macid)2040 enum rtw_phl_status rtw_phl_twt_sta_announce_to_fw(void *phl,
2041 				u16 macid)
2042 {
2043 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
2044 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
2045 	struct phl_twt_info *phl_twt_info = NULL;
2046 	struct phl_queue *annc_q = NULL;
2047 
2048 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_sta_announce_to_fw()\n");
2049 	if (false == twt_sup(phl_info)) {
2050 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_sta_announce_to_fw(): twt_sup == false\n");
2051 		return pstatus;
2052 	}
2053 	if (false == twt_init(phl_info)) {
2054 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_sta_announce_to_fw(): twt_init == false\n");
2055 		return pstatus;
2056 	}
2057 	phl_twt_info = get_twt_info(phl_info);
2058 	annc_q = &phl_twt_info->twt_annc_queue;
2059 	pstatus = _twt_sta_announce(phl_info, annc_q, macid);
2060 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_sta_announce_to_fw(): pstatus:%d, macid: %d\n",
2061 		pstatus, macid);
2062 	return pstatus;
2063 }
2064 
2065 #if 0
2066 /*
2067  * Handle twt c2h
2068  * @c: c2h content
2069  */
2070 enum rtw_phl_status rtw_phl_twt_handle_c2h(void *phl_com, void *c)
2071 {
2072 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
2073 	struct rtw_phl_com_t *phl_com_info= (struct rtw_phl_com_t *)phl_com;
2074 	struct phl_info_t *phl_info = (struct phl_info_t*)phl_com_info->phl_priv;
2075 	struct rtw_c2h_info *c2h = (struct rtw_c2h_info *)c;
2076 
2077 	if (false == twt_sup(phl_info)) {
2078 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_handle_c2h(): twt_sup == false\n");
2079 		return pstatus;
2080 	}
2081 	if (false == twt_init(phl_info)) {
2082 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_handle_c2h(): twt_init == false\n");
2083 		return pstatus;
2084 	}
2085 	if (C2H_FUN_WAIT_ANNC == c2h->c2h_func) {
2086 		pstatus = _twt_handle_c2h_wait_annc(phl_info, c2h->content);
2087 	}
2088 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_handle_c2h(): pstatus:%d cat:%d, class:%d, func:%d, len:%d, content:0x%x\n",
2089 		pstatus, c2h->c2h_cat, c2h->c2h_class, c2h->c2h_func,
2090 		c2h->content_len, *(c2h->content));
2091 	return pstatus;
2092 }
2093 #endif
2094 
2095 /*
2096  * Handle sta to config twt when sta accept the twt agreement
2097  * @phl_sta: sta entry that you wnat to config twt
2098  * @setup_info: twt setup info
2099  * @id: Output the id of twt confi entry
2100  * Note: for sta mode
2101  */
rtw_phl_twt_accept_for_sta_mode(void * phl,struct rtw_phl_stainfo_t * phl_sta,struct rtw_phl_twt_setup_info * setup_info,u8 * id)2102 enum rtw_phl_status rtw_phl_twt_accept_for_sta_mode(void *phl,
2103 			struct rtw_phl_stainfo_t *phl_sta,
2104 			struct rtw_phl_twt_setup_info *setup_info, u8 *id)
2105 {
2106 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
2107 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
2108 	struct rtw_phl_twt_element *element = &setup_info->twt_element;
2109 	struct rtw_phl_twt_control *twt_ctrl =&element->twt_ctrl;
2110 
2111 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_accept_for_sta_mode()\n");
2112 	if (false == twt_sup(phl_info)) {
2113 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_accept_for_sta_mode(): twt_sup == false\n");
2114 		return pstatus;
2115 	}
2116 	if (false == twt_init(phl_info)) {
2117 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_accept_for_sta_mode(): twt_init == false\n");
2118 		return pstatus;
2119 	}
2120 	if (RTW_PHL_INDIV_TWT == twt_ctrl->nego_type) {
2121 		pstatus = _twt_accept_indiv_by_sta(phl_info, setup_info, phl_sta, id);
2122 	} else {
2123 		pstatus = _twt_accept_bcast_by_sta(phl_info, setup_info, phl_sta, id);
2124 	}
2125 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_accept_for_sta_mode(): pstatus:%d, config_id:%d\n",
2126 		pstatus, *id);
2127 	return pstatus;
2128 }
2129 
2130 /*
2131  * Handle sta to disable twt when sta tx/rx twt teardown frame
2132  * @phl_sta: sta entry that you wnat to config twt
2133  * @twt_flow: twt flow field info
2134  * Note: for sta mode.
2135  */
rtw_phl_twt_teardown_for_sta_mode(void * phl,struct rtw_phl_stainfo_t * phl_sta,struct rtw_phl_twt_flow_field * twt_flow)2136 enum rtw_phl_status rtw_phl_twt_teardown_for_sta_mode(void *phl,
2137 				struct rtw_phl_stainfo_t *phl_sta,
2138 				struct rtw_phl_twt_flow_field *twt_flow)
2139 {
2140 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
2141 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
2142 	u8 bitmap =0; /*bitmap of empty config of twt*/
2143 	u8 i = 0;
2144 
2145 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "==> rtw_phl_twt_teardown_for_sta_mode()\n");
2146 	if (false == twt_sup(phl_info)) {
2147 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_teardown_for_sta_mode(): twt_sup == false\n");
2148 		goto exit;
2149 	}
2150 	if (false == twt_init(phl_info)) {
2151 		PHL_TRACE(COMP_PHL_TWT, _PHL_ERR_, "rtw_phl_twt_teardown_for_sta_mode(): twt_init == false\n");
2152 		goto exit;
2153 	}
2154 	pstatus = rtw_phl_twt_teardown_sta(phl, phl_sta, twt_flow, &bitmap);
2155 	if (RTW_PHL_STATUS_SUCCESS != pstatus)
2156 		goto exit;
2157 	if (bitmap == 0)
2158 		goto exit;
2159 	i = 0;
2160 	do {
2161 		if (((bitmap >> i) & BIT0)) {
2162 			pstatus = rtw_phl_twt_free_twt_config(phl, i);
2163 			PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "rtw_phl_twt_teardown_for_sta_mode():sta Q is empty in twt config entry(%d), we free it, pstatus:%d \n",
2164 				i, pstatus);
2165 		}
2166 		i++;
2167 	} while ((bitmap >> i) != 0);
2168 exit:
2169 	PHL_TRACE(COMP_PHL_TWT, _PHL_INFO_, "<== rtw_phl_twt_teardown_for_sta_mode(): pstatus(%d)\n",
2170 		pstatus);
2171 	return pstatus;
2172 }
2173 #endif /* CONFIG_PHL_TWT */
2174