diff options
author | Brian Cavagnolo <brian@cozybit.com> | 2011-03-17 14:58:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-30 14:15:13 -0400 |
commit | ac109fd0427008e5b55e0e52e59c364de6d686fe (patch) | |
tree | 17a2013e1818da02b6cc15aec3b100f1f3fb23cb /drivers/net/wireless/mwl8k.c | |
parent | e600707b021efdc109e7becd467798da339ec26d (diff) |
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>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-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 { | |||
137 | struct sk_buff **skb; | 137 | struct sk_buff **skb; |
138 | }; | 138 | }; |
139 | 139 | ||
140 | enum { | ||
141 | AMPDU_NO_STREAM, | ||
142 | AMPDU_STREAM_NEW, | ||
143 | AMPDU_STREAM_IN_PROGRESS, | ||
144 | AMPDU_STREAM_ACTIVE, | ||
145 | }; | ||
146 | |||
140 | struct mwl8k_ampdu_stream { | 147 | struct mwl8k_ampdu_stream { |
141 | struct ieee80211_sta *sta; | 148 | struct ieee80211_sta *sta; |
142 | u8 tid; | 149 | u8 tid; |
@@ -172,6 +179,8 @@ struct mwl8k_priv { | |||
172 | 179 | ||
173 | /* Ampdu stream information */ | 180 | /* Ampdu stream information */ |
174 | u8 num_ampdu_queues; | 181 | u8 num_ampdu_queues; |
182 | spinlock_t stream_lock; | ||
183 | struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
175 | 184 | ||
176 | /* firmware access */ | 185 | /* firmware access */ |
177 | struct mutex fw_mutex; | 186 | struct mutex fw_mutex; |
@@ -1594,6 +1603,74 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1594 | txq->txd = NULL; | 1603 | txq->txd = NULL; |
1595 | } | 1604 | } |
1596 | 1605 | ||
1606 | /* caller must hold priv->stream_lock when calling the stream functions */ | ||
1607 | struct mwl8k_ampdu_stream * | ||
1608 | mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) | ||
1609 | { | ||
1610 | struct mwl8k_ampdu_stream *stream; | ||
1611 | struct mwl8k_priv *priv = hw->priv; | ||
1612 | int i; | ||
1613 | |||
1614 | for (i = 0; i < priv->num_ampdu_queues; i++) { | ||
1615 | stream = &priv->ampdu[i]; | ||
1616 | if (stream->state == AMPDU_NO_STREAM) { | ||
1617 | stream->sta = sta; | ||
1618 | stream->state = AMPDU_STREAM_NEW; | ||
1619 | stream->tid = tid; | ||
1620 | stream->idx = i; | ||
1621 | stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; | ||
1622 | wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", | ||
1623 | sta->addr, tid); | ||
1624 | return stream; | ||
1625 | } | ||
1626 | } | ||
1627 | return NULL; | ||
1628 | } | ||
1629 | |||
1630 | static int | ||
1631 | mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1632 | { | ||
1633 | int ret; | ||
1634 | |||
1635 | /* if the stream has already been started, don't start it again */ | ||
1636 | if (stream->state != AMPDU_STREAM_NEW) | ||
1637 | return 0; | ||
1638 | ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); | ||
1639 | if (ret) | ||
1640 | wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " | ||
1641 | "%d\n", stream->sta->addr, stream->tid, ret); | ||
1642 | else | ||
1643 | wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", | ||
1644 | stream->sta->addr, stream->tid); | ||
1645 | return ret; | ||
1646 | } | ||
1647 | |||
1648 | static void | ||
1649 | mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1650 | { | ||
1651 | wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, | ||
1652 | stream->tid); | ||
1653 | memset(stream, 0, sizeof(*stream)); | ||
1654 | } | ||
1655 | |||
1656 | static struct mwl8k_ampdu_stream * | ||
1657 | mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) | ||
1658 | { | ||
1659 | struct mwl8k_priv *priv = hw->priv; | ||
1660 | int i; | ||
1661 | |||
1662 | for (i = 0 ; i < priv->num_ampdu_queues; i++) { | ||
1663 | struct mwl8k_ampdu_stream *stream; | ||
1664 | stream = &priv->ampdu[i]; | ||
1665 | if (stream->state == AMPDU_NO_STREAM) | ||
1666 | continue; | ||
1667 | if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && | ||
1668 | stream->tid == tid) | ||
1669 | return stream; | ||
1670 | } | ||
1671 | return NULL; | ||
1672 | } | ||
1673 | |||
1597 | static void | 1674 | static void |
1598 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | 1675 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) |
1599 | { | 1676 | { |
@@ -4854,6 +4931,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4854 | goto err_free_queues; | 4931 | goto err_free_queues; |
4855 | } | 4932 | } |
4856 | 4933 | ||
4934 | memset(priv->ampdu, 0, sizeof(priv->ampdu)); | ||
4935 | |||
4857 | /* | 4936 | /* |
4858 | * Temporarily enable interrupts. Initial firmware host | 4937 | * Temporarily enable interrupts. Initial firmware host |
4859 | * commands use interrupts and avoid polling. Disable | 4938 | * commands use interrupts and avoid polling. Disable |
@@ -5018,6 +5097,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
5018 | 5097 | ||
5019 | spin_lock_init(&priv->tx_lock); | 5098 | spin_lock_init(&priv->tx_lock); |
5020 | 5099 | ||
5100 | spin_lock_init(&priv->stream_lock); | ||
5101 | |||
5021 | priv->tx_wait = NULL; | 5102 | priv->tx_wait = NULL; |
5022 | 5103 | ||
5023 | rc = mwl8k_probe_hw(hw); | 5104 | rc = mwl8k_probe_hw(hw); |