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