xref: /linux/drivers/staging/rtl8192e/rtl819x_TSProc.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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 
RxPktPendingTimeout(struct timer_list * t)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 						  rx_ts_records[ts->num]);
16 
17 	struct rx_reorder_entry *reorder_entry = NULL;
18 
19 	unsigned long flags = 0;
20 	u8 index = 0;
21 	bool pkt_in_buf = 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 			reorder_entry = (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 = reorder_entry->seq_num;
31 
32 			if (SN_LESS(reorder_entry->seq_num,
33 				    ts->rx_indicate_seq) ||
34 			    SN_EQUAL(reorder_entry->seq_num,
35 				     ts->rx_indicate_seq)) {
36 				list_del_init(&reorder_entry->list);
37 
38 				if (SN_EQUAL(reorder_entry->seq_num,
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 seq_num: %d\n",
45 					   __func__, reorder_entry->seq_num);
46 				ieee->stats_IndicateArray[index] =
47 							 reorder_entry->prxb;
48 				index++;
49 
50 				list_add_tail(&reorder_entry->list,
51 					      &ieee->RxReorder_Unused_List);
52 			} else {
53 				pkt_in_buf = 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 		pkt_in_buf = false;
72 	}
73 
74 	if (pkt_in_buf && (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 
TsAddBaProcess(struct timer_list * t)83 static 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 
ResetTsCommonInfo(struct ts_common_info * ts_common_info)94 static 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 
ResetTxTsEntry(struct tx_ts_record * ts)100 static 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 
ResetRxTsEntry(struct rx_ts_record * ts)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 
rtllib_ts_init(struct rtllib_device * ieee)120 void 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 
SearchAdmitTRStream(struct rtllib_device * ieee,u8 * addr,u8 TID,enum tr_select tx_rx_select)172 static 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 
MakeTSEntry(struct ts_common_info * ts_common_info,u8 * addr,struct qos_tsinfo * pTSPEC)214 static 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 
rtllib_get_ts(struct rtllib_device * ieee,struct ts_common_info ** ppTS,u8 * addr,u8 TID,enum tr_select tx_rx_select,bool add_new_ts)227 bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
228 	   u8 *addr, u8 TID, enum tr_select tx_rx_select, bool add_new_ts)
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 (!add_new_ts) {
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 
RemoveTsEntry(struct rtllib_device * ieee,struct ts_common_info * pTs,enum tr_select tx_rx_select)323 static 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 seq_num %d!\n",
340 				   __func__, pRxReorderEntry->seq_num);
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 
remove_peer_ts(struct rtllib_device * ieee,u8 * addr)363 void 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 }
403 EXPORT_SYMBOL(remove_peer_ts);
404 
remove_all_ts(struct rtllib_device * ieee)405 void 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 
rtllib_ts_start_add_ba_process(struct rtllib_device * ieee,struct tx_ts_record * pTxTS)434 void rtllib_ts_start_add_ba_process(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