11n.c revision 19a898601ad192d8c59c3a8f1a4501919f53b94d
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 == NL80211_IFTYPE_STATION ||
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 == NL80211_IFTYPE_ADHOC) {
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_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
545				       HostCmd_ACT_GEN_SET, 0, &tx_buf);
546}
547
548/*
549 * This function checks if the given pointer is valid entry of
550 * Tx BA Stream table.
551 */
552static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
553				struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
554{
555	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
556
557	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
558		if (tx_ba_tsr_tbl == tx_tbl_ptr)
559			return true;
560	}
561
562	return false;
563}
564
565/*
566 * This function deletes the given entry in Tx BA Stream table.
567 *
568 * The function also performs a validity check on the supplied
569 * pointer before trying to delete.
570 */
571void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
572				struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
573{
574	if (!tx_ba_tsr_tbl &&
575			mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
576		return;
577
578	dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
579
580	list_del(&tx_ba_tsr_tbl->list);
581
582	kfree(tx_ba_tsr_tbl);
583}
584
585/*
586 * This function deletes all the entries in Tx BA Stream table.
587 */
588void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
589{
590	int i;
591	struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
592	unsigned long flags;
593
594	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
595	list_for_each_entry_safe(del_tbl_ptr, tmp_node,
596				 &priv->tx_ba_stream_tbl_ptr, list)
597		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
598	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
599
600	INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
601
602	for (i = 0; i < MAX_NUM_TID; ++i)
603		priv->aggr_prio_tbl[i].ampdu_ap =
604			priv->aggr_prio_tbl[i].ampdu_user;
605}
606
607/*
608 * This function returns the pointer to an entry in BA Stream
609 * table which matches the given RA/TID pair.
610 */
611struct mwifiex_tx_ba_stream_tbl *
612mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
613				 int tid, u8 *ra)
614{
615	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
616	unsigned long flags;
617
618	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
619	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
620		if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
621		    && (tx_ba_tsr_tbl->tid == tid)) {
622			spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
623					       flags);
624			return tx_ba_tsr_tbl;
625		}
626	}
627	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
628	return NULL;
629}
630
631/*
632 * This function creates an entry in Tx BA stream table for the
633 * given RA/TID pair.
634 */
635void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
636					 u8 *ra, int tid,
637					 enum mwifiex_ba_status ba_status)
638{
639	struct mwifiex_tx_ba_stream_tbl *new_node;
640	unsigned long flags;
641
642	if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
643		new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
644				   GFP_ATOMIC);
645		if (!new_node) {
646			dev_err(priv->adapter->dev,
647				"%s: failed to alloc new_node\n", __func__);
648			return;
649		}
650
651		INIT_LIST_HEAD(&new_node->list);
652
653		new_node->tid = tid;
654		new_node->ba_status = ba_status;
655		memcpy(new_node->ra, ra, ETH_ALEN);
656
657		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
658		list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
659		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
660	}
661}
662
663/*
664 * This function sends an add BA request to the given TID/RA pair.
665 */
666int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
667{
668	struct host_cmd_ds_11n_addba_req add_ba_req;
669	static u8 dialog_tok;
670	int ret;
671
672	dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
673
674	add_ba_req.block_ack_param_set = cpu_to_le16(
675		(u16) ((tid << BLOCKACKPARAM_TID_POS) |
676			 (priv->add_ba_param.
677			  tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
678			 IMMEDIATE_BLOCK_ACK));
679	add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
680
681	++dialog_tok;
682
683	if (dialog_tok == 0)
684		dialog_tok = 1;
685
686	add_ba_req.dialog_token = dialog_tok;
687	memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
688
689	/* We don't wait for the response of this command */
690	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
691				     0, 0, &add_ba_req);
692
693	return ret;
694}
695
696/*
697 * This function sends a delete BA request to the given TID/RA pair.
698 */
699int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
700		       int initiator)
701{
702	struct host_cmd_ds_11n_delba delba;
703	int ret;
704	uint16_t del_ba_param_set;
705
706	memset(&delba, 0, sizeof(delba));
707	delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
708
709	del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
710	if (initiator)
711		del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
712	else
713		del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
714
715	memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
716
717	/* We don't wait for the response of this command */
718	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
719				     HostCmd_ACT_GEN_SET, 0, &delba);
720
721	return ret;
722}
723
724/*
725 * This function handles the command response of a delete BA request.
726 */
727void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
728{
729	struct host_cmd_ds_11n_delba *cmd_del_ba =
730		(struct host_cmd_ds_11n_delba *) del_ba;
731	uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
732	int tid;
733
734	tid = del_ba_param_set >> DELBA_TID_POS;
735
736	mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
737					 TYPE_DELBA_RECEIVE,
738					 INITIATOR_BIT(del_ba_param_set));
739}
740
741/*
742 * This function retrieves the Rx reordering table.
743 */
744int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
745			       struct mwifiex_ds_rx_reorder_tbl *buf)
746{
747	int i;
748	struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
749	struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
750	int count = 0;
751	unsigned long flags;
752
753	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
754	list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
755			    list) {
756		rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
757		memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
758		rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
759		rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
760		for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
761			if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
762				rx_reo_tbl->buffer[i] = true;
763			else
764				rx_reo_tbl->buffer[i] = false;
765		}
766		rx_reo_tbl++;
767		count++;
768
769		if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
770			break;
771	}
772	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
773
774	return count;
775}
776
777/*
778 * This function retrieves the Tx BA stream table.
779 */
780int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
781				 struct mwifiex_ds_tx_ba_stream_tbl *buf)
782{
783	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
784	struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
785	int count = 0;
786	unsigned long flags;
787
788	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
789	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
790		rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
791		dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
792						__func__, rx_reo_tbl->tid);
793		memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
794		rx_reo_tbl++;
795		count++;
796		if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
797			break;
798	}
799	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
800
801	return count;
802}
803