mwifiex: rename long function names to shorter ones
[pandora-kernel.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, 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 /*
30  * This function dispatches all packets in the Rx reorder table.
31  *
32  * There could be holes in the buffer, which are skipped by the function.
33  * Since the buffer is linear, the function uses rotation to simulate
34  * circular buffer.
35  */
36 static void
37 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
38                                          struct mwifiex_rx_reorder_tbl
39                                          *rx_reor_tbl_ptr, int start_win)
40 {
41         int no_pkt_to_send, i;
42         void *rx_tmp_ptr;
43         unsigned long flags;
44
45         no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
46                 min((start_win - rx_reor_tbl_ptr->start_win),
47                     rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
48
49         for (i = 0; i < no_pkt_to_send; ++i) {
50                 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
51                 rx_tmp_ptr = NULL;
52                 if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
53                         rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
54                         rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
55                 }
56                 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
57                 if (rx_tmp_ptr)
58                         mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
59         }
60
61         spin_lock_irqsave(&priv->rx_pkt_lock, flags);
62         /*
63          * We don't have a circular buffer, hence use rotation to simulate
64          * circular buffer
65          */
66         for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) {
67                 rx_reor_tbl_ptr->rx_reorder_ptr[i] =
68                         rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
69                 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
70         }
71
72         rx_reor_tbl_ptr->start_win = start_win;
73         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
74 }
75
76 /*
77  * This function dispatches all packets in the Rx reorder table until
78  * a hole is found.
79  *
80  * The start window is adjusted automatically when a hole is located.
81  * Since the buffer is linear, the function uses rotation to simulate
82  * circular buffer.
83  */
84 static void
85 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
86                               struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
87 {
88         int i, j, xchg;
89         void *rx_tmp_ptr;
90         unsigned long flags;
91
92         for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
93                 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
94                 if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
95                         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
96                         break;
97                 }
98                 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
99                 rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
100                 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
101                 mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
102         }
103
104         spin_lock_irqsave(&priv->rx_pkt_lock, flags);
105         /*
106          * We don't have a circular buffer, hence use rotation to simulate
107          * circular buffer
108          */
109         if (i > 0) {
110                 xchg = rx_reor_tbl_ptr->win_size - i;
111                 for (j = 0; j < xchg; ++j) {
112                         rx_reor_tbl_ptr->rx_reorder_ptr[j] =
113                                 rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
114                         rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
115                 }
116         }
117         rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
118                 &(MAX_TID_VALUE - 1);
119         spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
120 }
121
122 /*
123  * This function deletes the Rx reorder table and frees the memory.
124  *
125  * The function stops the associated timer and dispatches all the
126  * pending packets in the Rx reorder table before deletion.
127  */
128 static void
129 mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
130                                        struct mwifiex_rx_reorder_tbl
131                                        *rx_reor_tbl_ptr)
132 {
133         unsigned long flags;
134
135         if (!rx_reor_tbl_ptr)
136                 return;
137
138         mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
139                                                  (rx_reor_tbl_ptr->start_win +
140                                                   rx_reor_tbl_ptr->win_size)
141                                                  &(MAX_TID_VALUE - 1));
142
143         del_timer(&rx_reor_tbl_ptr->timer_context.timer);
144
145         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
146         list_del(&rx_reor_tbl_ptr->list);
147         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
148
149         kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
150         kfree(rx_reor_tbl_ptr);
151 }
152
153 /*
154  * This function returns the pointer to an entry in Rx reordering
155  * table which matches the given TA/TID pair.
156  */
157 static struct mwifiex_rx_reorder_tbl *
158 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
159 {
160         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
161         unsigned long flags;
162
163         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
164         list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
165                 if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
166                     && (rx_reor_tbl_ptr->tid == tid)) {
167                         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
168                                                flags);
169                         return rx_reor_tbl_ptr;
170                 }
171         }
172         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
173
174         return NULL;
175 }
176
177 /*
178  * This function finds the last sequence number used in the packets
179  * buffered in Rx reordering table.
180  */
181 static int
182 mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
183 {
184         int i;
185
186         for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
187                 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
188                         return i;
189
190         return -1;
191 }
192
193 /*
194  * This function flushes all the packets in Rx reordering table.
195  *
196  * The function checks if any packets are currently buffered in the
197  * table or not. In case there are packets available, it dispatches
198  * them and then dumps the Rx reordering table.
199  */
200 static void
201 mwifiex_flush_data(unsigned long context)
202 {
203         struct reorder_tmr_cnxt *reorder_cnxt =
204                 (struct reorder_tmr_cnxt *) context;
205         int start_win;
206
207         start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
208         if (start_win >= 0) {
209                 dev_dbg(reorder_cnxt->priv->adapter->dev,
210                                 "info: flush data %d\n", start_win);
211                 mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
212                                 reorder_cnxt->ptr,
213                                 ((reorder_cnxt->ptr->start_win +
214                                   start_win + 1) & (MAX_TID_VALUE - 1)));
215         }
216 }
217
218 /*
219  * This function creates an entry in Rx reordering table for the
220  * given TA/TID.
221  *
222  * The function also initializes the entry with sequence number, window
223  * size as well as initializes the timer.
224  *
225  * If the received TA/TID pair is already present, all the packets are
226  * dispatched and the window size is moved until the SSN.
227  */
228 static void
229 mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
230                                  int tid, int win_size, int seq_num)
231 {
232         int i;
233         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
234         u16 last_seq = 0;
235         unsigned long flags;
236
237         /*
238          * If we get a TID, ta pair which is already present dispatch all the
239          * the packets and move the window size until the ssn
240          */
241         rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
242         if (rx_reor_tbl_ptr) {
243                 mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
244                                                          seq_num);
245                 return;
246         }
247         /* if !rx_reor_tbl_ptr then create one */
248         new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
249         if (!new_node) {
250                 dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
251                        __func__);
252                 return;
253         }
254
255         INIT_LIST_HEAD(&new_node->list);
256         new_node->tid = tid;
257         memcpy(new_node->ta, ta, ETH_ALEN);
258         new_node->start_win = seq_num;
259         if (mwifiex_queuing_ra_based(priv))
260                 /* TODO for adhoc */
261                 dev_dbg(priv->adapter->dev,
262                         "info: ADHOC:last_seq=%d start_win=%d\n",
263                         last_seq, new_node->start_win);
264         else
265                 last_seq = priv->rx_seq[tid];
266
267         if (last_seq >= new_node->start_win)
268                 new_node->start_win = last_seq + 1;
269
270         new_node->win_size = win_size;
271
272         new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
273                                         GFP_KERNEL);
274         if (!new_node->rx_reorder_ptr) {
275                 kfree((u8 *) new_node);
276                 dev_err(priv->adapter->dev,
277                         "%s: failed to alloc reorder_ptr\n", __func__);
278                 return;
279         }
280
281         new_node->timer_context.ptr = new_node;
282         new_node->timer_context.priv = priv;
283
284         init_timer(&new_node->timer_context.timer);
285         new_node->timer_context.timer.function = mwifiex_flush_data;
286         new_node->timer_context.timer.data =
287                         (unsigned long) &new_node->timer_context;
288
289         for (i = 0; i < win_size; ++i)
290                 new_node->rx_reorder_ptr[i] = NULL;
291
292         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
293         list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
294         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
295 }
296
297 /*
298  * This function prepares command for adding a BA request.
299  *
300  * Preparation includes -
301  *      - Setting command ID and proper size
302  *      - Setting add BA request buffer
303  *      - Ensuring correct endian-ness
304  */
305 int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
306 {
307         struct host_cmd_ds_11n_addba_req *add_ba_req =
308                 (struct host_cmd_ds_11n_addba_req *)
309                 &cmd->params.add_ba_req;
310
311         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
312         cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
313         memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
314
315         return 0;
316 }
317
318 /*
319  * This function prepares command for adding a BA response.
320  *
321  * Preparation includes -
322  *      - Setting command ID and proper size
323  *      - Setting add BA response buffer
324  *      - Ensuring correct endian-ness
325  */
326 int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
327                                   struct host_cmd_ds_command *cmd,
328                                   struct host_cmd_ds_11n_addba_req
329                                   *cmd_addba_req)
330 {
331         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
332                 (struct host_cmd_ds_11n_addba_rsp *)
333                 &cmd->params.add_ba_rsp;
334         u8 tid;
335         int win_size;
336         uint16_t block_ack_param_set;
337
338         cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
339         cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
340
341         memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
342                ETH_ALEN);
343         add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
344         add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
345         add_ba_rsp->ssn = cmd_addba_req->ssn;
346
347         block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
348         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
349                 >> BLOCKACKPARAM_TID_POS;
350         add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
351         block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
352         /* We donot support AMSDU inside AMPDU, hence reset the bit */
353         block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
354         block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
355                                              BLOCKACKPARAM_WINSIZE_POS);
356         add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
357         win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
358                                         & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
359                                         >> BLOCKACKPARAM_WINSIZE_POS;
360         cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
361
362         mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
363                             tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
364         return 0;
365 }
366
367 /*
368  * This function prepares command for deleting a BA request.
369  *
370  * Preparation includes -
371  *      - Setting command ID and proper size
372  *      - Setting del BA request buffer
373  *      - Ensuring correct endian-ness
374  */
375 int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
376 {
377         struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
378                 &cmd->params.del_ba;
379
380         cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
381         cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
382         memcpy(del_ba, data_buf, sizeof(*del_ba));
383
384         return 0;
385 }
386
387 /*
388  * This function identifies if Rx reordering is needed for a received packet.
389  *
390  * In case reordering is required, the function will do the reordering
391  * before sending it to kernel.
392  *
393  * The Rx reorder table is checked first with the received TID/TA pair. If
394  * not found, the received packet is dispatched immediately. But if found,
395  * the packet is reordered and all the packets in the updated Rx reordering
396  * table is dispatched until a hole is found.
397  *
398  * For sequence number less than the starting window, the packet is dropped.
399  */
400 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
401                                 u16 seq_num, u16 tid,
402                                 u8 *ta, u8 pkt_type, void *payload)
403 {
404         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
405         int start_win, end_win, win_size;
406         u16 pkt_index;
407
408         rx_reor_tbl_ptr =
409                 mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
410                                                 tid, ta);
411         if (!rx_reor_tbl_ptr) {
412                 if (pkt_type != PKT_TYPE_BAR)
413                         mwifiex_process_rx_packet(priv->adapter, payload);
414                 return 0;
415         }
416         start_win = rx_reor_tbl_ptr->start_win;
417         win_size = rx_reor_tbl_ptr->win_size;
418         end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
419         del_timer(&rx_reor_tbl_ptr->timer_context.timer);
420         mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
421                         + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
422
423         /*
424          * If seq_num is less then starting win then ignore and drop the
425          * packet
426          */
427         if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
428                 if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
429                                 && (seq_num < start_win))
430                         return -1;
431         } else if ((seq_num < start_win)
432                         || (seq_num > (start_win + (TWOPOW11)))) {
433                 return -1;
434         }
435
436         /*
437          * If this packet is a BAR we adjust seq_num as
438          * WinStart = seq_num
439          */
440         if (pkt_type == PKT_TYPE_BAR)
441                 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
442
443         if (((end_win < start_win)
444              && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
445              && (seq_num > end_win)) || ((end_win > start_win)
446              && ((seq_num > end_win) || (seq_num < start_win)))) {
447                 end_win = seq_num;
448                 if (((seq_num - win_size) + 1) >= 0)
449                         start_win = (end_win - win_size) + 1;
450                 else
451                         start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
452                 mwifiex_11n_dispatch_pkt_until_start_win(priv,
453                                                 rx_reor_tbl_ptr, start_win);
454         }
455
456         if (pkt_type != PKT_TYPE_BAR) {
457                 if (seq_num >= start_win)
458                         pkt_index = seq_num - start_win;
459                 else
460                         pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
461
462                 if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
463                         return -1;
464
465                 rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
466         }
467
468         /*
469          * Dispatch all packets sequentially from start_win until a
470          * hole is found and adjust the start_win appropriately
471          */
472         mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
473
474         return 0;
475 }
476
477 /*
478  * This function deletes an entry for a given TID/TA pair.
479  *
480  * The TID/TA are taken from del BA event body.
481  */
482 void
483 mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
484                    u8 type, int initiator)
485 {
486         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
487         struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
488         u8 cleanup_rx_reorder_tbl;
489         unsigned long flags;
490
491         if (type == TYPE_DELBA_RECEIVE)
492                 cleanup_rx_reorder_tbl = (initiator) ? true : false;
493         else
494                 cleanup_rx_reorder_tbl = (initiator) ? false : true;
495
496         dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
497                "initiator=%d\n", peer_mac, tid, initiator);
498
499         if (cleanup_rx_reorder_tbl) {
500                 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
501                                                                  peer_mac);
502                 if (!rx_reor_tbl_ptr) {
503                         dev_dbg(priv->adapter->dev,
504                                         "event: TID, TA not found in table\n");
505                         return;
506                 }
507                 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
508         } else {
509                 ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
510                 if (!ptx_tbl) {
511                         dev_dbg(priv->adapter->dev,
512                                         "event: TID, RA not found in table\n");
513                         return;
514                 }
515
516                 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
517                 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
518                 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
519         }
520 }
521
522 /*
523  * This function handles the command response of an add BA response.
524  *
525  * Handling includes changing the header fields into CPU format and
526  * creating the stream, provided the add BA is accepted.
527  */
528 int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
529                                struct host_cmd_ds_command *resp)
530 {
531         struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
532                 (struct host_cmd_ds_11n_addba_rsp *)
533                 &resp->params.add_ba_rsp;
534         int tid, win_size;
535         struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
536         uint16_t block_ack_param_set;
537
538         block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
539
540         tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
541                 >> BLOCKACKPARAM_TID_POS;
542         /*
543          * Check if we had rejected the ADDBA, if yes then do not create
544          * the stream
545          */
546         if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
547                 win_size = (block_ack_param_set &
548                         IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
549                         >> BLOCKACKPARAM_WINSIZE_POS;
550
551                 dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
552                        " tid=%d ssn=%d win_size=%d\n",
553                        add_ba_rsp->peer_mac_addr,
554                        tid, add_ba_rsp->ssn, win_size);
555         } else {
556                 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
557                                         add_ba_rsp->peer_mac_addr, tid);
558
559                 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
560                                         tid, add_ba_rsp->peer_mac_addr);
561                 if (rx_reor_tbl_ptr)
562                         mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
563                                 rx_reor_tbl_ptr);
564         }
565
566         return 0;
567 }
568
569 /*
570  * This function handles BA stream timeout event by preparing and sending
571  * a command to the firmware.
572  */
573 void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
574                                    struct host_cmd_ds_11n_batimeout *event)
575 {
576         struct host_cmd_ds_11n_delba delba;
577
578         memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
579         memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
580
581         delba.del_ba_param_set |=
582                 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
583         delba.del_ba_param_set |= cpu_to_le16(
584                 (u16) event->origninator << DELBA_INITIATOR_POS);
585         delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
586         mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
587 }
588
589 /*
590  * This function cleans up the Rx reorder table by deleting all the entries
591  * and re-initializing.
592  */
593 void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
594 {
595         struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
596         unsigned long flags;
597
598         spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
599         list_for_each_entry_safe(del_tbl_ptr, tmp_node,
600                                  &priv->rx_reorder_tbl_ptr, list) {
601                 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
602                 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
603                 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
604         }
605         spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
606
607         INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
608         memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
609 }