aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h10
-rw-r--r--drivers/net/wireless/ath9k/beacon.c3
-rw-r--r--drivers/net/wireless/ath9k/main.c1
-rw-r--r--drivers/net/wireless/ath9k/rc.h7
-rw-r--r--drivers/net/wireless/ath9k/virtual.c161
-rw-r--r--drivers/net/wireless/ath9k/xmit.c11
6 files changed, 191 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 386b93622e58..1153374f94fb 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -292,6 +292,7 @@ struct ath_atx_ac {
292struct ath_tx_control { 292struct ath_tx_control {
293 struct ath_txq *txq; 293 struct ath_txq *txq;
294 int if_id; 294 int if_id;
295 enum ath9k_internal_frame_type frame_type;
295}; 296};
296 297
297struct ath_xmit_status { 298struct ath_xmit_status {
@@ -392,6 +393,7 @@ struct ath_vif {
392 enum nl80211_iftype av_opmode; 393 enum nl80211_iftype av_opmode;
393 struct ath_buf *av_bcbuf; 394 struct ath_buf *av_bcbuf;
394 struct ath_tx_control av_btxctl; 395 struct ath_tx_control av_btxctl;
396 u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
395}; 397};
396 398
397/*******************/ 399/*******************/
@@ -619,6 +621,11 @@ struct ath_softc {
619struct ath_wiphy { 621struct ath_wiphy {
620 struct ath_softc *sc; /* shared for all virtual wiphys */ 622 struct ath_softc *sc; /* shared for all virtual wiphys */
621 struct ieee80211_hw *hw; 623 struct ieee80211_hw *hw;
624 enum ath_wiphy_state {
625 ATH_WIPHY_ACTIVE,
626 ATH_WIPHY_PAUSING,
627 ATH_WIPHY_PAUSED,
628 } state;
622}; 629};
623 630
624int ath_reset(struct ath_softc *sc, bool retry_tx); 631int ath_reset(struct ath_softc *sc, bool retry_tx);
@@ -684,5 +691,8 @@ static inline void ath9k_ps_restore(struct ath_softc *sc)
684void ath9k_set_bssid_mask(struct ieee80211_hw *hw); 691void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
685int ath9k_wiphy_add(struct ath_softc *sc); 692int ath9k_wiphy_add(struct ath_softc *sc);
686int ath9k_wiphy_del(struct ath_wiphy *aphy); 693int ath9k_wiphy_del(struct ath_wiphy *aphy);
694void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
695int ath9k_wiphy_pause(struct ath_wiphy *aphy);
696int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
687 697
688#endif /* ATH9K_H */ 698#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 760f5b80f79e..039c78136c50 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -125,6 +125,9 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
125 struct ieee80211_tx_info *info; 125 struct ieee80211_tx_info *info;
126 int cabq_depth; 126 int cabq_depth;
127 127
128 if (aphy->state != ATH_WIPHY_ACTIVE)
129 return NULL;
130
128 avp = (void *)vif->drv_priv; 131 avp = (void *)vif->drv_priv;
129 cabq = sc->beacon.cabq; 132 cabq = sc->beacon.cabq;
130 133
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 433a11c41838..7e44013ba6e7 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -2373,6 +2373,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
2373 case NL80211_IFTYPE_ADHOC: 2373 case NL80211_IFTYPE_ADHOC:
2374 /* Set BSSID */ 2374 /* Set BSSID */
2375 memcpy(sc->curbssid, conf->bssid, ETH_ALEN); 2375 memcpy(sc->curbssid, conf->bssid, ETH_ALEN);
2376 memcpy(avp->bssid, conf->bssid, ETH_ALEN);
2376 sc->curaid = 0; 2377 sc->curaid = 0;
2377 ath9k_hw_write_associd(sc); 2378 ath9k_hw_write_associd(sc);
2378 2379
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index 0584122341ad..db9b0b9a3431 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -194,12 +194,19 @@ struct ath_rate_priv {
194 struct ath_rate_softc *asc; 194 struct ath_rate_softc *asc;
195}; 195};
196 196
197enum ath9k_internal_frame_type {
198 ATH9K_NOT_INTERNAL,
199 ATH9K_INT_PAUSE,
200 ATH9K_INT_UNPAUSE
201};
202
197struct ath_tx_info_priv { 203struct ath_tx_info_priv {
198 struct ath_wiphy *aphy; 204 struct ath_wiphy *aphy;
199 struct ath_tx_status tx; 205 struct ath_tx_status tx;
200 int n_frames; 206 int n_frames;
201 int n_bad_frames; 207 int n_bad_frames;
202 bool update_rc; 208 bool update_rc;
209 enum ath9k_internal_frame_type frame_type;
203}; 210};
204 211
205#define ATH_TX_INFO_PRIV(tx_info) \ 212#define ATH_TX_INFO_PRIV(tx_info) \
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c
index 67bcb9343ca6..a8bac97bd847 100644
--- a/drivers/net/wireless/ath9k/virtual.c
+++ b/drivers/net/wireless/ath9k/virtual.c
@@ -175,3 +175,164 @@ int ath9k_wiphy_del(struct ath_wiphy *aphy)
175 spin_unlock_bh(&sc->wiphy_lock); 175 spin_unlock_bh(&sc->wiphy_lock);
176 return -ENOENT; 176 return -ENOENT;
177} 177}
178
179static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
180 struct ieee80211_vif *vif, const u8 *bssid,
181 int ps)
182{
183 struct ath_softc *sc = aphy->sc;
184 struct ath_tx_control txctl;
185 struct sk_buff *skb;
186 struct ieee80211_hdr *hdr;
187 __le16 fc;
188 struct ieee80211_tx_info *info;
189
190 skb = dev_alloc_skb(24);
191 if (skb == NULL)
192 return -ENOMEM;
193 hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
194 memset(hdr, 0, 24);
195 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
196 IEEE80211_FCTL_TODS);
197 if (ps)
198 fc |= cpu_to_le16(IEEE80211_FCTL_PM);
199 hdr->frame_control = fc;
200 memcpy(hdr->addr1, bssid, ETH_ALEN);
201 memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN);
202 memcpy(hdr->addr3, bssid, ETH_ALEN);
203
204 info = IEEE80211_SKB_CB(skb);
205 memset(info, 0, sizeof(*info));
206 info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS;
207 info->control.vif = vif;
208 info->control.rates[0].idx = 0;
209 info->control.rates[0].count = 4;
210 info->control.rates[1].idx = -1;
211
212 memset(&txctl, 0, sizeof(struct ath_tx_control));
213 txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
214 txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE;
215
216 if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
217 goto exit;
218
219 return 0;
220exit:
221 dev_kfree_skb_any(skb);
222 return -1;
223}
224
225/*
226 * ath9k version of ieee80211_tx_status() for TX frames that are generated
227 * internally in the driver.
228 */
229void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
230{
231 struct ath_wiphy *aphy = hw->priv;
232 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
233 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
234 struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
235
236 if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
237 aphy->state == ATH_WIPHY_PAUSING) {
238 if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
239 printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
240 "frame\n", wiphy_name(hw->wiphy));
241 /*
242 * The AP did not reply; ignore this to allow us to
243 * continue.
244 */
245 }
246 aphy->state = ATH_WIPHY_PAUSED;
247 }
248
249 kfree(tx_info_priv);
250 tx_info->rate_driver_data[0] = NULL;
251
252 dev_kfree_skb(skb);
253}
254
255static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
256{
257 struct ath_wiphy *aphy = data;
258 struct ath_vif *avp = (void *) vif->drv_priv;
259
260 switch (vif->type) {
261 case NL80211_IFTYPE_STATION:
262 if (!vif->bss_conf.assoc) {
263 aphy->state = ATH_WIPHY_PAUSED;
264 break;
265 }
266 /* TODO: could avoid this if already in PS mode */
267 ath9k_send_nullfunc(aphy, vif, avp->bssid, 1);
268 break;
269 case NL80211_IFTYPE_AP:
270 /* Beacon transmission is paused by aphy->state change */
271 aphy->state = ATH_WIPHY_PAUSED;
272 break;
273 default:
274 break;
275 }
276}
277
278/* caller must hold wiphy_lock */
279static int __ath9k_wiphy_pause(struct ath_wiphy *aphy)
280{
281 ieee80211_stop_queues(aphy->hw);
282 aphy->state = ATH_WIPHY_PAUSING;
283 /*
284 * TODO: handle PAUSING->PAUSED for the case where there are multiple
285 * active vifs (now we do it on the first vif getting ready; should be
286 * on the last)
287 */
288 ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter,
289 aphy);
290 return 0;
291}
292
293int ath9k_wiphy_pause(struct ath_wiphy *aphy)
294{
295 int ret;
296 spin_lock_bh(&aphy->sc->wiphy_lock);
297 ret = __ath9k_wiphy_pause(aphy);
298 spin_unlock_bh(&aphy->sc->wiphy_lock);
299 return ret;
300}
301
302static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
303{
304 struct ath_wiphy *aphy = data;
305 struct ath_vif *avp = (void *) vif->drv_priv;
306
307 switch (vif->type) {
308 case NL80211_IFTYPE_STATION:
309 if (!vif->bss_conf.assoc)
310 break;
311 ath9k_send_nullfunc(aphy, vif, avp->bssid, 0);
312 break;
313 case NL80211_IFTYPE_AP:
314 /* Beacon transmission is re-enabled by aphy->state change */
315 break;
316 default:
317 break;
318 }
319}
320
321/* caller must hold wiphy_lock */
322static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy)
323{
324 ieee80211_iterate_active_interfaces_atomic(aphy->hw,
325 ath9k_unpause_iter, aphy);
326 aphy->state = ATH_WIPHY_ACTIVE;
327 ieee80211_wake_queues(aphy->hw);
328 return 0;
329}
330
331int ath9k_wiphy_unpause(struct ath_wiphy *aphy)
332{
333 int ret;
334 spin_lock_bh(&aphy->sc->wiphy_lock);
335 ret = __ath9k_wiphy_unpause(aphy);
336 spin_unlock_bh(&aphy->sc->wiphy_lock);
337 return ret;
338}
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3c48fa5646f5..a82d2ab7c3a0 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -1514,6 +1514,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
1514 return -ENOMEM; 1514 return -ENOMEM;
1515 tx_info->rate_driver_data[0] = tx_info_priv; 1515 tx_info->rate_driver_data[0] = tx_info_priv;
1516 tx_info_priv->aphy = aphy; 1516 tx_info_priv->aphy = aphy;
1517 tx_info_priv->frame_type = txctl->frame_type;
1517 hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1518 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1518 fc = hdr->frame_control; 1519 fc = hdr->frame_control;
1519 1520
@@ -1722,11 +1723,14 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
1722 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 1723 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1723 struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); 1724 struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
1724 int hdrlen, padsize; 1725 int hdrlen, padsize;
1726 int frame_type = ATH9K_NOT_INTERNAL;
1725 1727
1726 DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); 1728 DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
1727 1729
1728 if (tx_info_priv) 1730 if (tx_info_priv) {
1729 hw = tx_info_priv->aphy->hw; 1731 hw = tx_info_priv->aphy->hw;
1732 frame_type = tx_info_priv->frame_type;
1733 }
1730 1734
1731 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || 1735 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
1732 tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { 1736 tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
@@ -1757,7 +1761,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
1757 skb_pull(skb, padsize); 1761 skb_pull(skb, padsize);
1758 } 1762 }
1759 1763
1760 ieee80211_tx_status(hw, skb); 1764 if (frame_type == ATH9K_NOT_INTERNAL)
1765 ieee80211_tx_status(hw, skb);
1766 else
1767 ath9k_tx_status(hw, skb);
1761} 1768}
1762 1769
1763static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 1770static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,