mwifiex: remove redundant local variables and comments
[deliverable/linux.git] / drivers / net / wireless / mwifiex / 11n.c
CommitLineData
5e6e3a92
BZ
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
6d2bd916
MY
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;
5e6e3a92 67 else
6d2bd916 68 ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5e6e3a92 69
6d2bd916
MY
70 if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
71 ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
5e6e3a92 72 else
6d2bd916 73 ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20;
5e6e3a92 74
6d2bd916
MY
75 if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
76 ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
5e6e3a92 77 else
6d2bd916 78 ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40;
5e6e3a92 79
5e6e3a92 80 if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
6d2bd916 81 ht_cap_info |= IEEE80211_HT_CAP_TX_STBC;
5e6e3a92 82 else
6d2bd916 83 ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
5e6e3a92 84
6d2bd916
MY
85 if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
86 ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
5e6e3a92 87 else
6d2bd916 88 ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
5e6e3a92 89
6d2bd916
MY
90 if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap))
91 ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD;
5e6e3a92 92 else
6d2bd916 93 ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD;
5e6e3a92 94
6d2bd916
MY
95 ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU;
96 ht_cap_info |= IEEE80211_HT_CAP_SM_PS;
5e6e3a92 97
6d2bd916
MY
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;
5e6e3a92
BZ
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
eecd8250 112 if (priv->bss_mode == NL80211_IFTYPE_STATION ||
6d2bd916 113 (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
5e6e3a92
BZ
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
5e6e3a92
BZ
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 */
572e8f3e 245int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf)
5e6e3a92
BZ
246{
247 struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
248 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
249
250 if (data_buf) {
251 tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
252 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
253 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
254 }
255 return 0;
256}
257
258/*
259 * This function prepares command of reconfigure Tx buffer.
260 *
261 * Preparation includes -
262 * - Setting command ID, action and proper size
263 * - Setting Tx buffer size (for SET only)
264 * - Ensuring correct endian-ness
265 */
266int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
267 struct host_cmd_ds_command *cmd, int cmd_action,
268 void *data_buf)
269{
270 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
271 u16 action = (u16) cmd_action;
272 u16 buf_size = *((u16 *) data_buf);
273
274 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
275 cmd->size =
276 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
277 tx_buf->action = cpu_to_le16(action);
278 switch (action) {
279 case HostCmd_ACT_GEN_SET:
280 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
281 tx_buf->buff_size = cpu_to_le16(buf_size);
282 break;
283 case HostCmd_ACT_GEN_GET:
284 default:
285 tx_buf->buff_size = 0;
286 break;
287 }
288 return 0;
289}
290
291/*
292 * This function prepares command of AMSDU aggregation control.
293 *
294 * Preparation includes -
295 * - Setting command ID, action and proper size
296 * - Setting AMSDU control parameters (for SET only)
297 * - Ensuring correct endian-ness
298 */
572e8f3e 299int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
5e6e3a92
BZ
300 int cmd_action, void *data_buf)
301{
302 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
303 &cmd->params.amsdu_aggr_ctrl;
304 u16 action = (u16) cmd_action;
305 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
306 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
307
308 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
309 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
310 + S_DS_GEN);
311 amsdu_ctrl->action = cpu_to_le16(action);
312 switch (action) {
313 case HostCmd_ACT_GEN_SET:
314 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
315 amsdu_ctrl->curr_buf_size = 0;
316 break;
317 case HostCmd_ACT_GEN_GET:
318 default:
319 amsdu_ctrl->curr_buf_size = 0;
320 break;
321 }
322 return 0;
323}
324
325/*
326 * This function handles the command response of AMSDU aggregation
327 * control request.
328 *
329 * Handling includes changing the header fields into CPU format.
330 */
572e8f3e 331int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
5e6e3a92
BZ
332 void *data_buf)
333{
334 struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
335 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
336 &resp->params.amsdu_aggr_ctrl;
337
338 if (data_buf) {
339 amsdu_aggr_ctrl =
340 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
341 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
342 amsdu_aggr_ctrl->curr_buf_size =
343 le16_to_cpu(amsdu_ctrl->curr_buf_size);
344 }
345 return 0;
346}
347
348/*
349 * This function prepares 11n configuration command.
350 *
351 * Preparation includes -
352 * - Setting command ID, action and proper size
353 * - Setting HT Tx capability and HT Tx information fields
354 * - Ensuring correct endian-ness
355 */
572e8f3e 356int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
5e6e3a92
BZ
357 u16 cmd_action, void *data_buf)
358{
359 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
360 struct mwifiex_ds_11n_tx_cfg *txcfg =
361 (struct mwifiex_ds_11n_tx_cfg *) data_buf;
362
363 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
364 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
365 htcfg->action = cpu_to_le16(cmd_action);
366 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
367 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
368 return 0;
369}
370
371/*
372 * This function appends an 11n TLV to a buffer.
373 *
374 * Buffer allocation is responsibility of the calling
375 * function. No size validation is made here.
376 *
377 * The function fills up the following sections, if applicable -
378 * - HT capability IE
379 * - HT information IE (with channel list)
380 * - 20/40 BSS Coexistence IE
381 * - HT Extended Capabilities IE
382 */
383int
384mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
385 struct mwifiex_bssdescriptor *bss_desc,
386 u8 **buffer)
387{
388 struct mwifiex_ie_types_htcap *ht_cap;
389 struct mwifiex_ie_types_htinfo *ht_info;
390 struct mwifiex_ie_types_chan_list_param_set *chan_list;
391 struct mwifiex_ie_types_2040bssco *bss_co_2040;
392 struct mwifiex_ie_types_extcap *ext_cap;
393 int ret_len = 0;
394
395 if (!buffer || !*buffer)
396 return ret_len;
397
398 if (bss_desc->bcn_ht_cap) {
399 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
400 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
401 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
402 ht_cap->header.len =
403 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
404 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
405 (u8 *) bss_desc->bcn_ht_cap +
406 sizeof(struct ieee_types_header),
407 le16_to_cpu(ht_cap->header.len));
408
409 mwifiex_fill_cap_info(priv, ht_cap);
410
411 *buffer += sizeof(struct mwifiex_ie_types_htcap);
412 ret_len += sizeof(struct mwifiex_ie_types_htcap);
413 }
414
415 if (bss_desc->bcn_ht_info) {
eecd8250 416 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
5e6e3a92
BZ
417 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
418 memset(ht_info, 0,
419 sizeof(struct mwifiex_ie_types_htinfo));
420 ht_info->header.type =
421 cpu_to_le16(WLAN_EID_HT_INFORMATION);
422 ht_info->header.len =
423 cpu_to_le16(sizeof(struct ieee80211_ht_info));
424
425 memcpy((u8 *) ht_info +
426 sizeof(struct mwifiex_ie_types_header),
427 (u8 *) bss_desc->bcn_ht_info +
428 sizeof(struct ieee_types_header),
429 le16_to_cpu(ht_info->header.len));
430
431 if (!ISSUPP_CHANWIDTH40
6d2bd916
MY
432 (priv->adapter->hw_dot_11n_dev_cap))
433 ht_info->ht_info.ht_param &=
434 ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
435 IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
5e6e3a92
BZ
436
437 *buffer += sizeof(struct mwifiex_ie_types_htinfo);
438 ret_len += sizeof(struct mwifiex_ie_types_htinfo);
439 }
440
441 chan_list =
442 (struct mwifiex_ie_types_chan_list_param_set *) *buffer;
443 memset(chan_list, 0,
444 sizeof(struct mwifiex_ie_types_chan_list_param_set));
445 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
446 chan_list->header.len = cpu_to_le16(
447 sizeof(struct mwifiex_ie_types_chan_list_param_set) -
448 sizeof(struct mwifiex_ie_types_header));
449 chan_list->chan_scan_param[0].chan_number =
450 bss_desc->bcn_ht_info->control_chan;
451 chan_list->chan_scan_param[0].radio_type =
452 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
453
6d2bd916
MY
454 if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap)
455 && (bss_desc->bcn_ht_info->ht_param &
456 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
5e6e3a92
BZ
457 SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
458 radio_type,
6d2bd916
MY
459 (bss_desc->bcn_ht_info->ht_param &
460 IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
5e6e3a92
BZ
461
462 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
463 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
464 }
465
466 if (bss_desc->bcn_bss_co_2040) {
467 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
468 memset(bss_co_2040, 0,
469 sizeof(struct mwifiex_ie_types_2040bssco));
470 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
471 bss_co_2040->header.len =
472 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
473
474 memcpy((u8 *) bss_co_2040 +
475 sizeof(struct mwifiex_ie_types_header),
476 (u8 *) bss_desc->bcn_bss_co_2040 +
477 sizeof(struct ieee_types_header),
478 le16_to_cpu(bss_co_2040->header.len));
479
480 *buffer += sizeof(struct mwifiex_ie_types_2040bssco);
481 ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
482 }
483
484 if (bss_desc->bcn_ext_cap) {
485 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
486 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
487 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
488 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
489
490 memcpy((u8 *) ext_cap +
491 sizeof(struct mwifiex_ie_types_header),
492 (u8 *) bss_desc->bcn_ext_cap +
493 sizeof(struct ieee_types_header),
494 le16_to_cpu(ext_cap->header.len));
495
496 *buffer += sizeof(struct mwifiex_ie_types_extcap);
497 ret_len += sizeof(struct mwifiex_ie_types_extcap);
498 }
499
500 return ret_len;
501}
502
503/*
504 * This function reconfigures the Tx buffer size in firmware.
505 *
506 * This function prepares a firmware command and issues it, if
507 * the current Tx buffer size is different from the one requested.
508 * Maximum configurable Tx buffer size is limited by the HT capability
509 * field value.
510 */
511void
512mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
513 struct mwifiex_bssdescriptor *bss_desc)
514{
515 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
516 u16 tx_buf = 0;
517 u16 curr_tx_buf_size = 0;
518
519 if (bss_desc->bcn_ht_cap) {
6d2bd916
MY
520 if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
521 IEEE80211_HT_CAP_MAX_AMSDU)
5e6e3a92
BZ
522 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
523 else
524 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
525 }
526
527 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
528
529 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
530 max_amsdu, priv->adapter->max_tx_buf_size);
531
532 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
533 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
534 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
535 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
536 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
537 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
538 if (curr_tx_buf_size != tx_buf)
600f5d90
AK
539 mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
540 HostCmd_ACT_GEN_SET, 0, &tx_buf);
5e6e3a92
BZ
541}
542
543/*
544 * This function checks if the given pointer is valid entry of
545 * Tx BA Stream table.
546 */
547static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
548 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
549{
550 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
551
552 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
553 if (tx_ba_tsr_tbl == tx_tbl_ptr)
554 return true;
555 }
556
557 return false;
558}
559
560/*
561 * This function deletes the given entry in Tx BA Stream table.
562 *
563 * The function also performs a validity check on the supplied
564 * pointer before trying to delete.
565 */
566void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
567 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
568{
569 if (!tx_ba_tsr_tbl &&
570 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
571 return;
572
573 dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
574
575 list_del(&tx_ba_tsr_tbl->list);
576
577 kfree(tx_ba_tsr_tbl);
5e6e3a92
BZ
578}
579
580/*
581 * This function deletes all the entries in Tx BA Stream table.
582 */
583void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
584{
585 int i;
586 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
587 unsigned long flags;
588
589 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
590 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
591 &priv->tx_ba_stream_tbl_ptr, list)
592 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
593 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
594
595 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
596
597 for (i = 0; i < MAX_NUM_TID; ++i)
598 priv->aggr_prio_tbl[i].ampdu_ap =
599 priv->aggr_prio_tbl[i].ampdu_user;
600}
601
602/*
603 * This function returns the pointer to an entry in BA Stream
604 * table which matches the given RA/TID pair.
605 */
606struct mwifiex_tx_ba_stream_tbl *
607mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
608 int tid, u8 *ra)
609{
610 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
611 unsigned long flags;
612
613 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
614 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
615 if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
616 && (tx_ba_tsr_tbl->tid == tid)) {
617 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
618 flags);
619 return tx_ba_tsr_tbl;
620 }
621 }
622 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
623 return NULL;
624}
625
626/*
627 * This function creates an entry in Tx BA stream table for the
628 * given RA/TID pair.
629 */
630void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
631 u8 *ra, int tid,
632 enum mwifiex_ba_status ba_status)
633{
634 struct mwifiex_tx_ba_stream_tbl *new_node;
635 unsigned long flags;
636
637 if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
638 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
639 GFP_ATOMIC);
640 if (!new_node) {
641 dev_err(priv->adapter->dev,
642 "%s: failed to alloc new_node\n", __func__);
643 return;
644 }
645
646 INIT_LIST_HEAD(&new_node->list);
647
648 new_node->tid = tid;
649 new_node->ba_status = ba_status;
650 memcpy(new_node->ra, ra, ETH_ALEN);
651
652 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
653 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
654 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
655 }
5e6e3a92
BZ
656}
657
658/*
659 * This function sends an add BA request to the given TID/RA pair.
660 */
661int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
662{
663 struct host_cmd_ds_11n_addba_req add_ba_req;
664 static u8 dialog_tok;
665 int ret;
666
667 dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
668
669 add_ba_req.block_ack_param_set = cpu_to_le16(
670 (u16) ((tid << BLOCKACKPARAM_TID_POS) |
671 (priv->add_ba_param.
672 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
673 IMMEDIATE_BLOCK_ACK));
674 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
675
676 ++dialog_tok;
677
678 if (dialog_tok == 0)
679 dialog_tok = 1;
680
681 add_ba_req.dialog_token = dialog_tok;
682 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
683
684 /* We don't wait for the response of this command */
600f5d90
AK
685 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
686 0, 0, &add_ba_req);
5e6e3a92
BZ
687
688 return ret;
689}
690
691/*
692 * This function sends a delete BA request to the given TID/RA pair.
693 */
694int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
695 int initiator)
696{
697 struct host_cmd_ds_11n_delba delba;
698 int ret;
699 uint16_t del_ba_param_set;
700
701 memset(&delba, 0, sizeof(delba));
702 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
703
704 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
705 if (initiator)
706 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
707 else
708 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
709
710 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
711
712 /* We don't wait for the response of this command */
600f5d90
AK
713 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
714 HostCmd_ACT_GEN_SET, 0, &delba);
5e6e3a92
BZ
715
716 return ret;
717}
718
719/*
720 * This function handles the command response of a delete BA request.
721 */
722void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
723{
724 struct host_cmd_ds_11n_delba *cmd_del_ba =
725 (struct host_cmd_ds_11n_delba *) del_ba;
726 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
727 int tid;
728
729 tid = del_ba_param_set >> DELBA_TID_POS;
730
731 mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
732 TYPE_DELBA_RECEIVE,
733 INITIATOR_BIT(del_ba_param_set));
734}
735
736/*
737 * This function retrieves the Rx reordering table.
738 */
739int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
740 struct mwifiex_ds_rx_reorder_tbl *buf)
741{
742 int i;
743 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
744 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
745 int count = 0;
746 unsigned long flags;
747
748 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
749 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
750 list) {
751 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
752 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
753 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
754 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
755 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
756 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
757 rx_reo_tbl->buffer[i] = true;
758 else
759 rx_reo_tbl->buffer[i] = false;
760 }
761 rx_reo_tbl++;
762 count++;
763
764 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
765 break;
766 }
767 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
768
769 return count;
770}
771
772/*
773 * This function retrieves the Tx BA stream table.
774 */
775int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
776 struct mwifiex_ds_tx_ba_stream_tbl *buf)
777{
778 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
779 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
780 int count = 0;
781 unsigned long flags;
782
783 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
784 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
785 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
786 dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
787 __func__, rx_reo_tbl->tid);
788 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
789 rx_reo_tbl++;
790 count++;
791 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
792 break;
793 }
794 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
795
796 return count;
797}
This page took 0.082519 seconds and 5 git commands to generate.