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
11static 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						  rx_ts_records[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
83static void TsAddBaProcess(struct timer_list *t)
84{
85	struct tx_ts_record *ts = from_timer(ts, t, ts_add_ba_timer);
86	u8 num = ts->num;
87	struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
88				     tx_ts_records[num]);
89
90	rtllib_ts_init_add_ba(ieee, ts, BA_POLICY_IMMEDIATE, false);
91	netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
92}
93
94static void ResetTsCommonInfo(struct ts_common_info *ts_common_info)
95{
96	eth_zero_addr(ts_common_info->addr);
97	memset(&ts_common_info->tspec, 0, sizeof(struct qos_tsinfo));
98}
99
100static void ResetTxTsEntry(struct tx_ts_record *ts)
101{
102	ResetTsCommonInfo(&ts->ts_common_info);
103	ts->tx_cur_seq = 0;
104	ts->add_ba_req_in_progress = false;
105	ts->add_ba_req_delayed = false;
106	ts->using_ba = false;
107	ts->disable_add_ba = false;
108	rtllib_reset_ba_entry(&ts->tx_admitted_ba_record);
109	rtllib_reset_ba_entry(&ts->tx_pending_ba_record);
110}
111
112static 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
120void rtllib_ts_init(struct rtllib_device *ieee)
121{
122	struct tx_ts_record *pTxTS  = ieee->tx_ts_records;
123	struct rx_ts_record *rxts  = ieee->rx_ts_records;
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->ts_add_ba_timer, TsAddBaProcess, 0);
134
135		timer_setup(&pTxTS->tx_pending_ba_record.timer, rtllib_ba_setup_timeout,
136			    0);
137		timer_setup(&pTxTS->tx_admitted_ba_record.timer,
138			    rtllib_tx_ba_inact_timeout, 0);
139
140		ResetTxTsEntry(pTxTS);
141		list_add_tail(&pTxTS->ts_common_info.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
172static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
173						  u8 *addr, u8 TID,
174						  enum tr_select tx_rx_select)
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 (tx_rx_select == 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 (tx_rx_select == 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.ts_id == 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
214static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr,
215			struct qos_tsinfo *pTSPEC)
216{
217	if (!ts_common_info)
218		return;
219
220	memcpy(ts_common_info->addr, addr, 6);
221
222	if (pTSPEC)
223		memcpy((u8 *)(&(ts_common_info->tspec)), (u8 *)pTSPEC,
224			sizeof(struct qos_tsinfo));
225}
226
227bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
228	   u8 *addr, u8 TID, enum tr_select tx_rx_select, 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, tx_rx_select);
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 = (tx_rx_select == TX_DIR) ?
278				(&ieee->Tx_TS_Unused_List) :
279				(&ieee->Rx_TS_Unused_List);
280
281	pAddmitList = (tx_rx_select == TX_DIR) ?
282				(&ieee->Tx_TS_Admit_List) :
283				(&ieee->Rx_TS_Admit_List);
284
285	Dir = ((tx_rx_select == 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 (tx_rx_select == TX_DIR) {
292			struct tx_ts_record *tmp =
293				container_of(*ppTS,
294				struct tx_ts_record,
295				ts_common_info);
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->ts_id = 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
323static void RemoveTsEntry(struct rtllib_device *ieee,
324			  struct ts_common_info *pTs, enum tr_select tx_rx_select)
325{
326	rtllib_ts_init_del_ba(ieee, pTs, tx_rx_select);
327
328	if (tx_rx_select == 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->ts_add_ba_timer);
360	}
361}
362
363void remove_peer_ts(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}
403EXPORT_SYMBOL(remove_peer_ts);
404
405void remove_all_ts(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
434void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
435{
436	if (pTxTS->add_ba_req_in_progress == false) {
437		pTxTS->add_ba_req_in_progress = true;
438
439		if (pTxTS->add_ba_req_delayed) {
440			netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
441			mod_timer(&pTxTS->ts_add_ba_timer, jiffies +
442				  msecs_to_jiffies(TS_ADDBA_DELAY));
443		} else {
444			netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
445			mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10);
446		}
447	} else {
448		netdev_dbg(ieee->dev, "BA timer is already added\n");
449	}
450}
451