]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/mwifiex/11n_rxreorder.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / net / wireless / mwifiex / 11n_rxreorder.c
1 /*
2  * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
3  *
4  * Copyright (C) 2011-2014, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8  * (the "License").  You may use, redistribute and/or modify this File in
9  * accordance with the terms and conditions of the License, a copy of which
10  * is available by writing to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13  *
14  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
17  * this warranty disclaimer.
18  */
19
20 #include "decl.h"
21 #include "ioctl.h"
22 #include "util.h"
23 #include "fw.h"
24 #include "main.h"
25 #include "wmm.h"
26 #include "11n.h"
27 #include "11n_rxreorder.h"
28
29 /* This function will dispatch amsdu packet and forward it to kernel/upper
30  * layer.
31  */
32 static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
33                                           struct sk_buff *skb)
34 {
35         struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
36         int ret;
37
38         if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
39                 struct sk_buff_head list;
40                 struct sk_buff *rx_skb;
41
42                 __skb_queue_head_init(&list);
43
44                 skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
45                 skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
46
47                 ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
48                                          priv->wdev.iftype, 0, false);
49
50                 while (!skb_queue_empty(&list)) {
51                         rx_skb = __skb_dequeue(&list);
52                         ret = mwifiex_recv_packet(priv, rx_skb);
53                         if (ret == -1)
54                                 mwifiex_dbg(priv->adapter, ERROR,
55                                             "Rx of A-MSDU failed");
56                 }
57                 return 0;
58         }
59
60         return -1;
61 }
62
63 /* This function will process the rx packet and forward it to kernel/upper
64  * layer.
65  */
66 static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
67 {
68         int ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
69
70         if (!ret)
71                 return 0;
72
73         if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
74                 return mwifiex_handle_uap_rx_forward(priv, payload);
75
76         return mwifiex_process_rx_packet(priv, payload);
77 }
78
79 /*
80  * This function dispatches all packets in the Rx reorder table until the
81  * start window.
82  *
83  * There could be holes in the buffer, which are skipped by the function.
84  * Since the buffer is linear, the function uses rotation to simulate
85  * circular buffer.
86  */
87 static void
88 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
89                                          struct mwifiex_rx_reorder_tbl *tbl,
90                                          int start_win)
91 {
92         int pkt_to_send, i;
93         void *rx_tmp_ptr;
94         unsigned long flags;
95
96         pkt_to_send = (start_win > tbl->start_win) ?
97                       min((start_win - tbl->start_win), tbl->win_size) :
98                       tbl->win_size;
99
100         for (i = 0; i < pkt_to_send; ++i) {
101                 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
102                 rx_tmp_ptr = NULL;
103                 if (tbl->rx_reorder_ptr[i]) {
104                         rx_tmp_ptr = tbl->rx_reorder_ptr[i];
105                         tbl->rx_reorder_ptr[i] = NULL;
106                 }
107                 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
108                 if (rx_tmp_ptr)
109                         mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
110         }
111
112         spin_lock_irqsave(&priv->rx_pkt_lock, flags);
113         /*
114          * We don't have a circular buffer, hence use rotation to simulate
115          * circular buffer
116          */
117         for (i = 0; i < tbl->win_size - pkt_to_send; ++i) {
118                 tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i];
119                 tbl->rx_reorder_ptr[pkt_to_send + i] = NULL;
120         }
121
122         tbl->start_win = start_win;
123         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
124 }
125
126 /*
127  * This function dispatches all packets in the Rx reorder table until
128  * a hole is found.
129  *
130  * The start window is adjusted automatically when a hole is located.
131  * Since the buffer is linear, the function uses rotation to simulate
132  * circular buffer.
133  */
134 static void
135 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
136                               struct mwifiex_rx_reorder_tbl *tbl)
137 {
138         int i, j, xchg;
139         void *rx_tmp_ptr;
140         unsigned long flags;
141
142         for (i = 0; i < tbl->win_size; ++i) {
143                 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
144                 if (!tbl->rx_reorder_ptr[i]) {
145                         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
146                         break;
147                 }
148                 rx_tmp_ptr = tbl->rx_reorder_ptr[i];
149                 tbl->rx_reorder_ptr[i] = NULL;
150                 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
151                 mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
152         }
153
154         spin_lock_irqsave(&priv->rx_pkt_lock, flags);
155         /*
156          * We don't have a circular buffer, hence use rotation to simulate
157          * circular buffer
158          */
159         if (i > 0) {
160                 xchg = tbl->win_size - i;
161                 for (j = 0; j < xchg; ++j) {
162                         tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j];
163                         tbl->rx_reorder_ptr[i + j] = NULL;
164                 }
165         }
166         tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
167         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
168 }
169
170 /*
171  * This function deletes the Rx reorder table and frees the memory.
172  *
173  * The function stops the associated timer and dispatches all the
174  * pending packets in the Rx reorder table before deletion.
175  */
176 static void
177 mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
178                              struct mwifiex_rx_reorder_tbl *tbl)
179 {
180         unsigned long flags;
181         int start_win;
182
183         if (!tbl)
184                 return;
185
186         spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
187         priv->adapter->rx_locked = true;
188         if (priv->adapter->rx_processing) {
189                 spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
190                 flush_workqueue(priv->adapter->rx_workqueue);
191         } else {
192                 spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
193         }
194
195         start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
196         mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
197
198         del_timer_sync(&tbl->timer_context.timer);
199         tbl->timer_context.timer_is_set = false;
200
201         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
202         list_del(&tbl->list);
203         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
204
205         kfree(tbl->rx_reorder_ptr);
206         kfree(tbl);
207
208         spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
209         priv->adapter->rx_locked = false;
210         spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
211
212 }
213
214 /*
215  * This function returns the pointer to an entry in Rx reordering
216  * table which matches the given TA/TID pair.
217  */
218 struct mwifiex_rx_reorder_tbl *
219 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
220 {
221         struct mwifiex_rx_reorder_tbl *tbl;
222         unsigned long flags;
223
224         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
225         list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
226                 if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
227                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
228                                                flags);
229                         return tbl;
230                 }
231         }
232         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
233
234         return NULL;
235 }
236
237 /* This function retrieves the pointer to an entry in Rx reordering
238  * table which matches the given TA and deletes it.
239  */
240 void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
241 {
242         struct mwifiex_rx_reorder_tbl *tbl, *tmp;
243         unsigned long flags;
244
245         if (!ta)
246                 return;
247
248         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
249         list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
250                 if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
251                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
252                                                flags);
253                         mwifiex_del_rx_reorder_entry(priv, tbl);
254                         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
255                 }
256         }
257         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
258
259         return;
260 }
261
262 /*
263  * This function finds the last sequence number used in the packets
264  * buffered in Rx reordering table.
265  */
266 static int
267 mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
268 {
269         struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
270         struct mwifiex_private *priv = ctx->priv;
271         unsigned long flags;
272         int i;
273
274         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
275         for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
276                 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
277                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
278                                                flags);
279                         return i;
280                 }
281         }
282         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
283
284         return -1;
285 }
286
287 /*
288  * This function flushes all the packets in Rx reordering table.
289  *
290  * The function checks if any packets are currently buffered in the
291  * table or not. In case there are packets available, it dispatches
292  * them and then dumps the Rx reordering table.
293  */
294 static void
295 mwifiex_flush_data(unsigned long context)
296 {
297         struct reorder_tmr_cnxt *ctx =
298                 (struct reorder_tmr_cnxt *) context;
299         int start_win, seq_num;
300
301         ctx->timer_is_set = false;
302         seq_num = mwifiex_11n_find_last_seq_num(ctx);
303
304         if (seq_num < 0)
305                 return;
306
307         mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
308         start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
309         mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
310                                                  start_win);
311 }
312
313 /*
314  * This function creates an entry in Rx reordering table for the
315  * given TA/TID.
316  *
317  * The function also initializes the entry with sequence number, window
318  * size as well as initializes the timer.
319  *
320  * If the received TA/TID pair is already present, all the packets are
321  * dispatched and the window size is moved until the SSN.
322  */
323 static void
324 mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
325                                   int tid, int win_size, int seq_num)
326 {
327         int i;
328         struct mwifiex_rx_reorder_tbl *tbl, *new_node;
329         u16 last_seq = 0;
330         unsigned long flags;
331         struct mwifiex_sta_node *node;
332
333         /*
334          * If we get a TID, ta pair which is already present dispatch all the
335          * the packets and move the window size until the ssn
336          */
337         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
338         if (tbl) {
339                 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
340                 return;
341         }
342         /* if !tbl then create one */
343         new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
344         if (!new_node)
345                 return;
346
347         INIT_LIST_HEAD(&new_node->list);
348         new_node->tid = tid;
349         memcpy(new_node->ta, ta, ETH_ALEN);
350         new_node->start_win = seq_num;
351         new_node->init_win = seq_num;
352         new_node->flags = 0;
353
354         spin_lock_irqsave(&priv->sta_list_spinlock, flags);
355         if (mwifiex_queuing_ra_based(priv)) {
356                 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
357                         node = mwifiex_get_sta_entry(priv, ta);
358                         if (node)
359                                 last_seq = node->rx_seq[tid];
360                 }
361         } else {
362                 node = mwifiex_get_sta_entry(priv, ta);
363                 if (node)
364                         last_seq = node->rx_seq[tid];
365                 else
366                         last_seq = priv->rx_seq[tid];
367         }
368         spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
369
370         mwifiex_dbg(priv->adapter, INFO,
371                     "info: last_seq=%d start_win=%d\n",
372                     last_seq, new_node->start_win);
373
374         if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
375             last_seq >= new_node->start_win) {
376                 new_node->start_win = last_seq + 1;
377                 new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
378         }
379
380         new_node->win_size = win_size;
381
382         new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
383                                         GFP_KERNEL);
384         if (!new_node->rx_reorder_ptr) {
385                 kfree((u8 *) new_node);
386                 mwifiex_dbg(priv->adapter, ERROR,
387                             "%s: failed to alloc reorder_ptr\n", __func__);
388                 return;
389         }
390
391         new_node->timer_context.ptr = new_node;
392         new_node->timer_context.priv = priv;
393         new_node->timer_context.timer_is_set = false;
394
395         setup_timer(&new_node->timer_context.timer, mwifiex_flush_data,
396                     (unsigned long)&new_node->timer_context);
397
398         for (i = 0; i < win_size; ++i)
399                 new_node->rx_reorder_ptr[i] = NULL;
400
401         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
402         list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
403         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
404 }
405
406 static void
407 mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
408 {
409         u32 min_flush_time;
410
411         if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
412                 min_flush_time = MIN_FLUSH_TIMER_15_MS;
413         else
414                 min_flush_time = MIN_FLUSH_TIMER_MS;
415
416         mod_timer(&tbl->timer_context.timer,
417                   jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
418
419         tbl->timer_context.timer_is_set = true;
420 }
421
422 /*
423  * This function prepares command for adding a BA request.
424  *
425  * Preparation includes -
426  *      - Setting command ID and proper size
427  *      - Setting add BA request buffer
428  *      - Ensuring correct endian-ness
429  */
430 int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
431 {
432         struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
433
434         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
435         cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
436         memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
437
438         return 0;
439 }
440
441 /*
442  * This function prepares command for adding a BA response.
443  *
444  * Preparation includes -
445  *      - Setting command ID and proper size
446  *      - Setting add BA response buffer
447  *      - Ensuring correct endian-ness
448  */
449 int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
450                                   struct host_cmd_ds_command *cmd,
451                                   struct host_cmd_ds_11n_addba_req
452                                   *cmd_addba_req)
453 {
454         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
455         struct mwifiex_sta_node *sta_ptr;
456         u32 rx_win_size = priv->add_ba_param.rx_win_size;
457         u8 tid;
458         int win_size;
459         unsigned long flags;
460         uint16_t block_ack_param_set;
461
462         if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
463             ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
464             priv->adapter->is_hw_11ac_capable &&
465             memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
466                 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
467                 sta_ptr = mwifiex_get_sta_entry(priv,
468                                                 cmd_addba_req->peer_mac_addr);
469                 if (!sta_ptr) {
470                         spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
471                         mwifiex_dbg(priv->adapter, ERROR,
472                                     "BA setup with unknown TDLS peer %pM!\n",
473                                     cmd_addba_req->peer_mac_addr);
474                         return -1;
475                 }
476                 if (sta_ptr->is_11ac_enabled)
477                         rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
478                 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
479         }
480
481         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
482         cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
483
484         memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
485                ETH_ALEN);
486         add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
487         add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
488         add_ba_rsp->ssn = cmd_addba_req->ssn;
489
490         block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
491         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
492                 >> BLOCKACKPARAM_TID_POS;
493         add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
494         block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
495
496         /* If we don't support AMSDU inside AMPDU, reset the bit */
497         if (!priv->add_ba_param.rx_amsdu ||
498             (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
499                 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
500         block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
501         add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
502         win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
503                                         & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
504                                         >> BLOCKACKPARAM_WINSIZE_POS;
505         cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
506
507         mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
508                                           tid, win_size,
509                                           le16_to_cpu(cmd_addba_req->ssn));
510         return 0;
511 }
512
513 /*
514  * This function prepares command for deleting a BA request.
515  *
516  * Preparation includes -
517  *      - Setting command ID and proper size
518  *      - Setting del BA request buffer
519  *      - Ensuring correct endian-ness
520  */
521 int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
522 {
523         struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
524
525         cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
526         cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
527         memcpy(del_ba, data_buf, sizeof(*del_ba));
528
529         return 0;
530 }
531
532 /*
533  * This function identifies if Rx reordering is needed for a received packet.
534  *
535  * In case reordering is required, the function will do the reordering
536  * before sending it to kernel.
537  *
538  * The Rx reorder table is checked first with the received TID/TA pair. If
539  * not found, the received packet is dispatched immediately. But if found,
540  * the packet is reordered and all the packets in the updated Rx reordering
541  * table is dispatched until a hole is found.
542  *
543  * For sequence number less than the starting window, the packet is dropped.
544  */
545 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
546                                 u16 seq_num, u16 tid,
547                                 u8 *ta, u8 pkt_type, void *payload)
548 {
549         struct mwifiex_rx_reorder_tbl *tbl;
550         int prev_start_win, start_win, end_win, win_size;
551         u16 pkt_index;
552         bool init_window_shift = false;
553         int ret = 0;
554
555         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
556         if (!tbl) {
557                 if (pkt_type != PKT_TYPE_BAR)
558                         mwifiex_11n_dispatch_pkt(priv, payload);
559                 return ret;
560         }
561
562         if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
563                 mwifiex_11n_dispatch_pkt(priv, payload);
564                 return ret;
565         }
566
567         start_win = tbl->start_win;
568         prev_start_win = start_win;
569         win_size = tbl->win_size;
570         end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
571         if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
572                 init_window_shift = true;
573                 tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
574         }
575
576         if (tbl->flags & RXREOR_FORCE_NO_DROP) {
577                 mwifiex_dbg(priv->adapter, INFO,
578                             "RXREOR_FORCE_NO_DROP when HS is activated\n");
579                 tbl->flags &= ~RXREOR_FORCE_NO_DROP;
580         } else if (init_window_shift && seq_num < start_win &&
581                    seq_num >= tbl->init_win) {
582                 mwifiex_dbg(priv->adapter, INFO,
583                             "Sender TID sequence number reset %d->%d for SSN %d\n",
584                             start_win, seq_num, tbl->init_win);
585                 tbl->start_win = start_win = seq_num;
586                 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
587         } else {
588                 /*
589                  * If seq_num is less then starting win then ignore and drop
590                  * the packet
591                  */
592                 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
593                         if (seq_num >= ((start_win + TWOPOW11) &
594                                         (MAX_TID_VALUE - 1)) &&
595                             seq_num < start_win) {
596                                 ret = -1;
597                                 goto done;
598                         }
599                 } else if ((seq_num < start_win) ||
600                            (seq_num >= (start_win + TWOPOW11))) {
601                         ret = -1;
602                         goto done;
603                 }
604         }
605
606         /*
607          * If this packet is a BAR we adjust seq_num as
608          * WinStart = seq_num
609          */
610         if (pkt_type == PKT_TYPE_BAR)
611                 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
612
613         if (((end_win < start_win) &&
614              (seq_num < start_win) && (seq_num > end_win)) ||
615             ((end_win > start_win) && ((seq_num > end_win) ||
616                                        (seq_num < start_win)))) {
617                 end_win = seq_num;
618                 if (((end_win - win_size) + 1) >= 0)
619                         start_win = (end_win - win_size) + 1;
620                 else
621                         start_win = (MAX_TID_VALUE - (win_size - end_win)) + 1;
622                 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
623         }
624
625         if (pkt_type != PKT_TYPE_BAR) {
626                 if (seq_num >= start_win)
627                         pkt_index = seq_num - start_win;
628                 else
629                         pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
630
631                 if (tbl->rx_reorder_ptr[pkt_index]) {
632                         ret = -1;
633                         goto done;
634                 }
635
636                 tbl->rx_reorder_ptr[pkt_index] = payload;
637         }
638
639         /*
640          * Dispatch all packets sequentially from start_win until a
641          * hole is found and adjust the start_win appropriately
642          */
643         mwifiex_11n_scan_and_dispatch(priv, tbl);
644
645 done:
646         if (!tbl->timer_context.timer_is_set ||
647             prev_start_win != tbl->start_win)
648                 mwifiex_11n_rxreorder_timer_restart(tbl);
649         return ret;
650 }
651
652 /*
653  * This function deletes an entry for a given TID/TA pair.
654  *
655  * The TID/TA are taken from del BA event body.
656  */
657 void
658 mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
659                    u8 type, int initiator)
660 {
661         struct mwifiex_rx_reorder_tbl *tbl;
662         struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
663         struct mwifiex_ra_list_tbl *ra_list;
664         u8 cleanup_rx_reorder_tbl;
665         unsigned long flags;
666         int tid_down;
667
668         if (type == TYPE_DELBA_RECEIVE)
669                 cleanup_rx_reorder_tbl = (initiator) ? true : false;
670         else
671                 cleanup_rx_reorder_tbl = (initiator) ? false : true;
672
673         mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
674                     peer_mac, tid, initiator);
675
676         if (cleanup_rx_reorder_tbl) {
677                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
678                                                                  peer_mac);
679                 if (!tbl) {
680                         mwifiex_dbg(priv->adapter, EVENT,
681                                     "event: TID, TA not found in table\n");
682                         return;
683                 }
684                 mwifiex_del_rx_reorder_entry(priv, tbl);
685         } else {
686                 ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
687                 if (!ptx_tbl) {
688                         mwifiex_dbg(priv->adapter, EVENT,
689                                     "event: TID, RA not found in table\n");
690                         return;
691                 }
692
693                 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
694                 ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
695                 if (ra_list) {
696                         ra_list->amsdu_in_ampdu = false;
697                         ra_list->ba_status = BA_SETUP_NONE;
698                 }
699                 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
700                 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
701                 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
702         }
703 }
704
705 /*
706  * This function handles the command response of an add BA response.
707  *
708  * Handling includes changing the header fields into CPU format and
709  * creating the stream, provided the add BA is accepted.
710  */
711 int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
712                                struct host_cmd_ds_command *resp)
713 {
714         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
715         int tid, win_size;
716         struct mwifiex_rx_reorder_tbl *tbl;
717         uint16_t block_ack_param_set;
718
719         block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
720
721         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
722                 >> BLOCKACKPARAM_TID_POS;
723         /*
724          * Check if we had rejected the ADDBA, if yes then do not create
725          * the stream
726          */
727         if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
728                 mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
729                             add_ba_rsp->peer_mac_addr, tid);
730
731                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
732                                                      add_ba_rsp->peer_mac_addr);
733                 if (tbl)
734                         mwifiex_del_rx_reorder_entry(priv, tbl);
735
736                 return 0;
737         }
738
739         win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
740                     >> BLOCKACKPARAM_WINSIZE_POS;
741
742         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
743                                              add_ba_rsp->peer_mac_addr);
744         if (tbl) {
745                 if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
746                     priv->add_ba_param.rx_amsdu &&
747                     (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
748                         tbl->amsdu = true;
749                 else
750                         tbl->amsdu = false;
751         }
752
753         mwifiex_dbg(priv->adapter, CMD,
754                     "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
755                 add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
756
757         return 0;
758 }
759
760 /*
761  * This function handles BA stream timeout event by preparing and sending
762  * a command to the firmware.
763  */
764 void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
765                                    struct host_cmd_ds_11n_batimeout *event)
766 {
767         struct host_cmd_ds_11n_delba delba;
768
769         memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
770         memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
771
772         delba.del_ba_param_set |=
773                 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
774         delba.del_ba_param_set |= cpu_to_le16(
775                 (u16) event->origninator << DELBA_INITIATOR_POS);
776         delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
777         mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
778 }
779
780 /*
781  * This function cleans up the Rx reorder table by deleting all the entries
782  * and re-initializing.
783  */
784 void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
785 {
786         struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
787         unsigned long flags;
788
789         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
790         list_for_each_entry_safe(del_tbl_ptr, tmp_node,
791                                  &priv->rx_reorder_tbl_ptr, list) {
792                 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
793                 mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
794                 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
795         }
796         INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
797         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
798
799         mwifiex_reset_11n_rx_seq_num(priv);
800 }
801
802 /*
803  * This function updates all rx_reorder_tbl's flags.
804  */
805 void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
806 {
807         struct mwifiex_private *priv;
808         struct mwifiex_rx_reorder_tbl *tbl;
809         unsigned long lock_flags;
810         int i;
811
812         for (i = 0; i < adapter->priv_num; i++) {
813                 priv = adapter->priv[i];
814                 if (!priv)
815                         continue;
816
817                 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
818                 if (list_empty(&priv->rx_reorder_tbl_ptr)) {
819                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
820                                                lock_flags);
821                         continue;
822                 }
823
824                 list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
825                         tbl->flags = flags;
826                 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
827         }
828
829         return;
830 }
831
832 /* This function update all the rx_win_size based on coex flag
833  */
834 static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
835                                            bool coex_flag)
836 {
837         u8 i;
838         u32 rx_win_size;
839         struct mwifiex_private *priv;
840
841         dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
842
843         for (i = 0; i < adapter->priv_num; i++) {
844                 if (!adapter->priv[i])
845                         continue;
846                 priv = adapter->priv[i];
847                 rx_win_size = priv->add_ba_param.rx_win_size;
848                 if (coex_flag) {
849                         if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
850                                 priv->add_ba_param.rx_win_size =
851                                         MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
852                         if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
853                                 priv->add_ba_param.rx_win_size =
854                                         MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
855                         if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
856                                 priv->add_ba_param.rx_win_size =
857                                         MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
858                 } else {
859                         if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
860                                 priv->add_ba_param.rx_win_size =
861                                         MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
862                         if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
863                                 priv->add_ba_param.rx_win_size =
864                                         MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
865                         if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
866                                 priv->add_ba_param.rx_win_size =
867                                         MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
868                 }
869
870                 if (adapter->coex_win_size && adapter->coex_rx_win_size)
871                         priv->add_ba_param.rx_win_size =
872                                         adapter->coex_rx_win_size;
873
874                 if (rx_win_size != priv->add_ba_param.rx_win_size) {
875                         if (!priv->media_connected)
876                                 continue;
877                         for (i = 0; i < MAX_NUM_TID; i++)
878                                 mwifiex_11n_delba(priv, i);
879                 }
880         }
881 }
882
883 /* This function check coex for RX BA
884  */
885 void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
886 {
887         u8 i;
888         struct mwifiex_private *priv;
889         u8 count = 0;
890
891         for (i = 0; i < adapter->priv_num; i++) {
892                 if (adapter->priv[i]) {
893                         priv = adapter->priv[i];
894                         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
895                                 if (priv->media_connected)
896                                         count++;
897                         }
898                         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
899                                 if (priv->bss_started)
900                                         count++;
901                         }
902                 }
903                 if (count >= MWIFIEX_BSS_COEX_COUNT)
904                         break;
905         }
906         if (count >= MWIFIEX_BSS_COEX_COUNT)
907                 mwifiex_update_ampdu_rxwinsize(adapter, true);
908         else
909                 mwifiex_update_ampdu_rxwinsize(adapter, false);
910 }