All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] wcn36xx locking and a-mpdu fixes
@ 2015-01-09 19:15 Bob Copeland
  2015-01-09 19:15 ` [PATCH 1/8] wcn36xx: initialize device defaults on start Bob Copeland
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

Hello,

These patches have been merged into the wcn36xx github tree but have
been collecting dust for some time.  I pinged Eugene (CCed) who said I
could just go ahead and send them upstream.  Rebased and re-tested on
an Android target (and newer checkpatch warnings removed).

At some point I can go through other patches (not by me) that aren't yet
upstream and send them along as well, unless someone else wants to do that.

Bob Copeland (8):
  wcn36xx: initialize device defaults on start
  wcn36xx: use !! when assigning int as a boolean
  wcn36xx: let device generate qos seq numbers
  wcn36xx: don't process 'valid' descriptors
  wcn36xx: initialize skb_lock
  wcn36xx: initialize dxe lock
  wcn36xx: move set_tx_pdu inside set_tx_data/mgmt
  wcn36xx: initiate TX BA sessions

 drivers/net/wireless/ath/wcn36xx/dxe.c     |    3 +
 drivers/net/wireless/ath/wcn36xx/main.c    |   16 +++++-
 drivers/net/wireless/ath/wcn36xx/smd.c     |   73 +++++++++++++++++++++++-
 drivers/net/wireless/ath/wcn36xx/txrx.c    |   83 ++++++++++++++++++++++------
 drivers/net/wireless/ath/wcn36xx/txrx.h    |    9 ++-
 drivers/net/wireless/ath/wcn36xx/wcn36xx.h |   20 +++++++
 6 files changed, 182 insertions(+), 22 deletions(-)

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/8] wcn36xx: initialize device defaults on start
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-23 17:12   ` [1/8] " Kalle Valo
  2015-01-09 19:15 ` [PATCH 2/8] wcn36xx: use !! when assigning int as a boolean Bob Copeland
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

Set up default configuration for the device when we call start.
The defaults come from dumps from the prima driver for the same
hardware.

This fixes transmit A-MPDU; previously only one MPDU would be
sent per A-MPDU due to missing MAX_MPDUS_IN_AMPDU setting.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/smd.c |   73 +++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 6398693..69ed397 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -21,6 +21,61 @@
 #include <linux/bitops.h>
 #include "smd.h"
 
+struct wcn36xx_cfg_val {
+	u32 cfg_id;
+	u32 value;
+};
+
+#define WCN36XX_CFG_VAL(id, val) \
+{ \
+	.cfg_id = WCN36XX_HAL_CFG_ ## id, \
+	.value = val \
+}
+
+static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
+	WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),
+	WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),
+	WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),
+	WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),
+	WCN36XX_CFG_VAL(CAL_PERIOD, 5),
+	WCN36XX_CFG_VAL(CAL_CONTROL, 1),
+	WCN36XX_CFG_VAL(PROXIMITY, 0),
+	WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),
+	WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000),
+	WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),
+	WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),
+	WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6),
+	WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6),
+	WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),
+	WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),
+	WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),
+	WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),
+	WCN36XX_CFG_VAL(FIXED_RATE, 0),
+	WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),
+	WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),
+	WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),
+	WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),
+	WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),
+	WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),
+	WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),
+	WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),
+	WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),
+	WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),
+	WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),
+	WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),
+	WCN36XX_CFG_VAL(STATS_PERIOD, 10),
+	WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),
+	WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),
+	WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),
+	WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),
+	WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),
+	WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
+	WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
+	WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
+	WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
+	WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
+};
+
 static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
 {
 	struct wcn36xx_hal_cfg *entry;
@@ -357,8 +412,10 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
 
 int wcn36xx_smd_start(struct wcn36xx *wcn)
 {
-	struct wcn36xx_hal_mac_start_req_msg msg_body;
+	struct wcn36xx_hal_mac_start_req_msg msg_body, *body;
 	int ret = 0;
+	int i;
+	size_t len;
 
 	mutex_lock(&wcn->hal_mutex);
 	INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);
@@ -368,10 +425,22 @@ int wcn36xx_smd_start(struct wcn36xx *wcn)
 
 	PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
+	body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf;
+	len = body->header.len;
+
+	for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) {
+		ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id,
+				      wcn36xx_cfg_vals[i].value);
+		if (ret)
+			goto out;
+	}
+	body->header.len = len;
+	body->params.len = len - sizeof(*body);
+
 	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n",
 		    msg_body.params.type);
 
-	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+	ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);
 	if (ret) {
 		wcn36xx_err("Sending hal_start failed\n");
 		goto out;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/8] wcn36xx: use !! when assigning int as a boolean
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
  2015-01-09 19:15 ` [PATCH 1/8] wcn36xx: initialize device defaults on start Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 3/8] wcn36xx: let device generate qos seq numbers Bob Copeland
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

bd->tx_comp is a single bit in a bitfield, so assigning
"info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS" only happens
to work because TX_STATUS is defined to BIT(0); if it were
any other bit this assignment would fail.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/txrx.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 32bb26a..f701873 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -237,7 +237,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
 
 	bd->dpu_rf = WCN36XX_BMU_WQ_TX;
 
-	bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS;
+	bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
 	if (bd->tx_comp) {
 		wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
 		spin_lock_irqsave(&wcn->dxe_lock, flags);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/8] wcn36xx: let device generate qos seq numbers
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
  2015-01-09 19:15 ` [PATCH 1/8] wcn36xx: initialize device defaults on start Bob Copeland
  2015-01-09 19:15 ` [PATCH 2/8] wcn36xx: use !! when assigning int as a boolean Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 4/8] wcn36xx: don't process 'valid' descriptors Bob Copeland
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

wcn36xx currently sends an incorrect sequence number into the BA session
setup firmware command: it should be saving or updating the ssn in the
TX_START ampdu_action callback instead of waiting until TX_OPERATIONAL.
However, we can sidestep the issue by letting the hardware generate the
sequence numbers for QoS frames, as is done in prima, so do that.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/txrx.c |    1 +
 drivers/net/wireless/ath/wcn36xx/txrx.h |    9 ++++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index f701873..277bc39 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -93,6 +93,7 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
 		bd->pdu.mpdu_header_off;
 	bd->pdu.mpdu_len = len;
 	bd->pdu.tid = tid;
+	bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS;
 }
 
 static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h
index bbfbcf8..032216e 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.h
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.h
@@ -32,6 +32,12 @@
 #define WCN36XX_BD_RATE_MGMT 2
 #define WCN36XX_BD_RATE_CTRL 3
 
+enum wcn36xx_txbd_ssn_type {
+	WCN36XX_TXBD_SSN_FILL_HOST = 0,
+	WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1,
+	WCN36XX_TXBD_SSN_FILL_DPU_QOS = 2,
+};
+
 struct wcn36xx_pdu {
 	u32	dpu_fb:8;
 	u32	adu_fb:8;
@@ -50,7 +56,8 @@ struct wcn36xx_pdu {
 	/* 0x0c*/
 	u32	reserved4:8;
 	u32	tid:4;
-	u32	reserved3:4;
+	u32	bd_ssn:2;
+	u32	reserved3:2;
 	u32	mpdu_len:16;
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/8] wcn36xx: don't process 'valid' descriptors
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (2 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 3/8] wcn36xx: let device generate qos seq numbers Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 5/8] wcn36xx: initialize skb_lock Bob Copeland
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

The DMA engine will reset the valid bit after a descriptor is
complete; any with the valid bit still set may still be in
use by the hardware, so check that before freeing the descriptor.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/dxe.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 73f12f1..3d6bc9b 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -354,6 +354,8 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 	 * and while-do will not make any cycles.
 	 */
 	do {
+		if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
+			break;
 		if (ctl->skb) {
 			dma_unmap_single(NULL, ctl->desc->src_addr_l,
 					 ctl->skb->len, DMA_TO_DEVICE);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/8] wcn36xx: initialize skb_lock
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (3 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 4/8] wcn36xx: don't process 'valid' descriptors Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 6/8] wcn36xx: initialize dxe lock Bob Copeland
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

ctl->skb_lock is never initialized, a fact caught by lockdep.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/dxe.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 3d6bc9b..086549b 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -84,6 +84,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
 		if (!cur_ctl)
 			goto out_fail;
 
+		spin_lock_init(&cur_ctl->skb_lock);
 		cur_ctl->ctl_blk_order = i;
 		if (i == 0) {
 			ch->head_blk_ctl = cur_ctl;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/8] wcn36xx: initialize dxe lock
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (4 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 5/8] wcn36xx: initialize skb_lock Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 7/8] wcn36xx: move set_tx_pdu inside set_tx_data/mgmt Bob Copeland
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

The dxe lock is missing its initialization, so add it.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/main.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7dd8873..972bb3e 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -298,6 +298,8 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
 	wcn36xx_debugfs_init(wcn);
 
 	INIT_LIST_HEAD(&wcn->vif_list);
+	spin_lock_init(&wcn->dxe_lock);
+
 	return 0;
 
 out_smd_stop:
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/8] wcn36xx: move set_tx_pdu inside set_tx_data/mgmt
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (5 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 6/8] wcn36xx: initialize dxe lock Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-09 19:15 ` [PATCH 8/8] wcn36xx: initiate TX BA sessions Bob Copeland
  2015-01-12  9:35 ` [PATCH 0/8] wcn36xx locking and a-mpdu fixes Eugene Krasnikov
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

The pdu is part of the buffer descriptor, so it makes
sense that one function would fill both.  Also, passing
the whole skb instead of just the header pointer to the
set_tx_data function paves the way for using its fields
for ampdu setup inside set_tx_data().

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/txrx.c |   37 +++++++++++++++++--------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 277bc39..7f0d9e6 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -115,9 +115,10 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
 				struct wcn36xx *wcn,
 				struct wcn36xx_vif **vif_priv,
 				struct wcn36xx_sta *sta_priv,
-				struct ieee80211_hdr *hdr,
+				struct sk_buff *skb,
 				bool bcast)
 {
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_vif *vif = NULL;
 	struct wcn36xx_vif *__vif_priv = NULL;
 	bd->bd_rate = WCN36XX_BD_RATE_DATA;
@@ -158,14 +159,21 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
 		bd->ack_policy = 1;
 	}
 	*vif_priv = __vif_priv;
+
+	wcn36xx_set_tx_pdu(bd,
+			   ieee80211_is_data_qos(hdr->frame_control) ?
+			   sizeof(struct ieee80211_qos_hdr) :
+			   sizeof(struct ieee80211_hdr_3addr),
+			   skb->len, sta_priv ? sta_priv->tid : 0);
 }
 
 static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
 				struct wcn36xx *wcn,
 				struct wcn36xx_vif **vif_priv,
-				struct ieee80211_hdr *hdr,
+				struct sk_buff *skb,
 				bool bcast)
 {
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct wcn36xx_vif *__vif_priv =
 		get_vif_by_addr(wcn, hdr->addr2);
 	bd->sta_index = __vif_priv->self_sta_index;
@@ -199,6 +207,12 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
 	} else
 		bd->queue_id = WCN36XX_TX_U_WQ_ID;
 	*vif_priv = __vif_priv;
+
+	wcn36xx_set_tx_pdu(bd,
+			   ieee80211_is_data_qos(hdr->frame_control) ?
+			   sizeof(struct ieee80211_qos_hdr) :
+			   sizeof(struct ieee80211_hdr_3addr),
+			   skb->len, WCN36XX_TID);
 }
 
 int wcn36xx_start_tx(struct wcn36xx *wcn,
@@ -260,22 +274,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
 	}
 
 	/* Data frames served first*/
-	if (is_low) {
-		wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast);
-		wcn36xx_set_tx_pdu(bd,
-			   ieee80211_is_data_qos(hdr->frame_control) ?
-			   sizeof(struct ieee80211_qos_hdr) :
-			   sizeof(struct ieee80211_hdr_3addr),
-			   skb->len, sta_priv ? sta_priv->tid : 0);
-	} else {
+	if (is_low)
+		wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast);
+	else
 		/* MGMT and CTRL frames are handeld here*/
-		wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast);
-		wcn36xx_set_tx_pdu(bd,
-			   ieee80211_is_data_qos(hdr->frame_control) ?
-			   sizeof(struct ieee80211_qos_hdr) :
-			   sizeof(struct ieee80211_hdr_3addr),
-			   skb->len, WCN36XX_TID);
-	}
+		wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast);
 
 	buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
 	bd->tx_bd_sign = 0xbdbdbdbd;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 8/8] wcn36xx: initiate TX BA sessions
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (6 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 7/8] wcn36xx: move set_tx_pdu inside set_tx_data/mgmt Bob Copeland
@ 2015-01-09 19:15 ` Bob Copeland
  2015-01-12  9:35 ` [PATCH 0/8] wcn36xx locking and a-mpdu fixes Eugene Krasnikov
  8 siblings, 0 replies; 11+ messages in thread
From: Bob Copeland @ 2015-01-09 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Eugene Krasnikov, Bob Copeland

Currently, wcn36xx only asks for a TX BA session if it has
already established one for RX.  Thus, two wcn36xx devices cannot
do a-mpdu between themselves since they both wait for the other
to go first.  Fix this by starting a BA session after a few QoS
data frames have been sent to a STA.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
 drivers/net/wireless/ath/wcn36xx/main.c    |   14 ++++++++-
 drivers/net/wireless/ath/wcn36xx/txrx.c    |   45 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/wcn36xx/wcn36xx.h |   20 +++++++++++++
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 972bb3e..0783d2e 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -797,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
 		    vif, sta->addr);
 
+	spin_lock_init(&sta_priv->ampdu_lock);
 	vif_priv->sta = sta_priv;
 	sta_priv->vif = vif_priv;
 	/*
@@ -875,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
 			get_sta_index(vif, sta_priv));
 		wcn36xx_smd_add_ba(wcn);
 		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
-		ieee80211_start_tx_ba_session(sta, tid, 0);
 		break;
 	case IEEE80211_AMPDU_RX_STOP:
 		wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
 		break;
 	case IEEE80211_AMPDU_TX_START:
+		spin_lock_bh(&sta_priv->ampdu_lock);
+		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+		spin_unlock_bh(&sta_priv->ampdu_lock);
+
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		spin_lock_bh(&sta_priv->ampdu_lock);
+		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
+		spin_unlock_bh(&sta_priv->ampdu_lock);
+
 		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
 			get_sta_index(vif, sta_priv));
 		break;
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 	case IEEE80211_AMPDU_TX_STOP_CONT:
+		spin_lock_bh(&sta_priv->ampdu_lock);
+		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
+		spin_unlock_bh(&sta_priv->ampdu_lock);
+
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	default:
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 7f0d9e6..9bec823 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -111,6 +111,42 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
 	wcn36xx_warn("vif %pM not found\n", addr);
 	return NULL;
 }
+
+static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
+				   struct wcn36xx_sta *sta_priv,
+				   struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_sta *sta;
+	u8 *qc, tid;
+
+	if (!conf_is_ht(&wcn->hw->conf))
+		return;
+
+	sta = wcn36xx_priv_to_sta(sta_priv);
+
+	if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
+		return;
+
+	if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+		return;
+
+	qc = ieee80211_get_qos_ctl(hdr);
+	tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+
+	spin_lock(&sta_priv->ampdu_lock);
+	if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
+		goto out_unlock;
+
+	if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
+		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+		sta_priv->non_agg_frame_ct = 0;
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+	}
+out_unlock:
+	spin_unlock(&sta_priv->ampdu_lock);
+}
+
 static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
 				struct wcn36xx *wcn,
 				struct wcn36xx_vif **vif_priv,
@@ -121,6 +157,8 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_vif *vif = NULL;
 	struct wcn36xx_vif *__vif_priv = NULL;
+	bool is_data_qos;
+
 	bd->bd_rate = WCN36XX_BD_RATE_DATA;
 
 	/*
@@ -160,11 +198,16 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
 	}
 	*vif_priv = __vif_priv;
 
+	is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
+
 	wcn36xx_set_tx_pdu(bd,
-			   ieee80211_is_data_qos(hdr->frame_control) ?
+			   is_data_qos ?
 			   sizeof(struct ieee80211_qos_hdr) :
 			   sizeof(struct ieee80211_hdr_3addr),
 			   skb->len, sta_priv ? sta_priv->tid : 0);
+
+	if (sta_priv && is_data_qos)
+		wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
 }
 
 static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index f0fb81d..7b41e83 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -32,6 +32,9 @@
 #define WLAN_NV_FILE               "wlan/prima/WCNSS_qcom_wlan_nv.bin"
 #define WCN36XX_AGGR_BUFFER_SIZE 64
 
+/* How many frames until we start a-mpdu TX session */
+#define WCN36XX_AMPDU_START_THRESH	20
+
 extern unsigned int wcn36xx_dbg_mask;
 
 enum wcn36xx_debug_mask {
@@ -74,6 +77,13 @@ enum wcn36xx_debug_mask {
 			       buf, len, false);		\
 } while (0)
 
+enum wcn36xx_ampdu_state {
+	WCN36XX_AMPDU_NONE,
+	WCN36XX_AMPDU_INIT,
+	WCN36XX_AMPDU_START,
+	WCN36XX_AMPDU_OPERATIONAL,
+};
+
 #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
 #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
 #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
@@ -165,6 +175,10 @@ struct wcn36xx_sta {
 	bool is_data_encrypted;
 	/* Rates */
 	struct wcn36xx_hal_supported_rates supported_rates;
+
+	spinlock_t ampdu_lock;		/* protects next two fields */
+	enum wcn36xx_ampdu_state ampdu_state[16];
+	int non_agg_frame_ct;
 };
 struct wcn36xx_dxe_ch;
 struct wcn36xx {
@@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
 }
 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
 
+static inline
+struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
+{
+	return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv);
+}
+
 #endif	/* _WCN36XX_H_ */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/8] wcn36xx locking and a-mpdu fixes
  2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
                   ` (7 preceding siblings ...)
  2015-01-09 19:15 ` [PATCH 8/8] wcn36xx: initiate TX BA sessions Bob Copeland
@ 2015-01-12  9:35 ` Eugene Krasnikov
  8 siblings, 0 replies; 11+ messages in thread
From: Eugene Krasnikov @ 2015-01-12  9:35 UTC (permalink / raw)
  To: Bob Copeland; +Cc: linux-wireless

Looks good to me!

2015-01-09 19:15 GMT+00:00 Bob Copeland <me@bobcopeland.com>:
> Hello,
>
> These patches have been merged into the wcn36xx github tree but have
> been collecting dust for some time.  I pinged Eugene (CCed) who said I
> could just go ahead and send them upstream.  Rebased and re-tested on
> an Android target (and newer checkpatch warnings removed).
>
> At some point I can go through other patches (not by me) that aren't yet
> upstream and send them along as well, unless someone else wants to do that.
>
> Bob Copeland (8):
>   wcn36xx: initialize device defaults on start
>   wcn36xx: use !! when assigning int as a boolean
>   wcn36xx: let device generate qos seq numbers
>   wcn36xx: don't process 'valid' descriptors
>   wcn36xx: initialize skb_lock
>   wcn36xx: initialize dxe lock
>   wcn36xx: move set_tx_pdu inside set_tx_data/mgmt
>   wcn36xx: initiate TX BA sessions
>
>  drivers/net/wireless/ath/wcn36xx/dxe.c     |    3 +
>  drivers/net/wireless/ath/wcn36xx/main.c    |   16 +++++-
>  drivers/net/wireless/ath/wcn36xx/smd.c     |   73 +++++++++++++++++++++++-
>  drivers/net/wireless/ath/wcn36xx/txrx.c    |   83 ++++++++++++++++++++++------
>  drivers/net/wireless/ath/wcn36xx/txrx.h    |    9 ++-
>  drivers/net/wireless/ath/wcn36xx/wcn36xx.h |   20 +++++++
>  6 files changed, 182 insertions(+), 22 deletions(-)
>
> --
> 1.7.10.4
>



-- 
Best regards,
Eugene

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [1/8] wcn36xx: initialize device defaults on start
  2015-01-09 19:15 ` [PATCH 1/8] wcn36xx: initialize device defaults on start Bob Copeland
@ 2015-01-23 17:12   ` Kalle Valo
  0 siblings, 0 replies; 11+ messages in thread
From: Kalle Valo @ 2015-01-23 17:12 UTC (permalink / raw)
  To: Bob Copeland; +Cc: linux-wireless, Eugene Krasnikov, Bob Copeland


> Set up default configuration for the device when we call start.
> The defaults come from dumps from the prima driver for the same
> hardware.
> 
> This fixes transmit A-MPDU; previously only one MPDU would be
> sent per A-MPDU due to missing MAX_MPDUS_IN_AMPDU setting.
> 
> Signed-off-by: Bob Copeland <me@bobcopeland.com>

Thanks, 8 patches applied to wireless-drivers-next.git:

69a88cc7b164 wcn36xx: initialize device defaults on start
f786a6d4af92 wcn36xx: use !! when assigning int as a boolean
232ddcd80fa5 wcn36xx: let device generate qos seq numbers
bfa6696b39ae wcn36xx: don't process 'valid' descriptors
90dccb73e985 wcn36xx: initialize skb_lock
4b12462a3a7f wcn36xx: initialize dxe lock
5f3f928585b2 wcn36xx: move set_tx_pdu inside set_tx_data/mgmt
e26dc173a66a wcn36xx: initiate TX BA sessions

Kalle Valo

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-01-23 17:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-09 19:15 [PATCH 0/8] wcn36xx locking and a-mpdu fixes Bob Copeland
2015-01-09 19:15 ` [PATCH 1/8] wcn36xx: initialize device defaults on start Bob Copeland
2015-01-23 17:12   ` [1/8] " Kalle Valo
2015-01-09 19:15 ` [PATCH 2/8] wcn36xx: use !! when assigning int as a boolean Bob Copeland
2015-01-09 19:15 ` [PATCH 3/8] wcn36xx: let device generate qos seq numbers Bob Copeland
2015-01-09 19:15 ` [PATCH 4/8] wcn36xx: don't process 'valid' descriptors Bob Copeland
2015-01-09 19:15 ` [PATCH 5/8] wcn36xx: initialize skb_lock Bob Copeland
2015-01-09 19:15 ` [PATCH 6/8] wcn36xx: initialize dxe lock Bob Copeland
2015-01-09 19:15 ` [PATCH 7/8] wcn36xx: move set_tx_pdu inside set_tx_data/mgmt Bob Copeland
2015-01-09 19:15 ` [PATCH 8/8] wcn36xx: initiate TX BA sessions Bob Copeland
2015-01-12  9:35 ` [PATCH 0/8] wcn36xx locking and a-mpdu fixes Eugene Krasnikov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.