diff options
author | Felix Fietkau <nbd@openwrt.org> | 2014-06-11 06:47:53 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-06-19 15:49:17 -0400 |
commit | befcf7e70e899db62307408259c51e0435bd9b3f (patch) | |
tree | 7a88faeb2fbac776cac1b8d389125fb46863aacb | |
parent | bff117669841c04d08bd1d23617818e0030b3299 (diff) |
ath9k: channel context based transmission
Force queueing of all frames that belong to a virtual interface on
a different channel context, to ensure that they are sent on the
correct channel.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 24 |
2 files changed, 23 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8f59cea33fd6..ddd2e81ccd58 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -275,8 +275,9 @@ struct ath_node { | |||
275 | struct ath_tx_control { | 275 | struct ath_tx_control { |
276 | struct ath_txq *txq; | 276 | struct ath_txq *txq; |
277 | struct ath_node *an; | 277 | struct ath_node *an; |
278 | u8 paprd; | ||
279 | struct ieee80211_sta *sta; | 278 | struct ieee80211_sta *sta; |
279 | u8 paprd; | ||
280 | bool force_channel; | ||
280 | }; | 281 | }; |
281 | 282 | ||
282 | 283 | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5aaed39459d2..7972e1e24dd2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -2185,13 +2185,18 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2185 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2185 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2186 | struct ieee80211_sta *sta = txctl->sta; | 2186 | struct ieee80211_sta *sta = txctl->sta; |
2187 | struct ieee80211_vif *vif = info->control.vif; | 2187 | struct ieee80211_vif *vif = info->control.vif; |
2188 | struct ath_vif *avp = NULL; | ||
2188 | struct ath_softc *sc = hw->priv; | 2189 | struct ath_softc *sc = hw->priv; |
2189 | struct ath_txq *txq = txctl->txq; | 2190 | struct ath_txq *txq = txctl->txq; |
2190 | struct ath_atx_tid *tid = NULL; | 2191 | struct ath_atx_tid *tid = NULL; |
2191 | struct ath_buf *bf; | 2192 | struct ath_buf *bf; |
2193 | bool queue; | ||
2192 | int q; | 2194 | int q; |
2193 | int ret; | 2195 | int ret; |
2194 | 2196 | ||
2197 | if (vif) | ||
2198 | avp = (void *)vif->drv_priv; | ||
2199 | |||
2195 | ret = ath_tx_prepare(hw, skb, txctl); | 2200 | ret = ath_tx_prepare(hw, skb, txctl); |
2196 | if (ret) | 2201 | if (ret) |
2197 | return ret; | 2202 | return ret; |
@@ -2212,15 +2217,28 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2212 | txq->stopped = true; | 2217 | txq->stopped = true; |
2213 | } | 2218 | } |
2214 | 2219 | ||
2215 | if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) | 2220 | queue = ieee80211_is_data_present(hdr->frame_control); |
2221 | |||
2222 | /* Force queueing of all frames that belong to a virtual interface on | ||
2223 | * a different channel context, to ensure that they are sent on the | ||
2224 | * correct channel. | ||
2225 | */ | ||
2226 | if (((avp && avp->chanctx != sc->cur_chan) || | ||
2227 | sc->cur_chan->stopped) && !txctl->force_channel) { | ||
2228 | if (!txctl->an) | ||
2229 | txctl->an = &avp->mcast_node; | ||
2230 | info->flags &= ~IEEE80211_TX_CTL_PS_RESPONSE; | ||
2231 | queue = true; | ||
2232 | } | ||
2233 | |||
2234 | if (txctl->an && queue) | ||
2216 | tid = ath_get_skb_tid(sc, txctl->an, skb); | 2235 | tid = ath_get_skb_tid(sc, txctl->an, skb); |
2217 | 2236 | ||
2218 | if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { | 2237 | if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { |
2219 | ath_txq_unlock(sc, txq); | 2238 | ath_txq_unlock(sc, txq); |
2220 | txq = sc->tx.uapsdq; | 2239 | txq = sc->tx.uapsdq; |
2221 | ath_txq_lock(sc, txq); | 2240 | ath_txq_lock(sc, txq); |
2222 | } else if (txctl->an && | 2241 | } else if (txctl->an && queue) { |
2223 | ieee80211_is_data_present(hdr->frame_control)) { | ||
2224 | WARN_ON(tid->ac->txq != txctl->txq); | 2242 | WARN_ON(tid->ac->txq != txctl->txq); |
2225 | 2243 | ||
2226 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | 2244 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) |