11n.c revision 6d2bd916afe6950b50f750cd82bbb9c6ff58611f
1/*
2 * Marvell Wireless LAN device driver: 802.11n
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
28/*
29 * Fills HT capability information field, AMPDU Parameters field, HT extended
30 * capability field, and supported MCS set fields.
31 *
32 * Only the following HT capability information fields are used, all other
33 * fields are always turned off.
34 *
35 *  Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz)
36 *  Bit 4 : Greenfield support (0: Not supported, 1: Supported)
37 *  Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported)
38 *  Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported)
39 *  Bit 7 : Tx STBC (0: Not supported, 1: Supported)
40 *  Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams)
41 *  Bit 10 : Delayed BA support (0: Not supported, 1: Supported)
42 *  Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets)
43 *  Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported)
44 *
45 *  In addition, the following AMPDU Parameters are set -
46 *      - Maximum AMPDU length exponent (set to 3)
47 *      - Minimum AMPDU start spacing (set to 0 - No restrictions)
48 *
49 *  MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz
50 *  support.
51 *
52 *  RD responder bit to set to clear in the extended capability header.
53 */
54void
55mwifiex_fill_cap_info(struct mwifiex_private *priv,
56		      struct mwifiex_ie_types_htcap *ht_cap)
57{
58	struct mwifiex_adapter *adapter = priv->adapter;
59	u8 *mcs;
60	int rx_mcs_supp;
61	uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
62	uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
63
64	/* Convert dev_cap to IEEE80211_HT_CAP */
65	if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
66		ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
67	else
68		ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
69
70	if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
71		ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
72	else
73		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20;
74
75	if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
76		ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
77	else
78		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40;
79
80	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
81		ht_cap_info |= IEEE80211_HT_CAP_TX_STBC;
82	else
83		ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
84
85	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
86		ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
87	else
88		ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
89
90	if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap))
91		ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD;
92	else
93		ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD;
94
95	ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU;
96	ht_cap_info |= IEEE80211_HT_CAP_SM_PS;
97
98	ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR;
99	ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY;
100
101	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
102
103	mcs = (u8 *)&ht_cap->ht_cap.mcs;
104
105	/* Set MCS for 1x1 */
106	memset(mcs, 0xff, rx_mcs_supp);
107
108	/* Clear all the other values */
109	memset(&mcs[rx_mcs_supp], 0,
110			sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
111
112	if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA ||
113			(ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
114		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
115		SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
116
117	/* Clear RD responder bit */
118	RESETHT_EXTCAP_RDG(ht_ext_cap);
119
120	ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
121	ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
122}
123
124/*
125 * This function returns the pointer to an entry in BA Stream
126 * table which matches the requested BA status.
127 */
128static struct mwifiex_tx_ba_stream_tbl *
129mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
130				  enum mwifiex_ba_status ba_status)
131{
132	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
133	unsigned long flags;
134
135	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
136	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
137		if (tx_ba_tsr_tbl->ba_status == ba_status) {
138			spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
139					       flags);
140			return tx_ba_tsr_tbl;
141		}
142	}
143	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
144	return NULL;
145}
146
147/*
148 * This function handles the command response of delete a block
149 * ack request.
150 *
151 * The function checks the response success status and takes action
152 * accordingly (send an add BA request in case of success, or recreate
153 * the deleted stream in case of failure, if the add BA was also
154 * initiated by us).
155 */
156int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
157			  struct host_cmd_ds_command *resp)
158{
159	int tid;
160	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
161	struct host_cmd_ds_11n_delba *del_ba =
162		(struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
163	uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
164
165	tid = del_ba_param_set >> DELBA_TID_POS;
166	if (del_ba->del_result == BA_RESULT_SUCCESS) {
167		mwifiex_11n_delete_ba_stream_tbl(priv, tid,
168				del_ba->peer_mac_addr, TYPE_DELBA_SENT,
169				INITIATOR_BIT(del_ba_param_set));
170
171		tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
172						BA_STREAM_SETUP_INPROGRESS);
173		if (tx_ba_tbl)
174			mwifiex_send_addba(priv, tx_ba_tbl->tid,
175					   tx_ba_tbl->ra);
176	} else { /*
177		  * In case of failure, recreate the deleted stream in case
178		  * we initiated the ADDBA
179		  */
180		if (INITIATOR_BIT(del_ba_param_set)) {
181			mwifiex_11n_create_tx_ba_stream_tbl(priv,
182					del_ba->peer_mac_addr, tid,
183					BA_STREAM_SETUP_INPROGRESS);
184
185			tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
186					BA_STREAM_SETUP_INPROGRESS);
187			if (tx_ba_tbl)
188				mwifiex_11n_delete_ba_stream_tbl(priv,
189						tx_ba_tbl->tid, tx_ba_tbl->ra,
190						TYPE_DELBA_SENT, true);
191		}
192	}
193
194	return 0;
195}
196
197/*
198 * This function handles the command response of add a block
199 * ack request.
200 *
201 * Handling includes changing the header fields to CPU formats, checking
202 * the response success status and taking actions accordingly (delete the
203 * BA stream table in case of failure).
204 */
205int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
206			      struct host_cmd_ds_command *resp)
207{
208	int tid;
209	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
210		(struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
211	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
212
213	add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
214			& SSN_MASK);
215
216	tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
217		& IEEE80211_ADDBA_PARAM_TID_MASK)
218		>> BLOCKACKPARAM_TID_POS;
219	if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
220		tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
221						add_ba_rsp->peer_mac_addr);
222		if (tx_ba_tbl) {
223			dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
224			tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
225		} else {
226			dev_err(priv->adapter->dev, "BA stream not created\n");
227		}
228	} else {
229		mwifiex_11n_delete_ba_stream_tbl(priv, tid,
230						add_ba_rsp->peer_mac_addr,
231						TYPE_DELBA_SENT, true);
232		if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
233			priv->aggr_prio_tbl[tid].ampdu_ap =
234				BA_STREAM_NOT_ALLOWED;
235	}
236
237	return 0;
238}
239
240/*
241 * This function handles the command response of 11n configuration request.
242 *
243 * Handling includes changing the header fields into CPU format.
244 */
245int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
246			struct host_cmd_ds_command *resp,
247			void *data_buf)
248{
249	struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
250	struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
251
252	if (data_buf) {
253		tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
254		tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
255		tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
256	}
257	return 0;
258}
259
260/*
261 * This function prepares command of reconfigure Tx buffer.
262 *
263 * Preparation includes -
264 *      - Setting command ID, action and proper size
265 *      - Setting Tx buffer size (for SET only)
266 *      - Ensuring correct endian-ness
267 */
268int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
269			     struct host_cmd_ds_command *cmd, int cmd_action,
270			     void *data_buf)
271{
272	struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
273	u16 action = (u16) cmd_action;
274	u16 buf_size = *((u16 *) data_buf);
275
276	cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
277	cmd->size =
278		cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
279	tx_buf->action = cpu_to_le16(action);
280	switch (action) {
281	case HostCmd_ACT_GEN_SET:
282		dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
283		tx_buf->buff_size = cpu_to_le16(buf_size);
284		break;
285	case HostCmd_ACT_GEN_GET:
286	default:
287		tx_buf->buff_size = 0;
288		break;
289	}
290	return 0;
291}
292
293/*
294 * This function prepares command of AMSDU aggregation control.
295 *
296 * Preparation includes -
297 *      - Setting command ID, action and proper size
298 *      - Setting AMSDU control parameters (for SET only)
299 *      - Ensuring correct endian-ness
300 */
301int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
302				struct host_cmd_ds_command *cmd,
303				int cmd_action, void *data_buf)
304{
305	struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
306		&cmd->params.amsdu_aggr_ctrl;
307	u16 action = (u16) cmd_action;
308	struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
309		(struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
310
311	cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
312	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
313				+ S_DS_GEN);
314	amsdu_ctrl->action = cpu_to_le16(action);
315	switch (action) {
316	case HostCmd_ACT_GEN_SET:
317		amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
318		amsdu_ctrl->curr_buf_size = 0;
319		break;
320	case HostCmd_ACT_GEN_GET:
321	default:
322		amsdu_ctrl->curr_buf_size = 0;
323		break;
324	}
325	return 0;
326}
327
328/*
329 * This function handles the command response of AMSDU aggregation
330 * control request.
331 *
332 * Handling includes changing the header fields into CPU format.
333 */
334int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
335				struct host_cmd_ds_command *resp,
336				void *data_buf)
337{
338	struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
339	struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
340		&resp->params.amsdu_aggr_ctrl;
341
342	if (data_buf) {
343		amsdu_aggr_ctrl =
344			(struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
345		amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
346		amsdu_aggr_ctrl->curr_buf_size =
347			le16_to_cpu(amsdu_ctrl->curr_buf_size);
348	}
349	return 0;
350}
351
352/*
353 * This function prepares 11n configuration command.
354 *
355 * Preparation includes -
356 *      - Setting command ID, action and proper size
357 *      - Setting HT Tx capability and HT Tx information fields
358 *      - Ensuring correct endian-ness
359 */
360int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
361			struct host_cmd_ds_command *cmd,
362			u16 cmd_action, void *data_buf)
363{
364	struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
365	struct mwifiex_ds_11n_tx_cfg *txcfg =
366		(struct mwifiex_ds_11n_tx_cfg *) data_buf;
367
368	cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
369	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
370	htcfg->action = cpu_to_le16(cmd_action);
371	htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
372	htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
373	return 0;
374}
375
376/*
377 * This function appends an 11n TLV to a buffer.
378 *
379 * Buffer allocation is responsibility of the calling
380 * function. No size validation is made here.
381 *
382 * The function fills up the following sections, if applicable -
383 *      - HT capability IE
384 *      - HT information IE (with channel list)
385 *      - 20/40 BSS Coexistence IE
386 *      - HT Extended Capabilities IE
387 */
388int
389mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
390			   struct mwifiex_bssdescriptor *bss_desc,
391			   u8 **buffer)
392{
393	struct mwifiex_ie_types_htcap *ht_cap;
394	struct mwifiex_ie_types_htinfo *ht_info;
395	struct mwifiex_ie_types_chan_list_param_set *chan_list;
396	struct mwifiex_ie_types_2040bssco *bss_co_2040;
397	struct mwifiex_ie_types_extcap *ext_cap;
398	int ret_len = 0;
399
400	if (!buffer || !*buffer)
401		return ret_len;
402
403	if (bss_desc->bcn_ht_cap) {
404		ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
405		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
406		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
407		ht_cap->header.len =
408				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
409		memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
410		       (u8 *) bss_desc->bcn_ht_cap +
411		       sizeof(struct ieee_types_header),
412		       le16_to_cpu(ht_cap->header.len));
413
414		mwifiex_fill_cap_info(priv, ht_cap);
415
416		*buffer += sizeof(struct mwifiex_ie_types_htcap);
417		ret_len += sizeof(struct mwifiex_ie_types_htcap);
418	}
419
420	if (bss_desc->bcn_ht_info) {
421		if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
422			ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
423			memset(ht_info, 0,
424			       sizeof(struct mwifiex_ie_types_htinfo));
425			ht_info->header.type =
426					cpu_to_le16(WLAN_EID_HT_INFORMATION);
427			ht_info->header.len =
428				cpu_to_le16(sizeof(struct ieee80211_ht_info));
429
430			memcpy((u8 *) ht_info +
431			       sizeof(struct mwifiex_ie_types_header),
432			       (u8 *) bss_desc->bcn_ht_info +
433			       sizeof(struct ieee_types_header),
434			       le16_to_cpu(ht_info->header.len));
435
436			if (!ISSUPP_CHANWIDTH40
437					(priv->adapter->hw_dot_11n_dev_cap))
438				ht_info->ht_info.ht_param &=
439					~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
440					IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
441
442			*buffer += sizeof(struct mwifiex_ie_types_htinfo);
443			ret_len += sizeof(struct mwifiex_ie_types_htinfo);
444		}
445
446		chan_list =
447			(struct mwifiex_ie_types_chan_list_param_set *) *buffer;
448		memset(chan_list, 0,
449		       sizeof(struct mwifiex_ie_types_chan_list_param_set));
450		chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
451		chan_list->header.len = cpu_to_le16(
452			sizeof(struct mwifiex_ie_types_chan_list_param_set) -
453			sizeof(struct mwifiex_ie_types_header));
454		chan_list->chan_scan_param[0].chan_number =
455			bss_desc->bcn_ht_info->control_chan;
456		chan_list->chan_scan_param[0].radio_type =
457			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
458
459		if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap)
460			&& (bss_desc->bcn_ht_info->ht_param &
461				IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
462			SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
463					  radio_type,
464					  (bss_desc->bcn_ht_info->ht_param &
465					  IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
466
467		*buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
468		ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
469	}
470
471	if (bss_desc->bcn_bss_co_2040) {
472		bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
473		memset(bss_co_2040, 0,
474		       sizeof(struct mwifiex_ie_types_2040bssco));
475		bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
476		bss_co_2040->header.len =
477		       cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
478
479		memcpy((u8 *) bss_co_2040 +
480		       sizeof(struct mwifiex_ie_types_header),
481		       (u8 *) bss_desc->bcn_bss_co_2040 +
482		       sizeof(struct ieee_types_header),
483		       le16_to_cpu(bss_co_2040->header.len));
484
485		*buffer += sizeof(struct mwifiex_ie_types_2040bssco);
486		ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
487	}
488
489	if (bss_desc->bcn_ext_cap) {
490		ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
491		memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
492		ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
493		ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
494
495		memcpy((u8 *) ext_cap +
496		       sizeof(struct mwifiex_ie_types_header),
497		       (u8 *) bss_desc->bcn_ext_cap +
498		       sizeof(struct ieee_types_header),
499		       le16_to_cpu(ext_cap->header.len));
500
501		*buffer += sizeof(struct mwifiex_ie_types_extcap);
502		ret_len += sizeof(struct mwifiex_ie_types_extcap);
503	}
504
505	return ret_len;
506}
507
508/*
509 * This function reconfigures the Tx buffer size in firmware.
510 *
511 * This function prepares a firmware command and issues it, if
512 * the current Tx buffer size is different from the one requested.
513 * Maximum configurable Tx buffer size is limited by the HT capability
514 * field value.
515 */
516void
517mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
518		   struct mwifiex_bssdescriptor *bss_desc)
519{
520	u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
521	u16 tx_buf = 0;
522	u16 curr_tx_buf_size = 0;
523
524	if (bss_desc->bcn_ht_cap) {
525		if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
526				IEEE80211_HT_CAP_MAX_AMSDU)
527			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
528		else
529			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
530	}
531
532	tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
533
534	dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
535			max_amsdu, priv->adapter->max_tx_buf_size);
536
537	if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
538		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
539	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
540		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
541	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
542		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
543	if (curr_tx_buf_size != tx_buf)
544		mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
545			HostCmd_ACT_GEN_SET, 0,
546			NULL, &tx_buf);
547
548	return;
549}
550
551/*
552 * This function checks if the given pointer is valid entry of
553 * Tx BA Stream table.
554 */
555static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
556				struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
557{
558	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
559
560	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
561		if (tx_ba_tsr_tbl == tx_tbl_ptr)
562			return true;
563	}
564
565	return false;
566}
567
568/*
569 * This function deletes the given entry in Tx BA Stream table.
570 *
571 * The function also performs a validity check on the supplied
572 * pointer before trying to delete.
573 */
574void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
575				struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
576{
577	if (!tx_ba_tsr_tbl &&
578			mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
579		return;
580
581	dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
582
583	list_del(&tx_ba_tsr_tbl->list);
584
585	kfree(tx_ba_tsr_tbl);
586
587	return;
588}
589
590/*
591 * This function deletes all the entries in Tx BA Stream table.
592 */
593void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
594{
595	int i;
596	struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
597	unsigned long flags;
598
599	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
600	list_for_each_entry_safe(del_tbl_ptr, tmp_node,
601				 &priv->tx_ba_stream_tbl_ptr, list)
602		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
603	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
604
605	INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
606
607	for (i = 0; i < MAX_NUM_TID; ++i)
608		priv->aggr_prio_tbl[i].ampdu_ap =
609			priv->aggr_prio_tbl[i].ampdu_user;
610}
611
612/*
613 * This function returns the pointer to an entry in BA Stream
614 * table which matches the given RA/TID pair.
615 */
616struct mwifiex_tx_ba_stream_tbl *
617mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
618				 int tid, u8 *ra)
619{
620	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
621	unsigned long flags;
622
623	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
624	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
625		if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
626		    && (tx_ba_tsr_tbl->tid == tid)) {
627			spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
628					       flags);
629			return tx_ba_tsr_tbl;
630		}
631	}
632	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
633	return NULL;
634}
635
636/*
637 * This function creates an entry in Tx BA stream table for the
638 * given RA/TID pair.
639 */
640void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
641					 u8 *ra, int tid,
642					 enum mwifiex_ba_status ba_status)
643{
644	struct mwifiex_tx_ba_stream_tbl *new_node;
645	unsigned long flags;
646
647	if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
648		new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
649				   GFP_ATOMIC);
650		if (!new_node) {
651			dev_err(priv->adapter->dev,
652				"%s: failed to alloc new_node\n", __func__);
653			return;
654		}
655
656		INIT_LIST_HEAD(&new_node->list);
657
658		new_node->tid = tid;
659		new_node->ba_status = ba_status;
660		memcpy(new_node->ra, ra, ETH_ALEN);
661
662		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
663		list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
664		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
665	}
666
667	return;
668}
669
670/*
671 * This function sends an add BA request to the given TID/RA pair.
672 */
673int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
674{
675	struct host_cmd_ds_11n_addba_req add_ba_req;
676	static u8 dialog_tok;
677	int ret;
678
679	dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
680
681	add_ba_req.block_ack_param_set = cpu_to_le16(
682		(u16) ((tid << BLOCKACKPARAM_TID_POS) |
683			 (priv->add_ba_param.
684			  tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
685			 IMMEDIATE_BLOCK_ACK));
686	add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
687
688	++dialog_tok;
689
690	if (dialog_tok == 0)
691		dialog_tok = 1;
692
693	add_ba_req.dialog_token = dialog_tok;
694	memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
695
696	/* We don't wait for the response of this command */
697	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
698				  0, 0, NULL, &add_ba_req);
699
700	return ret;
701}
702
703/*
704 * This function sends a delete BA request to the given TID/RA pair.
705 */
706int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
707		       int initiator)
708{
709	struct host_cmd_ds_11n_delba delba;
710	int ret;
711	uint16_t del_ba_param_set;
712
713	memset(&delba, 0, sizeof(delba));
714	delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
715
716	del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
717	if (initiator)
718		del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
719	else
720		del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
721
722	memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
723
724	/* We don't wait for the response of this command */
725	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
726				  HostCmd_ACT_GEN_SET, 0, NULL, &delba);
727
728	return ret;
729}
730
731/*
732 * This function handles the command response of a delete BA request.
733 */
734void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
735{
736	struct host_cmd_ds_11n_delba *cmd_del_ba =
737		(struct host_cmd_ds_11n_delba *) del_ba;
738	uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
739	int tid;
740
741	tid = del_ba_param_set >> DELBA_TID_POS;
742
743	mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
744					 TYPE_DELBA_RECEIVE,
745					 INITIATOR_BIT(del_ba_param_set));
746}
747
748/*
749 * This function retrieves the Rx reordering table.
750 */
751int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
752			       struct mwifiex_ds_rx_reorder_tbl *buf)
753{
754	int i;
755	struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
756	struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
757	int count = 0;
758	unsigned long flags;
759
760	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
761	list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
762			    list) {
763		rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
764		memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
765		rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
766		rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
767		for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
768			if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
769				rx_reo_tbl->buffer[i] = true;
770			else
771				rx_reo_tbl->buffer[i] = false;
772		}
773		rx_reo_tbl++;
774		count++;
775
776		if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
777			break;
778	}
779	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
780
781	return count;
782}
783
784/*
785 * This function retrieves the Tx BA stream table.
786 */
787int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
788				 struct mwifiex_ds_tx_ba_stream_tbl *buf)
789{
790	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
791	struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
792	int count = 0;
793	unsigned long flags;
794
795	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
796	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
797		rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
798		dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
799						__func__, rx_reo_tbl->tid);
800		memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
801		rx_reo_tbl++;
802		count++;
803		if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
804			break;
805	}
806	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
807
808	return count;
809}
810