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