Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/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                                 dev_err(priv->adapter->dev,
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         dev_dbg(ctx->priv->adapter->dev, "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                 dev_dbg(priv->adapter->dev,
357                         "info: AP/ADHOC:last_seq=%d start_win=%d\n",
358                         last_seq, new_node->start_win);
359                 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
360                         node = mwifiex_get_sta_entry(priv, ta);
361                         if (node)
362                                 last_seq = node->rx_seq[tid];
363                 }
364         } else {
365                 node = mwifiex_get_sta_entry(priv, ta);
366                 if (node)
367                         last_seq = node->rx_seq[tid];
368                 else
369                         last_seq = priv->rx_seq[tid];
370         }
371         spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
372
373         if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
374             last_seq >= new_node->start_win) {
375                 new_node->start_win = last_seq + 1;
376                 new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
377         }
378
379         new_node->win_size = win_size;
380
381         new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
382                                         GFP_KERNEL);
383         if (!new_node->rx_reorder_ptr) {
384                 kfree((u8 *) new_node);
385                 dev_err(priv->adapter->dev,
386                         "%s: failed to alloc reorder_ptr\n", __func__);
387                 return;
388         }
389
390         new_node->timer_context.ptr = new_node;
391         new_node->timer_context.priv = priv;
392         new_node->timer_context.timer_is_set = false;
393
394         init_timer(&new_node->timer_context.timer);
395         new_node->timer_context.timer.function = mwifiex_flush_data;
396         new_node->timer_context.timer.data =
397                         (unsigned long) &new_node->timer_context;
398
399         for (i = 0; i < win_size; ++i)
400                 new_node->rx_reorder_ptr[i] = NULL;
401
402         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
403         list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
404         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
405 }
406
407 static void
408 mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
409 {
410         u32 min_flush_time;
411
412         if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
413                 min_flush_time = MIN_FLUSH_TIMER_15_MS;
414         else
415                 min_flush_time = MIN_FLUSH_TIMER_MS;
416
417         mod_timer(&tbl->timer_context.timer,
418                   jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
419
420         tbl->timer_context.timer_is_set = true;
421 }
422
423 /*
424  * This function prepares command for adding a BA request.
425  *
426  * Preparation includes -
427  *      - Setting command ID and proper size
428  *      - Setting add BA request buffer
429  *      - Ensuring correct endian-ness
430  */
431 int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
432 {
433         struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
434
435         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
436         cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
437         memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
438
439         return 0;
440 }
441
442 /*
443  * This function prepares command for adding a BA response.
444  *
445  * Preparation includes -
446  *      - Setting command ID and proper size
447  *      - Setting add BA response buffer
448  *      - Ensuring correct endian-ness
449  */
450 int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
451                                   struct host_cmd_ds_command *cmd,
452                                   struct host_cmd_ds_11n_addba_req
453                                   *cmd_addba_req)
454 {
455         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
456         struct mwifiex_sta_node *sta_ptr;
457         u32 rx_win_size = priv->add_ba_param.rx_win_size;
458         u8 tid;
459         int win_size;
460         unsigned long flags;
461         uint16_t block_ack_param_set;
462
463         if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
464             ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
465             priv->adapter->is_hw_11ac_capable &&
466             memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
467                 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
468                 sta_ptr = mwifiex_get_sta_entry(priv,
469                                                 cmd_addba_req->peer_mac_addr);
470                 if (!sta_ptr) {
471                         dev_warn(priv->adapter->dev,
472                                  "BA setup with unknown TDLS peer %pM!\n",
473                                  cmd_addba_req->peer_mac_addr);
474                         spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
475                         return -1;
476                 }
477                 if (sta_ptr->is_11ac_enabled)
478                         rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
479                 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
480         }
481
482         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
483         cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
484
485         memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
486                ETH_ALEN);
487         add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
488         add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
489         add_ba_rsp->ssn = cmd_addba_req->ssn;
490
491         block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
492         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
493                 >> BLOCKACKPARAM_TID_POS;
494         add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
495         block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
496
497         /* If we don't support AMSDU inside AMPDU, reset the bit */
498         if (!priv->add_ba_param.rx_amsdu ||
499             (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
500                 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
501         block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
502         add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
503         win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
504                                         & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
505                                         >> BLOCKACKPARAM_WINSIZE_POS;
506         cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
507
508         mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
509                                           tid, win_size,
510                                           le16_to_cpu(cmd_addba_req->ssn));
511         return 0;
512 }
513
514 /*
515  * This function prepares command for deleting a BA request.
516  *
517  * Preparation includes -
518  *      - Setting command ID and proper size
519  *      - Setting del BA request buffer
520  *      - Ensuring correct endian-ness
521  */
522 int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
523 {
524         struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
525
526         cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
527         cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
528         memcpy(del_ba, data_buf, sizeof(*del_ba));
529
530         return 0;
531 }
532
533 /*
534  * This function identifies if Rx reordering is needed for a received packet.
535  *
536  * In case reordering is required, the function will do the reordering
537  * before sending it to kernel.
538  *
539  * The Rx reorder table is checked first with the received TID/TA pair. If
540  * not found, the received packet is dispatched immediately. But if found,
541  * the packet is reordered and all the packets in the updated Rx reordering
542  * table is dispatched until a hole is found.
543  *
544  * For sequence number less than the starting window, the packet is dropped.
545  */
546 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
547                                 u16 seq_num, u16 tid,
548                                 u8 *ta, u8 pkt_type, void *payload)
549 {
550         struct mwifiex_rx_reorder_tbl *tbl;
551         int prev_start_win, start_win, end_win, win_size;
552         u16 pkt_index;
553         bool init_window_shift = false;
554         int ret = 0;
555
556         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
557         if (!tbl) {
558                 if (pkt_type != PKT_TYPE_BAR)
559                         mwifiex_11n_dispatch_pkt(priv, payload);
560                 return ret;
561         }
562
563         if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
564                 mwifiex_11n_dispatch_pkt(priv, payload);
565                 return ret;
566         }
567
568         start_win = tbl->start_win;
569         prev_start_win = start_win;
570         win_size = tbl->win_size;
571         end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
572         if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
573                 init_window_shift = true;
574                 tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
575         }
576
577         if (tbl->flags & RXREOR_FORCE_NO_DROP) {
578                 dev_dbg(priv->adapter->dev,
579                         "RXREOR_FORCE_NO_DROP when HS is activated\n");
580                 tbl->flags &= ~RXREOR_FORCE_NO_DROP;
581         } else if (init_window_shift && seq_num < start_win &&
582                    seq_num >= tbl->init_win) {
583                 dev_dbg(priv->adapter->dev,
584                         "Sender TID sequence number reset %d->%d for SSN %d\n",
585                         start_win, seq_num, tbl->init_win);
586                 tbl->start_win = start_win = seq_num;
587                 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
588         } else {
589                 /*
590                  * If seq_num is less then starting win then ignore and drop
591                  * the packet
592                  */
593                 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
594                         if (seq_num >= ((start_win + TWOPOW11) &
595                                         (MAX_TID_VALUE - 1)) &&
596                             seq_num < start_win) {
597                                 ret = -1;
598                                 goto done;
599                         }
600                 } else if ((seq_num < start_win) ||
601                            (seq_num >= (start_win + TWOPOW11))) {
602                         ret = -1;
603                         goto done;
604                 }
605         }
606
607         /*
608          * If this packet is a BAR we adjust seq_num as
609          * WinStart = seq_num
610          */
611         if (pkt_type == PKT_TYPE_BAR)
612                 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
613
614         if (((end_win < start_win) &&
615              (seq_num < start_win) && (seq_num > end_win)) ||
616             ((end_win > start_win) && ((seq_num > end_win) ||
617                                        (seq_num < start_win)))) {
618                 end_win = seq_num;
619                 if (((seq_num - win_size) + 1) >= 0)
620                         start_win = (end_win - win_size) + 1;
621                 else
622                         start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
623                 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
624         }
625
626         if (pkt_type != PKT_TYPE_BAR) {
627                 if (seq_num >= start_win)
628                         pkt_index = seq_num - start_win;
629                 else
630                         pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
631
632                 if (tbl->rx_reorder_ptr[pkt_index]) {
633                         ret = -1;
634                         goto done;
635                 }
636
637                 tbl->rx_reorder_ptr[pkt_index] = payload;
638         }
639
640         /*
641          * Dispatch all packets sequentially from start_win until a
642          * hole is found and adjust the start_win appropriately
643          */
644         mwifiex_11n_scan_and_dispatch(priv, tbl);
645
646 done:
647         if (!tbl->timer_context.timer_is_set ||
648             prev_start_win != tbl->start_win)
649                 mwifiex_11n_rxreorder_timer_restart(tbl);
650         return ret;
651 }
652
653 /*
654  * This function deletes an entry for a given TID/TA pair.
655  *
656  * The TID/TA are taken from del BA event body.
657  */
658 void
659 mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
660                    u8 type, int initiator)
661 {
662         struct mwifiex_rx_reorder_tbl *tbl;
663         struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
664         u8 cleanup_rx_reorder_tbl;
665         unsigned long flags;
666
667         if (type == TYPE_DELBA_RECEIVE)
668                 cleanup_rx_reorder_tbl = (initiator) ? true : false;
669         else
670                 cleanup_rx_reorder_tbl = (initiator) ? false : true;
671
672         dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d initiator=%d\n",
673                 peer_mac, tid, initiator);
674
675         if (cleanup_rx_reorder_tbl) {
676                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
677                                                                  peer_mac);
678                 if (!tbl) {
679                         dev_dbg(priv->adapter->dev,
680                                 "event: TID, TA not found in table\n");
681                         return;
682                 }
683                 mwifiex_del_rx_reorder_entry(priv, tbl);
684         } else {
685                 ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
686                 if (!ptx_tbl) {
687                         dev_dbg(priv->adapter->dev,
688                                 "event: TID, RA not found in table\n");
689                         return;
690                 }
691
692                 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
693                 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
694                 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
695         }
696 }
697
698 /*
699  * This function handles the command response of an add BA response.
700  *
701  * Handling includes changing the header fields into CPU format and
702  * creating the stream, provided the add BA is accepted.
703  */
704 int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
705                                struct host_cmd_ds_command *resp)
706 {
707         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
708         int tid, win_size;
709         struct mwifiex_rx_reorder_tbl *tbl;
710         uint16_t block_ack_param_set;
711
712         block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
713
714         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
715                 >> BLOCKACKPARAM_TID_POS;
716         /*
717          * Check if we had rejected the ADDBA, if yes then do not create
718          * the stream
719          */
720         if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
721                 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
722                         add_ba_rsp->peer_mac_addr, tid);
723
724                 tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
725                                                      add_ba_rsp->peer_mac_addr);
726                 if (tbl)
727                         mwifiex_del_rx_reorder_entry(priv, tbl);
728
729                 return 0;
730         }
731
732         win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
733                     >> BLOCKACKPARAM_WINSIZE_POS;
734
735         tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
736                                              add_ba_rsp->peer_mac_addr);
737         if (tbl) {
738                 if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
739                     priv->add_ba_param.rx_amsdu &&
740                     (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
741                         tbl->amsdu = true;
742                 else
743                         tbl->amsdu = false;
744         }
745
746         dev_dbg(priv->adapter->dev,
747                 "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
748                 add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
749
750         return 0;
751 }
752
753 /*
754  * This function handles BA stream timeout event by preparing and sending
755  * a command to the firmware.
756  */
757 void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
758                                    struct host_cmd_ds_11n_batimeout *event)
759 {
760         struct host_cmd_ds_11n_delba delba;
761
762         memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
763         memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
764
765         delba.del_ba_param_set |=
766                 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
767         delba.del_ba_param_set |= cpu_to_le16(
768                 (u16) event->origninator << DELBA_INITIATOR_POS);
769         delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
770         mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
771 }
772
773 /*
774  * This function cleans up the Rx reorder table by deleting all the entries
775  * and re-initializing.
776  */
777 void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
778 {
779         struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
780         unsigned long flags;
781
782         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
783         list_for_each_entry_safe(del_tbl_ptr, tmp_node,
784                                  &priv->rx_reorder_tbl_ptr, list) {
785                 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
786                 mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
787                 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
788         }
789         INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
790         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
791
792         mwifiex_reset_11n_rx_seq_num(priv);
793 }
794
795 /*
796  * This function updates all rx_reorder_tbl's flags.
797  */
798 void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
799 {
800         struct mwifiex_private *priv;
801         struct mwifiex_rx_reorder_tbl *tbl;
802         unsigned long lock_flags;
803         int i;
804
805         for (i = 0; i < adapter->priv_num; i++) {
806                 priv = adapter->priv[i];
807                 if (!priv)
808                         continue;
809
810                 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
811                 if (list_empty(&priv->rx_reorder_tbl_ptr)) {
812                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
813                                                lock_flags);
814                         continue;
815                 }
816
817                 list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
818                         tbl->flags = flags;
819                 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
820         }
821
822         return;
823 }