blob: 0e04a21be0a31f958a5c5a841c4406095ae97639 [file] [log] [blame]
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001/*
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 if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) &&
65 ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))
66 SETHT_SUPPCHANWIDTH(ht_cap_info);
67 else
68 RESETHT_SUPPCHANWIDTH(ht_cap_info);
69
70 if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap) &&
71 ISSUPP_GREENFIELD(adapter->usr_dot_11n_dev_cap))
72 SETHT_GREENFIELD(ht_cap_info);
73 else
74 RESETHT_GREENFIELD(ht_cap_info);
75
76 if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap) &&
77 ISSUPP_SHORTGI20(adapter->usr_dot_11n_dev_cap))
78 SETHT_SHORTGI20(ht_cap_info);
79 else
80 RESETHT_SHORTGI20(ht_cap_info);
81
82 if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap) &&
83 ISSUPP_SHORTGI40(adapter->usr_dot_11n_dev_cap))
84 SETHT_SHORTGI40(ht_cap_info);
85 else
86 RESETHT_SHORTGI40(ht_cap_info);
87
88 /* No user config for RX STBC yet */
89 if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)
90 && ISSUPP_RXSTBC(adapter->usr_dot_11n_dev_cap))
91 SETHT_RXSTBC(ht_cap_info, 1);
92 else
93 RESETHT_RXSTBC(ht_cap_info);
94
95 /* No user config for TX STBC yet */
96 if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
97 SETHT_TXSTBC(ht_cap_info);
98 else
99 RESETHT_TXSTBC(ht_cap_info);
100
101 /* No user config for Delayed BACK yet */
102 if (GET_DELAYEDBACK(adapter->hw_dot_11n_dev_cap))
103 SETHT_DELAYEDBACK(ht_cap_info);
104 else
105 RESETHT_DELAYEDBACK(ht_cap_info);
106
107 if (ISENABLED_40MHZ_INTOLARENT(adapter->usr_dot_11n_dev_cap))
108 SETHT_40MHZ_INTOLARANT(ht_cap_info);
109 else
110 RESETHT_40MHZ_INTOLARANT(ht_cap_info);
111
112 SETAMPDU_SIZE(ht_cap->ht_cap.ampdu_params_info, AMPDU_FACTOR_64K);
113 SETAMPDU_SPACING(ht_cap->ht_cap.ampdu_params_info, 0);
114
115 /* Need change to support 8k AMSDU receive */
116 RESETHT_MAXAMSDU(ht_cap_info);
117
118 rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
119
120 mcs = (u8 *)&ht_cap->ht_cap.mcs;
121
122 /* Set MCS for 1x1 */
123 memset(mcs, 0xff, rx_mcs_supp);
124
125 /* Clear all the other values */
126 memset(&mcs[rx_mcs_supp], 0,
127 sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
128
129 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA ||
130 (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) &&
131 ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap)))
132 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
133 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
134
135 /* Clear RD responder bit */
136 RESETHT_EXTCAP_RDG(ht_ext_cap);
137
138 ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
139 ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
140}
141
142/*
143 * Shows HT capability information fields.
144 *
145 * The following HT capability information fields are supported.
146 * - Maximum AMSDU length (3839 bytes or 7935 bytes)
147 * - Beam forming support
148 * - Greenfield preamble support
149 * - AMPDU support
150 * - MIMO Power Save support
151 * - Rx STBC support
152 * - Tx STBC support
153 * - Short GI for 20 MHz support
154 * - Short GI for 40 MHz support
155 * - LDPC coded packets receive support
156 * - Number of delayed BA streams
157 * - Number of immediate BA streams
158 * - 10 MHz channel width support
159 * - 20 MHz channel width support
160 * - 40 MHz channel width support
161 * - Presence of Tx antenna A/B/C/D
162 * - Presence of Rx antenna A/B/C/D
163 */
164void
165mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap)
166{
167 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Max MSDU len = %s octets\n",
168 (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
169 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Beam forming %s\n",
170 (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
171 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Greenfield preamble %s\n",
172 (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
173 dev_dbg(adapter->dev, "info: GET_HW_SPEC: AMPDU %s\n",
174 (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
175 dev_dbg(adapter->dev, "info: GET_HW_SPEC: MIMO Power Save %s\n",
176 (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
177 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Rx STBC %s\n",
178 (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
179 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Tx STBC %s\n",
180 (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
181 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 40 Mhz %s\n",
182 (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
183 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 20 Mhz %s\n",
184 (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
185 dev_dbg(adapter->dev, "info: GET_HW_SPEC: LDPC coded packet receive %s\n",
186 (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
187 dev_dbg(adapter->dev,
188 "info: GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
189 GET_DELAYEDBACK(cap));
190 dev_dbg(adapter->dev,
191 "info: GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
192 GET_IMMEDIATEBACK(cap));
193 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 40 Mhz channel width %s\n",
194 (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
195 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 20 Mhz channel width %s\n",
196 (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
197 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 10 Mhz channel width %s\n",
198 (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
199
200 if (ISSUPP_RXANTENNAA(cap))
201 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea A\n");
202
203 if (ISSUPP_RXANTENNAB(cap))
204 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea B\n");
205
206 if (ISSUPP_RXANTENNAC(cap))
207 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea C\n");
208
209 if (ISSUPP_RXANTENNAD(cap))
210 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea D\n");
211
212 if (ISSUPP_TXANTENNAA(cap))
213 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea A\n");
214
215 if (ISSUPP_TXANTENNAB(cap))
216 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea B\n");
217
218 if (ISSUPP_TXANTENNAC(cap))
219 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea C\n");
220
221 if (ISSUPP_TXANTENNAD(cap))
222 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea D\n");
223
224 return;
225}
226
227/*
228 * Shows HT MCS support field.
229 */
230void
231mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support)
232{
233 dev_dbg(adapter->dev, "info: GET_HW_SPEC: MCSs for %dx%d MIMO\n",
234 GET_RXMCSSUPP(support), GET_TXMCSSUPP(support));
235 return;
236}
237
238/*
239 * This function returns the pointer to an entry in BA Stream
240 * table which matches the requested BA status.
241 */
242static struct mwifiex_tx_ba_stream_tbl *
243mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
244 enum mwifiex_ba_status ba_status)
245{
246 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
247 unsigned long flags;
248
249 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
250 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
251 if (tx_ba_tsr_tbl->ba_status == ba_status) {
252 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
253 flags);
254 return tx_ba_tsr_tbl;
255 }
256 }
257 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
258 return NULL;
259}
260
261/*
262 * This function handles the command response of delete a block
263 * ack request.
264 *
265 * The function checks the response success status and takes action
266 * accordingly (send an add BA request in case of success, or recreate
267 * the deleted stream in case of failure, if the add BA was also
268 * initiated by us).
269 */
270int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
271 struct host_cmd_ds_command *resp)
272{
273 int tid;
274 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
275 struct host_cmd_ds_11n_delba *del_ba =
276 (struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
277 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
278
279 tid = del_ba_param_set >> DELBA_TID_POS;
280 if (del_ba->del_result == BA_RESULT_SUCCESS) {
281 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
282 del_ba->peer_mac_addr, TYPE_DELBA_SENT,
283 INITIATOR_BIT(del_ba_param_set));
284
285 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
286 BA_STREAM_SETUP_INPROGRESS);
287 if (tx_ba_tbl)
288 mwifiex_send_addba(priv, tx_ba_tbl->tid,
289 tx_ba_tbl->ra);
290 } else { /*
291 * In case of failure, recreate the deleted stream in case
292 * we initiated the ADDBA
293 */
294 if (INITIATOR_BIT(del_ba_param_set)) {
295 mwifiex_11n_create_tx_ba_stream_tbl(priv,
296 del_ba->peer_mac_addr, tid,
297 BA_STREAM_SETUP_INPROGRESS);
298
299 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
300 BA_STREAM_SETUP_INPROGRESS);
301 if (tx_ba_tbl)
302 mwifiex_11n_delete_ba_stream_tbl(priv,
303 tx_ba_tbl->tid, tx_ba_tbl->ra,
304 TYPE_DELBA_SENT, true);
305 }
306 }
307
308 return 0;
309}
310
311/*
312 * This function handles the command response of add a block
313 * ack request.
314 *
315 * Handling includes changing the header fields to CPU formats, checking
316 * the response success status and taking actions accordingly (delete the
317 * BA stream table in case of failure).
318 */
319int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
320 struct host_cmd_ds_command *resp)
321{
322 int tid;
323 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
324 (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
325 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
326
327 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
328 & SSN_MASK);
329
330 tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
331 & IEEE80211_ADDBA_PARAM_TID_MASK)
332 >> BLOCKACKPARAM_TID_POS;
333 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
334 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
335 add_ba_rsp->peer_mac_addr);
336 if (tx_ba_tbl) {
337 dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
338 tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
339 } else {
340 dev_err(priv->adapter->dev, "BA stream not created\n");
341 }
342 } else {
343 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
344 add_ba_rsp->peer_mac_addr,
345 TYPE_DELBA_SENT, true);
346 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
347 priv->aggr_prio_tbl[tid].ampdu_ap =
348 BA_STREAM_NOT_ALLOWED;
349 }
350
351 return 0;
352}
353
354/*
355 * This function handles the command response of 11n configuration request.
356 *
357 * Handling includes changing the header fields into CPU format.
358 */
359int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
360 struct host_cmd_ds_command *resp,
361 void *data_buf)
362{
363 struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
364 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
365
366 if (data_buf) {
367 tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
368 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
369 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
370 }
371 return 0;
372}
373
374/*
375 * This function prepares command of reconfigure Tx buffer.
376 *
377 * Preparation includes -
378 * - Setting command ID, action and proper size
379 * - Setting Tx buffer size (for SET only)
380 * - Ensuring correct endian-ness
381 */
382int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
383 struct host_cmd_ds_command *cmd, int cmd_action,
384 void *data_buf)
385{
386 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
387 u16 action = (u16) cmd_action;
388 u16 buf_size = *((u16 *) data_buf);
389
390 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
391 cmd->size =
392 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
393 tx_buf->action = cpu_to_le16(action);
394 switch (action) {
395 case HostCmd_ACT_GEN_SET:
396 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
397 tx_buf->buff_size = cpu_to_le16(buf_size);
398 break;
399 case HostCmd_ACT_GEN_GET:
400 default:
401 tx_buf->buff_size = 0;
402 break;
403 }
404 return 0;
405}
406
407/*
408 * This function prepares command of AMSDU aggregation control.
409 *
410 * Preparation includes -
411 * - Setting command ID, action and proper size
412 * - Setting AMSDU control parameters (for SET only)
413 * - Ensuring correct endian-ness
414 */
415int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
416 struct host_cmd_ds_command *cmd,
417 int cmd_action, void *data_buf)
418{
419 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
420 &cmd->params.amsdu_aggr_ctrl;
421 u16 action = (u16) cmd_action;
422 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
423 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
424
425 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
426 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
427 + S_DS_GEN);
428 amsdu_ctrl->action = cpu_to_le16(action);
429 switch (action) {
430 case HostCmd_ACT_GEN_SET:
431 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
432 amsdu_ctrl->curr_buf_size = 0;
433 break;
434 case HostCmd_ACT_GEN_GET:
435 default:
436 amsdu_ctrl->curr_buf_size = 0;
437 break;
438 }
439 return 0;
440}
441
442/*
443 * This function handles the command response of AMSDU aggregation
444 * control request.
445 *
446 * Handling includes changing the header fields into CPU format.
447 */
448int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
449 struct host_cmd_ds_command *resp,
450 void *data_buf)
451{
452 struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
453 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
454 &resp->params.amsdu_aggr_ctrl;
455
456 if (data_buf) {
457 amsdu_aggr_ctrl =
458 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
459 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
460 amsdu_aggr_ctrl->curr_buf_size =
461 le16_to_cpu(amsdu_ctrl->curr_buf_size);
462 }
463 return 0;
464}
465
466/*
467 * This function prepares 11n configuration command.
468 *
469 * Preparation includes -
470 * - Setting command ID, action and proper size
471 * - Setting HT Tx capability and HT Tx information fields
472 * - Ensuring correct endian-ness
473 */
474int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
475 struct host_cmd_ds_command *cmd,
476 u16 cmd_action, void *data_buf)
477{
478 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
479 struct mwifiex_ds_11n_tx_cfg *txcfg =
480 (struct mwifiex_ds_11n_tx_cfg *) data_buf;
481
482 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
483 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
484 htcfg->action = cpu_to_le16(cmd_action);
485 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
486 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
487 return 0;
488}
489
490/*
491 * This function appends an 11n TLV to a buffer.
492 *
493 * Buffer allocation is responsibility of the calling
494 * function. No size validation is made here.
495 *
496 * The function fills up the following sections, if applicable -
497 * - HT capability IE
498 * - HT information IE (with channel list)
499 * - 20/40 BSS Coexistence IE
500 * - HT Extended Capabilities IE
501 */
502int
503mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
504 struct mwifiex_bssdescriptor *bss_desc,
505 u8 **buffer)
506{
507 struct mwifiex_ie_types_htcap *ht_cap;
508 struct mwifiex_ie_types_htinfo *ht_info;
509 struct mwifiex_ie_types_chan_list_param_set *chan_list;
510 struct mwifiex_ie_types_2040bssco *bss_co_2040;
511 struct mwifiex_ie_types_extcap *ext_cap;
512 int ret_len = 0;
513
514 if (!buffer || !*buffer)
515 return ret_len;
516
517 if (bss_desc->bcn_ht_cap) {
518 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
519 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
520 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
521 ht_cap->header.len =
522 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
523 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
524 (u8 *) bss_desc->bcn_ht_cap +
525 sizeof(struct ieee_types_header),
526 le16_to_cpu(ht_cap->header.len));
527
528 mwifiex_fill_cap_info(priv, ht_cap);
529
530 *buffer += sizeof(struct mwifiex_ie_types_htcap);
531 ret_len += sizeof(struct mwifiex_ie_types_htcap);
532 }
533
534 if (bss_desc->bcn_ht_info) {
535 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
536 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
537 memset(ht_info, 0,
538 sizeof(struct mwifiex_ie_types_htinfo));
539 ht_info->header.type =
540 cpu_to_le16(WLAN_EID_HT_INFORMATION);
541 ht_info->header.len =
542 cpu_to_le16(sizeof(struct ieee80211_ht_info));
543
544 memcpy((u8 *) ht_info +
545 sizeof(struct mwifiex_ie_types_header),
546 (u8 *) bss_desc->bcn_ht_info +
547 sizeof(struct ieee_types_header),
548 le16_to_cpu(ht_info->header.len));
549
550 if (!ISSUPP_CHANWIDTH40
551 (priv->adapter->hw_dot_11n_dev_cap)
552 || !ISSUPP_CHANWIDTH40(priv->adapter->
553 usr_dot_11n_dev_cap))
554 RESET_CHANWIDTH40(ht_info->ht_info.ht_param);
555
556 *buffer += sizeof(struct mwifiex_ie_types_htinfo);
557 ret_len += sizeof(struct mwifiex_ie_types_htinfo);
558 }
559
560 chan_list =
561 (struct mwifiex_ie_types_chan_list_param_set *) *buffer;
562 memset(chan_list, 0,
563 sizeof(struct mwifiex_ie_types_chan_list_param_set));
564 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
565 chan_list->header.len = cpu_to_le16(
566 sizeof(struct mwifiex_ie_types_chan_list_param_set) -
567 sizeof(struct mwifiex_ie_types_header));
568 chan_list->chan_scan_param[0].chan_number =
569 bss_desc->bcn_ht_info->control_chan;
570 chan_list->chan_scan_param[0].radio_type =
571 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
572
573 if ((ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
574 ISSUPP_CHANWIDTH40(priv->adapter->usr_dot_11n_dev_cap))
575 && ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_info->ht_param))
576 SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
577 radio_type,
578 GET_SECONDARYCHAN(bss_desc->
579 bcn_ht_info->ht_param));
580
581 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
582 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
583 }
584
585 if (bss_desc->bcn_bss_co_2040) {
586 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
587 memset(bss_co_2040, 0,
588 sizeof(struct mwifiex_ie_types_2040bssco));
589 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
590 bss_co_2040->header.len =
591 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
592
593 memcpy((u8 *) bss_co_2040 +
594 sizeof(struct mwifiex_ie_types_header),
595 (u8 *) bss_desc->bcn_bss_co_2040 +
596 sizeof(struct ieee_types_header),
597 le16_to_cpu(bss_co_2040->header.len));
598
599 *buffer += sizeof(struct mwifiex_ie_types_2040bssco);
600 ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
601 }
602
603 if (bss_desc->bcn_ext_cap) {
604 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
605 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
606 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
607 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
608
609 memcpy((u8 *) ext_cap +
610 sizeof(struct mwifiex_ie_types_header),
611 (u8 *) bss_desc->bcn_ext_cap +
612 sizeof(struct ieee_types_header),
613 le16_to_cpu(ext_cap->header.len));
614
615 *buffer += sizeof(struct mwifiex_ie_types_extcap);
616 ret_len += sizeof(struct mwifiex_ie_types_extcap);
617 }
618
619 return ret_len;
620}
621
622/*
623 * This function reconfigures the Tx buffer size in firmware.
624 *
625 * This function prepares a firmware command and issues it, if
626 * the current Tx buffer size is different from the one requested.
627 * Maximum configurable Tx buffer size is limited by the HT capability
628 * field value.
629 */
630void
631mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
632 struct mwifiex_bssdescriptor *bss_desc)
633{
634 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
635 u16 tx_buf = 0;
636 u16 curr_tx_buf_size = 0;
637
638 if (bss_desc->bcn_ht_cap) {
639 if (GETHT_MAXAMSDU(le16_to_cpu(bss_desc->bcn_ht_cap->cap_info)))
640 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
641 else
642 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
643 }
644
645 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
646
647 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
648 max_amsdu, priv->adapter->max_tx_buf_size);
649
650 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
651 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
652 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
653 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
654 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
655 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
656 if (curr_tx_buf_size != tx_buf)
657 mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
658 HostCmd_ACT_GEN_SET, 0,
659 NULL, &tx_buf);
660
661 return;
662}
663
664/*
665 * This function checks if the given pointer is valid entry of
666 * Tx BA Stream table.
667 */
668static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
669 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
670{
671 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
672
673 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
674 if (tx_ba_tsr_tbl == tx_tbl_ptr)
675 return true;
676 }
677
678 return false;
679}
680
681/*
682 * This function deletes the given entry in Tx BA Stream table.
683 *
684 * The function also performs a validity check on the supplied
685 * pointer before trying to delete.
686 */
687void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
688 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
689{
690 if (!tx_ba_tsr_tbl &&
691 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
692 return;
693
694 dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
695
696 list_del(&tx_ba_tsr_tbl->list);
697
698 kfree(tx_ba_tsr_tbl);
699
700 return;
701}
702
703/*
704 * This function deletes all the entries in Tx BA Stream table.
705 */
706void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
707{
708 int i;
709 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
710 unsigned long flags;
711
712 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
713 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
714 &priv->tx_ba_stream_tbl_ptr, list)
715 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
716 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
717
718 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
719
720 for (i = 0; i < MAX_NUM_TID; ++i)
721 priv->aggr_prio_tbl[i].ampdu_ap =
722 priv->aggr_prio_tbl[i].ampdu_user;
723}
724
725/*
726 * This function returns the pointer to an entry in BA Stream
727 * table which matches the given RA/TID pair.
728 */
729struct mwifiex_tx_ba_stream_tbl *
730mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
731 int tid, u8 *ra)
732{
733 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
734 unsigned long flags;
735
736 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
737 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
738 if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
739 && (tx_ba_tsr_tbl->tid == tid)) {
740 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
741 flags);
742 return tx_ba_tsr_tbl;
743 }
744 }
745 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
746 return NULL;
747}
748
749/*
750 * This function creates an entry in Tx BA stream table for the
751 * given RA/TID pair.
752 */
753void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
754 u8 *ra, int tid,
755 enum mwifiex_ba_status ba_status)
756{
757 struct mwifiex_tx_ba_stream_tbl *new_node;
758 unsigned long flags;
759
760 if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
761 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
762 GFP_ATOMIC);
763 if (!new_node) {
764 dev_err(priv->adapter->dev,
765 "%s: failed to alloc new_node\n", __func__);
766 return;
767 }
768
769 INIT_LIST_HEAD(&new_node->list);
770
771 new_node->tid = tid;
772 new_node->ba_status = ba_status;
773 memcpy(new_node->ra, ra, ETH_ALEN);
774
775 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
776 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
777 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
778 }
779
780 return;
781}
782
783/*
784 * This function sends an add BA request to the given TID/RA pair.
785 */
786int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
787{
788 struct host_cmd_ds_11n_addba_req add_ba_req;
789 static u8 dialog_tok;
790 int ret;
791
792 dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
793
794 add_ba_req.block_ack_param_set = cpu_to_le16(
795 (u16) ((tid << BLOCKACKPARAM_TID_POS) |
796 (priv->add_ba_param.
797 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
798 IMMEDIATE_BLOCK_ACK));
799 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
800
801 ++dialog_tok;
802
803 if (dialog_tok == 0)
804 dialog_tok = 1;
805
806 add_ba_req.dialog_token = dialog_tok;
807 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
808
809 /* We don't wait for the response of this command */
810 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
811 0, 0, NULL, &add_ba_req);
812
813 return ret;
814}
815
816/*
817 * This function sends a delete BA request to the given TID/RA pair.
818 */
819int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
820 int initiator)
821{
822 struct host_cmd_ds_11n_delba delba;
823 int ret;
824 uint16_t del_ba_param_set;
825
826 memset(&delba, 0, sizeof(delba));
827 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
828
829 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
830 if (initiator)
831 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
832 else
833 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
834
835 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
836
837 /* We don't wait for the response of this command */
838 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
839 HostCmd_ACT_GEN_SET, 0, NULL, &delba);
840
841 return ret;
842}
843
844/*
845 * This function handles the command response of a delete BA request.
846 */
847void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
848{
849 struct host_cmd_ds_11n_delba *cmd_del_ba =
850 (struct host_cmd_ds_11n_delba *) del_ba;
851 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
852 int tid;
853
854 tid = del_ba_param_set >> DELBA_TID_POS;
855
856 mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
857 TYPE_DELBA_RECEIVE,
858 INITIATOR_BIT(del_ba_param_set));
859}
860
861/*
862 * This function retrieves the Rx reordering table.
863 */
864int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
865 struct mwifiex_ds_rx_reorder_tbl *buf)
866{
867 int i;
868 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
869 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
870 int count = 0;
871 unsigned long flags;
872
873 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
874 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
875 list) {
876 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
877 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
878 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
879 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
880 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
881 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
882 rx_reo_tbl->buffer[i] = true;
883 else
884 rx_reo_tbl->buffer[i] = false;
885 }
886 rx_reo_tbl++;
887 count++;
888
889 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
890 break;
891 }
892 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
893
894 return count;
895}
896
897/*
898 * This function retrieves the Tx BA stream table.
899 */
900int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
901 struct mwifiex_ds_tx_ba_stream_tbl *buf)
902{
903 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
904 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
905 int count = 0;
906 unsigned long flags;
907
908 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
909 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
910 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
911 dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
912 __func__, rx_reo_tbl->tid);
913 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
914 rx_reo_tbl++;
915 count++;
916 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
917 break;
918 }
919 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
920
921 return count;
922}