Merge tag 'tty-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[linux-2.6-microblaze.git] / drivers / staging / rtl8192e / rtl819x_TSProc.c
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 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                                                   RxTsRecord[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
83 static void TsAddBaProcess(struct timer_list *t)
84 {
85         struct tx_ts_record *pTxTs = from_timer(pTxTs, t, TsAddBaTimer);
86         u8 num = pTxTs->num;
87         struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
88                                      TxTsRecord[num]);
89
90         rtllib_ts_init_add_ba(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
91         netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
92 }
93
94 static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
95 {
96         eth_zero_addr(pTsCommonInfo->addr);
97         memset(&pTsCommonInfo->TSpec, 0, sizeof(struct qos_tsinfo));
98 }
99
100 static void ResetTxTsEntry(struct tx_ts_record *ts)
101 {
102         ResetTsCommonInfo(&ts->TsCommonInfo);
103         ts->TxCurSeq = 0;
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);
110 }
111
112 static 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
120 void rtllib_ts_init(struct rtllib_device *ieee)
121 {
122         struct tx_ts_record *pTxTS  = ieee->TxTsRecord;
123         struct rx_ts_record *rxts  = ieee->RxTsRecord;
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->TsAddBaTimer, TsAddBaProcess, 0);
134
135                 timer_setup(&pTxTS->TxPendingBARecord.timer, rtllib_ba_setup_timeout,
136                             0);
137                 timer_setup(&pTxTS->TxAdmittedBARecord.timer,
138                             rtllib_tx_ba_inact_timeout, 0);
139
140                 ResetTxTsEntry(pTxTS);
141                 list_add_tail(&pTxTS->TsCommonInfo.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
172 static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
173                                                   u8 *addr, u8 TID,
174                                                   enum tr_select TxRxSelect)
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 (TxRxSelect == 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 (TxRxSelect == 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.ucTSID == 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
214 static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *addr,
215                         struct qos_tsinfo *pTSPEC)
216 {
217         if (!pTsCommonInfo)
218                 return;
219
220         memcpy(pTsCommonInfo->addr, addr, 6);
221
222         if (pTSPEC)
223                 memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC,
224                         sizeof(struct qos_tsinfo));
225 }
226
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)
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, TxRxSelect);
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 = (TxRxSelect == TX_DIR) ?
278                                 (&ieee->Tx_TS_Unused_List) :
279                                 (&ieee->Rx_TS_Unused_List);
280
281         pAddmitList = (TxRxSelect == TX_DIR) ?
282                                 (&ieee->Tx_TS_Admit_List) :
283                                 (&ieee->Rx_TS_Admit_List);
284
285         Dir = ((TxRxSelect == 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 (TxRxSelect == TX_DIR) {
292                         struct tx_ts_record *tmp =
293                                 container_of(*ppTS,
294                                 struct tx_ts_record,
295                                 TsCommonInfo);
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->ucTSID = 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
323 static void RemoveTsEntry(struct rtllib_device *ieee,
324                           struct ts_common_info *pTs, enum tr_select TxRxSelect)
325 {
326         rtllib_ts_init_del_ba(ieee, pTs, TxRxSelect);
327
328         if (TxRxSelect == 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->TsAddBaTimer);
360         }
361 }
362
363 void RemovePeerTS(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 }
403 EXPORT_SYMBOL(RemovePeerTS);
404
405 void RemoveAllTS(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
434 void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
435 {
436         if (pTxTS->bAddBaReqInProgress == false) {
437                 pTxTS->bAddBaReqInProgress = true;
438
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));
443                 } else {
444                         netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
445                         mod_timer(&pTxTS->TsAddBaTimer, jiffies + 10);
446                 }
447         } else {
448                 netdev_dbg(ieee->dev, "BA timer is already added\n");
449         }
450 }