iwlwifi: mvm: Disable power save for monitor interface
authorAlexander Bondar <alexander.bondar@intel.com>
Wed, 23 Oct 2013 09:50:34 +0000 (11:50 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 17 Dec 2013 17:39:42 +0000 (19:39 +0200)
When monitor interface is activated device power save needs
to be disabled.
Re-consider power management status on other active
interfaces when monitor interface is bound or unbound.

Signed-off-by: Alexander Bondar <alexander.bondar@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/power.c

index e1c379a61d83a46e83c7f4c6563e0e26b0fbba50..d36105fa4bf6305e970acc528c4a4d5bc7f93b39 100644 (file)
@@ -1610,7 +1610,13 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
                goto out_unlock;
 
        /*
-        * Setting the quota at this stage is only required for monitor
+        * Power state must be updated before quotas,
+        * otherwise fw will complain.
+        */
+       mvm->bound_vif_cnt++;
+       iwl_mvm_power_update_binding(mvm, vif, true);
+
+       /* Setting the quota at this stage is only required for monitor
         * interfaces. For the other types, the bss_info changed flow
         * will handle quota settings.
         */
@@ -1621,13 +1627,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
                        goto out_remove_binding;
        }
 
-       mvm->bound_vif_cnt++;
-       iwl_mvm_power_update_binding(mvm, vif);
-
        goto out_unlock;
 
  out_remove_binding:
        iwl_mvm_binding_remove_vif(mvm, vif);
+       mvm->bound_vif_cnt--;
+       iwl_mvm_power_update_binding(mvm, vif, false);
  out_unlock:
        mutex_unlock(&mvm->mutex);
        if (ret)
@@ -1662,7 +1667,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
 out_unlock:
        mvmvif->phy_ctxt = NULL;
        mvm->bound_vif_cnt--;
-       iwl_mvm_power_update_binding(mvm, vif);
+       iwl_mvm_power_update_binding(mvm, vif, false);
 
        mutex_unlock(&mvm->mutex);
 }
index 51b0e9a4883f06bac09a5a1d548df9e1cce4f4e6..7295f8e42f3e9f544ece7baabfc0e339d0b586bf 100644 (file)
@@ -164,7 +164,7 @@ struct iwl_mvm_power_ops {
        int (*power_update_device_mode)(struct iwl_mvm *mvm);
        int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
        void (*power_update_binding)(struct iwl_mvm *mvm,
-                                    struct ieee80211_vif *vif);
+                                    struct ieee80211_vif *vif, bool assign);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                char *buf, int bufsz);
@@ -568,6 +568,9 @@ struct iwl_mvm {
        u8 last_agg_queue;
 
        u8 bound_vif_cnt;
+
+       /* Indicate if device power save is allowed */
+       bool ps_prevented;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -787,10 +790,11 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
 }
 
 static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
-                                               struct ieee80211_vif *vif)
+                                               struct ieee80211_vif *vif,
+                                               bool assign)
 {
        if (mvm->pm_ops->power_update_binding)
-               mvm->pm_ops->power_update_binding(mvm, vif);
+               mvm->pm_ops->power_update_binding(mvm, vif, assign);
 }
 
 void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
index d5d4935bc0e9f831c43dfd335dcf1fd9514a58f5..cfed105b28b2b34a6b520836c4d33d068736efd2 100644 (file)
@@ -301,7 +301,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
        keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
        cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
 
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+           mvm->ps_prevented)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -447,7 +448,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
                                    sizeof(cmd), &cmd);
 }
 
-static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
 {
        struct iwl_device_power_cmd cmd = {
                .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
@@ -456,7 +457,8 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
                return 0;
 
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+           force_disable)
                cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -473,6 +475,11 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
                                    &cmd);
 }
 
+static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+{
+       return _iwl_mvm_power_update_device(mvm, false);
+}
+
 void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -525,8 +532,15 @@ static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
 }
 
 static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
-                                         struct ieee80211_vif *vif)
+                                         struct ieee80211_vif *vif,
+                                         bool assign)
 {
+       if (vif->type == NL80211_IFTYPE_MONITOR) {
+               int ret = _iwl_mvm_power_update_device(mvm, assign);
+               mvm->ps_prevented = assign;
+               WARN_ONCE(ret, "Failed to update power device state\n");
+       }
+
        ieee80211_iterate_active_interfaces(mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_power_binding_iterator,