diff options
author | Brian Cavagnolo <brian@cozybit.com> | 2011-03-17 11:58:45 -0700 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-30 14:15:13 -0400 |
commit | ac109fd0427008e5b55e0e52e59c364de6d686fe (patch) | |
tree | 17a2013e1818da02b6cc15aec3b100f1f3fb23cb | |
parent | e600707b021efdc109e7becd467798da339ec26d (diff) | |
download | linux-3.10-ac109fd0427008e5b55e0e52e59c364de6d686fe.tar.gz linux-3.10-ac109fd0427008e5b55e0e52e59c364de6d686fe.tar.bz2 linux-3.10-ac109fd0427008e5b55e0e52e59c364de6d686fe.zip |
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>
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 53581ee8b79..dcd4508b1fd 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -137,6 +137,13 @@ struct mwl8k_tx_queue { 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 @@ struct mwl8k_priv { /* 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 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) 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 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) 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 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->stream_lock); + priv->tx_wait = NULL; rc = mwl8k_probe_hw(hw); |