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