13aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/*
23aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
33aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *
43aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Copyright (C) 2011, Marvell International Ltd.
53aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *
6bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * This software file (the "File") is distributed by Marvell International
7bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * Ltd. under the terms of the GNU General Public License Version 2, June 1991
84fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller * (the "License").  You may use, redistribute and/or modify this File in
9e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller * accordance with the terms and conditions of the License, a copy of which
10bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * is available by writing to the Free Software Foundation, Inc.,
113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * this warranty disclaimer.
183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "decl.h"
213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "ioctl.h"
223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "util.h"
233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "fw.h"
243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "main.h"
253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "wmm.h"
263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "11n.h"
273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "11n_rxreorder.h"
283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/*
307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton * This function dispatches all packets in the Rx reorder table.
316e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora *
323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * There could be holes in the buffer, which are skipped by the function.
333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Since the buffer is linear, the function uses rotation to simulate
343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * circular buffer.
353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void
373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab					 struct mwifiex_rx_reorder_tbl
393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab					 *rx_reor_tbl_ptr, int start_win)
403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	int no_pkt_to_send, i;
423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	void *rx_tmp_ptr;
433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	unsigned long flags;
443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		min((start_win - rx_reor_tbl_ptr->start_win),
473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		    rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < no_pkt_to_send; ++i) {
503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		rx_tmp_ptr = NULL;
523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (rx_tmp_ptr)
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/*
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * We don't have a circular buffer, hence use rotation to simulate
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * circular buffer
653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 */
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) {
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		rx_reor_tbl_ptr->rx_reorder_ptr[i] =
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	rx_reor_tbl_ptr->start_win = start_win;
733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function dispatches all packets in the Rx reorder table until
783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * a hole is found.
793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The start window is adjusted automatically when a hole is located.
813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Since the buffer is linear, the function uses rotation to simulate
823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * circular buffer.
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			      struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i, j, xchg;
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	void *rx_tmp_ptr;
903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	unsigned long flags;
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			break;
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
1026ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	}
1036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
1053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/*
1063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	 * We don't have a circular buffer, hence use rotation to simulate
1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * circular buffer
1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 */
1093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (i > 0) {
1103aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		xchg = rx_reor_tbl_ptr->win_size - i;
1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		for (j = 0; j < xchg; ++j) {
1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			rx_reor_tbl_ptr->rx_reorder_ptr[j] =
1133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		&(MAX_TID_VALUE - 1);
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function deletes the Rx reorder table and frees the memory.
1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The function stops the associated timer and dispatches all the
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * pending packets in the Rx reorder table before deletion.
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				       struct mwifiex_rx_reorder_tbl
1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				       *rx_reor_tbl_ptr)
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	unsigned long flags;
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!rx_reor_tbl_ptr)
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return;
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton						 (rx_reor_tbl_ptr->start_win +
1406ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf						  rx_reor_tbl_ptr->win_size)
1416ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf						 &(MAX_TID_VALUE - 1));
142c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	del_timer(&rx_reor_tbl_ptr->timer_context.timer);
144d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller
1453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
1463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	list_del(&rx_reor_tbl_ptr->list);
147c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
148c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
149c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(rx_reor_tbl_ptr);
151d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller}
152d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller
1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
154d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller * This function returns the pointer to an entry in Rx reordering
155c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab * table which matches the given TA/TID pair.
1563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
1573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic struct mwifiex_rx_reorder_tbl *
1586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafmwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
1596ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
1603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
1613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	unsigned long flags;
1623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
163c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
1642fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
165c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
1663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		    && (rx_reor_tbl_ptr->tid == tid)) {
1673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
1683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab					       flags);
1693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return rx_reor_tbl_ptr;
1703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
1733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return NULL;
1753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
1783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function finds the last sequence number used in the packets
1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * buffered in Rx reordering table.
1803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
1813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int
1823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1846ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	int i;
1856ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
1863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
1873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
1883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return i;
1893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return -1;
1913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
1943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function flushes all the packets in Rx reordering table.
1953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
1963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The function checks if any packets are currently buffered in the
1973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * table or not. In case there are packets available, it dispatches
1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * them and then dumps the Rx reordering table.
1993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
2006ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic void
2016ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafmwifiex_flush_data(unsigned long context)
2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
2036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	struct reorder_tmr_cnxt *reorder_cnxt =
2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		(struct reorder_tmr_cnxt *) context;
2053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int start_win;
2063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
2083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (start_win >= 0) {
209e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		dev_dbg(reorder_cnxt->priv->adapter->dev,
210e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab				"info: flush data %d\n", start_win);
211e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
212e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab				reorder_cnxt->ptr,
213e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab				((reorder_cnxt->ptr->start_win +
214e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab				  start_win + 1) & (MAX_TID_VALUE - 1)));
215e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	}
216e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab}
217e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2182fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab/*
219e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * This function creates an entry in Rx reordering table for the
220e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * given TA/TID.
2213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *
2223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * The function also initializes the entry with sequence number, window
223227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * size as well as initializes the timer.
224227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab *
225227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * If the received TA/TID pair is already present, all the packets are
226227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * dispatched and the window size is moved until the SSN.
2273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
2287e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic void
2297e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonmwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
2307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton				 int tid, int win_size, int seq_num)
2317e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton{
2327e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	int i;
2337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
2347e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	u16 last_seq = 0;
2356e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	unsigned long flags;
2366e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora
2376e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	/*
2386e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	 * If we get a TID, ta pair which is already present dispatch all the
2396e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	 * the packets and move the window size until the ssn
2406e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	 */
2416e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
2426e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	if (rx_reor_tbl_ptr) {
2436e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
24417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller							 seq_num);
24517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		return;
24617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	}
24717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	/* if !rx_reor_tbl_ptr then create one */
24817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
24917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	if (!new_node) {
25017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
2513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       __func__);
2523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return;
2533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2543aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	INIT_LIST_HEAD(&new_node->list);
2563ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	new_node->tid = tid;
2573ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	memcpy(new_node->ta, ta, ETH_ALEN);
2586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	new_node->start_win = seq_num;
2593ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	if (mwifiex_queuing_ra_based(priv))
2603ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab		/* TODO for adhoc */
2613ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab		dev_dbg(priv->adapter->dev,
2623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			"info: ADHOC:last_seq=%d start_win=%d\n",
2633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			last_seq, new_node->start_win);
2643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	else
2653aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		last_seq = priv->rx_seq[tid];
2663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (last_seq >= new_node->start_win)
2683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		new_node->start_win = last_seq + 1;
2693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	new_node->win_size = win_size;
2713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
2733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					GFP_KERNEL);
2743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!new_node->rx_reorder_ptr) {
2753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		kfree((u8 *) new_node);
2763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		dev_err(priv->adapter->dev,
2773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			"%s: failed to alloc reorder_ptr\n", __func__);
2783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return;
2793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	new_node->timer_context.ptr = new_node;
2823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	new_node->timer_context.priv = priv;
2833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	init_timer(&new_node->timer_context.timer);
285d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuil	new_node->timer_context.timer.function = mwifiex_flush_data;
2863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	new_node->timer_context.timer.data =
2873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			(unsigned long) &new_node->timer_context;
2883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2893aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	for (i = 0; i < win_size; ++i)
2903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		new_node->rx_reorder_ptr[i] = NULL;
2913aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
2933aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
2943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
2953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
2983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for adding a BA request.
2993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes -
3013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Setting command ID and proper size
302e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab *      - Setting add BA request buffer
303e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab *      - Ensuring correct endian-ness
304e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab */
305e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabint mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
3063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct host_cmd_ds_11n_addba_req *add_ba_req =
3083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		(struct host_cmd_ds_11n_addba_req *)
3093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		&cmd->params.add_ba_req;
3103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
3123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
3133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
3143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
3193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for adding a BA response.
3203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes -
3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Setting command ID and proper size
3233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Setting add BA response buffer
3243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Ensuring correct endian-ness
325e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab */
3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				  struct host_cmd_ds_command *cmd,
3283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				  struct host_cmd_ds_11n_addba_req
3293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				  *cmd_addba_req)
3303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
3323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		(struct host_cmd_ds_11n_addba_rsp *)
3333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		&cmd->params.add_ba_rsp;
3343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	u8 tid;
3353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int win_size;
3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	uint16_t block_ack_param_set;
3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
34252284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab	       ETH_ALEN);
3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
3443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	add_ba_rsp->ssn = cmd_addba_req->ssn;
3463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		>> BLOCKACKPARAM_TID_POS;
3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* We donot support AMSDU inside AMPDU, hence reset the bit */
3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
3553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					     BLOCKACKPARAM_WINSIZE_POS);
3563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
3573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
3583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					& IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					>> BLOCKACKPARAM_WINSIZE_POS;
3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			    tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for deleting a BA request.
3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes -
3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Setting command ID and proper size
3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Setting del BA request buffer
3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *      - Ensuring correct endian-ness
3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
3783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		&cmd->params.del_ba;
3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	memcpy(del_ba, data_buf, sizeof(*del_ba));
3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
3883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function identifies if Rx reordering is needed for a received packet.
3893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * In case reordering is required, the function will do the reordering
3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * before sending it to kernel.
3923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The Rx reorder table is checked first with the received TID/TA pair. If
3943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * not found, the received packet is dispatched immediately. But if found,
3953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * the packet is reordered and all the packets in the updated Rx reordering
3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * table is dispatched until a hole is found.
3973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *
3983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * For sequence number less than the starting window, the packet is dropped.
3993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */
4003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
4013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				u16 seq_num, u16 tid,
4023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				u8 *ta, u8 pkt_type, void *payload)
4033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
4043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
405505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	int start_win, end_win, win_size;
406df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	u16 pkt_index;
407df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
408df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	rx_reor_tbl_ptr =
409df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
4103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton						tid, ta);
4116ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (!rx_reor_tbl_ptr) {
4126ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		if (pkt_type != PKT_TYPE_BAR)
4136ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			mwifiex_process_rx_packet(priv->adapter, payload);
4143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
4153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	start_win = rx_reor_tbl_ptr->start_win;
4173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	win_size = rx_reor_tbl_ptr->win_size;
418c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
4193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	del_timer(&rx_reor_tbl_ptr->timer_context.timer);
4203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
421f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf			+ (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
42210ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab
4234fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	/*
424e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	 * If seq_num is less then starting win then ignore and drop the
4253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * packet
4263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 */
4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
4283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
4293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				&& (seq_num < start_win))
4303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return -1;
4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else if ((seq_num < start_win)
432227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab			|| (seq_num > (start_win + (TWOPOW11)))) {
4337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		return -1;
43446510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE	}
43546510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE
436e5db5d44432abc82b1250dd05bd0a4b011392d9dDouglas Schilling Landgraf	/*
4373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * If this packet is a BAR we adjust seq_num as
4383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 * WinStart = seq_num
4393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	 */
4403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (pkt_type == PKT_TYPE_BAR)
4413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
4423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (((end_win < start_win)
4447e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	     && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
4456e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	     && (seq_num > end_win)) || ((end_win > start_win)
4466e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	     && ((seq_num > end_win) || (seq_num < start_win)))) {
4476e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		end_win = seq_num;
4486e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		if (((seq_num - win_size) + 1) >= 0)
4496e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			start_win = (end_win - win_size) + 1;
4506e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		else
4516e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
4526e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		mwifiex_11n_dispatch_pkt_until_start_win(priv,
4536e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora						rx_reor_tbl_ptr, start_win);
45417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	}
45517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
45617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	if (pkt_type != PKT_TYPE_BAR) {
45717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		if (seq_num >= start_win)
45817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			pkt_index = seq_num - start_win;
45917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		else
46017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
46117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
46217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
46317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			return -1;
46417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
46517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
46617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	}
4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/*
4693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	 * Dispatch all packets sequentially from start_win until a
4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	 * hole is found and adjust the start_win appropriately
4713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	 */
4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
4733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
4753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/*
4783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function deletes an entry for a given TID/TA pair.
4793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *
480d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky * The TID/TA are taken from del BA event body.
481d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky */
4823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabvoid
4833aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
4843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				u8 *peer_mac, u8 type, int initiator)
4853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
4866ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
4873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
4883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	u8 cleanup_rx_reorder_tbl;
4892fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	unsigned long flags;
490102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab
4913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (type == TYPE_DELBA_RECEIVE)
4923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		cleanup_rx_reorder_tbl = (initiator) ? true : false;
4933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	else
4942fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab		cleanup_rx_reorder_tbl = (initiator) ? false : true;
4953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
4973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	       "initiator=%d\n", peer_mac, tid, initiator);
4983aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4993aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (cleanup_rx_reorder_tbl) {
5003aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
5013aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab								 peer_mac);
502505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab		if (!rx_reor_tbl_ptr) {
503df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller			dev_dbg(priv->adapter->dev,
504df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller					"event: TID, TA not found in table\n");
505df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller			return;
506df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		}
5073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
5083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
5093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
5103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (!ptx_tbl) {
5113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			dev_dbg(priv->adapter->dev,
5123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab					"event: TID, RA not found in table\n");
5133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			return;
5143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		}
5153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
5173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
5183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
5193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
5203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/*
5233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * This function handles the command response of an add BA response.
5243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *
5253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Handling includes changing the header fields into CPU format and
5263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * creating the stream, provided the add BA is accepted.
5273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
5283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabint mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
5293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab			       struct host_cmd_ds_command *resp)
5303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
5313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
5323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		(struct host_cmd_ds_11n_addba_rsp *)
5333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		&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 */
573void 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 */
593void 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}
610