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 * The full GNU General Public License is included in this distribution in the
10 * file called LICENSE.
11 *
12 * Contact Information:
13 * wlanfae <wlanfae@realtek.com>
14******************************************************************************/
15#include "rtllib.h"
16#include <linux/etherdevice.h>
17#include "rtl819x_TS.h"
18
19static void TsSetupTimeOut(unsigned long data)
20{
21}
22
23static void TsInactTimeout(unsigned long data)
24{
25}
26
27static void RxPktPendingTimeout(unsigned long data)
28{
29	struct rx_ts_record *pRxTs = (struct rx_ts_record *)data;
30	struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device,
31						  RxTsRecord[pRxTs->num]);
32
33	struct rx_reorder_entry *pReorderEntry = NULL;
34
35	unsigned long flags = 0;
36	u8 index = 0;
37	bool bPktInBuf = false;
38
39	spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
40	if (pRxTs->RxTimeoutIndicateSeq != 0xffff) {
41		while (!list_empty(&pRxTs->RxPendingPktList)) {
42			pReorderEntry = (struct rx_reorder_entry *)
43					list_entry(pRxTs->RxPendingPktList.prev,
44					struct rx_reorder_entry, List);
45			if (index == 0)
46				pRxTs->RxIndicateSeq = pReorderEntry->SeqNum;
47
48			if (SN_LESS(pReorderEntry->SeqNum,
49				    pRxTs->RxIndicateSeq) ||
50			    SN_EQUAL(pReorderEntry->SeqNum,
51				     pRxTs->RxIndicateSeq)) {
52				list_del_init(&pReorderEntry->List);
53
54				if (SN_EQUAL(pReorderEntry->SeqNum,
55				    pRxTs->RxIndicateSeq))
56					pRxTs->RxIndicateSeq =
57					      (pRxTs->RxIndicateSeq + 1) % 4096;
58
59				netdev_dbg(ieee->dev,
60					   "%s(): Indicate SeqNum: %d\n",
61					   __func__, pReorderEntry->SeqNum);
62				ieee->stats_IndicateArray[index] =
63							 pReorderEntry->prxb;
64				index++;
65
66				list_add_tail(&pReorderEntry->List,
67					      &ieee->RxReorder_Unused_List);
68			} else {
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			netdev_warn(ieee->dev,
80				    "%s(): Rx Reorder struct buffer full\n",
81				    __func__);
82			spin_unlock_irqrestore(&(ieee->reorder_spinlock),
83					       flags);
84			return;
85		}
86		rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index);
87		bPktInBuf = false;
88	}
89
90	if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) {
91		pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq;
92		mod_timer(&pRxTs->RxPktPendingTimer,  jiffies +
93			  msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime)
94			  );
95	}
96	spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
97}
98
99static 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	netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
108}
109
110static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
111{
112	eth_zero_addr(pTsCommonInfo->Addr);
113	memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body));
114	memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM);
115	pTsCommonInfo->TClasProc = 0;
116	pTsCommonInfo->TClasNum = 0;
117}
118
119static void ResetTxTsEntry(struct tx_ts_record *pTS)
120{
121	ResetTsCommonInfo(&pTS->TsCommonInfo);
122	pTS->TxCurSeq = 0;
123	pTS->bAddBaReqInProgress = false;
124	pTS->bAddBaReqDelayed = false;
125	pTS->bUsingBa = false;
126	pTS->bDisable_AddBa = false;
127	ResetBaEntry(&pTS->TxAdmittedBARecord);
128	ResetBaEntry(&pTS->TxPendingBARecord);
129}
130
131static void ResetRxTsEntry(struct rx_ts_record *pTS)
132{
133	ResetTsCommonInfo(&pTS->TsCommonInfo);
134	pTS->RxIndicateSeq = 0xffff;
135	pTS->RxTimeoutIndicateSeq = 0xffff;
136	ResetBaEntry(&pTS->RxAdmittedBARecord);
137}
138
139void TSInitialize(struct rtllib_device *ieee)
140{
141	struct tx_ts_record *pTxTS  = ieee->TxTsRecord;
142	struct rx_ts_record *pRxTS  = ieee->RxTsRecord;
143	struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
144	u8				count = 0;
145
146	netdev_vdbg(ieee->dev, "%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,
154			    TsSetupTimeOut,
155			    (unsigned long) pTxTS);
156
157		setup_timer(&pTxTS->TsCommonInfo.InactTimer,
158			    TsInactTimeout,
159			    (unsigned long) pTxTS);
160
161		setup_timer(&pTxTS->TsAddBaTimer,
162			    TsAddBaProcess,
163			    (unsigned long) pTxTS);
164
165		setup_timer(&pTxTS->TxPendingBARecord.Timer,
166			    BaSetupTimeOut,
167			    (unsigned long) pTxTS);
168		setup_timer(&pTxTS->TxAdmittedBARecord.Timer,
169			    TxBaInactTimeout,
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,
186			    TsSetupTimeOut,
187			    (unsigned long) pRxTS);
188
189		setup_timer(&pRxTS->TsCommonInfo.InactTimer,
190			    TsInactTimeout,
191			    (unsigned long) pRxTS);
192
193		setup_timer(&pRxTS->RxAdmittedBARecord.Timer,
194			    RxBaInactTimeout,
195			    (unsigned long) pRxTS);
196
197		setup_timer(&pRxTS->RxPktPendingTimer,
198			    RxPktPendingTimeout,
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
217static 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_to_jiffies(InactTime));
226}
227
228static 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
237	if (ieee->iw_mode == IW_MODE_MASTER) {
238		if (TxRxSelect == TX_DIR) {
239			search_dir[DIR_DOWN] = true;
240			search_dir[DIR_BI_DIR] = true;
241		} else {
242			search_dir[DIR_UP] = true;
243			search_dir[DIR_BI_DIR] = true;
244		}
245	} else if (ieee->iw_mode == IW_MODE_ADHOC) {
246		if (TxRxSelect == TX_DIR)
247			search_dir[DIR_UP] = true;
248		else
249			search_dir[DIR_DOWN] = true;
250	} else {
251		if (TxRxSelect == TX_DIR) {
252			search_dir[DIR_UP] = true;
253			search_dir[DIR_BI_DIR] = true;
254			search_dir[DIR_DIRECT] = true;
255		} else {
256			search_dir[DIR_DOWN] = true;
257			search_dir[DIR_BI_DIR] = true;
258			search_dir[DIR_DIRECT] = true;
259		}
260	}
261
262	if (TxRxSelect == TX_DIR)
263		psearch_list = &ieee->Tx_TS_Admit_List;
264	else
265		psearch_list = &ieee->Rx_TS_Admit_List;
266
267	for (dir = 0; dir <= DIR_BI_DIR; dir++) {
268		if (!search_dir[dir])
269			continue;
270		list_for_each_entry(pRet, psearch_list, List) {
271			if (memcmp(pRet->Addr, Addr, 6) == 0 &&
272			    pRet->TSpec.f.TSInfo.field.ucTSID == TID &&
273			    pRet->TSpec.f.TSInfo.field.ucDirection == dir)
274				break;
275
276		}
277		if (&pRet->List  != psearch_list)
278			break;
279	}
280
281	if (pRet && &pRet->List  != psearch_list)
282		return pRet;
283	return NULL;
284}
285
286static 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
309bool 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	union tspec_body TSpec;
314	union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo;
315	struct list_head *pUnusedList;
316	struct list_head *pAddmitList;
317	enum direction_value Dir;
318
319	if (is_multicast_ether_addr(Addr)) {
320		netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n");
321		return false;
322	}
323	if (ieee->current_network.qos_data.supported == 0) {
324		UP = 0;
325	} else {
326		if (!IsACValid(TID)) {
327			netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n",
328				    __func__, TID);
329			return false;
330		}
331
332		switch (TID) {
333		case 0:
334		case 3:
335			UP = 0;
336			break;
337		case 1:
338		case 2:
339			UP = 2;
340			break;
341		case 4:
342		case 5:
343			UP = 5;
344			break;
345		case 6:
346		case 7:
347			UP = 7;
348			break;
349		}
350	}
351
352	*ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect);
353	if (*ppTS != NULL)
354		return true;
355
356	if (!bAddNewTs) {
357		netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP);
358		return false;
359	}
360
361	pUnusedList = (TxRxSelect == TX_DIR) ?
362				(&ieee->Tx_TS_Unused_List) :
363				(&ieee->Rx_TS_Unused_List);
364
365	pAddmitList = (TxRxSelect == TX_DIR) ?
366				(&ieee->Tx_TS_Admit_List) :
367				(&ieee->Rx_TS_Admit_List);
368
369	Dir = (ieee->iw_mode == IW_MODE_MASTER) ?
370				((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) :
371				((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
372
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		netdev_dbg(ieee->dev,
392			   "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n",
393			   UP, Dir, Addr, *ppTS);
394		pTSInfo->field.ucTrafficType = 0;
395		pTSInfo->field.ucTSID = UP;
396		pTSInfo->field.ucDirection = Dir;
397		pTSInfo->field.ucAccessPolicy = 1;
398		pTSInfo->field.ucAggregation = 0;
399		pTSInfo->field.ucPSB = 0;
400		pTSInfo->field.ucUP = UP;
401		pTSInfo->field.ucTSInfoAckPolicy = 0;
402		pTSInfo->field.ucSchedule = 0;
403
404		MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
405		AdmitTS(ieee, *ppTS, 0);
406		list_add_tail(&((*ppTS)->List), pAddmitList);
407
408		return true;
409	}
410
411	netdev_warn(ieee->dev,
412		    "There is not enough dir=%d(0=up down=1) TS record to be used!",
413		    Dir);
414	return false;
415}
416
417static void RemoveTsEntry(struct rtllib_device *ieee,
418			  struct ts_common_info *pTs, enum tr_select TxRxSelect)
419{
420	del_timer_sync(&pTs->SetupTimer);
421	del_timer_sync(&pTs->InactTimer);
422	TsInitDelBA(ieee, pTs, TxRxSelect);
423
424	if (TxRxSelect == RX_DIR) {
425		struct rx_reorder_entry *pRxReorderEntry;
426		struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs;
427
428		if (timer_pending(&pRxTS->RxPktPendingTimer))
429			del_timer_sync(&pRxTS->RxPktPendingTimer);
430
431		while (!list_empty(&pRxTS->RxPendingPktList)) {
432			pRxReorderEntry = (struct rx_reorder_entry *)
433					list_entry(pRxTS->RxPendingPktList.prev,
434					struct rx_reorder_entry, List);
435			netdev_dbg(ieee->dev,  "%s(): Delete SeqNum %d!\n",
436				   __func__, pRxReorderEntry->SeqNum);
437			list_del_init(&pRxReorderEntry->List);
438			{
439				int i = 0;
440				struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
441
442				if (unlikely(!prxb))
443					return;
444				for (i = 0; i < prxb->nr_subframes; i++)
445					dev_kfree_skb(prxb->subframes[i]);
446				kfree(prxb);
447				prxb = NULL;
448			}
449			list_add_tail(&pRxReorderEntry->List,
450				      &ieee->RxReorder_Unused_List);
451		}
452	} else {
453		struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
454
455		del_timer_sync(&pTxTS->TsAddBaTimer);
456	}
457}
458
459void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr)
460{
461	struct ts_common_info *pTS, *pTmpTS;
462
463	netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr);
464
465	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
466		if (memcmp(pTS->Addr, Addr, 6) == 0) {
467			RemoveTsEntry(ieee, pTS, TX_DIR);
468			list_del_init(&pTS->List);
469			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
470		}
471	}
472
473	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
474		if (memcmp(pTS->Addr, Addr, 6) == 0) {
475			netdev_info(ieee->dev,
476				    "====>remove Tx_TS_admin_list\n");
477			RemoveTsEntry(ieee, pTS, TX_DIR);
478			list_del_init(&pTS->List);
479			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
480		}
481	}
482
483	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
484		if (memcmp(pTS->Addr, Addr, 6) == 0) {
485			RemoveTsEntry(ieee, pTS, RX_DIR);
486			list_del_init(&pTS->List);
487			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
488		}
489	}
490
491	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
492		if (memcmp(pTS->Addr, Addr, 6) == 0) {
493			RemoveTsEntry(ieee, pTS, RX_DIR);
494			list_del_init(&pTS->List);
495			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
496		}
497	}
498}
499EXPORT_SYMBOL(RemovePeerTS);
500
501void RemoveAllTS(struct rtllib_device *ieee)
502{
503	struct ts_common_info *pTS, *pTmpTS;
504
505	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
506		RemoveTsEntry(ieee, pTS, TX_DIR);
507		list_del_init(&pTS->List);
508		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
509	}
510
511	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
512		RemoveTsEntry(ieee, pTS, TX_DIR);
513		list_del_init(&pTS->List);
514		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
515	}
516
517	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
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	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
524		RemoveTsEntry(ieee, pTS, RX_DIR);
525		list_del_init(&pTS->List);
526		list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
527	}
528}
529
530void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
531{
532	if (pTxTS->bAddBaReqInProgress == false) {
533		pTxTS->bAddBaReqInProgress = true;
534
535		if (pTxTS->bAddBaReqDelayed) {
536			netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
537			mod_timer(&pTxTS->TsAddBaTimer, jiffies +
538				  msecs_to_jiffies(TS_ADDBA_DELAY));
539		} else {
540			netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
541			mod_timer(&pTxTS->TsAddBaTimer, jiffies+10);
542		}
543	} else
544		netdev_dbg(ieee->dev, "BA timer is already added\n");
545}
546