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