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 * HT capability information field, AMPDU Parameters field, supported MCS set 33 * fields are retrieved from cfg80211 stack 34 * 35 * RD responder bit to set to clear in the extended capability header. 36 */ 37void 38mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, 39 struct mwifiex_ie_types_htcap *ht_cap) 40{ 41 uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); 42 struct ieee80211_supported_band *sband = 43 priv->wdev->wiphy->bands[radio_type]; 44 45 ht_cap->ht_cap.ampdu_params_info = 46 (sband->ht_cap.ampdu_factor & 47 IEEE80211_HT_AMPDU_PARM_FACTOR) | 48 ((sband->ht_cap.ampdu_density << 49 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & 50 IEEE80211_HT_AMPDU_PARM_DENSITY); 51 52 memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs, 53 sizeof(sband->ht_cap.mcs)); 54 55 if (priv->bss_mode == NL80211_IFTYPE_STATION || 56 sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) 57 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ 58 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); 59 60 /* Clear RD responder bit */ 61 ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; 62 63 ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap); 64 ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); 65} 66 67/* 68 * This function returns the pointer to an entry in BA Stream 69 * table which matches the requested BA status. 70 */ 71static struct mwifiex_tx_ba_stream_tbl * 72mwifiex_get_ba_status(struct mwifiex_private *priv, 73 enum mwifiex_ba_status ba_status) 74{ 75 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 76 unsigned long flags; 77 78 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 79 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 80 if (tx_ba_tsr_tbl->ba_status == ba_status) { 81 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, 82 flags); 83 return tx_ba_tsr_tbl; 84 } 85 } 86 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 87 return NULL; 88} 89 90/* 91 * This function handles the command response of delete a block 92 * ack request. 93 * 94 * The function checks the response success status and takes action 95 * accordingly (send an add BA request in case of success, or recreate 96 * the deleted stream in case of failure, if the add BA was also 97 * initiated by us). 98 */ 99int mwifiex_ret_11n_delba(struct mwifiex_private *priv, 100 struct host_cmd_ds_command *resp) 101{ 102 int tid; 103 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 104 struct host_cmd_ds_11n_delba *del_ba = 105 (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; 106 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); 107 108 tid = del_ba_param_set >> DELBA_TID_POS; 109 if (del_ba->del_result == BA_RESULT_SUCCESS) { 110 mwifiex_del_ba_tbl(priv, tid, del_ba->peer_mac_addr, 111 TYPE_DELBA_SENT, 112 INITIATOR_BIT(del_ba_param_set)); 113 114 tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 115 if (tx_ba_tbl) 116 mwifiex_send_addba(priv, tx_ba_tbl->tid, 117 tx_ba_tbl->ra); 118 } else { /* 119 * In case of failure, recreate the deleted stream in case 120 * we initiated the ADDBA 121 */ 122 if (!INITIATOR_BIT(del_ba_param_set)) 123 return 0; 124 125 mwifiex_create_ba_tbl(priv, del_ba->peer_mac_addr, tid, 126 BA_SETUP_INPROGRESS); 127 128 tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 129 130 if (tx_ba_tbl) 131 mwifiex_del_ba_tbl(priv, tx_ba_tbl->tid, tx_ba_tbl->ra, 132 TYPE_DELBA_SENT, true); 133 } 134 135 return 0; 136} 137 138/* 139 * This function handles the command response of add a block 140 * ack request. 141 * 142 * Handling includes changing the header fields to CPU formats, checking 143 * the response success status and taking actions accordingly (delete the 144 * BA stream table in case of failure). 145 */ 146int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, 147 struct host_cmd_ds_command *resp) 148{ 149 int tid; 150 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 151 (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; 152 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 153 154 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) 155 & SSN_MASK); 156 157 tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) 158 & IEEE80211_ADDBA_PARAM_TID_MASK) 159 >> BLOCKACKPARAM_TID_POS; 160 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { 161 tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, 162 add_ba_rsp->peer_mac_addr); 163 if (tx_ba_tbl) { 164 dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); 165 tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; 166 } else { 167 dev_err(priv->adapter->dev, "BA stream not created\n"); 168 } 169 } else { 170 mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, 171 TYPE_DELBA_SENT, true); 172 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) 173 priv->aggr_prio_tbl[tid].ampdu_ap = 174 BA_STREAM_NOT_ALLOWED; 175 } 176 177 return 0; 178} 179 180/* 181 * This function handles the command response of 11n configuration request. 182 * 183 * Handling includes changing the header fields into CPU format. 184 */ 185int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, 186 struct mwifiex_ds_11n_tx_cfg *tx_cfg) 187{ 188 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; 189 190 if (tx_cfg) { 191 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); 192 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); 193 } 194 return 0; 195} 196 197/* 198 * This function prepares command of reconfigure Tx buffer. 199 * 200 * Preparation includes - 201 * - Setting command ID, action and proper size 202 * - Setting Tx buffer size (for SET only) 203 * - Ensuring correct endian-ness 204 */ 205int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, 206 struct host_cmd_ds_command *cmd, int cmd_action, 207 u16 *buf_size) 208{ 209 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; 210 u16 action = (u16) cmd_action; 211 212 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); 213 cmd->size = 214 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); 215 tx_buf->action = cpu_to_le16(action); 216 switch (action) { 217 case HostCmd_ACT_GEN_SET: 218 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", *buf_size); 219 tx_buf->buff_size = cpu_to_le16(*buf_size); 220 break; 221 case HostCmd_ACT_GEN_GET: 222 default: 223 tx_buf->buff_size = 0; 224 break; 225 } 226 return 0; 227} 228 229/* 230 * This function prepares command of AMSDU aggregation control. 231 * 232 * Preparation includes - 233 * - Setting command ID, action and proper size 234 * - Setting AMSDU control parameters (for SET only) 235 * - Ensuring correct endian-ness 236 */ 237int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, 238 int cmd_action, 239 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl) 240{ 241 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 242 &cmd->params.amsdu_aggr_ctrl; 243 u16 action = (u16) cmd_action; 244 245 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); 246 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) 247 + S_DS_GEN); 248 amsdu_ctrl->action = cpu_to_le16(action); 249 switch (action) { 250 case HostCmd_ACT_GEN_SET: 251 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); 252 amsdu_ctrl->curr_buf_size = 0; 253 break; 254 case HostCmd_ACT_GEN_GET: 255 default: 256 amsdu_ctrl->curr_buf_size = 0; 257 break; 258 } 259 return 0; 260} 261 262/* 263 * This function handles the command response of AMSDU aggregation 264 * control request. 265 * 266 * Handling includes changing the header fields into CPU format. 267 */ 268int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, 269 struct mwifiex_ds_11n_amsdu_aggr_ctrl 270 *amsdu_aggr_ctrl) 271{ 272 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 273 &resp->params.amsdu_aggr_ctrl; 274 275 if (amsdu_aggr_ctrl) { 276 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); 277 amsdu_aggr_ctrl->curr_buf_size = 278 le16_to_cpu(amsdu_ctrl->curr_buf_size); 279 } 280 return 0; 281} 282 283/* 284 * This function prepares 11n configuration command. 285 * 286 * Preparation includes - 287 * - Setting command ID, action and proper size 288 * - Setting HT Tx capability and HT Tx information fields 289 * - Ensuring correct endian-ness 290 */ 291int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, 292 struct mwifiex_ds_11n_tx_cfg *txcfg) 293{ 294 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; 295 296 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); 297 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); 298 htcfg->action = cpu_to_le16(cmd_action); 299 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); 300 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); 301 return 0; 302} 303 304/* 305 * This function appends an 11n TLV to a buffer. 306 * 307 * Buffer allocation is responsibility of the calling 308 * function. No size validation is made here. 309 * 310 * The function fills up the following sections, if applicable - 311 * - HT capability IE 312 * - HT information IE (with channel list) 313 * - 20/40 BSS Coexistence IE 314 * - HT Extended Capabilities IE 315 */ 316int 317mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, 318 struct mwifiex_bssdescriptor *bss_desc, 319 u8 **buffer) 320{ 321 struct mwifiex_ie_types_htcap *ht_cap; 322 struct mwifiex_ie_types_htinfo *ht_info; 323 struct mwifiex_ie_types_chan_list_param_set *chan_list; 324 struct mwifiex_ie_types_2040bssco *bss_co_2040; 325 struct mwifiex_ie_types_extcap *ext_cap; 326 int ret_len = 0; 327 struct ieee80211_supported_band *sband; 328 u8 radio_type; 329 330 if (!buffer || !*buffer) 331 return ret_len; 332 333 radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 334 sband = priv->wdev->wiphy->bands[radio_type]; 335 336 if (bss_desc->bcn_ht_cap) { 337 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; 338 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 339 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 340 ht_cap->header.len = 341 cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 342 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), 343 (u8 *) bss_desc->bcn_ht_cap + 344 sizeof(struct ieee_types_header), 345 le16_to_cpu(ht_cap->header.len)); 346 347 mwifiex_fill_cap_info(priv, radio_type, ht_cap); 348 349 *buffer += sizeof(struct mwifiex_ie_types_htcap); 350 ret_len += sizeof(struct mwifiex_ie_types_htcap); 351 } 352 353 if (bss_desc->bcn_ht_info) { 354 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { 355 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; 356 memset(ht_info, 0, 357 sizeof(struct mwifiex_ie_types_htinfo)); 358 ht_info->header.type = 359 cpu_to_le16(WLAN_EID_HT_INFORMATION); 360 ht_info->header.len = 361 cpu_to_le16(sizeof(struct ieee80211_ht_info)); 362 363 memcpy((u8 *) ht_info + 364 sizeof(struct mwifiex_ie_types_header), 365 (u8 *) bss_desc->bcn_ht_info + 366 sizeof(struct ieee_types_header), 367 le16_to_cpu(ht_info->header.len)); 368 369 if (!(sband->ht_cap.cap & 370 IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 371 ht_info->ht_info.ht_param &= 372 ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | 373 IEEE80211_HT_PARAM_CHA_SEC_OFFSET); 374 375 *buffer += sizeof(struct mwifiex_ie_types_htinfo); 376 ret_len += sizeof(struct mwifiex_ie_types_htinfo); 377 } 378 379 chan_list = 380 (struct mwifiex_ie_types_chan_list_param_set *) *buffer; 381 memset(chan_list, 0, 382 sizeof(struct mwifiex_ie_types_chan_list_param_set)); 383 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 384 chan_list->header.len = cpu_to_le16( 385 sizeof(struct mwifiex_ie_types_chan_list_param_set) - 386 sizeof(struct mwifiex_ie_types_header)); 387 chan_list->chan_scan_param[0].chan_number = 388 bss_desc->bcn_ht_info->control_chan; 389 chan_list->chan_scan_param[0].radio_type = 390 mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 391 392 if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 393 bss_desc->bcn_ht_info->ht_param & 394 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) 395 SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. 396 radio_type, 397 (bss_desc->bcn_ht_info->ht_param & 398 IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); 399 400 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); 401 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); 402 } 403 404 if (bss_desc->bcn_bss_co_2040) { 405 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; 406 memset(bss_co_2040, 0, 407 sizeof(struct mwifiex_ie_types_2040bssco)); 408 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); 409 bss_co_2040->header.len = 410 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); 411 412 memcpy((u8 *) bss_co_2040 + 413 sizeof(struct mwifiex_ie_types_header), 414 (u8 *) bss_desc->bcn_bss_co_2040 + 415 sizeof(struct ieee_types_header), 416 le16_to_cpu(bss_co_2040->header.len)); 417 418 *buffer += sizeof(struct mwifiex_ie_types_2040bssco); 419 ret_len += sizeof(struct mwifiex_ie_types_2040bssco); 420 } 421 422 if (bss_desc->bcn_ext_cap) { 423 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; 424 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); 425 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); 426 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); 427 428 memcpy((u8 *) ext_cap + 429 sizeof(struct mwifiex_ie_types_header), 430 (u8 *) bss_desc->bcn_ext_cap + 431 sizeof(struct ieee_types_header), 432 le16_to_cpu(ext_cap->header.len)); 433 434 *buffer += sizeof(struct mwifiex_ie_types_extcap); 435 ret_len += sizeof(struct mwifiex_ie_types_extcap); 436 } 437 438 return ret_len; 439} 440 441/* 442 * This function reconfigures the Tx buffer size in firmware. 443 * 444 * This function prepares a firmware command and issues it, if 445 * the current Tx buffer size is different from the one requested. 446 * Maximum configurable Tx buffer size is limited by the HT capability 447 * field value. 448 */ 449void 450mwifiex_cfg_tx_buf(struct mwifiex_private *priv, 451 struct mwifiex_bssdescriptor *bss_desc) 452{ 453 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; 454 u16 tx_buf, curr_tx_buf_size = 0; 455 456 if (bss_desc->bcn_ht_cap) { 457 if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & 458 IEEE80211_HT_CAP_MAX_AMSDU) 459 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; 460 else 461 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; 462 } 463 464 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); 465 466 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", 467 max_amsdu, priv->adapter->max_tx_buf_size); 468 469 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) 470 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; 471 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) 472 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; 473 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) 474 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; 475 if (curr_tx_buf_size != tx_buf) 476 mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, 477 HostCmd_ACT_GEN_SET, 0, &tx_buf); 478} 479 480/* 481 * This function checks if the given pointer is valid entry of 482 * Tx BA Stream table. 483 */ 484static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, 485 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) 486{ 487 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 488 489 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 490 if (tx_ba_tsr_tbl == tx_tbl_ptr) 491 return true; 492 } 493 494 return false; 495} 496 497/* 498 * This function deletes the given entry in Tx BA Stream table. 499 * 500 * The function also performs a validity check on the supplied 501 * pointer before trying to delete. 502 */ 503void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, 504 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) 505{ 506 if (!tx_ba_tsr_tbl && 507 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) 508 return; 509 510 dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); 511 512 list_del(&tx_ba_tsr_tbl->list); 513 514 kfree(tx_ba_tsr_tbl); 515} 516 517/* 518 * This function deletes all the entries in Tx BA Stream table. 519 */ 520void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) 521{ 522 int i; 523 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; 524 unsigned long flags; 525 526 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 527 list_for_each_entry_safe(del_tbl_ptr, tmp_node, 528 &priv->tx_ba_stream_tbl_ptr, list) 529 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); 530 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 531 532 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); 533 534 for (i = 0; i < MAX_NUM_TID; ++i) 535 priv->aggr_prio_tbl[i].ampdu_ap = 536 priv->aggr_prio_tbl[i].ampdu_user; 537} 538 539/* 540 * This function returns the pointer to an entry in BA Stream 541 * table which matches the given RA/TID pair. 542 */ 543struct mwifiex_tx_ba_stream_tbl * 544mwifiex_get_ba_tbl(struct mwifiex_private *priv, int tid, u8 *ra) 545{ 546 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 547 unsigned long flags; 548 549 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 550 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 551 if (!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN) && 552 tx_ba_tsr_tbl->tid == tid) { 553 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, 554 flags); 555 return tx_ba_tsr_tbl; 556 } 557 } 558 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 559 return NULL; 560} 561 562/* 563 * This function creates an entry in Tx BA stream table for the 564 * given RA/TID pair. 565 */ 566void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, 567 enum mwifiex_ba_status ba_status) 568{ 569 struct mwifiex_tx_ba_stream_tbl *new_node; 570 unsigned long flags; 571 572 if (!mwifiex_get_ba_tbl(priv, tid, ra)) { 573 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), 574 GFP_ATOMIC); 575 if (!new_node) { 576 dev_err(priv->adapter->dev, 577 "%s: failed to alloc new_node\n", __func__); 578 return; 579 } 580 581 INIT_LIST_HEAD(&new_node->list); 582 583 new_node->tid = tid; 584 new_node->ba_status = ba_status; 585 memcpy(new_node->ra, ra, ETH_ALEN); 586 587 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 588 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); 589 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 590 } 591} 592 593/* 594 * This function sends an add BA request to the given TID/RA pair. 595 */ 596int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) 597{ 598 struct host_cmd_ds_11n_addba_req add_ba_req; 599 static u8 dialog_tok; 600 int ret; 601 602 dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); 603 604 add_ba_req.block_ack_param_set = cpu_to_le16( 605 (u16) ((tid << BLOCKACKPARAM_TID_POS) | 606 (priv->add_ba_param. 607 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | 608 IMMEDIATE_BLOCK_ACK)); 609 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); 610 611 ++dialog_tok; 612 613 if (dialog_tok == 0) 614 dialog_tok = 1; 615 616 add_ba_req.dialog_token = dialog_tok; 617 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); 618 619 /* We don't wait for the response of this command */ 620 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ, 621 0, 0, &add_ba_req); 622 623 return ret; 624} 625 626/* 627 * This function sends a delete BA request to the given TID/RA pair. 628 */ 629int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, 630 int initiator) 631{ 632 struct host_cmd_ds_11n_delba delba; 633 int ret; 634 uint16_t del_ba_param_set; 635 636 memset(&delba, 0, sizeof(delba)); 637 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); 638 639 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); 640 if (initiator) 641 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; 642 else 643 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; 644 645 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); 646 647 /* We don't wait for the response of this command */ 648 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 649 HostCmd_ACT_GEN_SET, 0, &delba); 650 651 return ret; 652} 653 654/* 655 * This function handles the command response of a delete BA request. 656 */ 657void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) 658{ 659 struct host_cmd_ds_11n_delba *cmd_del_ba = 660 (struct host_cmd_ds_11n_delba *) del_ba; 661 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); 662 int tid; 663 664 tid = del_ba_param_set >> DELBA_TID_POS; 665 666 mwifiex_del_ba_tbl(priv, tid, cmd_del_ba->peer_mac_addr, 667 TYPE_DELBA_RECEIVE, INITIATOR_BIT(del_ba_param_set)); 668} 669 670/* 671 * This function retrieves the Rx reordering table. 672 */ 673int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, 674 struct mwifiex_ds_rx_reorder_tbl *buf) 675{ 676 int i; 677 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; 678 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; 679 int count = 0; 680 unsigned long flags; 681 682 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 683 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, 684 list) { 685 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; 686 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); 687 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; 688 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; 689 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { 690 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 691 rx_reo_tbl->buffer[i] = true; 692 else 693 rx_reo_tbl->buffer[i] = false; 694 } 695 rx_reo_tbl++; 696 count++; 697 698 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) 699 break; 700 } 701 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 702 703 return count; 704} 705 706/* 707 * This function retrieves the Tx BA stream table. 708 */ 709int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, 710 struct mwifiex_ds_tx_ba_stream_tbl *buf) 711{ 712 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 713 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; 714 int count = 0; 715 unsigned long flags; 716 717 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 718 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 719 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; 720 dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", 721 __func__, rx_reo_tbl->tid); 722 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); 723 rx_reo_tbl++; 724 count++; 725 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) 726 break; 727 } 728 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 729 730 return count; 731} 732