summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-06-04 14:55:21 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-06-22 11:30:10 +0200
commit0abce402c0cbf94ef7c280e040388eca730bd8da (patch)
treee263531e0ae688159aa44f402dc83b2734a1ab6e /drivers
parentdd291bb98a2cdd6c4532baf052e902cd64018b68 (diff)
cw1200: Multi-tx confirmation is implemented.
Multi-tx offloads SDIO interface by reducing number of TX confirm messages. Multiple PDUs are acknowledged by a single multi-tx confirm message. Change-Id: Ie152a2dc9fc3ca18e2a8042965f626a6c2ec6409 Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24478 Reviewed-by: Robert MARKLUND <robert.marklund@stericsson.com> Tested-by: Robert MARKLUND <robert.marklund@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25618 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/cw1200/bh.c20
-rw-r--r--drivers/staging/cw1200/bh.h1
-rw-r--r--drivers/staging/cw1200/debug.c2
-rw-r--r--drivers/staging/cw1200/debug.h14
-rw-r--r--drivers/staging/cw1200/main.c3
-rw-r--r--drivers/staging/cw1200/sta.c3
-rw-r--r--drivers/staging/cw1200/wsm.c57
-rw-r--r--drivers/staging/cw1200/wsm.h14
8 files changed, 90 insertions, 24 deletions
diff --git a/drivers/staging/cw1200/bh.c b/drivers/staging/cw1200/bh.c
index cc27e8b4aa5..177274a00d2 100644
--- a/drivers/staging/cw1200/bh.c
+++ b/drivers/staging/cw1200/bh.c
@@ -112,15 +112,17 @@ static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv)
++priv->hw_bufs_used;
}
-static int wsm_release_tx_buffer(struct cw1200_common *priv)
+int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
{
int ret = 0;
- int hw_bufs_used = priv->hw_bufs_used--;
- if (WARN_ON(!hw_bufs_used))
+ int hw_bufs_used = priv->hw_bufs_used;
+
+ 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)
ret = 1;
- else if (hw_bufs_used == 1)
+ if (!priv->hw_bufs_used)
wake_up_interruptible(&priv->hw_bufs_used_wq);
return ret;
}
@@ -338,11 +340,7 @@ rx:
rx_resync = 0;
if (wsm_id & 0x0400) {
- int rc = wsm_release_tx_buffer(priv);
- /* TODO: 3.60 Multi-transmit confirmation
- * requires special handling.
- * Not supported yet. */
- BUG_ON((wsm_id & 0x3F) == 0x1E);
+ int rc = wsm_release_tx_buffer(priv, 1);
if (WARN_ON(rc < 0))
break;
else if (rc > 0)
@@ -390,7 +388,7 @@ tx:
wsm_alloc_tx_buffer(priv);
ret = wsm_get_tx(priv, &data, &tx_len);
if (ret <= 0) {
- wsm_release_tx_buffer(priv);
+ wsm_release_tx_buffer(priv, 1);
if (WARN_ON(ret < 0))
break;
} else {
@@ -425,7 +423,7 @@ tx:
if (WARN_ON(cw1200_data_write(priv,
data, tx_len))) {
- wsm_release_tx_buffer(priv);
+ wsm_release_tx_buffer(priv, 1);
break;
}
diff --git a/drivers/staging/cw1200/bh.h b/drivers/staging/cw1200/bh.h
index af71a5a1066..14b641fbe1d 100644
--- a/drivers/staging/cw1200/bh.h
+++ b/drivers/staging/cw1200/bh.h
@@ -25,5 +25,6 @@ void cw1200_bh_wakeup(struct cw1200_common *priv);
/* Must be called from BH thread. */
void cw1200_enable_powersave(struct cw1200_common *priv,
bool enable);
+int wsm_release_tx_buffer(struct cw1200_common *priv, int count);
#endif /* CW1200_BH_H */
diff --git a/drivers/staging/cw1200/debug.c b/drivers/staging/cw1200/debug.c
index 47e230f460d..498f072da78 100644
--- a/drivers/staging/cw1200/debug.c
+++ b/drivers/staging/cw1200/debug.c
@@ -249,6 +249,8 @@ static int cw1200_status_show(struct seq_file *seq, void *v)
d->tx_agg);
seq_printf(seq, "MORE TXed: %d\n",
d->tx_more);
+ seq_printf(seq, "MULTI TXed: %d (%d)\n",
+ d->tx_multi, d->tx_multi_frames);
seq_printf(seq, "RXed: %d\n",
d->rx);
seq_printf(seq, "AGG RXed: %d\n",
diff --git a/drivers/staging/cw1200/debug.h b/drivers/staging/cw1200/debug.h
index c813c54f86b..0c9ef1252c4 100644
--- a/drivers/staging/cw1200/debug.h
+++ b/drivers/staging/cw1200/debug.h
@@ -12,6 +12,8 @@ struct cw1200_debug_priv {
int tx_more;
int rx;
int rx_agg;
+ int tx_multi;
+ int tx_multi_frames;
};
int cw1200_debug_init(struct cw1200_common *priv);
@@ -32,6 +34,13 @@ static inline void cw1200_debug_txed_more(struct cw1200_common *priv)
++priv->debug->tx_more;
}
+static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
+ int count)
+{
+ ++priv->debug->tx_multi;
+ priv->debug->tx_multi_frames += count;
+}
+
static inline void cw1200_debug_rxed(struct cw1200_common *priv)
{
++priv->debug->rx;
@@ -65,6 +74,11 @@ static inline void cw1200_debug_txed_more(struct cw1200_common *priv)
{
}
+static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
+ int count)
+{
+}
+
static inline void cw1200_debug_rxed(struct cw1200_common *priv)
{
}
diff --git a/drivers/staging/cw1200/main.c b/drivers/staging/cw1200/main.c
index da61ba165cf..0a1193b8b41 100644
--- a/drivers/staging/cw1200/main.c
+++ b/drivers/staging/cw1200/main.c
@@ -465,6 +465,9 @@ int cw1200_probe(const struct sbus_ops *sbus_ops,
/* Set low-power mode. */
WARN_ON(wsm_set_operational_mode(priv, &mode));
+ /* Enable multi-TX confirmation */
+ WARN_ON(wsm_use_multi_tx_conf(priv, true));
+
err = cw1200_register_common(dev);
if (err) {
priv->sbus_ops->irq_unsubscribe(priv->sbus_priv);
diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c
index af6eabf2d49..145a370dc50 100644
--- a/drivers/staging/cw1200/sta.c
+++ b/drivers/staging/cw1200/sta.c
@@ -728,7 +728,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
/* Not that we really need _irqsafe variant here,
* but it offloads realtime bh thread and improve
* system performance. */
- ieee80211_rx_irqsafe(priv->hw, skb);
+ ieee80211_rx(priv->hw, skb);
*skb_p = NULL;
}
@@ -1073,6 +1073,7 @@ void cw1200_join_work(struct work_struct *work)
cw1200_update_listening(priv, priv->listening);
WARN_ON(wsm_set_pm(priv, &priv->powersave_mode));
} else {
+ /* Upload keys */
WARN_ON(cw1200_upload_keys(priv));
#if !defined(CW1200_FIRMWARE_DOES_NOT_SUPPORT_KEEPALIVE)
WARN_ON(wsm_keep_alive_period(priv, 30 /* sec */));
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index 028e668f137..c562f982477 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -19,6 +19,7 @@
#include "cw1200.h"
#include "wsm.h"
#include "bh.h"
+#include "debug.h"
#if defined(CONFIG_CW1200_WSM_DEBUG)
#define wsm_printk(...) printk(__VA_ARGS__)
@@ -362,18 +363,18 @@ int wsm_stop_scan(struct cw1200_common *priv)
static int wsm_tx_confirm(struct cw1200_common *priv, struct wsm_buf *buf)
{
- if (priv->wsm_cbc.tx_confirm) {
- struct wsm_tx_confirm tx_confirm;
-
- tx_confirm.packetID = WSM_GET32(buf);
- tx_confirm.status = WSM_GET32(buf);
- tx_confirm.txedRate = WSM_GET8(buf);
- tx_confirm.ackFailures = WSM_GET8(buf);
- tx_confirm.flags = WSM_GET16(buf);
- tx_confirm.mediaDelay = WSM_GET32(buf);
- tx_confirm.txQueueDelay = WSM_GET32(buf);
+ struct wsm_tx_confirm tx_confirm;
+
+ tx_confirm.packetID = WSM_GET32(buf);
+ tx_confirm.status = WSM_GET32(buf);
+ tx_confirm.txedRate = WSM_GET8(buf);
+ tx_confirm.ackFailures = WSM_GET8(buf);
+ tx_confirm.flags = WSM_GET16(buf);
+ tx_confirm.mediaDelay = WSM_GET32(buf);
+ tx_confirm.txQueueDelay = WSM_GET32(buf);
+
+ if (priv->wsm_cbc.tx_confirm)
priv->wsm_cbc.tx_confirm(priv, &tx_confirm);
- }
return 0;
underflow:
@@ -381,6 +382,37 @@ underflow:
return -EINVAL;
}
+static int wsm_multi_tx_confirm(struct cw1200_common *priv,
+ struct wsm_buf *buf)
+{
+ int ret;
+ int count;
+ int i;
+
+ count = WSM_GET32(buf);
+ if (WARN_ON(count <= 0))
+ return -EINVAL;
+ else if (count > 1) {
+ ret = wsm_release_tx_buffer(priv, count - 1);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ cw1200_bh_wakeup(priv);
+ }
+
+ cw1200_debug_txed_multi(priv, count);
+ for (i = 0; i < count; ++i) {
+ ret = wsm_tx_confirm(priv, buf);
+ if (ret)
+ return ret;
+ }
+ return ret;
+
+underflow:
+ WARN_ON(1);
+ return -EINVAL;
+}
+
/* ******************************************************************** */
static int wsm_join_confirm(struct cw1200_common *priv,
@@ -1085,7 +1117,8 @@ int wsm_handle_rx(struct cw1200_common *priv, int id,
if (id == 0x404) {
ret = wsm_tx_confirm(priv, &wsm_buf);
- cw1200_bh_wakeup(priv);
+ } else if (id == 0x41E) {
+ ret = wsm_multi_tx_confirm(priv, &wsm_buf);
} else if (id & 0x0400) {
void *wsm_arg;
u16 wsm_cmd;
diff --git a/drivers/staging/cw1200/wsm.h b/drivers/staging/cw1200/wsm.h
index fd84b147fde..4d446e9b924 100644
--- a/drivers/staging/cw1200/wsm.h
+++ b/drivers/staging/cw1200/wsm.h
@@ -471,6 +471,9 @@ struct cw1200_common;
/* Test Purposes Only */
#define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D
+/* 4.42 UseMultiTxConfMessage */
+#define WSM_MIB_USE_MULTI_TX_CONF 0x1024
+
/* 4.43 Keep-alive period */
#define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025
@@ -1443,6 +1446,17 @@ static inline int wsm_set_bssid_filtering(struct cw1200_common *priv,
&arg, sizeof(arg));
}
+/* UseMultiTxConfMessage */
+
+static inline int wsm_use_multi_tx_conf(struct cw1200_common *priv,
+ bool enabled)
+{
+ __le32 arg = enabled ? __cpu_to_le32(1) : 0;
+
+ return wsm_write_mib(priv, WSM_MIB_USE_MULTI_TX_CONF,
+ &arg, sizeof(arg));
+}
+
/* ******************************************************************** */
/* WSM TX port control */