From eac4322729aebf01ae231d3b3f63aae73d469a57 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:27:28 -0800 Subject: mwifiex: handle AMPDU supported check for AP interface This patch fixes a bug where we were checking for AP's AMPDU param setting even when transmitting traffic to associated station. Patch adds provision to pass additional parameter ra_list pointer to function which checks if AMPDU is allowed. If current BSS type is AP, we check station's AMPDU params else we check AP's AMPDU params. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 13eaeed03898..ee447893fe57 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1226,7 +1226,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) /* ra_list_spinlock has been freed in mwifiex_send_single_packet() */ } else { - if (mwifiex_is_ampdu_allowed(priv, tid) && + if (mwifiex_is_ampdu_allowed(priv, ptr, tid) && ptr->ba_pkt_count > ptr->ba_packet_thr) { if (mwifiex_space_avail_for_new_ba_stream(adapter)) { mwifiex_create_ba_tbl(priv, ptr->ra, tid, -- cgit v1.2.3 From 41a24a29142dd0352de965c40b840a90d6e55f6c Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:27:29 -0800 Subject: mwifiex: make tos_to_tid_inv part of mwifiex_private structure tos_to_tid_inv values are needed even during TDLS restore operations. Currently tos_to_tid_inv is part of wmm.c and is declared static. Make it part of private structure so that it can be used in other files as well. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index ee447893fe57..2999c3b1e112 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -64,21 +64,6 @@ static u8 tos_to_tid[] = { 0x07 /* 1 1 1 AC_VO */ }; -/* - * This table inverses the tos_to_tid operation to get a priority - * which is in sequential order, and can be compared. - * Use this to compare the priority of two different TIDs. - */ -static u8 tos_to_tid_inv[] = { - 0x02, /* from tos_to_tid[2] = 0 */ - 0x00, /* from tos_to_tid[0] = 1 */ - 0x01, /* from tos_to_tid[1] = 2 */ - 0x03, - 0x04, - 0x05, - 0x06, - 0x07}; - static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; /* @@ -213,8 +198,9 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) * This function map ACs to TIDs. */ static void -mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm) +mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv) { + struct mwifiex_wmm_desc *wmm = &priv->wmm; u8 *queue_priority = wmm->queue_priority; int i; @@ -224,7 +210,7 @@ mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm) } for (i = 0; i < MAX_NUM_TID; ++i) - tos_to_tid_inv[tos_to_tid[i]] = (u8)i; + priv->tos_to_tid_inv[tos_to_tid[i]] = (u8)i; atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID); } @@ -285,7 +271,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, } } - mwifiex_wmm_queue_priorities_tid(&priv->wmm); + mwifiex_wmm_queue_priorities_tid(priv); } /* @@ -421,9 +407,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) continue; for (i = 0; i < MAX_NUM_TID; ++i) { - priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; - priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; - priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].amsdu = priv->tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_ap = + priv->tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_user = + priv->tos_to_tid_inv[i]; } priv->aggr_prio_tbl[6].amsdu @@ -683,9 +671,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, ra_list->total_pkt_count++; if (atomic_read(&priv->wmm.highest_queued_prio) < - tos_to_tid_inv[tid_down]) + priv->tos_to_tid_inv[tid_down]) atomic_set(&priv->wmm.highest_queued_prio, - tos_to_tid_inv[tid_down]); + priv->tos_to_tid_inv[tid_down]); atomic_inc(&priv->wmm.tx_pkts_queued); -- cgit v1.2.3 From 5f2caaf32bc64c200007611505ce2453f4862276 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:27:33 -0800 Subject: mwifiex: parse TDLS action frames during RX This patch adds support for parsing TDLS action frames during station receive handler. Peer station capabilities are stored into station node. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 2999c3b1e112..557d36318d1d 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -374,8 +374,7 @@ mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) * AP is disabled (due to call admission control (ACM bit). Mapping * of TID to AC is taken care of internally. */ -static u8 -mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) +u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) { enum mwifiex_wmm_ac_e ac, ac_down; u8 new_tid; @@ -578,7 +577,7 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, * If no such node is found, a new node is added first and then * retrieved. */ -static struct mwifiex_ra_list_tbl * +struct mwifiex_ra_list_tbl * mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) { struct mwifiex_ra_list_tbl *ra_list; -- cgit v1.2.3 From 56bd24a18e1a7306a21f6b7d7716cced7e593057 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:30:35 -0800 Subject: mwifiex: provision for holding and restoring packets during TDLS setup While TDLS link is being setup, few packets from this station to peer station may be buffered at AP. It may happen that once TDLS link is setup, packets sent from station to peer on direct link get delivered before traffic from AP arrives at peer station. This results into packet reordering issue at peer station. To avoid this, we hold data packets destined to TDLS peer during TDLS setup. These packets are moved to temperory TDLS TX queue. Upon successful TDLS setup, they are moved to RA list created for this peer. Upon failure, packets are moved back to AP's RA list for that particular TID. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 557d36318d1d..e9f7628684ce 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -533,6 +533,7 @@ void mwifiex_clean_txrx(struct mwifiex_private *priv) { unsigned long flags; + struct sk_buff *skb, *tmp; mwifiex_11n_cleanup_reorder_tbl(priv); spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); @@ -549,6 +550,9 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) if (priv->adapter->if_ops.clean_pcie_ring) priv->adapter->if_ops.clean_pcie_ring(priv->adapter); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + + skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); } /* -- cgit v1.2.3 From d63bf5e5e00dc025c71532e9244a96966ac8e252 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:30:36 -0800 Subject: mwifiex: tdls related handling for data packets addressed to TDLS peer 1. If data packet is addressed to TDLS peer for which link is established, mark these packets with TDLS flag so that FW can send them on direct link instead of sending via AP. 2. If data packet is addressed to TDLS peer and TDLS setup is underway, move these packets to TDLS queue. 3. If this packet is TDLS setup packet, do not block it. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index e9f7628684ce..63496ed10272 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -631,6 +631,21 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list; u8 ra[ETH_ALEN], tid_down; unsigned long flags; + struct list_head list_head; + int tdls_status = TDLS_NOT_SETUP; + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + + memcpy(ra, eth_hdr->h_dest, ETH_ALEN); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && + ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) { + if (ntohs(eth_hdr->h_proto) == ETH_P_TDLS) + dev_dbg(adapter->dev, + "TDLS setup packet for %pM. Don't block\n", ra); + else + tdls_status = mwifiex_get_tdls_link_status(priv, ra); + } if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) { dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); @@ -649,12 +664,27 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, have only 1 raptr for a tid in case of infra */ if (!mwifiex_queuing_ra_based(priv) && !mwifiex_is_skb_mgmt_frame(skb)) { - if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) - ra_list = list_first_entry( - &priv->wmm.tid_tbl_ptr[tid_down].ra_list, - struct mwifiex_ra_list_tbl, list); - else - ra_list = NULL; + switch (tdls_status) { + case TDLS_SETUP_COMPLETE: + ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, + ra); + tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; + break; + case TDLS_SETUP_INPROGRESS: + skb_queue_tail(&priv->tdls_txq, skb); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + flags); + return; + default: + list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list; + if (!list_empty(&list_head)) + ra_list = list_first_entry( + &list_head, struct mwifiex_ra_list_tbl, + list); + else + ra_list = NULL; + break; + } } else { memcpy(ra, skb->data, ETH_ALEN); if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb)) -- cgit v1.2.3 From daeb5bb48256d7488246d48453b2315281ce9c75 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 7 Feb 2014 16:30:37 -0800 Subject: mwifiex: AMPDU support for TDLS link This patch adds AMPDU support for TDLS link. We have set 11n capabilities including AMPDU parameters during ENABLE_LINK. We set a variable in RA list to indicate this as TDLS link. This patch uses these capabilities to know if AMPDU is allowed on TDLS link and enables AMPDU aggregation for TX and RX reording support for RA list for this peer. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 63496ed10272..e0ba0115e5ae 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -160,8 +160,15 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) break; ra_list->is_11n_enabled = 0; + ra_list->tdls_link = false; if (!mwifiex_queuing_ra_based(priv)) { - ra_list->is_11n_enabled = IS_11N_ENABLED(priv); + if (mwifiex_get_tdls_link_status(priv, ra) == + TDLS_SETUP_COMPLETE) { + ra_list->is_11n_enabled = + mwifiex_tdls_peer_11n_enabled(priv, ra); + } else { + ra_list->is_11n_enabled = IS_11N_ENABLED(priv); + } } else { ra_list->is_11n_enabled = mwifiex_is_sta_11n_enabled(priv, node); -- cgit v1.2.3 From 4c9f9fb29b3cdfa751c8ccf984a84fbe9e643b91 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:31 -0800 Subject: 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 Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/mwifiex/wmm.c') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 1c5f2b66f057..0a7cc742aed7 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -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); -- cgit v1.2.3