Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / ath / ath9k / htc_drv_main.c
index abbd6effd60d31eb6a871e101ac10d0bbfa16f2e..374c32ed905ad95407368c13f340e7ef79d7cff7 100644 (file)
@@ -75,14 +75,19 @@ unlock:
 
 void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
 {
+       bool reset;
+
        mutex_lock(&priv->htc_pm_lock);
        if (--priv->ps_usecount != 0)
                goto unlock;
 
-       if (priv->ps_idle)
+       if (priv->ps_idle) {
+               ath9k_hw_setrxabort(priv->ah, true);
+               ath9k_hw_stopdmarecv(priv->ah, &reset);
                ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
-       else if (priv->ps_enabled)
+       } else if (priv->ps_enabled) {
                ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+       }
 
 unlock:
        mutex_unlock(&priv->htc_pm_lock);
@@ -250,7 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
        u8 cmd_rsp;
        int ret;
 
-       if (priv->op_flags & OP_INVALID)
+       if (test_bit(OP_INVALID, &priv->op_flags))
                return -EIO;
 
        fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
@@ -304,7 +309,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 
        htc_start(priv->htc);
 
-       if (!(priv->op_flags & OP_SCANNING) &&
+       if (!test_bit(OP_SCANNING, &priv->op_flags) &&
            !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
                ath9k_htc_vif_reconfig(priv);
 
@@ -750,7 +755,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
        common->ani.shortcal_timer = timestamp;
        common->ani.checkani_timer = timestamp;
 
-       priv->op_flags |= OP_ANI_RUNNING;
+       set_bit(OP_ANI_RUNNING, &priv->op_flags);
 
        ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
                                     msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@@ -759,7 +764,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
 void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
 {
        cancel_delayed_work_sync(&priv->ani_work);
-       priv->op_flags &= ~OP_ANI_RUNNING;
+       clear_bit(OP_ANI_RUNNING, &priv->op_flags);
 }
 
 void ath9k_htc_ani_work(struct work_struct *work)
@@ -944,7 +949,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
                ath_dbg(common, CONFIG,
                        "Failed to update capability in target\n");
 
-       priv->op_flags &= ~OP_INVALID;
+       clear_bit(OP_INVALID, &priv->op_flags);
        htc_start(priv->htc);
 
        spin_lock_bh(&priv->tx.tx_lock);
@@ -973,7 +978,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
 
-       if (priv->op_flags & OP_INVALID) {
+       if (test_bit(OP_INVALID, &priv->op_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&priv->mutex);
                return;
@@ -1015,7 +1020,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        ath9k_htc_ps_restore(priv);
        ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
-       priv->op_flags |= OP_INVALID;
+       set_bit(OP_INVALID, &priv->op_flags);
 
        ath_dbg(common, CONFIG, "Driver halt\n");
        mutex_unlock(&priv->mutex);
@@ -1105,7 +1110,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
        ath9k_htc_set_opmode(priv);
 
        if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
-           !(priv->op_flags & OP_ANI_RUNNING)) {
+           !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
                ath9k_hw_set_tsfadjust(priv->ah, 1);
                ath9k_htc_start_ani(priv);
        }
@@ -1178,24 +1183,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ieee80211_conf *conf = &hw->conf;
+       bool chip_reset = false;
+       int ret = 0;
 
        mutex_lock(&priv->mutex);
+       ath9k_htc_ps_wakeup(priv);
 
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-               bool enable_radio = false;
-               bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
-
                mutex_lock(&priv->htc_pm_lock);
-               if (!idle && priv->ps_idle)
-                       enable_radio = true;
-               priv->ps_idle = idle;
-               mutex_unlock(&priv->htc_pm_lock);
 
-               if (enable_radio) {
-                       ath_dbg(common, CONFIG, "not-idle: enabling radio\n");
-                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
-                       ath9k_htc_radio_enable(hw);
-               }
+               priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+               if (priv->ps_idle)
+                       chip_reset = true;
+
+               mutex_unlock(&priv->htc_pm_lock);
        }
 
        /*
@@ -1210,7 +1211,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                        ath9k_htc_remove_monitor_interface(priv);
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+       if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
 
@@ -1223,8 +1224,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 
                if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
                        ath_err(common, "Unable to set channel\n");
-                       mutex_unlock(&priv->mutex);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
 
        }
@@ -1246,21 +1247,10 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                                       priv->txpowlimit, &priv->curtxpow);
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-               mutex_lock(&priv->htc_pm_lock);
-               if (!priv->ps_idle) {
-                       mutex_unlock(&priv->htc_pm_lock);
-                       goto out;
-               }
-               mutex_unlock(&priv->htc_pm_lock);
-
-               ath_dbg(common, CONFIG, "idle: disabling radio\n");
-               ath9k_htc_radio_disable(hw);
-       }
-
 out:
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
-       return 0;
+       return ret;
 }
 
 #define SUPPORTED_FILTERS                      \
@@ -1285,7 +1275,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
        changed_flags &= SUPPORTED_FILTERS;
        *total_flags &= SUPPORTED_FILTERS;
 
-       if (priv->op_flags & OP_INVALID) {
+       if (test_bit(OP_INVALID, &priv->op_flags)) {
                ath_dbg(ath9k_hw_common(priv->ah), ANY,
                        "Unable to configure filter on invalid state\n");
                mutex_unlock(&priv->mutex);
@@ -1516,7 +1506,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
                        bss_conf->bssid);
                ath9k_htc_set_tsfadjust(priv, vif);
-               priv->op_flags |= OP_ENABLE_BEACON;
+               set_bit(OP_ENABLE_BEACON, &priv->op_flags);
                ath9k_htc_beacon_config(priv, vif);
        }
 
@@ -1529,7 +1519,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                        ath_dbg(common, CONFIG,
                                "Beacon disabled for BSS: %pM\n",
                                bss_conf->bssid);
-                       priv->op_flags &= ~OP_ENABLE_BEACON;
+                       clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
                        ath9k_htc_beacon_config(priv, vif);
                }
        }
@@ -1542,7 +1532,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                    (priv->nvifs == 1) &&
                    (priv->num_ap_vif == 1) &&
                    (vif->type == NL80211_IFTYPE_AP)) {
-                       priv->op_flags |= OP_TSF_RESET;
+                       set_bit(OP_TSF_RESET, &priv->op_flags);
                }
                ath_dbg(common, CONFIG,
                        "Beacon interval changed for BSS: %pM\n",
@@ -1654,7 +1644,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
        spin_lock_bh(&priv->beacon_lock);
-       priv->op_flags |= OP_SCANNING;
+       set_bit(OP_SCANNING, &priv->op_flags);
        spin_unlock_bh(&priv->beacon_lock);
        cancel_work_sync(&priv->ps_work);
        ath9k_htc_stop_ani(priv);
@@ -1667,7 +1657,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
        spin_lock_bh(&priv->beacon_lock);
-       priv->op_flags &= ~OP_SCANNING;
+       clear_bit(OP_SCANNING, &priv->op_flags);
        spin_unlock_bh(&priv->beacon_lock);
        ath9k_htc_ps_wakeup(priv);
        ath9k_htc_vif_reconfig(priv);