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