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