162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: 802.11n 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _MWIFIEX_11N_H_ 962306a36Sopenharmony_ci#define _MWIFIEX_11N_H_ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "11n_aggr.h" 1262306a36Sopenharmony_ci#include "11n_rxreorder.h" 1362306a36Sopenharmony_ci#include "wmm.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciint mwifiex_ret_11n_delba(struct mwifiex_private *priv, 1662306a36Sopenharmony_ci struct host_cmd_ds_command *resp); 1762306a36Sopenharmony_ciint mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, 1862306a36Sopenharmony_ci struct host_cmd_ds_command *resp); 1962306a36Sopenharmony_ciint mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, 2062306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, u16 cmd_action, 2162306a36Sopenharmony_ci struct mwifiex_ds_11n_tx_cfg *txcfg); 2262306a36Sopenharmony_ciint mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, 2362306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc, 2462306a36Sopenharmony_ci u8 **buffer); 2562306a36Sopenharmony_ciint mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, 2662306a36Sopenharmony_ci struct ieee80211_ht_cap *); 2762306a36Sopenharmony_ciint mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, 2862306a36Sopenharmony_ci u16 action, int *htcap_cfg); 2962306a36Sopenharmony_civoid mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, 3062306a36Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl 3162306a36Sopenharmony_ci *tx_tbl); 3262306a36Sopenharmony_civoid mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); 3362306a36Sopenharmony_cistruct mwifiex_tx_ba_stream_tbl *mwifiex_get_ba_tbl(struct 3462306a36Sopenharmony_ci mwifiex_private 3562306a36Sopenharmony_ci *priv, int tid, 3662306a36Sopenharmony_ci u8 *ra); 3762306a36Sopenharmony_civoid mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, 3862306a36Sopenharmony_ci enum mwifiex_ba_status ba_status); 3962306a36Sopenharmony_ciint mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); 4062306a36Sopenharmony_ciint mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, 4162306a36Sopenharmony_ci int initiator); 4262306a36Sopenharmony_civoid mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); 4362306a36Sopenharmony_ciint mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, 4462306a36Sopenharmony_ci struct mwifiex_ds_rx_reorder_tbl *buf); 4562306a36Sopenharmony_ciint mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, 4662306a36Sopenharmony_ci struct mwifiex_ds_tx_ba_stream_tbl *buf); 4762306a36Sopenharmony_ciint mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, 4862306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, 4962306a36Sopenharmony_ci int cmd_action, u16 *buf_size); 5062306a36Sopenharmony_ciint mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, 5162306a36Sopenharmony_ci int cmd_action, 5262306a36Sopenharmony_ci struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl); 5362306a36Sopenharmony_civoid mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra); 5462306a36Sopenharmony_ciu8 mwifiex_get_sec_chan_offset(int chan); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic inline u8 5762306a36Sopenharmony_cimwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv, 5862306a36Sopenharmony_ci struct mwifiex_ra_list_tbl *ptr, int tid) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct mwifiex_sta_node *node = mwifiex_get_sta_entry(priv, ptr->ra); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (unlikely(!node)) 6362306a36Sopenharmony_ci return false; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* This function checks whether AMPDU is allowed or not for a particular TID. */ 6962306a36Sopenharmony_cistatic inline u8 7062306a36Sopenharmony_cimwifiex_is_ampdu_allowed(struct mwifiex_private *priv, 7162306a36Sopenharmony_ci struct mwifiex_ra_list_tbl *ptr, int tid) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (is_broadcast_ether_addr(ptr->ra)) 7462306a36Sopenharmony_ci return false; 7562306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 7662306a36Sopenharmony_ci return mwifiex_is_station_ampdu_allowed(priv, ptr, tid); 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci if (ptr->tdls_link) 7962306a36Sopenharmony_ci return mwifiex_is_station_ampdu_allowed(priv, ptr, tid); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return (priv->aggr_prio_tbl[tid].ampdu_ap != 8262306a36Sopenharmony_ci BA_STREAM_NOT_ALLOWED) ? true : false; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * This function checks whether AMSDU is allowed or not for a particular TID. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic inline u8 9062306a36Sopenharmony_cimwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) && 9362306a36Sopenharmony_ci (priv->is_data_rate_auto || !(priv->bitmap_rates[2] & 0x03))) 9462306a36Sopenharmony_ci ? true : false); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * This function checks whether a space is available for new BA stream or not. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic inline u8 mwifiex_space_avail_for_new_ba_stream( 10162306a36Sopenharmony_ci struct mwifiex_adapter *adapter) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct mwifiex_private *priv; 10462306a36Sopenharmony_ci u8 i; 10562306a36Sopenharmony_ci size_t ba_stream_num = 0, ba_stream_max; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 11062306a36Sopenharmony_ci priv = adapter->priv[i]; 11162306a36Sopenharmony_ci if (priv) 11262306a36Sopenharmony_ci ba_stream_num += list_count_nodes( 11362306a36Sopenharmony_ci &priv->tx_ba_stream_tbl_ptr); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (adapter->fw_api_ver == MWIFIEX_FW_V15) { 11762306a36Sopenharmony_ci ba_stream_max = 11862306a36Sopenharmony_ci GETSUPP_TXBASTREAMS(adapter->hw_dot_11n_dev_cap); 11962306a36Sopenharmony_ci if (!ba_stream_max) 12062306a36Sopenharmony_ci ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return ((ba_stream_num < ba_stream_max) ? true : false); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * This function finds the correct Tx BA stream to delete. 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * Upon successfully locating, both the TID and the RA are returned. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic inline u8 13262306a36Sopenharmony_cimwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, 13362306a36Sopenharmony_ci int *ptid, u8 *ra) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci int tid; 13662306a36Sopenharmony_ci u8 ret = false; 13762306a36Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_tbl; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 14262306a36Sopenharmony_ci list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 14362306a36Sopenharmony_ci if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { 14462306a36Sopenharmony_ci tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; 14562306a36Sopenharmony_ci *ptid = tx_tbl->tid; 14662306a36Sopenharmony_ci memcpy(ra, tx_tbl->ra, ETH_ALEN); 14762306a36Sopenharmony_ci ret = true; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * This function checks whether associated station is 11n enabled 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv, 15962306a36Sopenharmony_ci struct mwifiex_sta_node *node) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci if (!node || ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP) && 16262306a36Sopenharmony_ci !priv->ap_11n_enabled) || 16362306a36Sopenharmony_ci ((priv->bss_mode == NL80211_IFTYPE_ADHOC) && 16462306a36Sopenharmony_ci !priv->adapter->adhoc_11n_enabled)) 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return node->is_11n_enabled; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline u8 17162306a36Sopenharmony_cimwifiex_tdls_peer_11n_enabled(struct mwifiex_private *priv, const u8 *ra) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct mwifiex_sta_node *node = mwifiex_get_sta_entry(priv, ra); 17462306a36Sopenharmony_ci if (node) 17562306a36Sopenharmony_ci return node->is_11n_enabled; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return false; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci#endif /* !_MWIFIEX_11N_H_ */ 180