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 11static void RxPktPendingTimeout(struct timer_list *t) 12{ 13 struct rx_ts_record *ts = from_timer(ts, t, rx_pkt_pending_timer); 14 struct rtllib_device *ieee = container_of(ts, struct rtllib_device, 15 rx_ts_records[ts->num]); 16 17 struct rx_reorder_entry *pReorderEntry = NULL; 18 19 unsigned long flags = 0; 20 u8 index = 0; 21 bool bPktInBuf = false; 22 23 spin_lock_irqsave(&(ieee->reorder_spinlock), flags); 24 if (ts->rx_timeout_indicate_seq != 0xffff) { 25 while (!list_empty(&ts->rx_pending_pkt_list)) { 26 pReorderEntry = (struct rx_reorder_entry *) 27 list_entry(ts->rx_pending_pkt_list.prev, 28 struct rx_reorder_entry, list); 29 if (index == 0) 30 ts->rx_indicate_seq = pReorderEntry->SeqNum; 31 32 if (SN_LESS(pReorderEntry->SeqNum, 33 ts->rx_indicate_seq) || 34 SN_EQUAL(pReorderEntry->SeqNum, 35 ts->rx_indicate_seq)) { 36 list_del_init(&pReorderEntry->list); 37 38 if (SN_EQUAL(pReorderEntry->SeqNum, 39 ts->rx_indicate_seq)) 40 ts->rx_indicate_seq = 41 (ts->rx_indicate_seq + 1) % 4096; 42 43 netdev_dbg(ieee->dev, 44 "%s(): Indicate SeqNum: %d\n", 45 __func__, pReorderEntry->SeqNum); 46 ieee->stats_IndicateArray[index] = 47 pReorderEntry->prxb; 48 index++; 49 50 list_add_tail(&pReorderEntry->list, 51 &ieee->RxReorder_Unused_List); 52 } else { 53 bPktInBuf = true; 54 break; 55 } 56 } 57 } 58 59 if (index > 0) { 60 ts->rx_timeout_indicate_seq = 0xffff; 61 62 if (index > REORDER_WIN_SIZE) { 63 netdev_warn(ieee->dev, 64 "%s(): Rx Reorder struct buffer full\n", 65 __func__); 66 spin_unlock_irqrestore(&(ieee->reorder_spinlock), 67 flags); 68 return; 69 } 70 rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index); 71 bPktInBuf = false; 72 } 73 74 if (bPktInBuf && (ts->rx_timeout_indicate_seq == 0xffff)) { 75 ts->rx_timeout_indicate_seq = ts->rx_indicate_seq; 76 mod_timer(&ts->rx_pkt_pending_timer, jiffies + 77 msecs_to_jiffies(ieee->ht_info->rx_reorder_pending_time) 78 ); 79 } 80 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); 81} 82 83static void TsAddBaProcess(struct timer_list *t) 84{ 85 struct tx_ts_record *ts = from_timer(ts, t, ts_add_ba_timer); 86 u8 num = ts->num; 87 struct rtllib_device *ieee = container_of(ts, struct rtllib_device, 88 tx_ts_records[num]); 89 90 rtllib_ts_init_add_ba(ieee, ts, BA_POLICY_IMMEDIATE, false); 91 netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__); 92} 93 94static void ResetTsCommonInfo(struct ts_common_info *ts_common_info) 95{ 96 eth_zero_addr(ts_common_info->addr); 97 memset(&ts_common_info->tspec, 0, sizeof(struct qos_tsinfo)); 98} 99 100static void ResetTxTsEntry(struct tx_ts_record *ts) 101{ 102 ResetTsCommonInfo(&ts->ts_common_info); 103 ts->tx_cur_seq = 0; 104 ts->add_ba_req_in_progress = false; 105 ts->add_ba_req_delayed = false; 106 ts->using_ba = false; 107 ts->disable_add_ba = false; 108 rtllib_reset_ba_entry(&ts->tx_admitted_ba_record); 109 rtllib_reset_ba_entry(&ts->tx_pending_ba_record); 110} 111 112static void ResetRxTsEntry(struct rx_ts_record *ts) 113{ 114 ResetTsCommonInfo(&ts->ts_common_info); 115 ts->rx_indicate_seq = 0xffff; 116 ts->rx_timeout_indicate_seq = 0xffff; 117 rtllib_reset_ba_entry(&ts->rx_admitted_ba_record); 118} 119 120void rtllib_ts_init(struct rtllib_device *ieee) 121{ 122 struct tx_ts_record *pTxTS = ieee->tx_ts_records; 123 struct rx_ts_record *rxts = ieee->rx_ts_records; 124 struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; 125 u8 count = 0; 126 127 INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); 128 INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); 129 INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); 130 131 for (count = 0; count < TOTAL_TS_NUM; count++) { 132 pTxTS->num = count; 133 timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0); 134 135 timer_setup(&pTxTS->tx_pending_ba_record.timer, rtllib_ba_setup_timeout, 136 0); 137 timer_setup(&pTxTS->tx_admitted_ba_record.timer, 138 rtllib_tx_ba_inact_timeout, 0); 139 140 ResetTxTsEntry(pTxTS); 141 list_add_tail(&pTxTS->ts_common_info.list, 142 &ieee->Tx_TS_Unused_List); 143 pTxTS++; 144 } 145 146 INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); 147 INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); 148 INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); 149 for (count = 0; count < TOTAL_TS_NUM; count++) { 150 rxts->num = count; 151 INIT_LIST_HEAD(&rxts->rx_pending_pkt_list); 152 timer_setup(&rxts->rx_admitted_ba_record.timer, 153 rtllib_rx_ba_inact_timeout, 0); 154 155 timer_setup(&rxts->rx_pkt_pending_timer, RxPktPendingTimeout, 0); 156 157 ResetRxTsEntry(rxts); 158 list_add_tail(&rxts->ts_common_info.list, 159 &ieee->Rx_TS_Unused_List); 160 rxts++; 161 } 162 INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); 163 for (count = 0; count < REORDER_ENTRY_NUM; count++) { 164 list_add_tail(&pRxReorderEntry->list, 165 &ieee->RxReorder_Unused_List); 166 if (count == (REORDER_ENTRY_NUM - 1)) 167 break; 168 pRxReorderEntry = &ieee->RxReorderEntry[count + 1]; 169 } 170} 171 172static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, 173 u8 *addr, u8 TID, 174 enum tr_select tx_rx_select) 175{ 176 u8 dir; 177 bool search_dir[4] = {0}; 178 struct list_head *psearch_list; 179 struct ts_common_info *pRet = NULL; 180 181 if (tx_rx_select == TX_DIR) { 182 search_dir[DIR_UP] = true; 183 search_dir[DIR_BI_DIR] = true; 184 search_dir[DIR_DIRECT] = true; 185 } else { 186 search_dir[DIR_DOWN] = true; 187 search_dir[DIR_BI_DIR] = true; 188 search_dir[DIR_DIRECT] = true; 189 } 190 191 if (tx_rx_select == TX_DIR) 192 psearch_list = &ieee->Tx_TS_Admit_List; 193 else 194 psearch_list = &ieee->Rx_TS_Admit_List; 195 196 for (dir = 0; dir <= DIR_BI_DIR; dir++) { 197 if (!search_dir[dir]) 198 continue; 199 list_for_each_entry(pRet, psearch_list, list) { 200 if (memcmp(pRet->addr, addr, 6) == 0 && 201 pRet->tspec.ts_id == TID && 202 pRet->tspec.ucDirection == dir) 203 break; 204 } 205 if (&pRet->list != psearch_list) 206 break; 207 } 208 209 if (pRet && &pRet->list != psearch_list) 210 return pRet; 211 return NULL; 212} 213 214static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr, 215 struct qos_tsinfo *pTSPEC) 216{ 217 if (!ts_common_info) 218 return; 219 220 memcpy(ts_common_info->addr, addr, 6); 221 222 if (pTSPEC) 223 memcpy((u8 *)(&(ts_common_info->tspec)), (u8 *)pTSPEC, 224 sizeof(struct qos_tsinfo)); 225} 226 227bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS, 228 u8 *addr, u8 TID, enum tr_select tx_rx_select, bool bAddNewTs) 229{ 230 u8 UP = 0; 231 struct qos_tsinfo tspec; 232 struct qos_tsinfo *ts_info = &tspec; 233 struct list_head *pUnusedList; 234 struct list_head *pAddmitList; 235 enum direction_value Dir; 236 237 if (is_multicast_ether_addr(addr)) { 238 netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n"); 239 return false; 240 } 241 if (ieee->current_network.qos_data.supported == 0) { 242 UP = 0; 243 } else { 244 switch (TID) { 245 case 0: 246 case 3: 247 UP = 0; 248 break; 249 case 1: 250 case 2: 251 UP = 2; 252 break; 253 case 4: 254 case 5: 255 UP = 5; 256 break; 257 case 6: 258 case 7: 259 UP = 7; 260 break; 261 default: 262 netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n", 263 __func__, TID); 264 return false; 265 } 266 } 267 268 *ppTS = SearchAdmitTRStream(ieee, addr, UP, tx_rx_select); 269 if (*ppTS) 270 return true; 271 272 if (!bAddNewTs) { 273 netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP); 274 return false; 275 } 276 277 pUnusedList = (tx_rx_select == TX_DIR) ? 278 (&ieee->Tx_TS_Unused_List) : 279 (&ieee->Rx_TS_Unused_List); 280 281 pAddmitList = (tx_rx_select == TX_DIR) ? 282 (&ieee->Tx_TS_Admit_List) : 283 (&ieee->Rx_TS_Admit_List); 284 285 Dir = ((tx_rx_select == TX_DIR) ? DIR_UP : DIR_DOWN); 286 287 if (!list_empty(pUnusedList)) { 288 (*ppTS) = list_entry(pUnusedList->next, 289 struct ts_common_info, list); 290 list_del_init(&(*ppTS)->list); 291 if (tx_rx_select == TX_DIR) { 292 struct tx_ts_record *tmp = 293 container_of(*ppTS, 294 struct tx_ts_record, 295 ts_common_info); 296 ResetTxTsEntry(tmp); 297 } else { 298 struct rx_ts_record *ts = 299 container_of(*ppTS, 300 struct rx_ts_record, 301 ts_common_info); 302 ResetRxTsEntry(ts); 303 } 304 305 netdev_dbg(ieee->dev, 306 "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", 307 UP, Dir, addr, *ppTS); 308 ts_info->ts_id = UP; 309 ts_info->ucDirection = Dir; 310 311 MakeTSEntry(*ppTS, addr, &tspec); 312 list_add_tail(&((*ppTS)->list), pAddmitList); 313 314 return true; 315 } 316 317 netdev_warn(ieee->dev, 318 "There is not enough dir=%d(0=up down=1) TS record to be used!", 319 Dir); 320 return false; 321} 322 323static void RemoveTsEntry(struct rtllib_device *ieee, 324 struct ts_common_info *pTs, enum tr_select tx_rx_select) 325{ 326 rtllib_ts_init_del_ba(ieee, pTs, tx_rx_select); 327 328 if (tx_rx_select == RX_DIR) { 329 struct rx_reorder_entry *pRxReorderEntry; 330 struct rx_ts_record *ts = (struct rx_ts_record *)pTs; 331 332 if (timer_pending(&ts->rx_pkt_pending_timer)) 333 del_timer_sync(&ts->rx_pkt_pending_timer); 334 335 while (!list_empty(&ts->rx_pending_pkt_list)) { 336 pRxReorderEntry = (struct rx_reorder_entry *) 337 list_entry(ts->rx_pending_pkt_list.prev, 338 struct rx_reorder_entry, list); 339 netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n", 340 __func__, pRxReorderEntry->SeqNum); 341 list_del_init(&pRxReorderEntry->list); 342 { 343 int i = 0; 344 struct rtllib_rxb *prxb = pRxReorderEntry->prxb; 345 346 if (unlikely(!prxb)) 347 return; 348 for (i = 0; i < prxb->nr_subframes; i++) 349 dev_kfree_skb(prxb->subframes[i]); 350 kfree(prxb); 351 prxb = NULL; 352 } 353 list_add_tail(&pRxReorderEntry->list, 354 &ieee->RxReorder_Unused_List); 355 } 356 } else { 357 struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; 358 359 del_timer_sync(&pTxTS->ts_add_ba_timer); 360 } 361} 362 363void remove_peer_ts(struct rtllib_device *ieee, u8 *addr) 364{ 365 struct ts_common_info *ts, *pTmpTS; 366 367 netdev_info(ieee->dev, "===========>%s, %pM\n", __func__, addr); 368 369 list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) { 370 if (memcmp(ts->addr, addr, 6) == 0) { 371 RemoveTsEntry(ieee, ts, TX_DIR); 372 list_del_init(&ts->list); 373 list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); 374 } 375 } 376 377 list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) { 378 if (memcmp(ts->addr, addr, 6) == 0) { 379 netdev_info(ieee->dev, 380 "====>remove Tx_TS_admin_list\n"); 381 RemoveTsEntry(ieee, ts, TX_DIR); 382 list_del_init(&ts->list); 383 list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); 384 } 385 } 386 387 list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) { 388 if (memcmp(ts->addr, addr, 6) == 0) { 389 RemoveTsEntry(ieee, ts, RX_DIR); 390 list_del_init(&ts->list); 391 list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); 392 } 393 } 394 395 list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) { 396 if (memcmp(ts->addr, addr, 6) == 0) { 397 RemoveTsEntry(ieee, ts, RX_DIR); 398 list_del_init(&ts->list); 399 list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); 400 } 401 } 402} 403EXPORT_SYMBOL(remove_peer_ts); 404 405void remove_all_ts(struct rtllib_device *ieee) 406{ 407 struct ts_common_info *ts, *pTmpTS; 408 409 list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) { 410 RemoveTsEntry(ieee, ts, TX_DIR); 411 list_del_init(&ts->list); 412 list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); 413 } 414 415 list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) { 416 RemoveTsEntry(ieee, ts, TX_DIR); 417 list_del_init(&ts->list); 418 list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); 419 } 420 421 list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) { 422 RemoveTsEntry(ieee, ts, RX_DIR); 423 list_del_init(&ts->list); 424 list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); 425 } 426 427 list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) { 428 RemoveTsEntry(ieee, ts, RX_DIR); 429 list_del_init(&ts->list); 430 list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); 431 } 432} 433 434void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) 435{ 436 if (pTxTS->add_ba_req_in_progress == false) { 437 pTxTS->add_ba_req_in_progress = true; 438 439 if (pTxTS->add_ba_req_delayed) { 440 netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n"); 441 mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 442 msecs_to_jiffies(TS_ADDBA_DELAY)); 443 } else { 444 netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); 445 mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10); 446 } 447 } else { 448 netdev_dbg(ieee->dev, "BA timer is already added\n"); 449 } 450} 451