mwl8k: add internal API for managing AMPDU streams
In particular, we can now add, start, lookup, and remove streams.
Based on work by Nishant Sarmukadam <nishants@marvell.com> and
Pradeep Nemavat <pnemavat@marvell.com>.
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Brian Cavagnolo <brian@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 53581ee..dcd4508 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -137,6 +137,13 @@
struct sk_buff **skb;
};
+enum {
+ AMPDU_NO_STREAM,
+ AMPDU_STREAM_NEW,
+ AMPDU_STREAM_IN_PROGRESS,
+ AMPDU_STREAM_ACTIVE,
+};
+
struct mwl8k_ampdu_stream {
struct ieee80211_sta *sta;
u8 tid;
@@ -172,6 +179,8 @@
/* Ampdu stream information */
u8 num_ampdu_queues;
+ spinlock_t stream_lock;
+ struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES];
/* firmware access */
struct mutex fw_mutex;
@@ -1594,6 +1603,74 @@
txq->txd = NULL;
}
+/* caller must hold priv->stream_lock when calling the stream functions */
+struct mwl8k_ampdu_stream *
+mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
+{
+ struct mwl8k_ampdu_stream *stream;
+ struct mwl8k_priv *priv = hw->priv;
+ int i;
+
+ for (i = 0; i < priv->num_ampdu_queues; i++) {
+ stream = &priv->ampdu[i];
+ if (stream->state == AMPDU_NO_STREAM) {
+ stream->sta = sta;
+ stream->state = AMPDU_STREAM_NEW;
+ stream->tid = tid;
+ stream->idx = i;
+ stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
+ wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
+ sta->addr, tid);
+ return stream;
+ }
+ }
+ return NULL;
+}
+
+static int
+mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+ int ret;
+
+ /* if the stream has already been started, don't start it again */
+ if (stream->state != AMPDU_STREAM_NEW)
+ return 0;
+ ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0);
+ if (ret)
+ wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: "
+ "%d\n", stream->sta->addr, stream->tid, ret);
+ else
+ wiphy_debug(hw->wiphy, "Started stream for %pM %d\n",
+ stream->sta->addr, stream->tid);
+ return ret;
+}
+
+static void
+mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+ wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr,
+ stream->tid);
+ memset(stream, 0, sizeof(*stream));
+}
+
+static struct mwl8k_ampdu_stream *
+mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int i;
+
+ for (i = 0 ; i < priv->num_ampdu_queues; i++) {
+ struct mwl8k_ampdu_stream *stream;
+ stream = &priv->ampdu[i];
+ if (stream->state == AMPDU_NO_STREAM)
+ continue;
+ if (!memcmp(stream->sta->addr, addr, ETH_ALEN) &&
+ stream->tid == tid)
+ return stream;
+ }
+ return NULL;
+}
+
static void
mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
{
@@ -4854,6 +4931,8 @@
goto err_free_queues;
}
+ memset(priv->ampdu, 0, sizeof(priv->ampdu));
+
/*
* Temporarily enable interrupts. Initial firmware host
* commands use interrupts and avoid polling. Disable
@@ -5018,6 +5097,8 @@
spin_lock_init(&priv->tx_lock);
+ spin_lock_init(&priv->stream_lock);
+
priv->tx_wait = NULL;
rc = mwl8k_probe_hw(hw);