[PATCH] Fix DXE TX routine to use both channels LOW and HIGH

Eugene Krasnikov k.eugene.e at gmail.com
Tue Apr 30 06:33:55 EDT 2013


Implement wcn36xx_dxe_tx in the way that all data frames
will go through low channel while all management frames
will go through high channel.

Signed-off-by: Eugene Krasnikov <k.eugene.e at gmail.com>
---
 dxe.c  | 59 +++++++++++++++++++++++++++++++++++++++++++----------------
 dxe.h  | 14 +++++++++++++-
 main.c |  9 +++++++--
 3 files changed, 63 insertions(+), 19 deletions(-)

diff --git a/dxe.c b/dxe.c
index c1aff1b..5e8a125 100644
--- a/dxe.c
+++ b/dxe.c
@@ -103,6 +103,21 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
 	wcn->dxe_rx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_L;
 	wcn->dxe_rx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_H;
 
+	wcn->dxe_tx_l_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_L;
+	wcn->dxe_tx_h_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_H;
+
+	wcn->dxe_tx_l_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_L_BD;
+	wcn->dxe_tx_h_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_H_BD;
+
+	wcn->dxe_tx_l_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_L_SKB;
+	wcn->dxe_tx_h_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_H_SKB;
+
+	wcn->dxe_tx_l_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_L;
+	wcn->dxe_tx_h_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_H;
+
+	wcn->dxe_tx_l_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_L;
+	wcn->dxe_tx_h_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_H;
+
 	//DEX control block allocation
 	wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_l_ch);
 	wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_h_ch);
@@ -371,31 +386,41 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
 		sizeof(u32), GFP_KERNEL);
 	return 0;
 }
-int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast)
+int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast, bool is_high)
 {
 	struct wcn36xx_dxe_ctl *cur_dxe_ctl = NULL;
 	struct wcn36xx_dxe_desc *cur_dxe_desc = NULL;
+	struct wcn36xx_dxe_mem_pool * mem_pool = NULL;
+	struct wcn36xx_dxe_ch * cur_ch = NULL;
+	if(is_high) {
+		wcn36xx_dbg("DXE TX: MGMT");
+		mem_pool = &wcn->mgmt_mem_pool;
+		cur_ch = &wcn->dxe_tx_h_ch;
+	} else {
+		wcn36xx_dbg("DXE TX: DATA");
+		mem_pool = &wcn->data_mem_pool;
+		cur_ch = &wcn->dxe_tx_l_ch;
+	}
 
-	wcn36xx_prepare_tx_bd(wcn->mgmt_mem_pool.virt_addr, skb->len);
-	wcn36xx_fill_tx_bd(wcn->mgmt_mem_pool.virt_addr, broadcast);
+	wcn36xx_prepare_tx_bd(mem_pool->virt_addr, skb->len);
+	wcn36xx_fill_tx_bd(mem_pool->virt_addr, broadcast);
 
-	cur_dxe_ctl = wcn->dxe_tx_h_ch.head_blk_ctl;
+	cur_dxe_ctl = cur_ch->head_blk_ctl;
 	cur_dxe_desc = cur_dxe_ctl->desc;
 
 	// Let's not forget the frame we are sending
-	cur_dxe_ctl->frame = wcn->mgmt_mem_pool.virt_addr;
+	cur_dxe_ctl->frame = mem_pool->virt_addr;
 
 	// Set source address of the BD we send
+	cur_dxe_desc->desc.src_addr_l = (int)mem_pool->phy_addr;
 
-	cur_dxe_desc->desc.src_addr_l = (int)wcn->mgmt_mem_pool.phy_addr;
-	// TODO fix me, if data then set it to WCN36XX_DXE_WQ_TX_L
-	cur_dxe_desc->desc.dst_addr_l = WCN36XX_DXE_WQ_TX_H;
+	cur_dxe_desc->desc.dst_addr_l = cur_ch->dxe_wq;
 	cur_dxe_desc->fr_len = sizeof(struct wcn36xx_tx_bd);
-	cur_dxe_desc->desc_ctl.ctrl = WCN36XX_DXE_CTRL_TX_H_BD;
+	cur_dxe_desc->desc_ctl.ctrl = cur_ch->ctrl_bd;
 
-	wcn36xx_dbg("DXE TX");
 	wcn36xx_dbg_dump("DESC1 >>> ", (char*)cur_dxe_desc, sizeof(*cur_dxe_desc));
-	wcn36xx_dbg_dump("BD   >>> ", (char*)wcn->mgmt_mem_pool.virt_addr, sizeof(struct wcn36xx_tx_bd));
+	wcn36xx_dbg_dump("BD   >>> ", (char*)mem_pool->virt_addr, sizeof(struct wcn36xx_tx_bd));
+
 	// Set source address of the SKB we send
 	cur_dxe_ctl = (struct wcn36xx_dxe_ctl*)cur_dxe_ctl->next;
 	cur_dxe_ctl->skb = skb;
@@ -404,20 +429,22 @@ int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast)
 		cur_dxe_ctl->skb->data,
 		cur_dxe_ctl->skb->len,
 		DMA_TO_DEVICE );
-	cur_dxe_desc->desc.dst_addr_l = WCN36XX_DXE_WQ_TX_H;
+
+	cur_dxe_desc->desc.dst_addr_l = cur_ch->dxe_wq;
 	cur_dxe_desc->fr_len = cur_dxe_ctl->skb->len;
+
 	// set it to VALID
-	cur_dxe_desc->desc_ctl.ctrl = WCN36XX_DXE_CTRL_TX_H_SKB;
+	cur_dxe_desc->desc_ctl.ctrl = cur_ch->ctrl_skb;
 
 	wcn36xx_dbg_dump("DESC2 >>> ", (char*)cur_dxe_desc, sizeof(*cur_dxe_desc));
 	wcn36xx_dbg_dump("SKB   >>> ", (char*)cur_dxe_ctl->skb->data, cur_dxe_ctl->skb->len);
 
 	// Move the head of the ring to the next empty descriptor
-	wcn->dxe_tx_h_ch.head_blk_ctl = cur_dxe_ctl->next;
+	 cur_ch->head_blk_ctl = cur_dxe_ctl->next;
+
 	//indicate End Of Packet and generate interrupt on descriptor Done
 	wcn36xx_dxe_write_register(wcn,
-		WCN36XX_DXE_REG_CTL_TX_H,
-		WCN36XX_DXE_CH_DEFAULT_CTL_TX_H);
+		cur_ch->reg_ctrl, cur_ch->def_ctrl);
 	return 0;
 }
 int wcn36xx_dxe_init(struct wcn36xx *wcn)
diff --git a/dxe.h b/dxe.h
index 86991d7..2bdc8b8 100644
--- a/dxe.h
+++ b/dxe.h
@@ -39,6 +39,8 @@ RX_HIGH	= DMA3
 #define WCN36XX_DXE_CTRL_RX_H			0x12d12f
 #define WCN36XX_DXE_CTRL_TX_H_BD		0x32ce45
 #define WCN36XX_DXE_CTRL_TX_H_SKB		0x32ce4d
+#define WCN36XX_DXE_CTRL_TX_L_BD		0x328a45
+#define WCN36XX_DXE_CTRL_TX_L_SKB		0x328a4d
 
 // TODO This must calculated properly but not hardcoded
 #define WCN36XX_DXE_WQ_TX_L			0x17
@@ -51,6 +53,8 @@ RX_HIGH	= DMA3
 #define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L		0x847EAD2F
 #define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H		0x84FED12F
 #define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H		0x853ECF4D
+#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L		0x843e8b4d
+
 // Common DXE registers
 #define WCN36XX_DXE_MEM_CSR          		WCN36XX_DXE_MEM_REG + 0x00
 #define WCN36XX_DXE_ENCH_ADDR          		WCN36XX_DXE_MEM_REG + 0x04
@@ -103,6 +107,7 @@ RX_HIGH	= DMA3
 #define WCN36XX_DXE_REG_CTL_RX_L		WCN36XX_DXE_MEM_REG + WCN36XX_DXE_RX_LOW_OFFSET
 #define WCN36XX_DXE_REG_CTL_RX_H		WCN36XX_DXE_MEM_REG + WCN36XX_DXE_RX_HIGH_OFFSET
 #define WCN36XX_DXE_REG_CTL_TX_H		WCN36XX_DXE_MEM_REG + WCN36XX_DXE_TX_HIGH_OFFSET
+#define WCN36XX_DXE_REG_CTL_TX_L		WCN36XX_DXE_MEM_REG + WCN36XX_DXE_TX_LOW_OFFSET
 
 #define WCN36XX_SMSM_WLAN_TX_ENABLE 		0x00000400
 #define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY	0x00000200
@@ -206,6 +211,13 @@ struct wcn36xx_dxe_ch {
 	struct wcn36xx_dxe_ctl		*head_blk_ctl;
 	struct wcn36xx_dxe_ctl		*tail_blk_ctl;
 	uint				num_free_desc;
+
+	// DXE channel specific configs
+	u32				dxe_wq;
+	u32				ctrl_bd;
+	u32				ctrl_skb;
+	u32				reg_ctrl;
+	u32				def_ctrl;
 };
 
 // Memory Pool for BD headers
@@ -222,5 +234,5 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn);
 int wcn36xx_dxe_init(struct wcn36xx *wcn);
 void wcn36xx_dxe_deinit(struct wcn36xx *wcn);
 int wcn36xx_dxe_init_channels(struct wcn36xx *wcn);
-int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast);
+int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast, bool is_high);
 #endif	/* _DXE_H_ */
diff --git a/main.c b/main.c
index a7ca463..342e5b9 100644
--- a/main.c
+++ b/main.c
@@ -132,7 +132,12 @@ static void wcn36xx_tx(struct ieee80211_hw *hw,  struct ieee80211_tx_control *co
 	struct ieee80211_mgmt *mgmt;
 	ENTER();
 	mgmt = (struct ieee80211_mgmt *)skb->data;
-	wcn36xx_dxe_tx(hw->priv, skb, is_broadcast_ether_addr(mgmt->da) || is_multicast_ether_addr(mgmt->da));
+	wcn36xx_dbg("wcn36xx_tx: = %x", mgmt->frame_control);
+	if (ieee80211_is_data(mgmt->frame_control) || (ieee80211_is_data_qos(mgmt->frame_control))) {
+		wcn36xx_dxe_tx(hw->priv, skb, is_broadcast_ether_addr(mgmt->da) || is_multicast_ether_addr(mgmt->da), false);
+	} else {
+		wcn36xx_dxe_tx(hw->priv, skb, is_broadcast_ether_addr(mgmt->da) || is_multicast_ether_addr(mgmt->da), true);
+	}
 }
 
 static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -168,7 +173,7 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
 		wcn36xx_smd_start_scan(wcn, ch);
 		// do this as timer
 		msleep(60);
-		wcn36xx_dxe_tx(hw->priv, prb_req, is_broadcast_ether_addr(mgmt->da) || is_multicast_ether_addr(mgmt->da));
+		wcn36xx_dxe_tx(hw->priv, prb_req, is_broadcast_ether_addr(mgmt->da) || is_multicast_ether_addr(mgmt->da), true);
 		msleep(60);
 
 		wcn36xx_smd_end_scan(wcn, ch);
-- 
1.7.11.3




More information about the wcn36xx mailing list