aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-06-11 06:47:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-06-19 15:49:17 -0400
commitbefcf7e70e899db62307408259c51e0435bd9b3f (patch)
tree7a88faeb2fbac776cac1b8d389125fb46863aacb
parentbff117669841c04d08bd1d23617818e0030b3299 (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.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c24
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 {
275struct ath_tx_control { 275struct 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)