Commit | Line | Data |
---|---|---|
94a79942 LF |
1 | /****************************************************************************** |
2 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. | |
3 | * | |
4 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
5 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
6 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
7 | * more details. | |
8 | * | |
94a79942 LF |
9 | * The full GNU General Public License is included in this distribution in the |
10 | * file called LICENSE. | |
11 | * | |
12 | * Contact Information: | |
13 | * wlanfae <wlanfae@realtek.com> | |
14 | ******************************************************************************/ | |
15 | #include "rtllib.h" | |
16 | #include <linux/etherdevice.h> | |
17 | #include "rtl819x_TS.h" | |
cb762154 | 18 | |
ec0dc6be | 19 | static void TsSetupTimeOut(unsigned long data) |
94a79942 LF |
20 | { |
21 | } | |
22 | ||
ec0dc6be | 23 | static void TsInactTimeout(unsigned long data) |
94a79942 LF |
24 | { |
25 | } | |
26 | ||
ec0dc6be | 27 | static void RxPktPendingTimeout(unsigned long data) |
94a79942 | 28 | { |
2c47ae28 | 29 | struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; |
f88ec6cb LF |
30 | struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, |
31 | RxTsRecord[pRxTs->num]); | |
94a79942 | 32 | |
8cba1432 | 33 | struct rx_reorder_entry *pReorderEntry = NULL; |
94a79942 LF |
34 | |
35 | unsigned long flags = 0; | |
94a79942 LF |
36 | u8 index = 0; |
37 | bool bPktInBuf = false; | |
38 | ||
39 | spin_lock_irqsave(&(ieee->reorder_spinlock), flags); | |
f88ec6cb LF |
40 | if (pRxTs->RxTimeoutIndicateSeq != 0xffff) { |
41 | while (!list_empty(&pRxTs->RxPendingPktList)) { | |
42 | pReorderEntry = (struct rx_reorder_entry *) | |
43 | list_entry(pRxTs->RxPendingPktList.prev, | |
44 | struct rx_reorder_entry, List); | |
94a79942 LF |
45 | if (index == 0) |
46 | pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; | |
47 | ||
35e33b04 MK |
48 | if (SN_LESS(pReorderEntry->SeqNum, |
49 | pRxTs->RxIndicateSeq) || | |
50 | SN_EQUAL(pReorderEntry->SeqNum, | |
51 | pRxTs->RxIndicateSeq)) { | |
94a79942 LF |
52 | list_del_init(&pReorderEntry->List); |
53 | ||
f88ec6cb LF |
54 | if (SN_EQUAL(pReorderEntry->SeqNum, |
55 | pRxTs->RxIndicateSeq)) | |
56 | pRxTs->RxIndicateSeq = | |
57 | (pRxTs->RxIndicateSeq + 1) % 4096; | |
94a79942 | 58 | |
b94436b5 MK |
59 | netdev_dbg(ieee->dev, |
60 | "%s(): Indicate SeqNum: %d\n", | |
61 | __func__, pReorderEntry->SeqNum); | |
2eed3dee | 62 | ieee->stats_IndicateArray[index] = |
f88ec6cb | 63 | pReorderEntry->prxb; |
94a79942 LF |
64 | index++; |
65 | ||
f88ec6cb LF |
66 | list_add_tail(&pReorderEntry->List, |
67 | &ieee->RxReorder_Unused_List); | |
68 | } else { | |
94a79942 LF |
69 | bPktInBuf = true; |
70 | break; | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
f88ec6cb | 75 | if (index > 0) { |
94a79942 LF |
76 | pRxTs->RxTimeoutIndicateSeq = 0xffff; |
77 | ||
f88ec6cb | 78 | if (index > REORDER_WIN_SIZE) { |
11e672c3 MK |
79 | netdev_warn(ieee->dev, |
80 | "%s(): Rx Reorder struct buffer full\n", | |
81 | __func__); | |
f88ec6cb LF |
82 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), |
83 | flags); | |
94a79942 LF |
84 | return; |
85 | } | |
2eed3dee | 86 | rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index); |
94a79942 LF |
87 | bPktInBuf = false; |
88 | } | |
89 | ||
f88ec6cb | 90 | if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) { |
94a79942 | 91 | pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; |
f88ec6cb | 92 | mod_timer(&pRxTs->RxPktPendingTimer, jiffies + |
35e33b04 MK |
93 | msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime) |
94 | ); | |
94a79942 LF |
95 | } |
96 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); | |
97 | } | |
98 | ||
ec0dc6be | 99 | static void TsAddBaProcess(unsigned long data) |
94a79942 | 100 | { |
60554f2b | 101 | struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; |
94a79942 | 102 | u8 num = pTxTs->num; |
f88ec6cb LF |
103 | struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, |
104 | TxTsRecord[num]); | |
94a79942 LF |
105 | |
106 | TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); | |
b94436b5 | 107 | netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__); |
94a79942 LF |
108 | } |
109 | ||
ec0dc6be | 110 | static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) |
94a79942 | 111 | { |
3e3148c5 | 112 | eth_zero_addr(pTsCommonInfo->Addr); |
ed306e48 | 113 | memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body)); |
626f951d | 114 | memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM); |
94a79942 LF |
115 | pTsCommonInfo->TClasProc = 0; |
116 | pTsCommonInfo->TClasNum = 0; | |
117 | } | |
118 | ||
ec0dc6be | 119 | static void ResetTxTsEntry(struct tx_ts_record *pTS) |
94a79942 LF |
120 | { |
121 | ResetTsCommonInfo(&pTS->TsCommonInfo); | |
122 | pTS->TxCurSeq = 0; | |
123 | pTS->bAddBaReqInProgress = false; | |
124 | pTS->bAddBaReqDelayed = false; | |
125 | pTS->bUsingBa = false; | |
126 | pTS->bDisable_AddBa = false; | |
127 | ResetBaEntry(&pTS->TxAdmittedBARecord); | |
128 | ResetBaEntry(&pTS->TxPendingBARecord); | |
129 | } | |
130 | ||
ec0dc6be | 131 | static void ResetRxTsEntry(struct rx_ts_record *pTS) |
94a79942 LF |
132 | { |
133 | ResetTsCommonInfo(&pTS->TsCommonInfo); | |
134 | pTS->RxIndicateSeq = 0xffff; | |
135 | pTS->RxTimeoutIndicateSeq = 0xffff; | |
136 | ResetBaEntry(&pTS->RxAdmittedBARecord); | |
137 | } | |
94a79942 LF |
138 | |
139 | void TSInitialize(struct rtllib_device *ieee) | |
140 | { | |
60554f2b | 141 | struct tx_ts_record *pTxTS = ieee->TxTsRecord; |
2c47ae28 | 142 | struct rx_ts_record *pRxTS = ieee->RxTsRecord; |
8cba1432 | 143 | struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; |
94a79942 | 144 | u8 count = 0; |
3a6b70c3 | 145 | |
b94436b5 | 146 | netdev_vdbg(ieee->dev, "%s()\n", __func__); |
94a79942 LF |
147 | INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); |
148 | INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); | |
149 | INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); | |
150 | ||
f88ec6cb | 151 | for (count = 0; count < TOTAL_TS_NUM; count++) { |
94a79942 | 152 | pTxTS->num = count; |
2e59e40d | 153 | setup_timer(&pTxTS->TsCommonInfo.SetupTimer, |
94a79942 LF |
154 | TsSetupTimeOut, |
155 | (unsigned long) pTxTS); | |
156 | ||
2e59e40d | 157 | setup_timer(&pTxTS->TsCommonInfo.InactTimer, |
94a79942 LF |
158 | TsInactTimeout, |
159 | (unsigned long) pTxTS); | |
160 | ||
2e59e40d | 161 | setup_timer(&pTxTS->TsAddBaTimer, |
94a79942 LF |
162 | TsAddBaProcess, |
163 | (unsigned long) pTxTS); | |
164 | ||
2e59e40d | 165 | setup_timer(&pTxTS->TxPendingBARecord.Timer, |
94a79942 LF |
166 | BaSetupTimeOut, |
167 | (unsigned long) pTxTS); | |
2e59e40d | 168 | setup_timer(&pTxTS->TxAdmittedBARecord.Timer, |
94a79942 LF |
169 | TxBaInactTimeout, |
170 | (unsigned long) pTxTS); | |
171 | ||
172 | ResetTxTsEntry(pTxTS); | |
173 | list_add_tail(&pTxTS->TsCommonInfo.List, | |
174 | &ieee->Tx_TS_Unused_List); | |
175 | pTxTS++; | |
176 | } | |
177 | ||
178 | INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); | |
179 | INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); | |
180 | INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); | |
f88ec6cb | 181 | for (count = 0; count < TOTAL_TS_NUM; count++) { |
94a79942 LF |
182 | pRxTS->num = count; |
183 | INIT_LIST_HEAD(&pRxTS->RxPendingPktList); | |
184 | ||
2e59e40d | 185 | setup_timer(&pRxTS->TsCommonInfo.SetupTimer, |
94a79942 LF |
186 | TsSetupTimeOut, |
187 | (unsigned long) pRxTS); | |
188 | ||
2e59e40d | 189 | setup_timer(&pRxTS->TsCommonInfo.InactTimer, |
94a79942 LF |
190 | TsInactTimeout, |
191 | (unsigned long) pRxTS); | |
192 | ||
2e59e40d | 193 | setup_timer(&pRxTS->RxAdmittedBARecord.Timer, |
94a79942 LF |
194 | RxBaInactTimeout, |
195 | (unsigned long) pRxTS); | |
196 | ||
2e59e40d | 197 | setup_timer(&pRxTS->RxPktPendingTimer, |
94a79942 LF |
198 | RxPktPendingTimeout, |
199 | (unsigned long) pRxTS); | |
200 | ||
201 | ResetRxTsEntry(pRxTS); | |
f88ec6cb LF |
202 | list_add_tail(&pRxTS->TsCommonInfo.List, |
203 | &ieee->Rx_TS_Unused_List); | |
94a79942 LF |
204 | pRxTS++; |
205 | } | |
206 | INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); | |
f88ec6cb LF |
207 | for (count = 0; count < REORDER_ENTRY_NUM; count++) { |
208 | list_add_tail(&pRxReorderEntry->List, | |
209 | &ieee->RxReorder_Unused_List); | |
94a79942 LF |
210 | if (count == (REORDER_ENTRY_NUM-1)) |
211 | break; | |
212 | pRxReorderEntry = &ieee->RxReorderEntry[count+1]; | |
213 | } | |
214 | ||
215 | } | |
216 | ||
ec0dc6be LF |
217 | static void AdmitTS(struct rtllib_device *ieee, |
218 | struct ts_common_info *pTsCommonInfo, u32 InactTime) | |
94a79942 LF |
219 | { |
220 | del_timer_sync(&pTsCommonInfo->SetupTimer); | |
221 | del_timer_sync(&pTsCommonInfo->InactTimer); | |
222 | ||
f88ec6cb LF |
223 | if (InactTime != 0) |
224 | mod_timer(&pTsCommonInfo->InactTimer, jiffies + | |
8b9733c1 | 225 | msecs_to_jiffies(InactTime)); |
94a79942 LF |
226 | } |
227 | ||
ec0dc6be LF |
228 | static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, |
229 | u8 *Addr, u8 TID, | |
230 | enum tr_select TxRxSelect) | |
94a79942 LF |
231 | { |
232 | u8 dir; | |
ec0dc6be | 233 | bool search_dir[4] = {0}; |
f88ec6cb | 234 | struct list_head *psearch_list; |
74724de1 | 235 | struct ts_common_info *pRet = NULL; |
3a6b70c3 | 236 | |
f88ec6cb LF |
237 | if (ieee->iw_mode == IW_MODE_MASTER) { |
238 | if (TxRxSelect == TX_DIR) { | |
94a79942 | 239 | search_dir[DIR_DOWN] = true; |
f88ec6cb LF |
240 | search_dir[DIR_BI_DIR] = true; |
241 | } else { | |
242 | search_dir[DIR_UP] = true; | |
243 | search_dir[DIR_BI_DIR] = true; | |
94a79942 | 244 | } |
f88ec6cb | 245 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { |
94a79942 | 246 | if (TxRxSelect == TX_DIR) |
f88ec6cb | 247 | search_dir[DIR_UP] = true; |
94a79942 LF |
248 | else |
249 | search_dir[DIR_DOWN] = true; | |
f88ec6cb LF |
250 | } else { |
251 | if (TxRxSelect == TX_DIR) { | |
252 | search_dir[DIR_UP] = true; | |
253 | search_dir[DIR_BI_DIR] = true; | |
254 | search_dir[DIR_DIRECT] = true; | |
255 | } else { | |
94a79942 | 256 | search_dir[DIR_DOWN] = true; |
f88ec6cb LF |
257 | search_dir[DIR_BI_DIR] = true; |
258 | search_dir[DIR_DIRECT] = true; | |
94a79942 LF |
259 | } |
260 | } | |
261 | ||
262 | if (TxRxSelect == TX_DIR) | |
263 | psearch_list = &ieee->Tx_TS_Admit_List; | |
264 | else | |
265 | psearch_list = &ieee->Rx_TS_Admit_List; | |
266 | ||
f88ec6cb | 267 | for (dir = 0; dir <= DIR_BI_DIR; dir++) { |
4bb01423 | 268 | if (!search_dir[dir]) |
94a79942 | 269 | continue; |
f88ec6cb | 270 | list_for_each_entry(pRet, psearch_list, List) { |
35e33b04 MK |
271 | if (memcmp(pRet->Addr, Addr, 6) == 0 && |
272 | pRet->TSpec.f.TSInfo.field.ucTSID == TID && | |
273 | pRet->TSpec.f.TSInfo.field.ucDirection == dir) | |
274 | break; | |
94a79942 LF |
275 | |
276 | } | |
277 | if (&pRet->List != psearch_list) | |
278 | break; | |
279 | } | |
280 | ||
d7613e53 | 281 | if (pRet && &pRet->List != psearch_list) |
6af19767 | 282 | return pRet; |
13402f7b | 283 | return NULL; |
94a79942 LF |
284 | } |
285 | ||
ec0dc6be LF |
286 | static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr, |
287 | union tspec_body *pTSPEC, union qos_tclas *pTCLAS, | |
288 | u8 TCLAS_Num, u8 TCLAS_Proc) | |
94a79942 LF |
289 | { |
290 | u8 count; | |
291 | ||
292 | if (pTsCommonInfo == NULL) | |
293 | return; | |
294 | ||
295 | memcpy(pTsCommonInfo->Addr, Addr, 6); | |
296 | ||
297 | if (pTSPEC != NULL) | |
f88ec6cb LF |
298 | memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC, |
299 | sizeof(union tspec_body)); | |
94a79942 LF |
300 | |
301 | for (count = 0; count < TCLAS_Num; count++) | |
f88ec6cb LF |
302 | memcpy((u8 *)(&(pTsCommonInfo->TClass[count])), |
303 | (u8 *)pTCLAS, sizeof(union qos_tclas)); | |
94a79942 LF |
304 | |
305 | pTsCommonInfo->TClasProc = TCLAS_Proc; | |
306 | pTsCommonInfo->TClasNum = TCLAS_Num; | |
307 | } | |
308 | ||
fd181f7d AB |
309 | static bool IsACValid(unsigned int tid) |
310 | { | |
311 | return tid < 7; | |
312 | } | |
313 | ||
f88ec6cb LF |
314 | bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, |
315 | u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs) | |
94a79942 LF |
316 | { |
317 | u8 UP = 0; | |
285b7c00 MK |
318 | union tspec_body TSpec; |
319 | union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo; | |
320 | struct list_head *pUnusedList; | |
321 | struct list_head *pAddmitList; | |
322 | enum direction_value Dir; | |
3a6b70c3 | 323 | |
14fc4235 | 324 | if (is_multicast_ether_addr(Addr)) { |
11e672c3 | 325 | netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n"); |
94a79942 LF |
326 | return false; |
327 | } | |
328 | if (ieee->current_network.qos_data.supported == 0) { | |
329 | UP = 0; | |
330 | } else { | |
331 | if (!IsACValid(TID)) { | |
11e672c3 MK |
332 | netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n", |
333 | __func__, TID); | |
94a79942 LF |
334 | return false; |
335 | } | |
336 | ||
337 | switch (TID) { | |
338 | case 0: | |
339 | case 3: | |
340 | UP = 0; | |
341 | break; | |
342 | case 1: | |
343 | case 2: | |
344 | UP = 2; | |
345 | break; | |
346 | case 4: | |
347 | case 5: | |
348 | UP = 5; | |
349 | break; | |
350 | case 6: | |
351 | case 7: | |
352 | UP = 7; | |
353 | break; | |
354 | } | |
355 | } | |
356 | ||
f88ec6cb | 357 | *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect); |
285b7c00 | 358 | if (*ppTS != NULL) |
94a79942 | 359 | return true; |
285b7c00 MK |
360 | |
361 | if (!bAddNewTs) { | |
b94436b5 | 362 | netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP); |
285b7c00 MK |
363 | return false; |
364 | } | |
365 | ||
366 | pUnusedList = (TxRxSelect == TX_DIR) ? | |
f88ec6cb LF |
367 | (&ieee->Tx_TS_Unused_List) : |
368 | (&ieee->Rx_TS_Unused_List); | |
369 | ||
285b7c00 | 370 | pAddmitList = (TxRxSelect == TX_DIR) ? |
f88ec6cb LF |
371 | (&ieee->Tx_TS_Admit_List) : |
372 | (&ieee->Rx_TS_Admit_List); | |
373 | ||
285b7c00 MK |
374 | Dir = (ieee->iw_mode == IW_MODE_MASTER) ? |
375 | ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) : | |
376 | ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN); | |
377 | ||
285b7c00 MK |
378 | if (!list_empty(pUnusedList)) { |
379 | (*ppTS) = list_entry(pUnusedList->next, | |
380 | struct ts_common_info, List); | |
381 | list_del_init(&(*ppTS)->List); | |
382 | if (TxRxSelect == TX_DIR) { | |
383 | struct tx_ts_record *tmp = | |
384 | container_of(*ppTS, | |
385 | struct tx_ts_record, | |
386 | TsCommonInfo); | |
387 | ResetTxTsEntry(tmp); | |
388 | } else { | |
389 | struct rx_ts_record *tmp = | |
390 | container_of(*ppTS, | |
391 | struct rx_ts_record, | |
392 | TsCommonInfo); | |
393 | ResetRxTsEntry(tmp); | |
94a79942 | 394 | } |
285b7c00 | 395 | |
b94436b5 MK |
396 | netdev_dbg(ieee->dev, |
397 | "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", | |
398 | UP, Dir, Addr, *ppTS); | |
285b7c00 MK |
399 | pTSInfo->field.ucTrafficType = 0; |
400 | pTSInfo->field.ucTSID = UP; | |
401 | pTSInfo->field.ucDirection = Dir; | |
402 | pTSInfo->field.ucAccessPolicy = 1; | |
403 | pTSInfo->field.ucAggregation = 0; | |
404 | pTSInfo->field.ucPSB = 0; | |
405 | pTSInfo->field.ucUP = UP; | |
406 | pTSInfo->field.ucTSInfoAckPolicy = 0; | |
407 | pTSInfo->field.ucSchedule = 0; | |
408 | ||
409 | MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); | |
410 | AdmitTS(ieee, *ppTS, 0); | |
411 | list_add_tail(&((*ppTS)->List), pAddmitList); | |
412 | ||
413 | return true; | |
94a79942 | 414 | } |
285b7c00 | 415 | |
11e672c3 MK |
416 | netdev_warn(ieee->dev, |
417 | "There is not enough dir=%d(0=up down=1) TS record to be used!", | |
418 | Dir); | |
285b7c00 | 419 | return false; |
94a79942 LF |
420 | } |
421 | ||
35e33b04 MK |
422 | static void RemoveTsEntry(struct rtllib_device *ieee, |
423 | struct ts_common_info *pTs, enum tr_select TxRxSelect) | |
94a79942 LF |
424 | { |
425 | del_timer_sync(&pTs->SetupTimer); | |
426 | del_timer_sync(&pTs->InactTimer); | |
427 | TsInitDelBA(ieee, pTs, TxRxSelect); | |
428 | ||
f88ec6cb | 429 | if (TxRxSelect == RX_DIR) { |
8cba1432 | 430 | struct rx_reorder_entry *pRxReorderEntry; |
2c47ae28 | 431 | struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; |
94a79942 LF |
432 | |
433 | if (timer_pending(&pRxTS->RxPktPendingTimer)) | |
434 | del_timer_sync(&pRxTS->RxPktPendingTimer); | |
435 | ||
f88ec6cb LF |
436 | while (!list_empty(&pRxTS->RxPendingPktList)) { |
437 | pRxReorderEntry = (struct rx_reorder_entry *) | |
438 | list_entry(pRxTS->RxPendingPktList.prev, | |
439 | struct rx_reorder_entry, List); | |
b94436b5 MK |
440 | netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n", |
441 | __func__, pRxReorderEntry->SeqNum); | |
94a79942 LF |
442 | list_del_init(&pRxReorderEntry->List); |
443 | { | |
444 | int i = 0; | |
f88ec6cb | 445 | struct rtllib_rxb *prxb = pRxReorderEntry->prxb; |
3a6b70c3 | 446 | |
f88ec6cb | 447 | if (unlikely(!prxb)) |
94a79942 | 448 | return; |
f88ec6cb | 449 | for (i = 0; i < prxb->nr_subframes; i++) |
94a79942 | 450 | dev_kfree_skb(prxb->subframes[i]); |
94a79942 LF |
451 | kfree(prxb); |
452 | prxb = NULL; | |
453 | } | |
f88ec6cb LF |
454 | list_add_tail(&pRxReorderEntry->List, |
455 | &ieee->RxReorder_Unused_List); | |
94a79942 | 456 | } |
f88ec6cb | 457 | } else { |
60554f2b | 458 | struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; |
3a6b70c3 | 459 | |
94a79942 LF |
460 | del_timer_sync(&pTxTS->TsAddBaTimer); |
461 | } | |
462 | } | |
463 | ||
f88ec6cb | 464 | void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr) |
94a79942 | 465 | { |
74724de1 | 466 | struct ts_common_info *pTS, *pTmpTS; |
3a6b70c3 | 467 | |
d69d2054 | 468 | netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr); |
4f6807e8 | 469 | |
f88ec6cb LF |
470 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { |
471 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
472 | RemoveTsEntry(ieee, pTS, TX_DIR); |
473 | list_del_init(&pTS->List); | |
474 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
475 | } | |
476 | } | |
477 | ||
f88ec6cb LF |
478 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { |
479 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
d69d2054 MK |
480 | netdev_info(ieee->dev, |
481 | "====>remove Tx_TS_admin_list\n"); | |
94a79942 LF |
482 | RemoveTsEntry(ieee, pTS, TX_DIR); |
483 | list_del_init(&pTS->List); | |
484 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
485 | } | |
486 | } | |
487 | ||
f88ec6cb LF |
488 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { |
489 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
490 | RemoveTsEntry(ieee, pTS, RX_DIR); |
491 | list_del_init(&pTS->List); | |
492 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
493 | } | |
494 | } | |
495 | ||
f88ec6cb LF |
496 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { |
497 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
498 | RemoveTsEntry(ieee, pTS, RX_DIR); |
499 | list_del_init(&pTS->List); | |
500 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
501 | } | |
502 | } | |
94a79942 | 503 | } |
3b28499c | 504 | EXPORT_SYMBOL(RemovePeerTS); |
94a79942 | 505 | |
f88ec6cb | 506 | void RemoveAllTS(struct rtllib_device *ieee) |
94a79942 | 507 | { |
74724de1 | 508 | struct ts_common_info *pTS, *pTmpTS; |
4f6807e8 | 509 | |
f88ec6cb | 510 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { |
94a79942 LF |
511 | RemoveTsEntry(ieee, pTS, TX_DIR); |
512 | list_del_init(&pTS->List); | |
513 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
514 | } | |
515 | ||
f88ec6cb | 516 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { |
94a79942 LF |
517 | RemoveTsEntry(ieee, pTS, TX_DIR); |
518 | list_del_init(&pTS->List); | |
519 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
520 | } | |
521 | ||
f88ec6cb | 522 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { |
94a79942 LF |
523 | RemoveTsEntry(ieee, pTS, RX_DIR); |
524 | list_del_init(&pTS->List); | |
525 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
526 | } | |
527 | ||
f88ec6cb | 528 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { |
94a79942 LF |
529 | RemoveTsEntry(ieee, pTS, RX_DIR); |
530 | list_del_init(&pTS->List); | |
531 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
532 | } | |
94a79942 LF |
533 | } |
534 | ||
f88ec6cb | 535 | void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) |
94a79942 | 536 | { |
f88ec6cb | 537 | if (pTxTS->bAddBaReqInProgress == false) { |
94a79942 | 538 | pTxTS->bAddBaReqInProgress = true; |
4f6807e8 | 539 | |
f88ec6cb | 540 | if (pTxTS->bAddBaReqDelayed) { |
b94436b5 | 541 | netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n"); |
f88ec6cb | 542 | mod_timer(&pTxTS->TsAddBaTimer, jiffies + |
8b9733c1 | 543 | msecs_to_jiffies(TS_ADDBA_DELAY)); |
f88ec6cb | 544 | } else { |
b94436b5 | 545 | netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); |
94a79942 LF |
546 | mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); |
547 | } | |
f88ec6cb | 548 | } else |
b94436b5 | 549 | netdev_dbg(ieee->dev, "BA timer is already added\n"); |
94a79942 | 550 | } |