summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2012-02-29 15:15:23 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:06:47 +0200
commit8dbf0822728423475733c21d42a19c52479d812e (patch)
treedd1289013241228a1697f2388c8822f02acfa47d
parentfd079d0c51ec4831187025d77de67a99f3ded897 (diff)
cw1200: Dynamic BA.
Patch implements enabling of block ACK only if valuable data traffic is detected on the interface. BA is disabled for small packets (in assumption of voice/video) and low-thoughput data traffic. ST-Ericsson ID: 405634, 407777 ST-Ericsson FOSS-OUT ID: NA Change-Id: Ic30b65a5b8ea83fe6c865866209a786f26d00c18 Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/41129 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com>
-rw-r--r--drivers/staging/cw1200/ap.c7
-rw-r--r--drivers/staging/cw1200/cw1200.h12
-rw-r--r--drivers/staging/cw1200/debug.c14
-rw-r--r--drivers/staging/cw1200/debug.h14
-rw-r--r--drivers/staging/cw1200/main.c8
-rw-r--r--drivers/staging/cw1200/pm.c10
-rw-r--r--drivers/staging/cw1200/sta.c56
-rw-r--r--drivers/staging/cw1200/sta.h2
-rw-r--r--drivers/staging/cw1200/txrx.c25
9 files changed, 140 insertions, 8 deletions
diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c
index ce82ba5e87f..9f7f38681c1 100644
--- a/drivers/staging/cw1200/ap.c
+++ b/drivers/staging/cw1200/ap.c
@@ -496,13 +496,6 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev,
priv->beacon_int * priv->join_dtim_period >
MAX_BEACON_SKIP_TIME_MS ? 1 :
priv->join_dtim_period, 0));
- if (sta && cw1200_is_ht(&priv->ht_info)) {
- ap_printk(KERN_DEBUG
- "[STA] Enabling Block ACK\n");
- WARN_ON(wsm_set_block_ack_policy(priv,
- priv->ba_tid_mask,
- priv->ba_tid_mask));
- }
cw1200_set_pm(priv, &priv->powersave_mode);
if (priv->vif->p2p) {
diff --git a/drivers/staging/cw1200/cw1200.h b/drivers/staging/cw1200/cw1200.h
index ff69098c8a7..3ae1b915566 100644
--- a/drivers/staging/cw1200/cw1200.h
+++ b/drivers/staging/cw1200/cw1200.h
@@ -52,6 +52,11 @@
#define CW1200_MAX_TID (8)
+#define CW1200_BLOCK_ACK_CNT (30)
+#define CW1200_BLOCK_ACK_THLD (800)
+#define CW1200_BLOCK_ACK_HIST (3)
+#define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST)
+
/* Please keep order */
enum cw1200_join_status {
CW1200_JOIN_STATUS_PASSIVE = 0,
@@ -156,6 +161,13 @@ struct cw1200_common {
bool disable_beacon_filter;
struct work_struct update_filtering_work;
u8 ba_tid_mask;
+ int ba_acc;
+ int ba_cnt;
+ int ba_hist;
+ struct timer_list ba_timer;
+ spinlock_t ba_lock;
+ bool ba_ena;
+ struct work_struct ba_work;
struct cw1200_pm_state pm_state;
struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo;
struct wsm_uapsd_info uapsd_info;
diff --git a/drivers/staging/cw1200/debug.c b/drivers/staging/cw1200/debug.c
index 2056101a3f4..43b2c257c57 100644
--- a/drivers/staging/cw1200/debug.c
+++ b/drivers/staging/cw1200/debug.c
@@ -105,6 +105,17 @@ static int cw1200_status_show(struct seq_file *seq, void *v)
struct list_head *item;
struct cw1200_common *priv = seq->private;
struct cw1200_debug_priv *d = priv->debug;
+ int ba_cnt, ba_acc, ba_avg = 0;
+ bool ba_ena;
+
+ spin_lock_bh(&priv->ba_lock);
+ ba_cnt = priv->debug->ba_cnt;
+ ba_acc = priv->debug->ba_acc;
+ ba_ena = priv->ba_ena;
+ if (ba_cnt)
+ ba_avg = ba_acc / ba_cnt;
+ spin_unlock_bh(&priv->ba_lock);
+
seq_puts(seq, "CW1200 Wireless LAN driver status\n");
seq_printf(seq, "Hardware: %d.%d\n",
priv->wsm_caps.hardwareId,
@@ -216,6 +227,9 @@ static int cw1200_status_show(struct seq_file *seq, void *v)
++i;
spin_unlock_bh(&priv->tx_policy_cache.lock);
seq_printf(seq, "RC in use: %d\n", i);
+ seq_printf(seq, "BA stat: %d, %d (%d)\n",
+ ba_cnt, ba_acc, ba_avg);
+ seq_printf(seq, "Block ACK: %s\n", ba_ena ? "on" : "off");
seq_puts(seq, "\n");
for (i = 0; i < 4; ++i) {
diff --git a/drivers/staging/cw1200/debug.h b/drivers/staging/cw1200/debug.h
index 02943e699b8..c901a6a64e9 100644
--- a/drivers/staging/cw1200/debug.h
+++ b/drivers/staging/cw1200/debug.h
@@ -29,6 +29,8 @@ struct cw1200_debug_priv {
int tx_ttl;
int tx_burst;
int rx_burst;
+ int ba_cnt;
+ int ba_acc;
};
int cw1200_debug_init(struct cw1200_common *priv);
@@ -86,6 +88,13 @@ static inline void cw1200_debug_rx_burst(struct cw1200_common *priv)
++priv->debug->rx_burst;
}
+static inline void cw1200_debug_ba(struct cw1200_common *priv,
+ int ba_cnt, int ba_acc)
+{
+ priv->debug->ba_cnt = ba_cnt;
+ priv->debug->ba_acc = ba_acc;
+}
+
#else /* CONFIG_CW1200_DEBUGFS */
static inline int cw1200_debug_init(struct cw1200_common *priv)
@@ -138,6 +147,11 @@ static inline void cw1200_debug_rx_burst(struct cw1200_common *priv)
{
}
+static inline void cw1200_debug_ba(struct cw1200_common *priv,
+ int ba_cnt, int ba_acc)
+{
+}
+
#endif /* CONFIG_CW1200_DEBUGFS */
#endif /* CW1200_DEBUG_H_INCLUDED */
diff --git a/drivers/staging/cw1200/main.c b/drivers/staging/cw1200/main.c
index f6ddac68823..a6f920e3399 100644
--- a/drivers/staging/cw1200/main.c
+++ b/drivers/staging/cw1200/main.c
@@ -348,9 +348,14 @@ struct ieee80211_hw *cw1200_init_common(size_t priv_data_len)
INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
#endif
INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
+ INIT_WORK(&priv->ba_work, cw1200_ba_work);
init_timer(&priv->mcast_timeout);
priv->mcast_timeout.data = (unsigned long)priv;
priv->mcast_timeout.function = cw1200_mcast_timeout;
+ spin_lock_init(&priv->ba_lock);
+ init_timer(&priv->ba_timer);
+ priv->ba_timer.data = (unsigned long)priv;
+ priv->ba_timer.function = cw1200_ba_timer;
if (unlikely(cw1200_pm_init(&priv->pm_state, priv))) {
ieee80211_free_hw(hw);
@@ -430,6 +435,9 @@ void cw1200_unregister_common(struct ieee80211_hw *dev)
ieee80211_unregister_hw(dev);
+ del_timer_sync(&priv->mcast_timeout);
+ del_timer_sync(&priv->ba_timer);
+
priv->sbus_ops->irq_unsubscribe(priv->sbus_priv);
cw1200_unregister_bh(priv);
diff --git a/drivers/staging/cw1200/pm.c b/drivers/staging/cw1200/pm.c
index 550ee1482b1..fc9c2354758 100644
--- a/drivers/staging/cw1200/pm.c
+++ b/drivers/staging/cw1200/pm.c
@@ -274,6 +274,9 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (ret)
goto revert5;
+ /* Cancel block ack stat timer */
+ del_timer_sync(&priv->ba_timer);
+
/* Store suspend state */
pm_state->suspend_state = state;
@@ -352,6 +355,13 @@ int cw1200_wow_resume(struct ieee80211_hw *hw)
cw1200_resume_work(priv, &priv->link_id_gc_work,
state->link_id_gc);
+ /* Restart block ack stat */
+ spin_lock_bh(&priv->ba_lock);
+ if (priv->ba_cnt)
+ mod_timer(&priv->ba_timer,
+ jiffies + CW1200_BLOCK_ACK_INTERVAL);
+ spin_unlock_bh(&priv->ba_lock);
+
/* Unlock datapath */
wsm_unlock_tx(priv);
diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c
index 85e57d2f7b3..c5b79f25060 100644
--- a/drivers/staging/cw1200/sta.c
+++ b/drivers/staging/cw1200/sta.c
@@ -123,6 +123,7 @@ void cw1200_stop(struct ieee80211_hw *dev)
cancel_delayed_work_sync(&priv->link_id_gc_work);
flush_workqueue(priv->workqueue);
del_timer_sync(&priv->mcast_timeout);
+ del_timer_sync(&priv->ba_timer);
mutex_lock(&priv->conf_mutex);
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -1360,6 +1361,13 @@ void cw1200_join_work(struct work_struct *work)
WARN_ON(wsm_set_block_ack_policy(priv,
0, priv->ba_tid_mask));
+ spin_lock_bh(&priv->ba_lock);
+ priv->ba_ena = false;
+ priv->ba_cnt = 0;
+ priv->ba_acc = 0;
+ priv->ba_hist = 0;
+ spin_unlock_bh(&priv->ba_lock);
+
mgmt_policy.protectedMgmtEnable = 0;
mgmt_policy.unprotectedMgmtFramesAllowed = 1;
mgmt_policy.encryptionForAuthFrame = 1;
@@ -1409,6 +1417,7 @@ void cw1200_unjoin_work(struct work_struct *work)
.reset_statistics = true,
};
+ del_timer_sync(&priv->ba_timer);
mutex_lock(&priv->conf_mutex);
if (unlikely(atomic_read(&priv->scan.in_progress))) {
if (priv->delayed_unjoin) {
@@ -1543,6 +1552,53 @@ int cw1200_set_uapsd_param(struct cw1200_common *priv,
return ret;
}
+void cw1200_ba_work(struct work_struct *work)
+{
+ struct cw1200_common *priv =
+ container_of(work, struct cw1200_common, ba_work);
+ u8 tx_ba_tid_mask;
+
+ if (priv->join_status != CW1200_JOIN_STATUS_STA)
+ return;
+ if (!priv->setbssparams_done)
+ return;
+
+ spin_lock_bh(&priv->ba_lock);
+ tx_ba_tid_mask = priv->ba_ena ? priv->ba_tid_mask : 0;
+ spin_unlock_bh(&priv->ba_lock);
+
+ WARN_ON(wsm_set_block_ack_policy(priv,
+ tx_ba_tid_mask, priv->ba_tid_mask));
+}
+
+void cw1200_ba_timer(unsigned long arg)
+{
+ bool ba_ena;
+ struct cw1200_common *priv =
+ (struct cw1200_common *)arg;
+
+ spin_lock_bh(&priv->ba_lock);
+ cw1200_debug_ba(priv, priv->ba_cnt, priv->ba_acc);
+
+ ba_ena = (priv->ba_cnt >= CW1200_BLOCK_ACK_CNT &&
+ priv->ba_acc / priv->ba_cnt >= CW1200_BLOCK_ACK_THLD);
+ priv->ba_cnt = 0;
+ priv->ba_acc = 0;
+
+ if (ba_ena != priv->ba_ena) {
+ if (ba_ena || ++priv->ba_hist >= CW1200_BLOCK_ACK_HIST) {
+ priv->ba_ena = ba_ena;
+ priv->ba_hist = 0;
+ sta_printk(KERN_DEBUG "[STA] %s block ACK:\n",
+ ba_ena ? "enable" : "disable");
+ queue_work(priv->workqueue, &priv->ba_work);
+ }
+ } else if (priv->ba_hist)
+ --priv->ba_hist;
+
+ spin_unlock_bh(&priv->ba_lock);
+}
+
/* ******************************************************************** */
/* STA privates */
diff --git a/drivers/staging/cw1200/sta.h b/drivers/staging/cw1200/sta.h
index e1257828004..4e4833afcf7 100644
--- a/drivers/staging/cw1200/sta.h
+++ b/drivers/staging/cw1200/sta.h
@@ -81,5 +81,7 @@ int cw1200_enable_listening(struct cw1200_common *priv);
int cw1200_disable_listening(struct cw1200_common *priv);
int cw1200_set_uapsd_param(struct cw1200_common *priv,
const struct wsm_edca_params *arg);
+void cw1200_ba_work(struct work_struct *work);
+void cw1200_ba_timer(unsigned long arg);
#endif
diff --git a/drivers/staging/cw1200/txrx.c b/drivers/staging/cw1200/txrx.c
index fb80d218dfa..39470c46f23 100644
--- a/drivers/staging/cw1200/txrx.c
+++ b/drivers/staging/cw1200/txrx.c
@@ -738,7 +738,7 @@ cw1200_tx_h_rate_policy(struct cw1200_common *priv,
static bool
cw1200_tx_h_pm_state(struct cw1200_common *priv,
- struct cw1200_txinfo *t)
+ struct cw1200_txinfo *t)
{
int was_buffered = 1;
@@ -757,6 +757,28 @@ cw1200_tx_h_pm_state(struct cw1200_common *priv,
return !was_buffered;
}
+static void
+cw1200_tx_h_ba_stat(struct cw1200_common *priv,
+ struct cw1200_txinfo *t)
+{
+ if (priv->join_status != CW1200_JOIN_STATUS_STA)
+ return;
+ if (!cw1200_is_ht(&priv->ht_info))
+ return;
+ if (!priv->setbssparams_done)
+ return;
+ if (!ieee80211_is_data(t->hdr->frame_control))
+ return;
+
+ spin_lock_bh(&priv->ba_lock);
+ priv->ba_acc += t->skb->len - t->hdrlen;
+ if (!priv->ba_cnt++) {
+ mod_timer(&priv->ba_timer,
+ jiffies + CW1200_BLOCK_ACK_INTERVAL);
+ }
+ spin_unlock_bh(&priv->ba_lock);
+}
+
/* ******************************************************************** */
void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -818,6 +840,7 @@ void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
rcu_read_lock();
sta = rcu_dereference(t.tx_info->control.sta);
+ cw1200_tx_h_ba_stat(priv, &t);
spin_lock_bh(&priv->ps_state_lock);
{
tid_update = cw1200_tx_h_pm_state(priv, &t);