/* * Indication of hardware PHY state change */ void ath_hw_phystate_change(struct ath_softc *sc, int newstate) { if (sc->sc_hw_phystate == newstate) return; sc->sc_hw_phystate = newstate; /* save the hardware switch state */ #ifdef ATH_SUPPORT_LINUX_STA /* TODO: rfkill support in Linux*/ if (newstate) { ath_radio_enable(sc); sc->sc_ieee_ops->ath_net80211_resume(sc->sc_ieee); } else { sc->sc_ieee_ops->ath_net80211_suspend(sc->sc_ieee); ath_radio_disable(sc); } #endif }
int ath9k_wiphy_select(struct ath_wiphy *aphy) { struct ath_softc *sc = aphy->sc; bool now; spin_lock_bh(&sc->wiphy_lock); if (__ath9k_wiphy_scanning(sc)) { /* * For now, we are using mac80211 sw scan and it expects to * have full control over channel changes, so avoid wiphy * scheduling during a scan. This could be optimized if the * scanning control were moved into the driver. */ spin_unlock_bh(&sc->wiphy_lock); return -EBUSY; } if (__ath9k_wiphy_pausing(sc)) { if (sc->wiphy_select_failures == 0) sc->wiphy_select_first_fail = jiffies; sc->wiphy_select_failures++; if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) { printk(KERN_DEBUG "ath9k: Previous wiphy select timed " "out; disable/enable hw to recover\n"); __ath9k_wiphy_mark_all_paused(sc); /* * TODO: this workaround to fix hardware is unlikely to * be specific to virtual wiphy changes. It can happen * on normal channel change, too, and as such, this * should really be made more generic. For example, * tricker radio disable/enable on GTT interrupt burst * (say, 10 GTT interrupts received without any TX * frame being completed) */ spin_unlock_bh(&sc->wiphy_lock); ath_radio_disable(sc); ath_radio_enable(sc); queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); return -EBUSY; /* previous select still in progress */ } spin_unlock_bh(&sc->wiphy_lock); return -EBUSY; /* previous select still in progress */ } sc->wiphy_select_failures = 0; /* Store the new channel */ sc->chan_idx = aphy->chan_idx; sc->chan_is_ht = aphy->chan_is_ht; sc->next_wiphy = aphy; __ath9k_wiphy_pause_all(sc); now = !__ath9k_wiphy_pausing(aphy->sc); spin_unlock_bh(&sc->wiphy_lock); if (now) { /* Ready to request channel change immediately */ queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); } /* * wiphys will be unpaused in ath9k_tx_status() once channel has been * changed if any wiphy needs time to become paused. */ return 0; }