diff options
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/beacon.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/rc.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/virtual.c | 161 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/xmit.c | 11 |
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 { | |||
292 | struct ath_tx_control { | 292 | struct 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 | ||
297 | struct ath_xmit_status { | 298 | struct 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 { | |||
619 | struct ath_wiphy { | 621 | struct 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 | ||
624 | int ath_reset(struct ath_softc *sc, bool retry_tx); | 631 | int ath_reset(struct ath_softc *sc, bool retry_tx); |
@@ -684,5 +691,8 @@ static inline void ath9k_ps_restore(struct ath_softc *sc) | |||
684 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw); | 691 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw); |
685 | int ath9k_wiphy_add(struct ath_softc *sc); | 692 | int ath9k_wiphy_add(struct ath_softc *sc); |
686 | int ath9k_wiphy_del(struct ath_wiphy *aphy); | 693 | int ath9k_wiphy_del(struct ath_wiphy *aphy); |
694 | void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); | ||
695 | int ath9k_wiphy_pause(struct ath_wiphy *aphy); | ||
696 | int 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 | ||
197 | enum ath9k_internal_frame_type { | ||
198 | ATH9K_NOT_INTERNAL, | ||
199 | ATH9K_INT_PAUSE, | ||
200 | ATH9K_INT_UNPAUSE | ||
201 | }; | ||
202 | |||
197 | struct ath_tx_info_priv { | 203 | struct 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 | |||
179 | static 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; | ||
220 | exit: | ||
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 | */ | ||
229 | void 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 | |||
255 | static 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 */ | ||
279 | static 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 | |||
293 | int 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 | |||
302 | static 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 */ | ||
322 | static 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 | |||
331 | int 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 | ||
1763 | static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | 1770 | static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, |