iwlwifi: mvm: add D0i3 power configurations
authorEliad Peller <eliad@wizery.com>
Tue, 7 Jan 2014 12:00:24 +0000 (14:00 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 3 Feb 2014 20:23:39 +0000 (22:23 +0200)
Configure skip-over-dtim and beacon filtering on D0i3
enter/exit.

Since the D0i3 entry/exit commands require different
command flags (e.g. CMD_HIGH_PRIORITY), add a new parameter
to the functions being called, and make the current users
pass CMD_SYNC.

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

index f6bed07d3d46ffdaf8edd616e93d3c4bb2d75786..a46895eaa374a703b76c0fdd5732a073c82acb0b 100644 (file)
@@ -457,9 +457,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
        mutex_lock(&mvm->mutex);
        iwl_dbgfs_update_bf(vif, param, value);
        if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
-               ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+               ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
        else
-               ret = iwl_mvm_enable_beacon_filter(mvm, vif);
+               ret = iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC);
        mutex_unlock(&mvm->mutex);
 
        return ret ?: count;
index 884c0872530883ae55646b0c177d9d2ae172e1da..cbbcd8e284e4bec620eb7e272b02941b3805aa0b 100644 (file)
@@ -301,54 +301,65 @@ struct iwl_beacon_filter_cmd {
 
 /* Beacon filtering and beacon abort */
 #define IWL_BF_ENERGY_DELTA_DEFAULT 5
+#define IWL_BF_ENERGY_DELTA_D0I3 20
 #define IWL_BF_ENERGY_DELTA_MAX 255
 #define IWL_BF_ENERGY_DELTA_MIN 0
 
 #define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1
+#define IWL_BF_ROAMING_ENERGY_DELTA_D0I3 20
 #define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255
 #define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0
 
 #define IWL_BF_ROAMING_STATE_DEFAULT 72
+#define IWL_BF_ROAMING_STATE_D0I3 72
 #define IWL_BF_ROAMING_STATE_MAX 255
 #define IWL_BF_ROAMING_STATE_MIN 0
 
 #define IWL_BF_TEMP_THRESHOLD_DEFAULT 112
+#define IWL_BF_TEMP_THRESHOLD_D0I3 112
 #define IWL_BF_TEMP_THRESHOLD_MAX 255
 #define IWL_BF_TEMP_THRESHOLD_MIN 0
 
 #define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1
+#define IWL_BF_TEMP_FAST_FILTER_D0I3 1
 #define IWL_BF_TEMP_FAST_FILTER_MAX 255
 #define IWL_BF_TEMP_FAST_FILTER_MIN 0
 
 #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5
+#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5
 #define IWL_BF_TEMP_SLOW_FILTER_MAX 255
 #define IWL_BF_TEMP_SLOW_FILTER_MIN 0
 
 #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1
 
 #define IWL_BF_DEBUG_FLAG_DEFAULT 0
+#define IWL_BF_DEBUG_FLAG_D0I3 0
 
 #define IWL_BF_ESCAPE_TIMER_DEFAULT 50
+#define IWL_BF_ESCAPE_TIMER_D0I3 1024
 #define IWL_BF_ESCAPE_TIMER_MAX 1024
 #define IWL_BF_ESCAPE_TIMER_MIN 0
 
 #define IWL_BA_ESCAPE_TIMER_DEFAULT 6
+#define IWL_BA_ESCAPE_TIMER_D0I3 6
 #define IWL_BA_ESCAPE_TIMER_D3 9
 #define IWL_BA_ESCAPE_TIMER_MAX 1024
 #define IWL_BA_ESCAPE_TIMER_MIN 0
 
 #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1
 
-#define IWL_BF_CMD_CONFIG_DEFAULTS                                          \
-       .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT),         \
-       .bf_roaming_energy_delta =                                           \
-               cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT),            \
-       .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT),       \
-       .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT),     \
-       .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \
-       .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \
-       .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT),             \
-       .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT),         \
-       .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT)
+#define IWL_BF_CMD_CONFIG(mode)                                             \
+       .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA ## mode),          \
+       .bf_roaming_energy_delta =                                            \
+               cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA ## mode),             \
+       .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE ## mode),        \
+       .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD ## mode),      \
+       .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER ## mode),  \
+       .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER ## mode),  \
+       .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG ## mode),              \
+       .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER ## mode),          \
+       .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER ## mode)
 
+#define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT)
+#define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3)
 #endif
index 67c0dfcc7285ffc8854ab5cf7e318db8c21be527..de38deb7e4f2df4908718d70444878c4f716fc78 100644 (file)
@@ -677,7 +677,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        iwl_mvm_power_disable(mvm, vif);
 
        /* beacon filtering */
-       ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+       ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
        if (ret)
                goto out_remove_mac;
 
@@ -1213,7 +1213,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                IWL_DEBUG_MAC80211(mvm, "cqm info_changed");
                /* reset cqm events tracking */
                mvmvif->bf_data.last_cqm_event = 0;
-               ret = iwl_mvm_update_beacon_filter(mvm, vif);
+               ret = iwl_mvm_update_beacon_filter(mvm, vif, false, CMD_SYNC);
                if (ret)
                        IWL_ERR(mvm, "failed to update CQM thresholds\n");
        }
@@ -1561,12 +1561,12 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTHORIZED) {
                /* enable beacon filtering */
-               WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
+               WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC));
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTHORIZED &&
                   new_state == IEEE80211_STA_ASSOC) {
                /* disable beacon filtering */
-               WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif));
+               WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC));
                ret = 0;
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH) {
@@ -2149,8 +2149,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
                        return -EINVAL;
 
                if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]))
-                       return iwl_mvm_enable_beacon_filter(mvm, vif);
-               return iwl_mvm_disable_beacon_filter(mvm, vif);
+                       return iwl_mvm_enable_beacon_filter(mvm, vif,
+                                                           CMD_SYNC);
+               return iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
        }
 
        return -EOPNOTSUPP;
index 3202a6ee7e96c8057e783bf7a64d892c1974cedb..0a8c65bd18a075b3ef8313a971e67f6457a00eae 100644 (file)
@@ -912,16 +912,24 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
                                         struct iwl_beacon_filter_cmd *cmd)
 {}
 #endif
+int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
+                                  struct ieee80211_vif *vif,
+                                  bool enable, u32 flags);
 int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
-                                struct ieee80211_vif *vif);
+                                struct ieee80211_vif *vif,
+                                u32 flags);
 int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif);
+                                 struct ieee80211_vif *vif,
+                                 u32 flags);
 int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
-                                  struct iwl_beacon_filter_cmd *cmd);
+                                  struct iwl_beacon_filter_cmd *cmd,
+                                  u32 flags);
 int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
                                struct ieee80211_vif *vif, bool enable);
 int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif);
+                                struct ieee80211_vif *vif,
+                                bool force,
+                                u32 flags);
 
 /* SMPS */
 void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
index 436c7e0ae6b1276a38eb307d2cdfb3f118643e8d..b20771c5e84b3f7a7c80e3bb52f0ccdb0c633085 100644 (file)
 #define POWER_KEEP_ALIVE_PERIOD_SEC    25
 
 int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
-                                  struct iwl_beacon_filter_cmd *cmd)
+                                  struct iwl_beacon_filter_cmd *cmd,
+                                  u32 flags)
 {
        int ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC,
+       ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
                                   sizeof(struct iwl_beacon_filter_cmd), cmd);
 
        if (!ret) {
@@ -145,7 +146,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
        mvmvif->bf_data.ba_enabled = enable;
        iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
        iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
-       return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+       return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, CMD_SYNC);
 }
 
 static void iwl_mvm_power_log(struct iwl_mvm *mvm,
@@ -686,32 +687,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
 }
 #endif
 
-int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
-                                struct ieee80211_vif *vif)
+static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+                                        struct ieee80211_vif *vif,
+                                        struct iwl_beacon_filter_cmd *cmd,
+                                        u32 cmd_flags,
+                                        bool d0i3)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_beacon_filter_cmd cmd = {
-               IWL_BF_CMD_CONFIG_DEFAULTS,
-               .bf_enable_beacon_filter = cpu_to_le32(1),
-       };
        int ret;
 
        if (mvmvif != mvm->bf_allowed_vif ||
            vif->type != NL80211_IFTYPE_STATION || vif->p2p)
                return 0;
 
-       iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
-       iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
-       ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+       iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);
+       if (!d0i3)
+               iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);
+       ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags);
 
-       if (!ret)
+       /* don't change bf_enabled in case of temporary d0i3 configuration */
+       if (!ret && !d0i3)
                mvmvif->bf_data.bf_enabled = true;
 
        return ret;
 }
 
+int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif,
+                                u32 flags)
+{
+       struct iwl_beacon_filter_cmd cmd = {
+               IWL_BF_CMD_CONFIG_DEFAULTS,
+               .bf_enable_beacon_filter = cpu_to_le32(1),
+       };
+
+       return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false);
+}
+
 int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif)
+                                 struct ieee80211_vif *vif,
+                                 u32 flags)
 {
        struct iwl_beacon_filter_cmd cmd = {};
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -721,7 +736,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
            vif->type != NL80211_IFTYPE_STATION || vif->p2p)
                return 0;
 
-       ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+       ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
 
        if (!ret)
                mvmvif->bf_data.bf_enabled = false;
@@ -729,15 +744,78 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
        return ret;
 }
 
+int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
+                                  struct ieee80211_vif *vif,
+                                  bool enable, u32 flags)
+{
+       int ret;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mac_power_cmd cmd = {};
+
+       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+               return 0;
+
+       if (!vif->bss_conf.assoc)
+               return 0;
+
+       iwl_mvm_power_build_cmd(mvm, vif, &cmd);
+       if (enable) {
+               /* configure skip over dtim up to 300 msec */
+               int dtimper = mvm->hw->conf.ps_dtim_period ?: 1;
+               int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+
+               if (WARN_ON(!dtimper_msec))
+                       return 0;
+
+               cmd.flags |=
+                       cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+               cmd.skip_dtim_periods = 300 / dtimper_msec;
+       }
+       iwl_mvm_power_log(mvm, &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags,
+                                  sizeof(cmd), &cmd);
+       if (ret)
+               return ret;
+
+       /* configure beacon filtering */
+       if (mvmvif != mvm->bf_allowed_vif)
+               return 0;
+
+       if (enable) {
+               struct iwl_beacon_filter_cmd cmd_bf = {
+                       IWL_BF_CMD_CONFIG_D0I3,
+                       .bf_enable_beacon_filter = cpu_to_le32(1),
+               };
+               ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
+                                                   flags, true);
+       } else {
+               if (mvmvif->bf_data.bf_enabled)
+                       ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags);
+               else
+                       ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags);
+       }
+
+       return ret;
+}
+
 int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
-                                struct ieee80211_vif *vif)
+                                struct ieee80211_vif *vif,
+                                bool force,
+                                u32 flags)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       if (!mvmvif->bf_data.bf_enabled)
+       if (mvmvif != mvm->bf_allowed_vif)
                return 0;
 
-       return iwl_mvm_enable_beacon_filter(mvm, vif);
+       if (!mvmvif->bf_data.bf_enabled) {
+               /* disable beacon filtering explicitly if force is true */
+               if (force)
+                       return iwl_mvm_disable_beacon_filter(mvm, vif, flags);
+               return 0;
+       }
+
+       return iwl_mvm_enable_beacon_filter(mvm, vif, flags);
 }
 
 const struct iwl_mvm_power_ops pm_mac_ops = {