iwlwifi: mvm: refactor power code
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 27 Jan 2014 14:57:33 +0000 (16:57 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 3 Feb 2014 20:43:57 +0000 (22:43 +0200)
The main complexity of the power code is that it needs to
take into account the firmware limitations.
These limitations state that we need to have a global
picture of the vifs present in the system to be able to
decide if we can enable power management on a specific vif.

Even device power save (as opposed to vif power management)
must be disabled in certain circumstances (monitor vif).

Refactor the current code to make this clearer by defining
a function that explicitely computes these constraints.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/utils.c

index a9850aa909d8872463d5e0c9f10c679cc5abea92..e3a9cec45566f94b7cda7b43231283320157d803 100644 (file)
@@ -1195,7 +1195,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        if (ret)
                goto out;
 
-       ret = iwl_mvm_power_mac_update_mode(mvm, vif);
+       ret = iwl_mvm_power_update_mac(mvm, vif);
        if (ret)
                goto out;
 
index 9c0708eb540c96e42376776e676096e95ad0081b..29b4396018b1d45c81afe3050a3289cad9598b53 100644 (file)
@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
 
        mutex_lock(&mvm->mutex);
        iwl_dbgfs_update_pm(mvm, vif, param, val);
-       ret = iwl_mvm_power_mac_update_mode(mvm, vif);
+       ret = iwl_mvm_power_update_mac(mvm, vif);
        mutex_unlock(&mvm->mutex);
 
        return ret ?: count;
index 9d290697fbbaaeb34295c284fd04cee137c7950d..b9b6bfb5b25b4bfa9c8352a001e94c09293d90c3 100644 (file)
@@ -717,7 +717,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_release;
 
-       iwl_mvm_power_mac_update_mode(mvm, vif);
+       ret = iwl_mvm_power_update_mac(mvm, vif);
+       if (ret)
+               goto out_release;
 
        /* beacon filtering */
        ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
@@ -867,6 +869,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
        if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
                mvm->vif_count--;
 
+       iwl_mvm_power_update_mac(mvm, vif);
        iwl_mvm_mac_ctxt_remove(mvm, vif);
 
 out_release:
@@ -1231,7 +1234,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                          &mvmvif->time_event_data);
        } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
                              BSS_CHANGED_QOS)) {
-               ret = iwl_mvm_power_mac_update_mode(mvm, vif);
+               ret = iwl_mvm_power_update_mac(mvm, vif);
                if (ret)
                        IWL_ERR(mvm, "failed to update power mode\n");
        }
@@ -1298,7 +1301,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 
        /* power updated needs to be done before quotas */
        mvm->bound_vif_cnt++;
-       iwl_mvm_power_update_binding(mvm, vif, true);
+       iwl_mvm_power_update_mac(mvm, vif);
 
        ret = iwl_mvm_update_quotas(mvm, vif);
        if (ret)
@@ -1317,7 +1320,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 
 out_quota_failed:
        mvm->bound_vif_cnt--;
-       iwl_mvm_power_update_binding(mvm, vif, false);
+       iwl_mvm_power_update_mac(mvm, vif);
        mvmvif->ap_ibss_active = false;
        iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
 out_unbind:
@@ -1354,7 +1357,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
        iwl_mvm_binding_remove_vif(mvm, vif);
 
        mvm->bound_vif_cnt--;
-       iwl_mvm_power_update_binding(mvm, vif, false);
+       iwl_mvm_power_update_mac(mvm, vif);
 
        iwl_mvm_mac_ctxt_remove(mvm, vif);
 
@@ -2088,7 +2091,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
         * otherwise fw will complain.
         */
        mvm->bound_vif_cnt++;
-       iwl_mvm_power_update_binding(mvm, vif, true);
+       iwl_mvm_power_update_mac(mvm, vif);
 
        /* Setting the quota at this stage is only required for monitor
         * interfaces. For the other types, the bss_info changed flow
@@ -2106,7 +2109,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
  out_remove_binding:
        iwl_mvm_binding_remove_vif(mvm, vif);
        mvm->bound_vif_cnt--;
-       iwl_mvm_power_update_binding(mvm, vif, false);
+       iwl_mvm_power_update_mac(mvm, vif);
  out_unlock:
        mutex_unlock(&mvm->mutex);
        if (ret)
@@ -2139,7 +2142,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
 
        iwl_mvm_binding_remove_vif(mvm, vif);
        mvm->bound_vif_cnt--;
-       iwl_mvm_power_update_binding(mvm, vif, false);
+       iwl_mvm_power_update_mac(mvm, vif);
 
 out_unlock:
        mvmvif->phy_ctxt = NULL;
index bf6b6022ceb939e57c2b34f6e91f5e9c64211ed0..ab6e1e9706db7219e5d59e9aec36f7e4f590390b 100644 (file)
@@ -588,7 +588,9 @@ struct iwl_mvm {
        u8 bound_vif_cnt;
 
        /* Indicate if device power save is allowed */
-       bool ps_prevented;
+       bool ps_disabled;
+       /* Indicate if device power management is allowed */
+       bool pm_disabled;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -812,11 +814,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
 /* power management */
 int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
 
-int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif);
 int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
-void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif, bool assign);
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                 char *buf, int bufsz);
 
index 5671b83e0ac4d966aca45d911a96abc36bfb47ca..4da1ea44f39abc70fa82f0e68380fd9b0923c2ab 100644 (file)
@@ -298,8 +298,7 @@ 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 ||
-           mvm->ps_prevented)
+       if (mvm->ps_disabled)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -309,8 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
            mvmvif->dbgfs_pm.disable_power_off)
                cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
 #endif
-       if (!vif->bss_conf.ps || mvm->bound_vif_cnt > 1 ||
-           iwl_mvm_vif_low_latency(mvmvif))
+       if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
+           mvm->pm_disabled)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -417,7 +416,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 }
 
-static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
+static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
                                         struct ieee80211_vif *vif)
 {
        struct iwl_mac_power_cmd cmd = {};
@@ -439,39 +438,22 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
                                    sizeof(cmd), &cmd);
 }
 
-int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif)
-
-{
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       bool ba_enable;
-       int ret;
-
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
-               return 0;
-
-       ret = _iwl_mvm_power_mac_update_mode(mvm, vif);
-       if (ret)
-               return ret;
-
-       ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
-                     mvm->ps_prevented || mvm->bound_vif_cnt > 1 ||
-                     !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
-
-       return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable);
-}
-
-static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
+int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
 {
        struct iwl_device_power_cmd cmd = {
                .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
        };
 
+       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
+               return 0;
+
        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 ||
-           force_disable)
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+               mvm->ps_disabled = true;
+
+       if (mvm->ps_disabled)
                cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -488,14 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
                                    &cmd);
 }
 
-int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
-{
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
-               return 0;
-
-       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);
@@ -534,64 +508,119 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
        return 0;
 }
 
-struct iwl_mvm_power_iterator {
-       struct iwl_mvm *mvm;
+struct iwl_power_constraint {
        struct ieee80211_vif *bf_vif;
+       struct ieee80211_vif *bss_vif;
+       bool pm_disabled;
+       bool ps_disabled;
 };
 
-static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
-                                          struct ieee80211_vif *vif)
+static void iwl_mvm_power_iterator(void *_data, u8 *mac,
+                                  struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_mvm_power_iterator *power_iterator = _data;
-       struct iwl_mvm *mvm = power_iterator->mvm;
-       int ret;
+       struct iwl_power_constraint *power_iterator = _data;
+
+       switch (ieee80211_vif_type_p2p(vif)) {
+       case NL80211_IFTYPE_P2P_DEVICE:
+               break;
+
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_AP:
+               /* no BSS power mgmt if we have an active AP */
+               if (mvmvif->ap_ibss_active)
+                       power_iterator->pm_disabled = true;
+               break;
+
+       case NL80211_IFTYPE_MONITOR:
+               /* no BSS power mgmt and no device power save */
+               power_iterator->pm_disabled = true;
+               power_iterator->ps_disabled = true;
+               break;
+
+       case NL80211_IFTYPE_P2P_CLIENT:
+               /* no BSS power mgmt if we have a P2P client*/
+               power_iterator->pm_disabled = true;
+               break;
+
+       case NL80211_IFTYPE_STATION:
+               /* we should have only one BSS vif */
+               WARN_ON(power_iterator->bss_vif);
+               power_iterator->bss_vif = vif;
+
+               if (mvmvif->bf_data.bf_enabled &&
+                   !WARN_ON(power_iterator->bf_vif))
+                       power_iterator->bf_vif = vif;
+               break;
+
+       default:
+               break;
+       }
+}
 
-       ret = _iwl_mvm_power_mac_update_mode(mvm, vif);
+static void
+iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm,
+                                   struct iwl_power_constraint *constraint)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
+               constraint->pm_disabled = true;
+               constraint->ps_disabled = true;
+       }
 
-       if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif))
-               power_iterator->bf_vif = vif;
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_power_iterator, constraint);
 
-       WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n");
+       /* TODO: remove this and determine this variable in the iterator */
+       if (mvm->bound_vif_cnt > 1)
+               constraint->pm_disabled = true;
 }
 
-void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif, bool assign)
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
-       bool ba_enable;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_mvm_power_iterator power_it = {
-               .mvm = mvm,
-       };
+       struct iwl_power_constraint constraint = {};
+       bool ba_enable;
+       int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
-               return;
+               return 0;
+
+       iwl_mvm_power_get_global_constraint(mvm, &constraint);
+       mvm->ps_disabled = constraint.ps_disabled;
+       mvm->pm_disabled = constraint.pm_disabled;
 
+       /* don't update device power state unless we add / remove monitor */
        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");
+               ret = iwl_mvm_power_update_device(mvm);
+               if (ret)
+                       return ret;
        }
 
-       ieee80211_iterate_active_interfaces(mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_power_binding_iterator,
-                                           &power_it);
+       ret = iwl_mvm_power_send_cmd(mvm, vif);
+       if (ret)
+               return ret;
 
-       if (!power_it.bf_vif)
-               return;
+       if (constraint.bss_vif && vif != constraint.bss_vif) {
+               ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif);
+               if (ret)
+                       return ret;
+       }
+
+       if (!constraint.bf_vif)
+               return 0;
 
-       vif = power_it.bf_vif;
+       vif = constraint.bf_vif;
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
-                     mvm->ps_prevented || mvm->bound_vif_cnt > 1 ||
+       ba_enable = !(constraint.pm_disabled || constraint.ps_disabled ||
                      !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
 
-       WARN_ON_ONCE(iwl_mvm_update_beacon_abort(mvm, power_it.bf_vif,
-                                                ba_enable));
+       return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
index d4d901068e90ad51c45eb2a34325cc526c71626f..7440ffa766e644ee8f135ff71d35ca4b47cadbc3 100644 (file)
@@ -564,5 +564,5 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        iwl_mvm_bt_coex_vif_change(mvm);
 
-       return iwl_mvm_power_mac_update_mode(mvm, vif);
+       return iwl_mvm_power_update_mac(mvm, vif);
 }