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 | } | ||
