diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/virtual.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/virtual.c | 662 |
1 files changed, 662 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c new file mode 100644 index 000000000000..1ff429b027d7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/virtual.c | |||
@@ -0,0 +1,662 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | struct ath9k_vif_iter_data { | ||
20 | int count; | ||
21 | u8 *addr; | ||
22 | }; | ||
23 | |||
24 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
25 | { | ||
26 | struct ath9k_vif_iter_data *iter_data = data; | ||
27 | u8 *nbuf; | ||
28 | |||
29 | nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN, | ||
30 | GFP_ATOMIC); | ||
31 | if (nbuf == NULL) | ||
32 | return; | ||
33 | |||
34 | memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN); | ||
35 | iter_data->addr = nbuf; | ||
36 | iter_data->count++; | ||
37 | } | ||
38 | |||
39 | void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | ||
40 | { | ||
41 | struct ath_wiphy *aphy = hw->priv; | ||
42 | struct ath_softc *sc = aphy->sc; | ||
43 | struct ath9k_vif_iter_data iter_data; | ||
44 | int i, j; | ||
45 | u8 mask[ETH_ALEN]; | ||
46 | |||
47 | /* | ||
48 | * Add primary MAC address even if it is not in active use since it | ||
49 | * will be configured to the hardware as the starting point and the | ||
50 | * BSSID mask will need to be changed if another address is active. | ||
51 | */ | ||
52 | iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); | ||
53 | if (iter_data.addr) { | ||
54 | memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); | ||
55 | iter_data.count = 1; | ||
56 | } else | ||
57 | iter_data.count = 0; | ||
58 | |||
59 | /* Get list of all active MAC addresses */ | ||
60 | spin_lock_bh(&sc->wiphy_lock); | ||
61 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, | ||
62 | &iter_data); | ||
63 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
64 | if (sc->sec_wiphy[i] == NULL) | ||
65 | continue; | ||
66 | ieee80211_iterate_active_interfaces_atomic( | ||
67 | sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); | ||
68 | } | ||
69 | spin_unlock_bh(&sc->wiphy_lock); | ||
70 | |||
71 | /* Generate an address mask to cover all active addresses */ | ||
72 | memset(mask, 0, ETH_ALEN); | ||
73 | for (i = 0; i < iter_data.count; i++) { | ||
74 | u8 *a1 = iter_data.addr + i * ETH_ALEN; | ||
75 | for (j = i + 1; j < iter_data.count; j++) { | ||
76 | u8 *a2 = iter_data.addr + j * ETH_ALEN; | ||
77 | mask[0] |= a1[0] ^ a2[0]; | ||
78 | mask[1] |= a1[1] ^ a2[1]; | ||
79 | mask[2] |= a1[2] ^ a2[2]; | ||
80 | mask[3] |= a1[3] ^ a2[3]; | ||
81 | mask[4] |= a1[4] ^ a2[4]; | ||
82 | mask[5] |= a1[5] ^ a2[5]; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | kfree(iter_data.addr); | ||
87 | |||
88 | /* Invert the mask and configure hardware */ | ||
89 | sc->bssidmask[0] = ~mask[0]; | ||
90 | sc->bssidmask[1] = ~mask[1]; | ||
91 | sc->bssidmask[2] = ~mask[2]; | ||
92 | sc->bssidmask[3] = ~mask[3]; | ||
93 | sc->bssidmask[4] = ~mask[4]; | ||
94 | sc->bssidmask[5] = ~mask[5]; | ||
95 | |||
96 | ath9k_hw_setbssidmask(sc); | ||
97 | } | ||
98 | |||
99 | int ath9k_wiphy_add(struct ath_softc *sc) | ||
100 | { | ||
101 | int i, error; | ||
102 | struct ath_wiphy *aphy; | ||
103 | struct ieee80211_hw *hw; | ||
104 | u8 addr[ETH_ALEN]; | ||
105 | |||
106 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); | ||
107 | if (hw == NULL) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | spin_lock_bh(&sc->wiphy_lock); | ||
111 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
112 | if (sc->sec_wiphy[i] == NULL) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (i == sc->num_sec_wiphy) { | ||
117 | /* No empty slot available; increase array length */ | ||
118 | struct ath_wiphy **n; | ||
119 | n = krealloc(sc->sec_wiphy, | ||
120 | (sc->num_sec_wiphy + 1) * | ||
121 | sizeof(struct ath_wiphy *), | ||
122 | GFP_ATOMIC); | ||
123 | if (n == NULL) { | ||
124 | spin_unlock_bh(&sc->wiphy_lock); | ||
125 | ieee80211_free_hw(hw); | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | n[i] = NULL; | ||
129 | sc->sec_wiphy = n; | ||
130 | sc->num_sec_wiphy++; | ||
131 | } | ||
132 | |||
133 | SET_IEEE80211_DEV(hw, sc->dev); | ||
134 | |||
135 | aphy = hw->priv; | ||
136 | aphy->sc = sc; | ||
137 | aphy->hw = hw; | ||
138 | sc->sec_wiphy[i] = aphy; | ||
139 | spin_unlock_bh(&sc->wiphy_lock); | ||
140 | |||
141 | memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); | ||
142 | addr[0] |= 0x02; /* Locally managed address */ | ||
143 | /* | ||
144 | * XOR virtual wiphy index into the least significant bits to generate | ||
145 | * a different MAC address for each virtual wiphy. | ||
146 | */ | ||
147 | addr[5] ^= i & 0xff; | ||
148 | addr[4] ^= (i & 0xff00) >> 8; | ||
149 | addr[3] ^= (i & 0xff0000) >> 16; | ||
150 | |||
151 | SET_IEEE80211_PERM_ADDR(hw, addr); | ||
152 | |||
153 | ath_set_hw_capab(sc, hw); | ||
154 | |||
155 | error = ieee80211_register_hw(hw); | ||
156 | |||
157 | if (error == 0) { | ||
158 | /* Make sure wiphy scheduler is started (if enabled) */ | ||
159 | ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); | ||
160 | } | ||
161 | |||
162 | return error; | ||
163 | } | ||
164 | |||
165 | int ath9k_wiphy_del(struct ath_wiphy *aphy) | ||
166 | { | ||
167 | struct ath_softc *sc = aphy->sc; | ||
168 | int i; | ||
169 | |||
170 | spin_lock_bh(&sc->wiphy_lock); | ||
171 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
172 | if (aphy == sc->sec_wiphy[i]) { | ||
173 | sc->sec_wiphy[i] = NULL; | ||
174 | spin_unlock_bh(&sc->wiphy_lock); | ||
175 | ieee80211_unregister_hw(aphy->hw); | ||
176 | ieee80211_free_hw(aphy->hw); | ||
177 | return 0; | ||
178 | } | ||
179 | } | ||
180 | spin_unlock_bh(&sc->wiphy_lock); | ||
181 | return -ENOENT; | ||
182 | } | ||
183 | |||
184 | static int ath9k_send_nullfunc(struct ath_wiphy *aphy, | ||
185 | struct ieee80211_vif *vif, const u8 *bssid, | ||
186 | int ps) | ||
187 | { | ||
188 | struct ath_softc *sc = aphy->sc; | ||
189 | struct ath_tx_control txctl; | ||
190 | struct sk_buff *skb; | ||
191 | struct ieee80211_hdr *hdr; | ||
192 | __le16 fc; | ||
193 | struct ieee80211_tx_info *info; | ||
194 | |||
195 | skb = dev_alloc_skb(24); | ||
196 | if (skb == NULL) | ||
197 | return -ENOMEM; | ||
198 | hdr = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
199 | memset(hdr, 0, 24); | ||
200 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
201 | IEEE80211_FCTL_TODS); | ||
202 | if (ps) | ||
203 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
204 | hdr->frame_control = fc; | ||
205 | memcpy(hdr->addr1, bssid, ETH_ALEN); | ||
206 | memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); | ||
207 | memcpy(hdr->addr3, bssid, ETH_ALEN); | ||
208 | |||
209 | info = IEEE80211_SKB_CB(skb); | ||
210 | memset(info, 0, sizeof(*info)); | ||
211 | info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
212 | info->control.vif = vif; | ||
213 | info->control.rates[0].idx = 0; | ||
214 | info->control.rates[0].count = 4; | ||
215 | info->control.rates[1].idx = -1; | ||
216 | |||
217 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | ||
218 | txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; | ||
219 | txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; | ||
220 | |||
221 | if (ath_tx_start(aphy->hw, skb, &txctl) != 0) | ||
222 | goto exit; | ||
223 | |||
224 | return 0; | ||
225 | exit: | ||
226 | dev_kfree_skb_any(skb); | ||
227 | return -1; | ||
228 | } | ||
229 | |||
230 | static bool __ath9k_wiphy_pausing(struct ath_softc *sc) | ||
231 | { | ||
232 | int i; | ||
233 | if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) | ||
234 | return true; | ||
235 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
236 | if (sc->sec_wiphy[i] && | ||
237 | sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) | ||
238 | return true; | ||
239 | } | ||
240 | return false; | ||
241 | } | ||
242 | |||
243 | static bool ath9k_wiphy_pausing(struct ath_softc *sc) | ||
244 | { | ||
245 | bool ret; | ||
246 | spin_lock_bh(&sc->wiphy_lock); | ||
247 | ret = __ath9k_wiphy_pausing(sc); | ||
248 | spin_unlock_bh(&sc->wiphy_lock); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static bool __ath9k_wiphy_scanning(struct ath_softc *sc) | ||
253 | { | ||
254 | int i; | ||
255 | if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) | ||
256 | return true; | ||
257 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
258 | if (sc->sec_wiphy[i] && | ||
259 | sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) | ||
260 | return true; | ||
261 | } | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | bool ath9k_wiphy_scanning(struct ath_softc *sc) | ||
266 | { | ||
267 | bool ret; | ||
268 | spin_lock_bh(&sc->wiphy_lock); | ||
269 | ret = __ath9k_wiphy_scanning(sc); | ||
270 | spin_unlock_bh(&sc->wiphy_lock); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); | ||
275 | |||
276 | /* caller must hold wiphy_lock */ | ||
277 | static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) | ||
278 | { | ||
279 | if (aphy == NULL) | ||
280 | return; | ||
281 | if (aphy->chan_idx != aphy->sc->chan_idx) | ||
282 | return; /* wiphy not on the selected channel */ | ||
283 | __ath9k_wiphy_unpause(aphy); | ||
284 | } | ||
285 | |||
286 | static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) | ||
287 | { | ||
288 | int i; | ||
289 | spin_lock_bh(&sc->wiphy_lock); | ||
290 | __ath9k_wiphy_unpause_ch(sc->pri_wiphy); | ||
291 | for (i = 0; i < sc->num_sec_wiphy; i++) | ||
292 | __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); | ||
293 | spin_unlock_bh(&sc->wiphy_lock); | ||
294 | } | ||
295 | |||
296 | void ath9k_wiphy_chan_work(struct work_struct *work) | ||
297 | { | ||
298 | struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); | ||
299 | struct ath_wiphy *aphy = sc->next_wiphy; | ||
300 | |||
301 | if (aphy == NULL) | ||
302 | return; | ||
303 | |||
304 | /* | ||
305 | * All pending interfaces paused; ready to change | ||
306 | * channels. | ||
307 | */ | ||
308 | |||
309 | /* Change channels */ | ||
310 | mutex_lock(&sc->mutex); | ||
311 | /* XXX: remove me eventually */ | ||
312 | ath9k_update_ichannel(sc, aphy->hw, | ||
313 | &sc->sc_ah->channels[sc->chan_idx]); | ||
314 | ath_update_chainmask(sc, sc->chan_is_ht); | ||
315 | if (ath_set_channel(sc, aphy->hw, | ||
316 | &sc->sc_ah->channels[sc->chan_idx]) < 0) { | ||
317 | printk(KERN_DEBUG "ath9k: Failed to set channel for new " | ||
318 | "virtual wiphy\n"); | ||
319 | mutex_unlock(&sc->mutex); | ||
320 | return; | ||
321 | } | ||
322 | mutex_unlock(&sc->mutex); | ||
323 | |||
324 | ath9k_wiphy_unpause_channel(sc); | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * ath9k version of ieee80211_tx_status() for TX frames that are generated | ||
329 | * internally in the driver. | ||
330 | */ | ||
331 | void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
332 | { | ||
333 | struct ath_wiphy *aphy = hw->priv; | ||
334 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
335 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
336 | struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); | ||
337 | |||
338 | if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && | ||
339 | aphy->state == ATH_WIPHY_PAUSING) { | ||
340 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) { | ||
341 | printk(KERN_DEBUG "ath9k: %s: no ACK for pause " | ||
342 | "frame\n", wiphy_name(hw->wiphy)); | ||
343 | /* | ||
344 | * The AP did not reply; ignore this to allow us to | ||
345 | * continue. | ||
346 | */ | ||
347 | } | ||
348 | aphy->state = ATH_WIPHY_PAUSED; | ||
349 | if (!ath9k_wiphy_pausing(aphy->sc)) { | ||
350 | /* | ||
351 | * Drop from tasklet to work to allow mutex for channel | ||
352 | * change. | ||
353 | */ | ||
354 | queue_work(aphy->sc->hw->workqueue, | ||
355 | &aphy->sc->chan_work); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | kfree(tx_info_priv); | ||
360 | tx_info->rate_driver_data[0] = NULL; | ||
361 | |||
362 | dev_kfree_skb(skb); | ||
363 | } | ||
364 | |||
365 | static void ath9k_mark_paused(struct ath_wiphy *aphy) | ||
366 | { | ||
367 | struct ath_softc *sc = aphy->sc; | ||
368 | aphy->state = ATH_WIPHY_PAUSED; | ||
369 | if (!__ath9k_wiphy_pausing(sc)) | ||
370 | queue_work(sc->hw->workqueue, &sc->chan_work); | ||
371 | } | ||
372 | |||
373 | static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
374 | { | ||
375 | struct ath_wiphy *aphy = data; | ||
376 | struct ath_vif *avp = (void *) vif->drv_priv; | ||
377 | |||
378 | switch (vif->type) { | ||
379 | case NL80211_IFTYPE_STATION: | ||
380 | if (!vif->bss_conf.assoc) { | ||
381 | ath9k_mark_paused(aphy); | ||
382 | break; | ||
383 | } | ||
384 | /* TODO: could avoid this if already in PS mode */ | ||
385 | if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { | ||
386 | printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", | ||
387 | __func__); | ||
388 | ath9k_mark_paused(aphy); | ||
389 | } | ||
390 | break; | ||
391 | case NL80211_IFTYPE_AP: | ||
392 | /* Beacon transmission is paused by aphy->state change */ | ||
393 | ath9k_mark_paused(aphy); | ||
394 | break; | ||
395 | default: | ||
396 | break; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | /* caller must hold wiphy_lock */ | ||
401 | static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) | ||
402 | { | ||
403 | ieee80211_stop_queues(aphy->hw); | ||
404 | aphy->state = ATH_WIPHY_PAUSING; | ||
405 | /* | ||
406 | * TODO: handle PAUSING->PAUSED for the case where there are multiple | ||
407 | * active vifs (now we do it on the first vif getting ready; should be | ||
408 | * on the last) | ||
409 | */ | ||
410 | ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, | ||
411 | aphy); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | int ath9k_wiphy_pause(struct ath_wiphy *aphy) | ||
416 | { | ||
417 | int ret; | ||
418 | spin_lock_bh(&aphy->sc->wiphy_lock); | ||
419 | ret = __ath9k_wiphy_pause(aphy); | ||
420 | spin_unlock_bh(&aphy->sc->wiphy_lock); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
425 | { | ||
426 | struct ath_wiphy *aphy = data; | ||
427 | struct ath_vif *avp = (void *) vif->drv_priv; | ||
428 | |||
429 | switch (vif->type) { | ||
430 | case NL80211_IFTYPE_STATION: | ||
431 | if (!vif->bss_conf.assoc) | ||
432 | break; | ||
433 | ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); | ||
434 | break; | ||
435 | case NL80211_IFTYPE_AP: | ||
436 | /* Beacon transmission is re-enabled by aphy->state change */ | ||
437 | break; | ||
438 | default: | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | /* caller must hold wiphy_lock */ | ||
444 | static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) | ||
445 | { | ||
446 | ieee80211_iterate_active_interfaces_atomic(aphy->hw, | ||
447 | ath9k_unpause_iter, aphy); | ||
448 | aphy->state = ATH_WIPHY_ACTIVE; | ||
449 | ieee80211_wake_queues(aphy->hw); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | int ath9k_wiphy_unpause(struct ath_wiphy *aphy) | ||
454 | { | ||
455 | int ret; | ||
456 | spin_lock_bh(&aphy->sc->wiphy_lock); | ||
457 | ret = __ath9k_wiphy_unpause(aphy); | ||
458 | spin_unlock_bh(&aphy->sc->wiphy_lock); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) | ||
463 | { | ||
464 | int i; | ||
465 | if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) | ||
466 | sc->pri_wiphy->state = ATH_WIPHY_PAUSED; | ||
467 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
468 | if (sc->sec_wiphy[i] && | ||
469 | sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) | ||
470 | sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /* caller must hold wiphy_lock */ | ||
475 | static void __ath9k_wiphy_pause_all(struct ath_softc *sc) | ||
476 | { | ||
477 | int i; | ||
478 | if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) | ||
479 | __ath9k_wiphy_pause(sc->pri_wiphy); | ||
480 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
481 | if (sc->sec_wiphy[i] && | ||
482 | sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) | ||
483 | __ath9k_wiphy_pause(sc->sec_wiphy[i]); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | int ath9k_wiphy_select(struct ath_wiphy *aphy) | ||
488 | { | ||
489 | struct ath_softc *sc = aphy->sc; | ||
490 | bool now; | ||
491 | |||
492 | spin_lock_bh(&sc->wiphy_lock); | ||
493 | if (__ath9k_wiphy_scanning(sc)) { | ||
494 | /* | ||
495 | * For now, we are using mac80211 sw scan and it expects to | ||
496 | * have full control over channel changes, so avoid wiphy | ||
497 | * scheduling during a scan. This could be optimized if the | ||
498 | * scanning control were moved into the driver. | ||
499 | */ | ||
500 | spin_unlock_bh(&sc->wiphy_lock); | ||
501 | return -EBUSY; | ||
502 | } | ||
503 | if (__ath9k_wiphy_pausing(sc)) { | ||
504 | if (sc->wiphy_select_failures == 0) | ||
505 | sc->wiphy_select_first_fail = jiffies; | ||
506 | sc->wiphy_select_failures++; | ||
507 | if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) | ||
508 | { | ||
509 | printk(KERN_DEBUG "ath9k: Previous wiphy select timed " | ||
510 | "out; disable/enable hw to recover\n"); | ||
511 | __ath9k_wiphy_mark_all_paused(sc); | ||
512 | /* | ||
513 | * TODO: this workaround to fix hardware is unlikely to | ||
514 | * be specific to virtual wiphy changes. It can happen | ||
515 | * on normal channel change, too, and as such, this | ||
516 | * should really be made more generic. For example, | ||
517 | * tricker radio disable/enable on GTT interrupt burst | ||
518 | * (say, 10 GTT interrupts received without any TX | ||
519 | * frame being completed) | ||
520 | */ | ||
521 | spin_unlock_bh(&sc->wiphy_lock); | ||
522 | ath_radio_disable(sc); | ||
523 | ath_radio_enable(sc); | ||
524 | queue_work(aphy->sc->hw->workqueue, | ||
525 | &aphy->sc->chan_work); | ||
526 | return -EBUSY; /* previous select still in progress */ | ||
527 | } | ||
528 | spin_unlock_bh(&sc->wiphy_lock); | ||
529 | return -EBUSY; /* previous select still in progress */ | ||
530 | } | ||
531 | sc->wiphy_select_failures = 0; | ||
532 | |||
533 | /* Store the new channel */ | ||
534 | sc->chan_idx = aphy->chan_idx; | ||
535 | sc->chan_is_ht = aphy->chan_is_ht; | ||
536 | sc->next_wiphy = aphy; | ||
537 | |||
538 | __ath9k_wiphy_pause_all(sc); | ||
539 | now = !__ath9k_wiphy_pausing(aphy->sc); | ||
540 | spin_unlock_bh(&sc->wiphy_lock); | ||
541 | |||
542 | if (now) { | ||
543 | /* Ready to request channel change immediately */ | ||
544 | queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * wiphys will be unpaused in ath9k_tx_status() once channel has been | ||
549 | * changed if any wiphy needs time to become paused. | ||
550 | */ | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | bool ath9k_wiphy_started(struct ath_softc *sc) | ||
556 | { | ||
557 | int i; | ||
558 | spin_lock_bh(&sc->wiphy_lock); | ||
559 | if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { | ||
560 | spin_unlock_bh(&sc->wiphy_lock); | ||
561 | return true; | ||
562 | } | ||
563 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
564 | if (sc->sec_wiphy[i] && | ||
565 | sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { | ||
566 | spin_unlock_bh(&sc->wiphy_lock); | ||
567 | return true; | ||
568 | } | ||
569 | } | ||
570 | spin_unlock_bh(&sc->wiphy_lock); | ||
571 | return false; | ||
572 | } | ||
573 | |||
574 | static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, | ||
575 | struct ath_wiphy *selected) | ||
576 | { | ||
577 | if (selected->state == ATH_WIPHY_SCAN) { | ||
578 | if (aphy == selected) | ||
579 | return; | ||
580 | /* | ||
581 | * Pause all other wiphys for the duration of the scan even if | ||
582 | * they are on the current channel now. | ||
583 | */ | ||
584 | } else if (aphy->chan_idx == selected->chan_idx) | ||
585 | return; | ||
586 | aphy->state = ATH_WIPHY_PAUSED; | ||
587 | ieee80211_stop_queues(aphy->hw); | ||
588 | } | ||
589 | |||
590 | void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, | ||
591 | struct ath_wiphy *selected) | ||
592 | { | ||
593 | int i; | ||
594 | spin_lock_bh(&sc->wiphy_lock); | ||
595 | if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) | ||
596 | ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); | ||
597 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
598 | if (sc->sec_wiphy[i] && | ||
599 | sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) | ||
600 | ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); | ||
601 | } | ||
602 | spin_unlock_bh(&sc->wiphy_lock); | ||
603 | } | ||
604 | |||
605 | void ath9k_wiphy_work(struct work_struct *work) | ||
606 | { | ||
607 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
608 | wiphy_work.work); | ||
609 | struct ath_wiphy *aphy = NULL; | ||
610 | bool first = true; | ||
611 | |||
612 | spin_lock_bh(&sc->wiphy_lock); | ||
613 | |||
614 | if (sc->wiphy_scheduler_int == 0) { | ||
615 | /* wiphy scheduler is disabled */ | ||
616 | spin_unlock_bh(&sc->wiphy_lock); | ||
617 | return; | ||
618 | } | ||
619 | |||
620 | try_again: | ||
621 | sc->wiphy_scheduler_index++; | ||
622 | while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { | ||
623 | aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; | ||
624 | if (aphy && aphy->state != ATH_WIPHY_INACTIVE) | ||
625 | break; | ||
626 | |||
627 | sc->wiphy_scheduler_index++; | ||
628 | aphy = NULL; | ||
629 | } | ||
630 | if (aphy == NULL) { | ||
631 | sc->wiphy_scheduler_index = 0; | ||
632 | if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { | ||
633 | if (first) { | ||
634 | first = false; | ||
635 | goto try_again; | ||
636 | } | ||
637 | /* No wiphy is ready to be scheduled */ | ||
638 | } else | ||
639 | aphy = sc->pri_wiphy; | ||
640 | } | ||
641 | |||
642 | spin_unlock_bh(&sc->wiphy_lock); | ||
643 | |||
644 | if (aphy && | ||
645 | aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && | ||
646 | ath9k_wiphy_select(aphy)) { | ||
647 | printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " | ||
648 | "change\n"); | ||
649 | } | ||
650 | |||
651 | queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, | ||
652 | sc->wiphy_scheduler_int); | ||
653 | } | ||
654 | |||
655 | void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) | ||
656 | { | ||
657 | cancel_delayed_work_sync(&sc->wiphy_work); | ||
658 | sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); | ||
659 | if (sc->wiphy_scheduler_int) | ||
660 | queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, | ||
661 | sc->wiphy_scheduler_int); | ||
662 | } | ||