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