diff options
author | Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | 2011-06-04 14:55:21 +0200 |
---|---|---|
committer | Philippe LANGLAIS <philippe.langlais@stericsson.com> | 2011-06-22 11:30:10 +0200 |
commit | 0abce402c0cbf94ef7c280e040388eca730bd8da (patch) | |
tree | e263531e0ae688159aa44f402dc83b2734a1ab6e /drivers | |
parent | dd291bb98a2cdd6c4532baf052e902cd64018b68 (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.c | 20 | ||||
-rw-r--r-- | drivers/staging/cw1200/bh.h | 1 | ||||
-rw-r--r-- | drivers/staging/cw1200/debug.c | 2 | ||||
-rw-r--r-- | drivers/staging/cw1200/debug.h | 14 | ||||
-rw-r--r-- | drivers/staging/cw1200/main.c | 3 | ||||
-rw-r--r-- | drivers/staging/cw1200/sta.c | 3 | ||||
-rw-r--r-- | drivers/staging/cw1200/wsm.c | 57 | ||||
-rw-r--r-- | drivers/staging/cw1200/wsm.h | 14 |
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 */ |