11n.c revision 6d2bd916afe6950b50f750cd82bbb9c6ff58611f
1/* 2 * Marvell Wireless LAN device driver: 802.11n 3 * 4 * Copyright (C) 2011, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available by writing to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13 * 14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17 * this warranty disclaimer. 18 */ 19 20#include "decl.h" 21#include "ioctl.h" 22#include "util.h" 23#include "fw.h" 24#include "main.h" 25#include "wmm.h" 26#include "11n.h" 27 28/* 29 * Fills HT capability information field, AMPDU Parameters field, HT extended 30 * capability field, and supported MCS set fields. 31 * 32 * Only the following HT capability information fields are used, all other 33 * fields are always turned off. 34 * 35 * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) 36 * Bit 4 : Greenfield support (0: Not supported, 1: Supported) 37 * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) 38 * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) 39 * Bit 7 : Tx STBC (0: Not supported, 1: Supported) 40 * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) 41 * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) 42 * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) 43 * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) 44 * 45 * In addition, the following AMPDU Parameters are set - 46 * - Maximum AMPDU length exponent (set to 3) 47 * - Minimum AMPDU start spacing (set to 0 - No restrictions) 48 * 49 * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz 50 * support. 51 * 52 * RD responder bit to set to clear in the extended capability header. 53 */ 54void 55mwifiex_fill_cap_info(struct mwifiex_private *priv, 56 struct mwifiex_ie_types_htcap *ht_cap) 57{ 58 struct mwifiex_adapter *adapter = priv->adapter; 59 u8 *mcs; 60 int rx_mcs_supp; 61 uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); 62 uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); 63 64 /* Convert dev_cap to IEEE80211_HT_CAP */ 65 if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) 66 ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 67 else 68 ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 69 70 if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) 71 ht_cap_info |= IEEE80211_HT_CAP_SGI_20; 72 else 73 ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; 74 75 if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) 76 ht_cap_info |= IEEE80211_HT_CAP_SGI_40; 77 else 78 ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; 79 80 if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) 81 ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; 82 else 83 ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; 84 85 if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) 86 ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; 87 else 88 ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 89 90 if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) 91 ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; 92 else 93 ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; 94 95 ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; 96 ht_cap_info |= IEEE80211_HT_CAP_SM_PS; 97 98 ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; 99 ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; 100 101 rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); 102 103 mcs = (u8 *)&ht_cap->ht_cap.mcs; 104 105 /* Set MCS for 1x1 */ 106 memset(mcs, 0xff, rx_mcs_supp); 107 108 /* Clear all the other values */ 109 memset(&mcs[rx_mcs_supp], 0, 110 sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); 111 112 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || 113 (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 114 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ 115 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); 116 117 /* Clear RD responder bit */ 118 RESETHT_EXTCAP_RDG(ht_ext_cap); 119 120 ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); 121 ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); 122} 123 124/* 125 * This function returns the pointer to an entry in BA Stream 126 * table which matches the requested BA status. 127 */ 128static struct mwifiex_tx_ba_stream_tbl * 129mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, 130 enum mwifiex_ba_status ba_status) 131{ 132 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 133 unsigned long flags; 134 135 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 136 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 137 if (tx_ba_tsr_tbl->ba_status == ba_status) { 138 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, 139 flags); 140 return tx_ba_tsr_tbl; 141 } 142 } 143 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 144 return NULL; 145} 146 147/* 148 * This function handles the command response of delete a block 149 * ack request. 150 * 151 * The function checks the response success status and takes action 152 * accordingly (send an add BA request in case of success, or recreate 153 * the deleted stream in case of failure, if the add BA was also 154 * initiated by us). 155 */ 156int mwifiex_ret_11n_delba(struct mwifiex_private *priv, 157 struct host_cmd_ds_command *resp) 158{ 159 int tid; 160 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 161 struct host_cmd_ds_11n_delba *del_ba = 162 (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; 163 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); 164 165 tid = del_ba_param_set >> DELBA_TID_POS; 166 if (del_ba->del_result == BA_RESULT_SUCCESS) { 167 mwifiex_11n_delete_ba_stream_tbl(priv, tid, 168 del_ba->peer_mac_addr, TYPE_DELBA_SENT, 169 INITIATOR_BIT(del_ba_param_set)); 170 171 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, 172 BA_STREAM_SETUP_INPROGRESS); 173 if (tx_ba_tbl) 174 mwifiex_send_addba(priv, tx_ba_tbl->tid, 175 tx_ba_tbl->ra); 176 } else { /* 177 * In case of failure, recreate the deleted stream in case 178 * we initiated the ADDBA 179 */ 180 if (INITIATOR_BIT(del_ba_param_set)) { 181 mwifiex_11n_create_tx_ba_stream_tbl(priv, 182 del_ba->peer_mac_addr, tid, 183 BA_STREAM_SETUP_INPROGRESS); 184 185 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, 186 BA_STREAM_SETUP_INPROGRESS); 187 if (tx_ba_tbl) 188 mwifiex_11n_delete_ba_stream_tbl(priv, 189 tx_ba_tbl->tid, tx_ba_tbl->ra, 190 TYPE_DELBA_SENT, true); 191 } 192 } 193 194 return 0; 195} 196 197/* 198 * This function handles the command response of add a block 199 * ack request. 200 * 201 * Handling includes changing the header fields to CPU formats, checking 202 * the response success status and taking actions accordingly (delete the 203 * BA stream table in case of failure). 204 */ 205int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, 206 struct host_cmd_ds_command *resp) 207{ 208 int tid; 209 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 210 (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; 211 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 212 213 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) 214 & SSN_MASK); 215 216 tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) 217 & IEEE80211_ADDBA_PARAM_TID_MASK) 218 >> BLOCKACKPARAM_TID_POS; 219 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { 220 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, 221 add_ba_rsp->peer_mac_addr); 222 if (tx_ba_tbl) { 223 dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); 224 tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; 225 } else { 226 dev_err(priv->adapter->dev, "BA stream not created\n"); 227 } 228 } else { 229 mwifiex_11n_delete_ba_stream_tbl(priv, tid, 230 add_ba_rsp->peer_mac_addr, 231 TYPE_DELBA_SENT, true); 232 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) 233 priv->aggr_prio_tbl[tid].ampdu_ap = 234 BA_STREAM_NOT_ALLOWED; 235 } 236 237 return 0; 238} 239 240/* 241 * This function handles the command response of 11n configuration request. 242 * 243 * Handling includes changing the header fields into CPU format. 244 */ 245int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, 246 struct host_cmd_ds_command *resp, 247 void *data_buf) 248{ 249 struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; 250 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; 251 252 if (data_buf) { 253 tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; 254 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); 255 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); 256 } 257 return 0; 258} 259 260/* 261 * This function prepares command of reconfigure Tx buffer. 262 * 263 * Preparation includes - 264 * - Setting command ID, action and proper size 265 * - Setting Tx buffer size (for SET only) 266 * - Ensuring correct endian-ness 267 */ 268int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, 269 struct host_cmd_ds_command *cmd, int cmd_action, 270 void *data_buf) 271{ 272 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; 273 u16 action = (u16) cmd_action; 274 u16 buf_size = *((u16 *) data_buf); 275 276 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); 277 cmd->size = 278 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); 279 tx_buf->action = cpu_to_le16(action); 280 switch (action) { 281 case HostCmd_ACT_GEN_SET: 282 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); 283 tx_buf->buff_size = cpu_to_le16(buf_size); 284 break; 285 case HostCmd_ACT_GEN_GET: 286 default: 287 tx_buf->buff_size = 0; 288 break; 289 } 290 return 0; 291} 292 293/* 294 * This function prepares command of AMSDU aggregation control. 295 * 296 * Preparation includes - 297 * - Setting command ID, action and proper size 298 * - Setting AMSDU control parameters (for SET only) 299 * - Ensuring correct endian-ness 300 */ 301int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, 302 struct host_cmd_ds_command *cmd, 303 int cmd_action, void *data_buf) 304{ 305 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 306 &cmd->params.amsdu_aggr_ctrl; 307 u16 action = (u16) cmd_action; 308 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = 309 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; 310 311 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); 312 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) 313 + S_DS_GEN); 314 amsdu_ctrl->action = cpu_to_le16(action); 315 switch (action) { 316 case HostCmd_ACT_GEN_SET: 317 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); 318 amsdu_ctrl->curr_buf_size = 0; 319 break; 320 case HostCmd_ACT_GEN_GET: 321 default: 322 amsdu_ctrl->curr_buf_size = 0; 323 break; 324 } 325 return 0; 326} 327 328/* 329 * This function handles the command response of AMSDU aggregation 330 * control request. 331 * 332 * Handling includes changing the header fields into CPU format. 333 */ 334int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, 335 struct host_cmd_ds_command *resp, 336 void *data_buf) 337{ 338 struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; 339 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 340 &resp->params.amsdu_aggr_ctrl; 341 342 if (data_buf) { 343 amsdu_aggr_ctrl = 344 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; 345 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); 346 amsdu_aggr_ctrl->curr_buf_size = 347 le16_to_cpu(amsdu_ctrl->curr_buf_size); 348 } 349 return 0; 350} 351 352/* 353 * This function prepares 11n configuration command. 354 * 355 * Preparation includes - 356 * - Setting command ID, action and proper size 357 * - Setting HT Tx capability and HT Tx information fields 358 * - Ensuring correct endian-ness 359 */ 360int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, 361 struct host_cmd_ds_command *cmd, 362 u16 cmd_action, void *data_buf) 363{ 364 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; 365 struct mwifiex_ds_11n_tx_cfg *txcfg = 366 (struct mwifiex_ds_11n_tx_cfg *) data_buf; 367 368 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); 369 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); 370 htcfg->action = cpu_to_le16(cmd_action); 371 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); 372 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); 373 return 0; 374} 375 376/* 377 * This function appends an 11n TLV to a buffer. 378 * 379 * Buffer allocation is responsibility of the calling 380 * function. No size validation is made here. 381 * 382 * The function fills up the following sections, if applicable - 383 * - HT capability IE 384 * - HT information IE (with channel list) 385 * - 20/40 BSS Coexistence IE 386 * - HT Extended Capabilities IE 387 */ 388int 389mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, 390 struct mwifiex_bssdescriptor *bss_desc, 391 u8 **buffer) 392{ 393 struct mwifiex_ie_types_htcap *ht_cap; 394 struct mwifiex_ie_types_htinfo *ht_info; 395 struct mwifiex_ie_types_chan_list_param_set *chan_list; 396 struct mwifiex_ie_types_2040bssco *bss_co_2040; 397 struct mwifiex_ie_types_extcap *ext_cap; 398 int ret_len = 0; 399 400 if (!buffer || !*buffer) 401 return ret_len; 402 403 if (bss_desc->bcn_ht_cap) { 404 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; 405 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 406 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 407 ht_cap->header.len = 408 cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 409 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), 410 (u8 *) bss_desc->bcn_ht_cap + 411 sizeof(struct ieee_types_header), 412 le16_to_cpu(ht_cap->header.len)); 413 414 mwifiex_fill_cap_info(priv, ht_cap); 415 416 *buffer += sizeof(struct mwifiex_ie_types_htcap); 417 ret_len += sizeof(struct mwifiex_ie_types_htcap); 418 } 419 420 if (bss_desc->bcn_ht_info) { 421 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { 422 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; 423 memset(ht_info, 0, 424 sizeof(struct mwifiex_ie_types_htinfo)); 425 ht_info->header.type = 426 cpu_to_le16(WLAN_EID_HT_INFORMATION); 427 ht_info->header.len = 428 cpu_to_le16(sizeof(struct ieee80211_ht_info)); 429 430 memcpy((u8 *) ht_info + 431 sizeof(struct mwifiex_ie_types_header), 432 (u8 *) bss_desc->bcn_ht_info + 433 sizeof(struct ieee_types_header), 434 le16_to_cpu(ht_info->header.len)); 435 436 if (!ISSUPP_CHANWIDTH40 437 (priv->adapter->hw_dot_11n_dev_cap)) 438 ht_info->ht_info.ht_param &= 439 ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | 440 IEEE80211_HT_PARAM_CHA_SEC_OFFSET); 441 442 *buffer += sizeof(struct mwifiex_ie_types_htinfo); 443 ret_len += sizeof(struct mwifiex_ie_types_htinfo); 444 } 445 446 chan_list = 447 (struct mwifiex_ie_types_chan_list_param_set *) *buffer; 448 memset(chan_list, 0, 449 sizeof(struct mwifiex_ie_types_chan_list_param_set)); 450 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 451 chan_list->header.len = cpu_to_le16( 452 sizeof(struct mwifiex_ie_types_chan_list_param_set) - 453 sizeof(struct mwifiex_ie_types_header)); 454 chan_list->chan_scan_param[0].chan_number = 455 bss_desc->bcn_ht_info->control_chan; 456 chan_list->chan_scan_param[0].radio_type = 457 mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 458 459 if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) 460 && (bss_desc->bcn_ht_info->ht_param & 461 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) 462 SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. 463 radio_type, 464 (bss_desc->bcn_ht_info->ht_param & 465 IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); 466 467 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); 468 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); 469 } 470 471 if (bss_desc->bcn_bss_co_2040) { 472 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; 473 memset(bss_co_2040, 0, 474 sizeof(struct mwifiex_ie_types_2040bssco)); 475 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); 476 bss_co_2040->header.len = 477 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); 478 479 memcpy((u8 *) bss_co_2040 + 480 sizeof(struct mwifiex_ie_types_header), 481 (u8 *) bss_desc->bcn_bss_co_2040 + 482 sizeof(struct ieee_types_header), 483 le16_to_cpu(bss_co_2040->header.len)); 484 485 *buffer += sizeof(struct mwifiex_ie_types_2040bssco); 486 ret_len += sizeof(struct mwifiex_ie_types_2040bssco); 487 } 488 489 if (bss_desc->bcn_ext_cap) { 490 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; 491 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); 492 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); 493 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); 494 495 memcpy((u8 *) ext_cap + 496 sizeof(struct mwifiex_ie_types_header), 497 (u8 *) bss_desc->bcn_ext_cap + 498 sizeof(struct ieee_types_header), 499 le16_to_cpu(ext_cap->header.len)); 500 501 *buffer += sizeof(struct mwifiex_ie_types_extcap); 502 ret_len += sizeof(struct mwifiex_ie_types_extcap); 503 } 504 505 return ret_len; 506} 507 508/* 509 * This function reconfigures the Tx buffer size in firmware. 510 * 511 * This function prepares a firmware command and issues it, if 512 * the current Tx buffer size is different from the one requested. 513 * Maximum configurable Tx buffer size is limited by the HT capability 514 * field value. 515 */ 516void 517mwifiex_cfg_tx_buf(struct mwifiex_private *priv, 518 struct mwifiex_bssdescriptor *bss_desc) 519{ 520 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; 521 u16 tx_buf = 0; 522 u16 curr_tx_buf_size = 0; 523 524 if (bss_desc->bcn_ht_cap) { 525 if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & 526 IEEE80211_HT_CAP_MAX_AMSDU) 527 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; 528 else 529 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; 530 } 531 532 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); 533 534 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", 535 max_amsdu, priv->adapter->max_tx_buf_size); 536 537 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) 538 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; 539 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) 540 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; 541 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) 542 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; 543 if (curr_tx_buf_size != tx_buf) 544 mwifiex_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 */ 555static 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 */ 574void 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 */ 593void 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 */ 616struct mwifiex_tx_ba_stream_tbl * 617mwifiex_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 */ 640void 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 */ 673int 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 */ 706int 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 */ 734void 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 */ 751int 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 */ 787int 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} 810