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 * 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" 18 19static void TsSetupTimeOut(unsigned long data) 20{ 21} 22 23static void TsInactTimeout(unsigned long data) 24{ 25} 26 27static void RxPktPendingTimeout(unsigned long data) 28{ 29 struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; 30 struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, 31 RxTsRecord[pRxTs->num]); 32 33 struct rx_reorder_entry *pReorderEntry = NULL; 34 35 unsigned long flags = 0; 36 u8 index = 0; 37 bool bPktInBuf = false; 38 39 spin_lock_irqsave(&(ieee->reorder_spinlock), flags); 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); 45 if (index == 0) 46 pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; 47 48 if (SN_LESS(pReorderEntry->SeqNum, 49 pRxTs->RxIndicateSeq) || 50 SN_EQUAL(pReorderEntry->SeqNum, 51 pRxTs->RxIndicateSeq)) { 52 list_del_init(&pReorderEntry->List); 53 54 if (SN_EQUAL(pReorderEntry->SeqNum, 55 pRxTs->RxIndicateSeq)) 56 pRxTs->RxIndicateSeq = 57 (pRxTs->RxIndicateSeq + 1) % 4096; 58 59 netdev_dbg(ieee->dev, 60 "%s(): Indicate SeqNum: %d\n", 61 __func__, pReorderEntry->SeqNum); 62 ieee->stats_IndicateArray[index] = 63 pReorderEntry->prxb; 64 index++; 65 66 list_add_tail(&pReorderEntry->List, 67 &ieee->RxReorder_Unused_List); 68 } else { 69 bPktInBuf = true; 70 break; 71 } 72 } 73 } 74 75 if (index > 0) { 76 pRxTs->RxTimeoutIndicateSeq = 0xffff; 77 78 if (index > REORDER_WIN_SIZE) { 79 netdev_warn(ieee->dev, 80 "%s(): Rx Reorder struct buffer full\n", 81 __func__); 82 spin_unlock_irqrestore(&(ieee->reorder_spinlock), 83 flags); 84 return; 85 } 86 rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index); 87 bPktInBuf = false; 88 } 89 90 if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) { 91 pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; 92 mod_timer(&pRxTs->RxPktPendingTimer, jiffies + 93 msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime) 94 ); 95 } 96 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); 97} 98 99static void TsAddBaProcess(unsigned long data) 100{ 101 struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; 102 u8 num = pTxTs->num; 103 struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, 104 TxTsRecord[num]); 105 106 TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); 107 netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__); 108} 109 110static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) 111{ 112 eth_zero_addr(pTsCommonInfo->Addr); 113 memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body)); 114 memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM); 115 pTsCommonInfo->TClasProc = 0; 116 pTsCommonInfo->TClasNum = 0; 117} 118 119static void ResetTxTsEntry(struct tx_ts_record *pTS) 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 131static void ResetRxTsEntry(struct rx_ts_record *pTS) 132{ 133 ResetTsCommonInfo(&pTS->TsCommonInfo); 134 pTS->RxIndicateSeq = 0xffff; 135 pTS->RxTimeoutIndicateSeq = 0xffff; 136 ResetBaEntry(&pTS->RxAdmittedBARecord); 137} 138 139void TSInitialize(struct rtllib_device *ieee) 140{ 141 struct tx_ts_record *pTxTS = ieee->TxTsRecord; 142 struct rx_ts_record *pRxTS = ieee->RxTsRecord; 143 struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; 144 u8 count = 0; 145 146 netdev_vdbg(ieee->dev, "%s()\n", __func__); 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 151 for (count = 0; count < TOTAL_TS_NUM; count++) { 152 pTxTS->num = count; 153 setup_timer(&pTxTS->TsCommonInfo.SetupTimer, 154 TsSetupTimeOut, 155 (unsigned long) pTxTS); 156 157 setup_timer(&pTxTS->TsCommonInfo.InactTimer, 158 TsInactTimeout, 159 (unsigned long) pTxTS); 160 161 setup_timer(&pTxTS->TsAddBaTimer, 162 TsAddBaProcess, 163 (unsigned long) pTxTS); 164 165 setup_timer(&pTxTS->TxPendingBARecord.Timer, 166 BaSetupTimeOut, 167 (unsigned long) pTxTS); 168 setup_timer(&pTxTS->TxAdmittedBARecord.Timer, 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); 181 for (count = 0; count < TOTAL_TS_NUM; count++) { 182 pRxTS->num = count; 183 INIT_LIST_HEAD(&pRxTS->RxPendingPktList); 184 185 setup_timer(&pRxTS->TsCommonInfo.SetupTimer, 186 TsSetupTimeOut, 187 (unsigned long) pRxTS); 188 189 setup_timer(&pRxTS->TsCommonInfo.InactTimer, 190 TsInactTimeout, 191 (unsigned long) pRxTS); 192 193 setup_timer(&pRxTS->RxAdmittedBARecord.Timer, 194 RxBaInactTimeout, 195 (unsigned long) pRxTS); 196 197 setup_timer(&pRxTS->RxPktPendingTimer, 198 RxPktPendingTimeout, 199 (unsigned long) pRxTS); 200 201 ResetRxTsEntry(pRxTS); 202 list_add_tail(&pRxTS->TsCommonInfo.List, 203 &ieee->Rx_TS_Unused_List); 204 pRxTS++; 205 } 206 INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); 207 for (count = 0; count < REORDER_ENTRY_NUM; count++) { 208 list_add_tail(&pRxReorderEntry->List, 209 &ieee->RxReorder_Unused_List); 210 if (count == (REORDER_ENTRY_NUM-1)) 211 break; 212 pRxReorderEntry = &ieee->RxReorderEntry[count+1]; 213 } 214 215} 216 217static void AdmitTS(struct rtllib_device *ieee, 218 struct ts_common_info *pTsCommonInfo, u32 InactTime) 219{ 220 del_timer_sync(&pTsCommonInfo->SetupTimer); 221 del_timer_sync(&pTsCommonInfo->InactTimer); 222 223 if (InactTime != 0) 224 mod_timer(&pTsCommonInfo->InactTimer, jiffies + 225 msecs_to_jiffies(InactTime)); 226} 227 228static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, 229 u8 *Addr, u8 TID, 230 enum tr_select TxRxSelect) 231{ 232 u8 dir; 233 bool search_dir[4] = {0}; 234 struct list_head *psearch_list; 235 struct ts_common_info *pRet = NULL; 236 237 if (ieee->iw_mode == IW_MODE_MASTER) { 238 if (TxRxSelect == TX_DIR) { 239 search_dir[DIR_DOWN] = true; 240 search_dir[DIR_BI_DIR] = true; 241 } else { 242 search_dir[DIR_UP] = true; 243 search_dir[DIR_BI_DIR] = true; 244 } 245 } else if (ieee->iw_mode == IW_MODE_ADHOC) { 246 if (TxRxSelect == TX_DIR) 247 search_dir[DIR_UP] = true; 248 else 249 search_dir[DIR_DOWN] = true; 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 { 256 search_dir[DIR_DOWN] = true; 257 search_dir[DIR_BI_DIR] = true; 258 search_dir[DIR_DIRECT] = true; 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 267 for (dir = 0; dir <= DIR_BI_DIR; dir++) { 268 if (!search_dir[dir]) 269 continue; 270 list_for_each_entry(pRet, psearch_list, List) { 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; 275 276 } 277 if (&pRet->List != psearch_list) 278 break; 279 } 280 281 if (pRet && &pRet->List != psearch_list) 282 return pRet; 283 return NULL; 284} 285 286static 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) 289{ 290 u8 count; 291 292 if (pTsCommonInfo == NULL) 293 return; 294 295 memcpy(pTsCommonInfo->Addr, Addr, 6); 296 297 if (pTSPEC != NULL) 298 memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC, 299 sizeof(union tspec_body)); 300 301 for (count = 0; count < TCLAS_Num; count++) 302 memcpy((u8 *)(&(pTsCommonInfo->TClass[count])), 303 (u8 *)pTCLAS, sizeof(union qos_tclas)); 304 305 pTsCommonInfo->TClasProc = TCLAS_Proc; 306 pTsCommonInfo->TClasNum = TCLAS_Num; 307} 308 309bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, 310 u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs) 311{ 312 u8 UP = 0; 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; 318 319 if (is_multicast_ether_addr(Addr)) { 320 netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n"); 321 return false; 322 } 323 if (ieee->current_network.qos_data.supported == 0) { 324 UP = 0; 325 } else { 326 if (!IsACValid(TID)) { 327 netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n", 328 __func__, TID); 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 352 *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect); 353 if (*ppTS != NULL) 354 return true; 355 356 if (!bAddNewTs) { 357 netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP); 358 return false; 359 } 360 361 pUnusedList = (TxRxSelect == TX_DIR) ? 362 (&ieee->Tx_TS_Unused_List) : 363 (&ieee->Rx_TS_Unused_List); 364 365 pAddmitList = (TxRxSelect == TX_DIR) ? 366 (&ieee->Tx_TS_Admit_List) : 367 (&ieee->Rx_TS_Admit_List); 368 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 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); 389 } 390 391 netdev_dbg(ieee->dev, 392 "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", 393 UP, Dir, Addr, *ppTS); 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; 409 } 410 411 netdev_warn(ieee->dev, 412 "There is not enough dir=%d(0=up down=1) TS record to be used!", 413 Dir); 414 return false; 415} 416 417static void RemoveTsEntry(struct rtllib_device *ieee, 418 struct ts_common_info *pTs, enum tr_select TxRxSelect) 419{ 420 del_timer_sync(&pTs->SetupTimer); 421 del_timer_sync(&pTs->InactTimer); 422 TsInitDelBA(ieee, pTs, TxRxSelect); 423 424 if (TxRxSelect == RX_DIR) { 425 struct rx_reorder_entry *pRxReorderEntry; 426 struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; 427 428 if (timer_pending(&pRxTS->RxPktPendingTimer)) 429 del_timer_sync(&pRxTS->RxPktPendingTimer); 430 431 while (!list_empty(&pRxTS->RxPendingPktList)) { 432 pRxReorderEntry = (struct rx_reorder_entry *) 433 list_entry(pRxTS->RxPendingPktList.prev, 434 struct rx_reorder_entry, List); 435 netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n", 436 __func__, pRxReorderEntry->SeqNum); 437 list_del_init(&pRxReorderEntry->List); 438 { 439 int i = 0; 440 struct rtllib_rxb *prxb = pRxReorderEntry->prxb; 441 442 if (unlikely(!prxb)) 443 return; 444 for (i = 0; i < prxb->nr_subframes; i++) 445 dev_kfree_skb(prxb->subframes[i]); 446 kfree(prxb); 447 prxb = NULL; 448 } 449 list_add_tail(&pRxReorderEntry->List, 450 &ieee->RxReorder_Unused_List); 451 } 452 } else { 453 struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; 454 455 del_timer_sync(&pTxTS->TsAddBaTimer); 456 } 457} 458 459void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr) 460{ 461 struct ts_common_info *pTS, *pTmpTS; 462 463 netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr); 464 465 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { 466 if (memcmp(pTS->Addr, Addr, 6) == 0) { 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 473 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { 474 if (memcmp(pTS->Addr, Addr, 6) == 0) { 475 netdev_info(ieee->dev, 476 "====>remove Tx_TS_admin_list\n"); 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 483 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { 484 if (memcmp(pTS->Addr, Addr, 6) == 0) { 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 491 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { 492 if (memcmp(pTS->Addr, Addr, 6) == 0) { 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 } 498} 499EXPORT_SYMBOL(RemovePeerTS); 500 501void RemoveAllTS(struct rtllib_device *ieee) 502{ 503 struct ts_common_info *pTS, *pTmpTS; 504 505 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { 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 511 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { 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 517 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { 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 523 list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { 524 RemoveTsEntry(ieee, pTS, RX_DIR); 525 list_del_init(&pTS->List); 526 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); 527 } 528} 529 530void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) 531{ 532 if (pTxTS->bAddBaReqInProgress == false) { 533 pTxTS->bAddBaReqInProgress = true; 534 535 if (pTxTS->bAddBaReqDelayed) { 536 netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n"); 537 mod_timer(&pTxTS->TsAddBaTimer, jiffies + 538 msecs_to_jiffies(TS_ADDBA_DELAY)); 539 } else { 540 netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); 541 mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); 542 } 543 } else 544 netdev_dbg(ieee->dev, "BA timer is already added\n"); 545} 546