[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