mwifiex: add AMSDU inside AMPDU support
authorAmitkumar Karwar <akarwar@marvell.com>
Sat, 8 Mar 2014 03:41:31 +0000 (19:41 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 14 Mar 2014 18:49:14 +0000 (14:49 -0400)
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>
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/11n.h
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/mwifiex/uap_txrx.c
drivers/net/wireless/mwifiex/wmm.c

index ebc4cf648e151f11ac6955a4a602aeeb35a9a335..70159dd01acfd521149d9c27821a654d4a4f5bc1 100644 (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;
 }
index 12bb6acbdd58ce53dd97d5cc0fdeb2bbb10a5e29..40b007a00f4bd9e786c24f8f53059c38e29e79a4 100644 (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,
index 2be015b77b15014bafbdea1c876b83db26efb061..0c3571f830b0d70cc609e64d9b0b6fde3cf17209 100644 (file)
 #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);
index 1fb2212079aebac25cde7dd78bf9792ccf74de39..ee494db5406097c35a0f22b365e2ad2e1ac674f8 100644 (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
index 713dd247a1533ba0670e9a74d0b1baacc88f13d3..a67f7da12b30e9f00c2b6c3c52ff5f306f56cef7 100644 (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;
 };
 
index b6aa958bd6e4e37e63129a937fd2afda2a8c0d23..ed26387eccf56db59bca98f7ed6fd7e6a4065aae 100644 (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");
index 3c74eb25492790410b9627dbb9a6ca0a0555f010..9a56bc61cb1d29993ebcc057fb4cf058bd1100f2 100644 (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");
index 1c5f2b66f0578304f1613eb2df49cd6fe30f151d..0a7cc742aed71e0fd31267305be7a26ec71b8b52 100644 (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);