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