summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-06-07 09:12:07 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:06:19 +0200
commit8baff0cf82469a4ebfabc775b56772dcd0b6fdfc (patch)
tree57fb798f0166d5f77ff5bad61be8f83c1c4a5368 /drivers
parentf21ed94daa73a203b5c537c18cf8d0ecfd320f5c (diff)
cw1200: throughput optimization and fine-tuning.
* Fixed: Do not allocate a dedicated communication channel (buffer) for WSM command stream, use it for data traffic when needed. * Additional statistics added to DebugFS: counters for TX policy cache misses and unaligned skbs memmove. * Fixed: Strip IV/ICV in the driver to prevent mac80211 layer from double-verification. Change-Id: I600664466d577df4c2bc62ff49fb22f2d3b024cc Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24482 Reviewed-by: Robert MARKLUND <robert.marklund@stericsson.com> Tested-by: Robert MARKLUND <robert.marklund@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25622 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/cw1200/bh.c6
-rw-r--r--drivers/staging/cw1200/debug.c5
-rw-r--r--drivers/staging/cw1200/debug.h20
-rw-r--r--drivers/staging/cw1200/txrx.c62
4 files changed, 78 insertions, 15 deletions
diff --git a/drivers/staging/cw1200/bh.c b/drivers/staging/cw1200/bh.c
index 177274a00d2..d49f9fdf732 100644
--- a/drivers/staging/cw1200/bh.c
+++ b/drivers/staging/cw1200/bh.c
@@ -120,7 +120,7 @@ int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
priv->hw_bufs_used -= count;
if (WARN_ON(priv->hw_bufs_used < 0))
ret = -1;
- else if (hw_bufs_used >= priv->wsm_caps.numInpChBufs - 1)
+ else if (hw_bufs_used >= priv->wsm_caps.numInpChBufs)
ret = 1;
if (!priv->hw_bufs_used)
wake_up_interruptible(&priv->hw_bufs_used_wq);
@@ -363,9 +363,7 @@ tx:
/* HACK! One buffer is reserved for control path */
BUG_ON(priv->hw_bufs_used > priv->wsm_caps.numInpChBufs);
tx_allowed =
- priv->hw_bufs_used + 1 < priv->wsm_caps.numInpChBufs;
- if (unlikely(!tx_allowed && priv->wsm_cmd.ptr))
- tx_allowed = 1;
+ priv->hw_bufs_used < priv->wsm_caps.numInpChBufs;
if (tx && tx_allowed) {
size_t tx_len;
diff --git a/drivers/staging/cw1200/debug.c b/drivers/staging/cw1200/debug.c
index b4c2da23135..13c4570372f 100644
--- a/drivers/staging/cw1200/debug.c
+++ b/drivers/staging/cw1200/debug.c
@@ -253,7 +253,10 @@ static int cw1200_status_show(struct seq_file *seq, void *v)
d->rx);
seq_printf(seq, "AGG RXed: %d\n",
d->rx_agg);
-
+ seq_printf(seq, "TX miss: %d\n",
+ d->tx_cache_miss);
+ seq_printf(seq, "TX copy: %d\n",
+ d->tx_copy);
seq_printf(seq, "Scan: %s\n",
atomic_read(&priv->scan.in_progress) ? "active" : "idle");
seq_printf(seq, "Led state: 0x%.2X\n",
diff --git a/drivers/staging/cw1200/debug.h b/drivers/staging/cw1200/debug.h
index a19083a49b9..e7fc4d2daef 100644
--- a/drivers/staging/cw1200/debug.h
+++ b/drivers/staging/cw1200/debug.h
@@ -13,6 +13,8 @@ struct cw1200_debug_priv {
int rx_agg;
int tx_multi;
int tx_multi_frames;
+ int tx_cache_miss;
+ int tx_copy;
};
int cw1200_debug_init(struct cw1200_common *priv);
@@ -45,6 +47,16 @@ static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
++priv->debug->rx_agg;
}
+static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
+{
+ ++priv->debug->tx_cache_miss;
+}
+
+static inline void cw1200_debug_tx_copy(struct cw1200_common *priv)
+{
+ ++priv->debug->tx_copy;
+}
+
#else /* CONFIG_CW1200_DEBUGFS */
static inline int cw1200_debug_init(struct cw1200_common *priv)
@@ -77,6 +89,14 @@ static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
{
}
+static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_tx_copy(struct cw1200_common *priv)
+{
+}
+
#endif /* CONFIG_CW1200_DEBUGFS */
#endif /* CW1200_DEBUG_H_INCLUDED */
diff --git a/drivers/staging/cw1200/txrx.c b/drivers/staging/cw1200/txrx.c
index eb2802af318..8616d1d2ffe 100644
--- a/drivers/staging/cw1200/txrx.c
+++ b/drivers/staging/cw1200/txrx.c
@@ -323,6 +323,7 @@ static int tx_policy_upload(struct cw1200_common *priv)
}
}
spin_unlock_bh(&cache->lock);
+ cw1200_debug_tx_cache_miss(priv);
tx_policy_printk(KERN_DEBUG "[TX policy] Upload %d policies\n",
arg.hdr.numTxRatePolicies);
return wsm_set_tx_rate_retry_policy(priv, &arg);
@@ -501,6 +502,7 @@ int cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
p = skb_push(skb, offset);
memmove(p, &p[offset], skb->len - offset);
skb_trim(skb, skb->len - offset);
+ cw1200_debug_tx_copy(priv);
}
if (ieee80211_is_action(hdr->frame_control))
@@ -647,7 +649,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) {
/* STA is stopped. */
- return;
+ goto drop;
}
if (unlikely(arg->status)) {
@@ -656,17 +658,18 @@ void cw1200_rx_cb(struct cw1200_common *priv,
hdr->flag |= RX_FLAG_MMIC_ERROR;
} else if (arg->status == WSM_STATUS_NO_KEY_FOUND) {
txrx_printk(KERN_DEBUG "[RX] No key found.\n");
- return;
+ goto drop;
} else {
txrx_printk(KERN_DEBUG "[RX] Receive failure: %d.\n",
arg->status);
- return;
+ goto drop;
}
}
if (skb->len < sizeof(struct ieee80211_hdr_3addr)) {
- wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed.\n");
- return;
+ wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. "
+ "Size is lesser than IEEE header.\n");
+ goto drop;
}
frame_control = *(__le16*)skb->data;
@@ -691,13 +694,47 @@ void cw1200_rx_cb(struct cw1200_common *priv,
hdr->antenna = 0;
if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) {
- hdr->flag |= RX_FLAG_DECRYPTED;
- if (!arg->status &&
- (WSM_RX_STATUS_ENCRYPTION(arg->flags) ==
- WSM_RX_STATUS_TKIP)) {
+ size_t iv_len = 0, icv_len = 0;
+ size_t hdrlen = ieee80211_hdrlen(frame_control);
+
+ hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED;
+
+ /* Oops... There is no fast way to ask mac80211 about
+ * IV/ICV lengths. Even defineas are not exposed.*/
+ switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) {
+ case WSM_RX_STATUS_WEP:
+ iv_len = 4 /* WEP_IV_LEN */;
+ icv_len = 4 /* WEP_ICV_LEN */;
+ break;
+ case WSM_RX_STATUS_TKIP:
+ iv_len = 8 /* TKIP_IV_LEN */;
+ icv_len = 4 /* TKIP_ICV_LEN */
+ + 8 /*MICHAEL_MIC_LEN*/;
hdr->flag |= RX_FLAG_MMIC_STRIPPED;
- skb_trim(skb, skb->len - 8 /*MICHAEL_MIC_LEN*/);
+ break;
+ case WSM_RX_STATUS_AES:
+ iv_len = 8 /* CCMP_HDR_LEN */;
+ icv_len = 8 /* CCMP_MIC_LEN */;
+ break;
+ case WSM_RX_STATUS_WAPI:
+ iv_len = 18 /* WAPI_HDR_LEN */;
+ icv_len = 16 /* WAPI_MIC_LEN */;
+ break;
+ default:
+ WARN_ON("Unknown encryption type");
+ goto drop;
}
+
+ if (skb->len < hdrlen + iv_len + icv_len) {
+ wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. "
+ "Size is lesser than crypto headers.\n");
+ goto drop;
+ }
+
+ /* Remove IV, ICV and MIC */
+ skb_trim(skb, skb->len - icv_len);
+ memmove(skb->data + iv_len, skb->data, hdrlen);
+ skb_pull(skb, iv_len);
}
cw1200_debug_rxed(priv);
@@ -714,6 +751,11 @@ void cw1200_rx_cb(struct cw1200_common *priv,
* system performance. */
ieee80211_rx_irqsafe(priv->hw, skb);
*skb_p = NULL;
+ return;
+
+drop:
+ /* TODO: update failure counters */
+ return;
}
/* ******************************************************************** */