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