iwlwifi: mvm: Add beacon filtering support
authorHila Gonen <hila.gonen@intel.com>
Wed, 12 Dec 2012 09:16:19 +0000 (11:16 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 May 2013 16:11:22 +0000 (18:11 +0200)
Add iwl_beacon_filter_cmd struct, disable and enable beacon
filtering as needed.

Signed-off-by: Hila Gonen <hila.gonen@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/power.c

index 81fe45f46be7e97f1d346ada8c457d065b9a377e..90fdfcda15b6c2c0bd9f4856f62fb78a1f9b53ee 100644 (file)
@@ -117,4 +117,80 @@ struct iwl_powertable_cmd {
        __le32 lprx_rssi_threshold;
 } __packed;
 
+/**
+ * struct iwl_beacon_filter_cmd
+ * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
+ * @id_and_color: MAC contex identifier
+ * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon
+ *      to driver if delta in Energy values calculated for this and last
+ *      passed beacon is greater than this threshold. Zero value means that
+ *      the Energy change is ignored for beacon filtering, and beacon will
+ *      not be forced to be sent to driver regardless of this delta. Typical
+ *      energy delta 5dB.
+ * @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state.
+ *      Send beacon to driver if delta in Energy values calculated for this
+ *      and last passed beacon is greater than this threshold. Zero value
+ *      means that the Energy change is ignored for beacon filtering while in
+ *      Roaming state, typical energy delta 1dB.
+ * @bf_roaming_state: Used for RSSI filtering. If absolute Energy values
+ *      calculated for current beacon is less than the threshold, use
+ *      Roaming Energy Delta Threshold, otherwise use normal Energy Delta
+ *      Threshold. Typical energy threshold is -72dBm.
+ * @bf_temperature_delta: Send Beacon to driver if delta in temperature values
+ *      calculated for this and the last passed beacon is greater than  this
+ *      threshold. Zero value means that the temperature changeis ignored for
+ *      beacon filtering; beacons will not be  forced to be sent to driver
+ *      regardless of whether its temerature has been changed.
+ * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled.
+ * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed
+ *      for a specific period of time. Units: Beacons.
+ * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed
+ *      for a longer period of time then this escape-timeout. Units: Beacons.
+ * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled.
+ */
+struct iwl_beacon_filter_cmd {
+       u8 bf_energy_delta;
+       u8 bf_roaming_energy_delta;
+       u8 bf_roaming_state;
+       u8 bf_temperature_delta;
+       u8 bf_enable_beacon_filter;
+       u8 bf_debug_flag;
+       __le16 reserved1;
+       __le32 bf_escape_timer;
+       __le32 ba_escape_timer;
+       u8 ba_enable_beacon_abort;
+       u8 reserved2[3];
+} __packed;
+
+/* Beacon filtering and beacon abort */
+#define IWL_BF_ENERGY_DELTA_DEFAULT 5
+#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_MAX 255
+#define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0
+
+#define IWL_BF_ROAMING_STATE_DEFAULT 72
+#define IWL_BF_ROAMING_STATE_MAX 255
+#define IWL_BF_ROAMING_STATE_MIN 0
+
+#define IWL_BF_TEMPERATURE_DELTA_DEFAULT 5
+#define IWL_BF_TEMPERATURE_DELTA_MAX 255
+#define IWL_BF_TEMPERATURE_DELTA_MIN 0
+
+#define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1
+
+#define IWL_BF_DEBUG_FLAG_DEFAULT 0
+
+#define IWL_BF_ESCAPE_TIMER_DEFAULT 50
+#define IWL_BF_ESCAPE_TIMER_MAX 1024
+#define IWL_BF_ESCAPE_TIMER_MIN 0
+
+#define IWL_BA_ESCAPE_TIMER_DEFAULT 3
+#define IWL_BA_ESCAPE_TIMER_MAX 1024
+#define IWL_BA_ESCAPE_TIMER_MIN 0
+
+#define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1
+
 #endif
index 191dcae8ba476573e2da094ab8f2a8a262ad89ce..6031dbf83a964ba0dc8603c1c1436f95f971408a 100644 (file)
@@ -170,6 +170,8 @@ enum {
        BT_COEX_PROT_ENV = 0xcd,
        BT_PROFILE_NOTIFICATION = 0xce,
 
+       REPLY_BEACON_FILTERING_CMD = 0xd2,
+
        REPLY_DEBUG_CMD = 0xf0,
        DEBUG_LOG_MSG = 0xf7,
 
index dd158ec571fbb183374858e20ffd80325206db9d..e2cf6d92217b43ad73ecd3cb83f8d2459a559306 100644 (file)
@@ -530,6 +530,17 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
         */
        iwl_mvm_power_update_mode(mvm, vif);
 
+       /* beacon filtering */
+       if (!mvm->bf_allowed_vif &&
+           vif->type == NL80211_IFTYPE_STATION && !vif->p2p){
+               mvm->bf_allowed_vif = mvmvif;
+               vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+       }
+
+       ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+       if (ret)
+               goto out_release;
+
        /*
         * P2P_DEVICE interface does not have a channel context assigned to it,
         * so a dedicated PHY context is allocated to it and the corresponding
@@ -646,6 +657,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
+       if (mvm->bf_allowed_vif == mvmvif) {
+               mvm->bf_allowed_vif = NULL;
+               vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+       }
+
        iwl_mvm_vif_dbgfs_clean(mvm, vif);
 
        /*
@@ -984,9 +1000,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                                             mvmvif->phy_ctxt->channel->band);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTHORIZED) {
+               /* enable beacon filtering */
+               WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
                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));
                ret = 0;
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH) {
index 8269bc5629519726c7092314cf8ce3d9d955606c..4fc64d50dc50234807d1332090b679932db821eb 100644 (file)
@@ -266,6 +266,12 @@ struct iwl_mvm {
 
        unsigned long status;
 
+       /*
+        * for beacon filtering -
+        * currently only one interface can be supported
+        */
+       struct iwl_mvm_vif *bf_allowed_vif;
+
        enum iwl_ucode_type cur_ucode;
        bool ucode_loaded;
        bool init_ucode_run;
@@ -533,4 +539,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                           enum ieee80211_rssi_event rssi_event);
 void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 
+/* beacon filtering */
+int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif);
+int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                 struct ieee80211_vif *vif);
+
 #endif /* __IWL_MVM_H__ */
index fe031d304d1eddfcdf7131cb3bf172d54a6121d0..5bf1eaf9046a0a8e42d3eacae197fbb7eef18c4d 100644 (file)
@@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(BT_COEX_PROT_ENV),
        CMD(BT_PROFILE_NOTIFICATION),
        CMD(BT_CONFIG),
+       CMD(REPLY_BEACON_FILTERING_CMD),
 };
 #undef CMD
 
index ed77e437aac49d513525b12725f3d70baad461e9..30a5c27bd62329ab0f2809adc7001d33cb2baf95 100644 (file)
@@ -178,3 +178,70 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
                                    sizeof(cmd), &cmd);
 }
+
+static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
+                                         struct iwl_beacon_filter_cmd *cmd)
+{
+       int ret;
+
+       ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC,
+                                  sizeof(struct iwl_beacon_filter_cmd), cmd);
+
+       if (!ret) {
+               IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
+                               cmd->ba_enable_beacon_abort);
+               IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
+                               cmd->ba_escape_timer);
+               IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
+                               cmd->bf_debug_flag);
+               IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
+                               cmd->bf_enable_beacon_filter);
+               IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
+                               cmd->bf_energy_delta);
+               IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
+                               cmd->bf_escape_timer);
+               IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
+                               cmd->bf_roaming_energy_delta);
+               IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
+                               cmd->bf_roaming_state);
+               IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n",
+                               cmd->bf_temperature_delta);
+       }
+       return ret;
+}
+
+int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_beacon_filter_cmd cmd = {
+               .bf_enable_beacon_filter = 1,
+               .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT,
+               .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT,
+               .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT,
+               .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT,
+               .bf_debug_flag = 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),
+               .ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT,
+       };
+
+       if (mvmvif != mvm->bf_allowed_vif ||
+           vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+               return 0;
+
+       return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+}
+
+int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                 struct ieee80211_vif *vif)
+{
+       struct iwl_beacon_filter_cmd cmd = {
+               .bf_enable_beacon_filter = 0,
+       };
+
+       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+               return 0;
+
+       return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+}