mwifiex: add AMSDU inside AMPDU support

Currently AMPDU aggregation is preferred over AMSDU. AMSDU
aggregation is performed only if AMPDU streams in firmware
are full.
This patch adds simultaneous AMSDU and AMPDU aggregation
support. This mechanism helps to improve throughput.
AMSDU is enabled only for 8897 chipsets which supports 4K
transmit buffer. User can disable AMSDU using
'disable_tx_amsdu' module parameter.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Amitkumar Karwar 2014-03-07 19:41:31 -08:00 committed by John W. Linville
parent 5e6e43eb20
commit 4c9f9fb29b
8 changed files with 132 additions and 61 deletions

View File

@ -159,13 +159,13 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
int tid;
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
& SSN_MASK);
tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
& IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr,
TYPE_DELBA_SENT, true);
@ -179,6 +179,12 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
if (tx_ba_tbl) {
dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
tx_ba_tbl->ba_status = BA_SETUP_COMPLETE;
if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
priv->add_ba_param.tx_amsdu &&
(priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
tx_ba_tbl->amsdu = true;
else
tx_ba_tbl->amsdu = false;
} else {
dev_err(priv->adapter->dev, "BA stream not created\n");
}
@ -541,6 +547,7 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
u32 tx_win_size = priv->add_ba_param.tx_win_size;
static u8 dialog_tok;
int ret;
u16 block_ack_param_set;
dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
@ -559,10 +566,16 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
}
add_ba_req.block_ack_param_set = cpu_to_le16(
(u16) ((tid << BLOCKACKPARAM_TID_POS) |
tx_win_size << BLOCKACKPARAM_WINSIZE_POS |
IMMEDIATE_BLOCK_ACK));
block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) |
tx_win_size << BLOCKACKPARAM_WINSIZE_POS |
IMMEDIATE_BLOCK_ACK);
/* enable AMSDU inside AMPDU */
if (priv->add_ba_param.tx_amsdu &&
(priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set);
add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
++dialog_tok;
@ -677,6 +690,7 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
__func__, rx_reo_tbl->tid);
memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu;
rx_reo_tbl++;
count++;
if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
@ -732,5 +746,8 @@ void mwifiex_set_ba_params(struct mwifiex_private *priv)
MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
}
priv->add_ba_param.tx_amsdu = true;
priv->add_ba_param.rx_amsdu = true;
return;
}

View File

@ -76,6 +76,20 @@ mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv,
return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false;
}
/* This function checks whether AMSDU is allowed for BA stream. */
static inline u8
mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int tid)
{
struct mwifiex_tx_ba_stream_tbl *tx_tbl;
tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra);
if (tx_tbl)
return tx_tbl->amsdu;
return false;
}
/* This function checks whether AMPDU is allowed or not for a particular TID. */
static inline u8
mwifiex_is_ampdu_allowed(struct mwifiex_private *priv,

View File

@ -26,11 +26,50 @@
#include "11n.h"
#include "11n_rxreorder.h"
/* This function will dispatch amsdu packet and forward it to kernel/upper
* layer.
*/
static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
struct sk_buff *skb)
{
struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
int ret;
if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(priv, rx_skb);
if (ret == -1)
dev_err(priv->adapter->dev,
"Rx of A-MSDU failed");
}
return 0;
}
return -1;
}
/* This function will process the rx packet and forward it to kernel/upper
* layer.
*/
static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
{
int ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
if (!ret)
return 0;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
return mwifiex_handle_uap_rx_forward(priv, payload);
@ -406,8 +445,11 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
>> BLOCKACKPARAM_TID_POS;
add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
/* We donot support AMSDU inside AMPDU, hence reset the bit */
block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
/* If we don't support AMSDU inside AMPDU, reset the bit */
if (!priv->add_ba_param.rx_amsdu ||
(priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
@ -468,6 +510,12 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
mwifiex_11n_dispatch_pkt(priv, payload);
return 0;
}
if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
mwifiex_11n_dispatch_pkt(priv, payload);
return 0;
}
start_win = tbl->start_win;
win_size = tbl->win_size;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
@ -627,6 +675,17 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS;
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
add_ba_rsp->peer_mac_addr);
if (tbl) {
if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
priv->add_ba_param.rx_amsdu &&
(priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
tbl->amsdu = true;
else
tbl->amsdu = false;
}
dev_dbg(priv->adapter->dev,
"cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);

View File

@ -177,6 +177,7 @@ struct mwifiex_ds_rx_reorder_tbl {
struct mwifiex_ds_tx_ba_stream_tbl {
u16 tid;
u8 ra[ETH_ALEN];
u8 amsdu;
};
#define DBG_CMD_NUM 5

View File

@ -192,6 +192,8 @@ struct mwifiex_add_ba_param {
u32 tx_win_size;
u32 rx_win_size;
u32 timeout;
u8 tx_amsdu;
u8 rx_amsdu;
};
struct mwifiex_tx_aggr {
@ -560,6 +562,7 @@ struct mwifiex_tx_ba_stream_tbl {
int tid;
u8 ra[ETH_ALEN];
enum mwifiex_ba_status ba_status;
u8 amsdu;
};
struct mwifiex_rx_reorder_tbl;
@ -579,6 +582,7 @@ struct mwifiex_rx_reorder_tbl {
int win_size;
void **rx_reorder_ptr;
struct reorder_tmr_cnxt timer_context;
u8 amsdu;
u8 flags;
};

View File

@ -201,26 +201,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
return ret;
}
if (rx_pkt_type == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
skb_pull(skb, rx_pkt_offset);
skb_trim(skb, rx_pkt_length);
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(priv, rx_skb);
if (ret == -1)
dev_err(adapter->dev, "Rx of A-MSDU failed");
}
return 0;
} else if (rx_pkt_type == PKT_TYPE_MGMT) {
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
dev_err(adapter->dev, "Rx of mgmt packet failed");

View File

@ -284,27 +284,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
return 0;
}
if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(priv, rx_skb);
if (ret)
dev_err(adapter->dev,
"AP:Rx A-MSDU failed");
}
return 0;
} else if (rx_pkt_type == PKT_TYPE_MGMT) {
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
dev_err(adapter->dev, "Rx of mgmt packet failed");

View File

@ -37,8 +37,8 @@
/* Offset for TOS field in the IP header */
#define IPTOS_OFFSET 5
static bool enable_tx_amsdu;
module_param(enable_tx_amsdu, bool, 0644);
static bool disable_tx_amsdu;
module_param(disable_tx_amsdu, bool, 0644);
/* WMM information IE */
static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
@ -413,7 +413,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
continue;
for (i = 0; i < MAX_NUM_TID; ++i) {
priv->aggr_prio_tbl[i].amsdu = priv->tos_to_tid_inv[i];
if (!disable_tx_amsdu &&
adapter->tx_buf_size > MWIFIEX_TX_DATA_BUF_SIZE_2K)
priv->aggr_prio_tbl[i].amsdu =
priv->tos_to_tid_inv[i];
else
priv->aggr_prio_tbl[i].amsdu =
BA_STREAM_NOT_ALLOWED;
priv->aggr_prio_tbl[i].ampdu_ap =
priv->tos_to_tid_inv[i];
priv->aggr_prio_tbl[i].ampdu_user =
@ -1247,13 +1253,22 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
if (!ptr->is_11n_enabled ||
mwifiex_is_ba_stream_setup(priv, ptr, tid) ||
priv->wps.session_enable ||
((priv->sec_info.wpa_enabled ||
priv->sec_info.wpa2_enabled) &&
!priv->wpa_is_gtk_set)) {
mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
/* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */
priv->wps.session_enable) {
if (ptr->is_11n_enabled &&
mwifiex_is_ba_stream_setup(priv, ptr, tid) &&
mwifiex_is_amsdu_in_ampdu_allowed(priv, ptr, tid) &&
mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
/* ra_list_spinlock has been freed in
* mwifiex_11n_aggregate_pkt()
*/
else
mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
/* ra_list_spinlock has been freed in
* mwifiex_send_single_packet()
*/
} else {
if (mwifiex_is_ampdu_allowed(priv, ptr, tid) &&
ptr->ba_pkt_count > ptr->ba_packet_thr) {
@ -1268,7 +1283,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1);
}
}
if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
if (mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);