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 | ||
f88ec6cb LF |
309 | bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, |
310 | u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs) | |
94a79942 LF |
311 | { |
312 | u8 UP = 0; | |
285b7c00 MK |
313 | union tspec_body TSpec; |
314 | union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo; | |
315 | struct list_head *pUnusedList; | |
316 | struct list_head *pAddmitList; | |
317 | enum direction_value Dir; | |
3a6b70c3 | 318 | |
14fc4235 | 319 | if (is_multicast_ether_addr(Addr)) { |
11e672c3 | 320 | netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n"); |
94a79942 LF |
321 | return false; |
322 | } | |
323 | if (ieee->current_network.qos_data.supported == 0) { | |
324 | UP = 0; | |
325 | } else { | |
326 | if (!IsACValid(TID)) { | |
11e672c3 MK |
327 | netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n", |
328 | __func__, TID); | |
94a79942 LF |
329 | return false; |
330 | } | |
331 | ||
332 | switch (TID) { | |
333 | case 0: | |
334 | case 3: | |
335 | UP = 0; | |
336 | break; | |
337 | case 1: | |
338 | case 2: | |
339 | UP = 2; | |
340 | break; | |
341 | case 4: | |
342 | case 5: | |
343 | UP = 5; | |
344 | break; | |
345 | case 6: | |
346 | case 7: | |
347 | UP = 7; | |
348 | break; | |
349 | } | |
350 | } | |
351 | ||
f88ec6cb | 352 | *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect); |
285b7c00 | 353 | if (*ppTS != NULL) |
94a79942 | 354 | return true; |
285b7c00 MK |
355 | |
356 | if (!bAddNewTs) { | |
b94436b5 | 357 | netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP); |
285b7c00 MK |
358 | return false; |
359 | } | |
360 | ||
361 | pUnusedList = (TxRxSelect == TX_DIR) ? | |
f88ec6cb LF |
362 | (&ieee->Tx_TS_Unused_List) : |
363 | (&ieee->Rx_TS_Unused_List); | |
364 | ||
285b7c00 | 365 | pAddmitList = (TxRxSelect == TX_DIR) ? |
f88ec6cb LF |
366 | (&ieee->Tx_TS_Admit_List) : |
367 | (&ieee->Rx_TS_Admit_List); | |
368 | ||
285b7c00 MK |
369 | Dir = (ieee->iw_mode == IW_MODE_MASTER) ? |
370 | ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) : | |
371 | ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN); | |
372 | ||
285b7c00 MK |
373 | if (!list_empty(pUnusedList)) { |
374 | (*ppTS) = list_entry(pUnusedList->next, | |
375 | struct ts_common_info, List); | |
376 | list_del_init(&(*ppTS)->List); | |
377 | if (TxRxSelect == TX_DIR) { | |
378 | struct tx_ts_record *tmp = | |
379 | container_of(*ppTS, | |
380 | struct tx_ts_record, | |
381 | TsCommonInfo); | |
382 | ResetTxTsEntry(tmp); | |
383 | } else { | |
384 | struct rx_ts_record *tmp = | |
385 | container_of(*ppTS, | |
386 | struct rx_ts_record, | |
387 | TsCommonInfo); | |
388 | ResetRxTsEntry(tmp); | |
94a79942 | 389 | } |
285b7c00 | 390 | |
b94436b5 MK |
391 | netdev_dbg(ieee->dev, |
392 | "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", | |
393 | UP, Dir, Addr, *ppTS); | |
285b7c00 MK |
394 | pTSInfo->field.ucTrafficType = 0; |
395 | pTSInfo->field.ucTSID = UP; | |
396 | pTSInfo->field.ucDirection = Dir; | |
397 | pTSInfo->field.ucAccessPolicy = 1; | |
398 | pTSInfo->field.ucAggregation = 0; | |
399 | pTSInfo->field.ucPSB = 0; | |
400 | pTSInfo->field.ucUP = UP; | |
401 | pTSInfo->field.ucTSInfoAckPolicy = 0; | |
402 | pTSInfo->field.ucSchedule = 0; | |
403 | ||
404 | MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); | |
405 | AdmitTS(ieee, *ppTS, 0); | |
406 | list_add_tail(&((*ppTS)->List), pAddmitList); | |
407 | ||
408 | return true; | |
94a79942 | 409 | } |
285b7c00 | 410 | |
11e672c3 MK |
411 | netdev_warn(ieee->dev, |
412 | "There is not enough dir=%d(0=up down=1) TS record to be used!", | |
413 | Dir); | |
285b7c00 | 414 | return false; |
94a79942 LF |
415 | } |
416 | ||
35e33b04 MK |
417 | static void RemoveTsEntry(struct rtllib_device *ieee, |
418 | struct ts_common_info *pTs, enum tr_select TxRxSelect) | |
94a79942 LF |
419 | { |
420 | del_timer_sync(&pTs->SetupTimer); | |
421 | del_timer_sync(&pTs->InactTimer); | |
422 | TsInitDelBA(ieee, pTs, TxRxSelect); | |
423 | ||
f88ec6cb | 424 | if (TxRxSelect == RX_DIR) { |
8cba1432 | 425 | struct rx_reorder_entry *pRxReorderEntry; |
2c47ae28 | 426 | struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; |
94a79942 LF |
427 | |
428 | if (timer_pending(&pRxTS->RxPktPendingTimer)) | |
429 | del_timer_sync(&pRxTS->RxPktPendingTimer); | |
430 | ||
f88ec6cb LF |
431 | while (!list_empty(&pRxTS->RxPendingPktList)) { |
432 | pRxReorderEntry = (struct rx_reorder_entry *) | |
433 | list_entry(pRxTS->RxPendingPktList.prev, | |
434 | struct rx_reorder_entry, List); | |
b94436b5 MK |
435 | netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n", |
436 | __func__, pRxReorderEntry->SeqNum); | |
94a79942 LF |
437 | list_del_init(&pRxReorderEntry->List); |
438 | { | |
439 | int i = 0; | |
f88ec6cb | 440 | struct rtllib_rxb *prxb = pRxReorderEntry->prxb; |
3a6b70c3 | 441 | |
f88ec6cb | 442 | if (unlikely(!prxb)) |
94a79942 | 443 | return; |
f88ec6cb | 444 | for (i = 0; i < prxb->nr_subframes; i++) |
94a79942 | 445 | dev_kfree_skb(prxb->subframes[i]); |
94a79942 LF |
446 | kfree(prxb); |
447 | prxb = NULL; | |
448 | } | |
f88ec6cb LF |
449 | list_add_tail(&pRxReorderEntry->List, |
450 | &ieee->RxReorder_Unused_List); | |
94a79942 | 451 | } |
f88ec6cb | 452 | } else { |
60554f2b | 453 | struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; |
3a6b70c3 | 454 | |
94a79942 LF |
455 | del_timer_sync(&pTxTS->TsAddBaTimer); |
456 | } | |
457 | } | |
458 | ||
f88ec6cb | 459 | void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr) |
94a79942 | 460 | { |
74724de1 | 461 | struct ts_common_info *pTS, *pTmpTS; |
3a6b70c3 | 462 | |
d69d2054 | 463 | netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr); |
4f6807e8 | 464 | |
f88ec6cb LF |
465 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { |
466 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
467 | RemoveTsEntry(ieee, pTS, TX_DIR); |
468 | list_del_init(&pTS->List); | |
469 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
470 | } | |
471 | } | |
472 | ||
f88ec6cb LF |
473 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { |
474 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
d69d2054 MK |
475 | netdev_info(ieee->dev, |
476 | "====>remove Tx_TS_admin_list\n"); | |
94a79942 LF |
477 | RemoveTsEntry(ieee, pTS, TX_DIR); |
478 | list_del_init(&pTS->List); | |
479 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
480 | } | |
481 | } | |
482 | ||
f88ec6cb LF |
483 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { |
484 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
485 | RemoveTsEntry(ieee, pTS, RX_DIR); |
486 | list_del_init(&pTS->List); | |
487 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
488 | } | |
489 | } | |
490 | ||
f88ec6cb LF |
491 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { |
492 | if (memcmp(pTS->Addr, Addr, 6) == 0) { | |
94a79942 LF |
493 | RemoveTsEntry(ieee, pTS, RX_DIR); |
494 | list_del_init(&pTS->List); | |
495 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
496 | } | |
497 | } | |
94a79942 | 498 | } |
3b28499c | 499 | EXPORT_SYMBOL(RemovePeerTS); |
94a79942 | 500 | |
f88ec6cb | 501 | void RemoveAllTS(struct rtllib_device *ieee) |
94a79942 | 502 | { |
74724de1 | 503 | struct ts_common_info *pTS, *pTmpTS; |
4f6807e8 | 504 | |
f88ec6cb | 505 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { |
94a79942 LF |
506 | RemoveTsEntry(ieee, pTS, TX_DIR); |
507 | list_del_init(&pTS->List); | |
508 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
509 | } | |
510 | ||
f88ec6cb | 511 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { |
94a79942 LF |
512 | RemoveTsEntry(ieee, pTS, TX_DIR); |
513 | list_del_init(&pTS->List); | |
514 | list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); | |
515 | } | |
516 | ||
f88ec6cb | 517 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { |
94a79942 LF |
518 | RemoveTsEntry(ieee, pTS, RX_DIR); |
519 | list_del_init(&pTS->List); | |
520 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
521 | } | |
522 | ||
f88ec6cb | 523 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { |
94a79942 LF |
524 | RemoveTsEntry(ieee, pTS, RX_DIR); |
525 | list_del_init(&pTS->List); | |
526 | list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); | |
527 | } | |
94a79942 LF |
528 | } |
529 | ||
f88ec6cb | 530 | void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) |
94a79942 | 531 | { |
f88ec6cb | 532 | if (pTxTS->bAddBaReqInProgress == false) { |
94a79942 | 533 | pTxTS->bAddBaReqInProgress = true; |
4f6807e8 | 534 | |
f88ec6cb | 535 | if (pTxTS->bAddBaReqDelayed) { |
b94436b5 | 536 | netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n"); |
f88ec6cb | 537 | mod_timer(&pTxTS->TsAddBaTimer, jiffies + |
8b9733c1 | 538 | msecs_to_jiffies(TS_ADDBA_DELAY)); |
f88ec6cb | 539 | } else { |
b94436b5 | 540 | netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); |
94a79942 LF |
541 | mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); |
542 | } | |
f88ec6cb | 543 | } else |
b94436b5 | 544 | netdev_dbg(ieee->dev, "BA timer is already added\n"); |
94a79942 | 545 | } |