1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
5 * Contact Information: wlanfae <wlanfae@realtek.com>
8 #include <linux/etherdevice.h>
9 #include "rtl819x_TS.h"
11 static void RxPktPendingTimeout(struct timer_list *t)
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,
17 struct rx_reorder_entry *pReorderEntry = NULL;
19 unsigned long flags = 0;
21 bool bPktInBuf = false;
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);
30 ts->rx_indicate_seq = pReorderEntry->SeqNum;
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);
38 if (SN_EQUAL(pReorderEntry->SeqNum,
41 (ts->rx_indicate_seq + 1) % 4096;
44 "%s(): Indicate SeqNum: %d\n",
45 __func__, pReorderEntry->SeqNum);
46 ieee->stats_IndicateArray[index] =
50 list_add_tail(&pReorderEntry->List,
51 &ieee->RxReorder_Unused_List);
60 ts->rx_timeout_indicate_seq = 0xffff;
62 if (index > REORDER_WIN_SIZE) {
63 netdev_warn(ieee->dev,
64 "%s(): Rx Reorder struct buffer full\n",
66 spin_unlock_irqrestore(&(ieee->reorder_spinlock),
70 rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index);
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)
80 spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
83 static void TsAddBaProcess(struct timer_list *t)
85 struct tx_ts_record *pTxTs = from_timer(pTxTs, t, TsAddBaTimer);
87 struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
90 rtllib_ts_init_add_ba(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
91 netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
94 static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
96 eth_zero_addr(pTsCommonInfo->addr);
97 memset(&pTsCommonInfo->TSpec, 0, sizeof(struct qos_tsinfo));
100 static void ResetTxTsEntry(struct tx_ts_record *ts)
102 ResetTsCommonInfo(&ts->TsCommonInfo);
104 ts->bAddBaReqInProgress = false;
105 ts->bAddBaReqDelayed = false;
106 ts->bUsingBa = false;
107 ts->bDisable_AddBa = false;
108 rtllib_reset_ba_entry(&ts->TxAdmittedBARecord);
109 rtllib_reset_ba_entry(&ts->TxPendingBARecord);
112 static void ResetRxTsEntry(struct rx_ts_record *ts)
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);
120 void rtllib_ts_init(struct rtllib_device *ieee)
122 struct tx_ts_record *pTxTS = ieee->TxTsRecord;
123 struct rx_ts_record *rxts = ieee->RxTsRecord;
124 struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
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);
131 for (count = 0; count < TOTAL_TS_NUM; count++) {
133 timer_setup(&pTxTS->TsAddBaTimer, TsAddBaProcess, 0);
135 timer_setup(&pTxTS->TxPendingBARecord.timer, rtllib_ba_setup_timeout,
137 timer_setup(&pTxTS->TxAdmittedBARecord.timer,
138 rtllib_tx_ba_inact_timeout, 0);
140 ResetTxTsEntry(pTxTS);
141 list_add_tail(&pTxTS->TsCommonInfo.List,
142 &ieee->Tx_TS_Unused_List);
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++) {
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);
155 timer_setup(&rxts->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
157 ResetRxTsEntry(rxts);
158 list_add_tail(&rxts->ts_common_info.List,
159 &ieee->Rx_TS_Unused_List);
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))
168 pRxReorderEntry = &ieee->RxReorderEntry[count + 1];
172 static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
174 enum tr_select TxRxSelect)
177 bool search_dir[4] = {0};
178 struct list_head *psearch_list;
179 struct ts_common_info *pRet = NULL;
181 if (TxRxSelect == TX_DIR) {
182 search_dir[DIR_UP] = true;
183 search_dir[DIR_BI_DIR] = true;
184 search_dir[DIR_DIRECT] = true;
186 search_dir[DIR_DOWN] = true;
187 search_dir[DIR_BI_DIR] = true;
188 search_dir[DIR_DIRECT] = true;
191 if (TxRxSelect == TX_DIR)
192 psearch_list = &ieee->Tx_TS_Admit_List;
194 psearch_list = &ieee->Rx_TS_Admit_List;
196 for (dir = 0; dir <= DIR_BI_DIR; dir++) {
197 if (!search_dir[dir])
199 list_for_each_entry(pRet, psearch_list, List) {
200 if (memcmp(pRet->addr, addr, 6) == 0 &&
201 pRet->TSpec.ucTSID == TID &&
202 pRet->TSpec.ucDirection == dir)
205 if (&pRet->List != psearch_list)
209 if (pRet && &pRet->List != psearch_list)
214 static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *addr,
215 struct qos_tsinfo *pTSPEC)
220 memcpy(pTsCommonInfo->addr, addr, 6);
223 memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC,
224 sizeof(struct qos_tsinfo));
227 bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
228 u8 *addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
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;
237 if (is_multicast_ether_addr(addr)) {
238 netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n");
241 if (ieee->current_network.qos_data.supported == 0) {
262 netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n",
268 *ppTS = SearchAdmitTRStream(ieee, addr, UP, TxRxSelect);
273 netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP);
277 pUnusedList = (TxRxSelect == TX_DIR) ?
278 (&ieee->Tx_TS_Unused_List) :
279 (&ieee->Rx_TS_Unused_List);
281 pAddmitList = (TxRxSelect == TX_DIR) ?
282 (&ieee->Tx_TS_Admit_List) :
283 (&ieee->Rx_TS_Admit_List);
285 Dir = ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
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 (TxRxSelect == TX_DIR) {
292 struct tx_ts_record *tmp =
298 struct rx_ts_record *ts =
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->ucTSID = UP;
309 ts_info->ucDirection = Dir;
311 MakeTSEntry(*ppTS, addr, &TSpec);
312 list_add_tail(&((*ppTS)->List), pAddmitList);
317 netdev_warn(ieee->dev,
318 "There is not enough dir=%d(0=up down=1) TS record to be used!",
323 static void RemoveTsEntry(struct rtllib_device *ieee,
324 struct ts_common_info *pTs, enum tr_select TxRxSelect)
326 rtllib_ts_init_del_ba(ieee, pTs, TxRxSelect);
328 if (TxRxSelect == RX_DIR) {
329 struct rx_reorder_entry *pRxReorderEntry;
330 struct rx_ts_record *ts = (struct rx_ts_record *)pTs;
332 if (timer_pending(&ts->rx_pkt_pending_timer))
333 del_timer_sync(&ts->rx_pkt_pending_timer);
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);
344 struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
348 for (i = 0; i < prxb->nr_subframes; i++)
349 dev_kfree_skb(prxb->subframes[i]);
353 list_add_tail(&pRxReorderEntry->List,
354 &ieee->RxReorder_Unused_List);
357 struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
359 del_timer_sync(&pTxTS->TsAddBaTimer);
363 void RemovePeerTS(struct rtllib_device *ieee, u8 *addr)
365 struct ts_common_info *ts, *pTmpTS;
367 netdev_info(ieee->dev, "===========>%s, %pM\n", __func__, addr);
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);
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);
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);
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);
403 EXPORT_SYMBOL(RemovePeerTS);
405 void RemoveAllTS(struct rtllib_device *ieee)
407 struct ts_common_info *ts, *pTmpTS;
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);
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);
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);
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);
434 void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
436 if (pTxTS->bAddBaReqInProgress == false) {
437 pTxTS->bAddBaReqInProgress = true;
439 if (pTxTS->bAddBaReqDelayed) {
440 netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
441 mod_timer(&pTxTS->TsAddBaTimer, jiffies +
442 msecs_to_jiffies(TS_ADDBA_DELAY));
444 netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
445 mod_timer(&pTxTS->TsAddBaTimer, jiffies + 10);
448 netdev_dbg(ieee->dev, "BA timer is already added\n");