Commit 872b345f authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Luciano Coelho

wl18xx: implement immediate Tx completion

Implement immediate Tx completion for the 18xx family. Move 18xx
specific Tx code to new tx.c/h files and create helper header files
for definitions.
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 30e2dd79
wl18xx-objs = main.o wl18xx-objs = main.o tx.o
obj-$(CONFIG_WL18XX) += wl18xx.o obj-$(CONFIG_WL18XX) += wl18xx.o
...@@ -33,11 +33,9 @@ ...@@ -33,11 +33,9 @@
#include "reg.h" #include "reg.h"
#include "conf.h" #include "conf.h"
#include "tx.h"
#include "wl18xx.h" #include "wl18xx.h"
#define WL18XX_TX_HW_BLOCK_SPARE 1
#define WL18XX_TX_HW_GEM_BLOCK_SPARE 2
#define WL18XX_TX_HW_BLOCK_SIZE 268
static const u8 wl18xx_rate_to_idx_2ghz[] = { static const u8 wl18xx_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */ /* MCS rates are used only with 11n */
...@@ -470,6 +468,11 @@ static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, ...@@ -470,6 +468,11 @@ static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
return data_len - sizeof(*desc); return data_len - sizeof(*desc);
} }
static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
{
wl18xx_tx_immediate_complete(wl);
}
static struct wlcore_ops wl18xx_ops = { static struct wlcore_ops wl18xx_ops = {
.identify_chip = wl18xx_identify_chip, .identify_chip = wl18xx_identify_chip,
.boot = wl18xx_boot, .boot = wl18xx_boot,
...@@ -480,6 +483,8 @@ static struct wlcore_ops wl18xx_ops = { ...@@ -480,6 +483,8 @@ static struct wlcore_ops wl18xx_ops = {
.set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
.get_rx_buf_align = wl18xx_get_rx_buf_align, .get_rx_buf_align = wl18xx_get_rx_buf_align,
.get_rx_packet_len = wl18xx_get_rx_packet_len, .get_rx_packet_len = wl18xx_get_rx_packet_len,
.tx_immediate_compl = wl18xx_tx_immediate_completion,
.tx_delayed_compl = NULL,
}; };
int __devinit wl18xx_probe(struct platform_device *pdev) int __devinit wl18xx_probe(struct platform_device *pdev)
......
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "../wlcore/wlcore.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
#include "../wlcore/acx.h"
#include "../wlcore/tx.h"
#include "wl18xx.h"
#include "tx.h"
static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
{
struct ieee80211_tx_info *info;
struct sk_buff *skb;
int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
bool tx_success;
/* check for id legality */
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
wl1271_warning("illegal id in tx completion: %d", id);
return;
}
/* a zero bit indicates Tx success */
tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
if (wl12xx_is_dummy_packet(wl, skb)) {
wl1271_free_tx_id(wl, id);
return;
}
/* update the TX status info */
if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK;
/* no real data about Tx completion */
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
info->status.rates[0].flags = 0;
info->status.ack_signal = -1;
if (!tx_success)
wl->stats.retry_count++;
/*
* TODO: update sequence number for encryption? seems to be
* unsupported for now. needed for recovery with encryption.
*/
/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
/* remove TKIP header space if present */
if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
}
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
id, skb, tx_success);
/* return the packet to the stack */
skb_queue_tail(&wl->deferred_tx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work);
wl1271_free_tx_id(wl, id);
}
void wl18xx_tx_immediate_complete(struct wl1271 *wl)
{
struct wl18xx_fw_status_priv *status_priv =
(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
struct wl18xx_priv *priv = wl->priv;
u8 i;
/* nothing to do here */
if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
return;
/* freed Tx descriptors */
wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
priv->last_fw_rls_idx, status_priv->fw_release_idx);
if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
wl1271_error("invalid desc release index %d",
status_priv->fw_release_idx);
WARN_ON(1);
return;
}
for (i = priv->last_fw_rls_idx;
i != status_priv->fw_release_idx;
i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
wl18xx_tx_complete_packet(wl,
status_priv->released_tx_desc[i]);
wl->tx_results_count++;
}
priv->last_fw_rls_idx = status_priv->fw_release_idx;
}
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_TX_H__
#define __WL18XX_TX_H__
#include "../wlcore/wlcore.h"
#define WL18XX_TX_HW_BLOCK_SPARE 1
#define WL18XX_TX_HW_GEM_BLOCK_SPARE 2
#define WL18XX_TX_HW_BLOCK_SIZE 268
#define WL18XX_TX_STATUS_DESC_ID_MASK 0x7F
#define WL18XX_TX_STATUS_STAT_BIT_IDX 7
void wl18xx_tx_immediate_complete(struct wl1271 *wl);
#endif /* __WL12XX_TX_H__ */
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
struct wl18xx_priv { struct wl18xx_priv {
/* buffer for sending commands to FW */ /* buffer for sending commands to FW */
u8 cmd_buf[WL18XX_CMD_MAX_SIZE]; u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
/* Index of last released Tx desc in FW */
u8 last_fw_rls_idx;
}; };
#define WL18XX_FW_MAX_TX_STATUS_DESC 33 #define WL18XX_FW_MAX_TX_STATUS_DESC 33
......
...@@ -72,7 +72,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) ...@@ -72,7 +72,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
return id; return id;
} }
static void wl1271_free_tx_id(struct wl1271 *wl, int id) void wl1271_free_tx_id(struct wl1271 *wl, int id)
{ {
if (__test_and_clear_bit(id, wl->tx_frames_map)) { if (__test_and_clear_bit(id, wl->tx_frames_map)) {
if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc)) if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
...@@ -82,6 +82,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) ...@@ -82,6 +82,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
wl->tx_frames_cnt--; wl->tx_frames_cnt--;
} }
} }
EXPORT_SYMBOL(wl1271_free_tx_id);
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -127,6 +128,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) ...@@ -127,6 +128,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
{ {
return wl->dummy_packet == skb; return wl->dummy_packet == skb;
} }
EXPORT_SYMBOL(wl12xx_is_dummy_packet);
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb) struct sk_buff *skb)
......
...@@ -237,6 +237,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); ...@@ -237,6 +237,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length); unsigned int packet_length);
void wl1271_free_tx_id(struct wl1271 *wl, int id);
/* from main.c */ /* from main.c */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment