Commit 7df15b1e authored by Hila Gonen's avatar Hila Gonen Committed by Johannes Berg

iwlwifi: mvm: Add beacon filtering support

Add iwl_beacon_filter_cmd struct, disable and enable beacon
filtering as needed.
Signed-off-by: default avatarHila Gonen <hila.gonen@intel.com>
Reviewed-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent bd5f6a34
...@@ -117,4 +117,80 @@ struct iwl_powertable_cmd { ...@@ -117,4 +117,80 @@ struct iwl_powertable_cmd {
__le32 lprx_rssi_threshold; __le32 lprx_rssi_threshold;
} __packed; } __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 #endif
...@@ -170,6 +170,8 @@ enum { ...@@ -170,6 +170,8 @@ enum {
BT_COEX_PROT_ENV = 0xcd, BT_COEX_PROT_ENV = 0xcd,
BT_PROFILE_NOTIFICATION = 0xce, BT_PROFILE_NOTIFICATION = 0xce,
REPLY_BEACON_FILTERING_CMD = 0xd2,
REPLY_DEBUG_CMD = 0xf0, REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7, DEBUG_LOG_MSG = 0xf7,
......
...@@ -530,6 +530,17 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ...@@ -530,6 +530,17 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
*/ */
iwl_mvm_power_update_mode(mvm, vif); 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, * P2P_DEVICE interface does not have a channel context assigned to it,
* so a dedicated PHY context is allocated to it and the corresponding * 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, ...@@ -646,6 +657,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex); 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); iwl_mvm_vif_dbgfs_clean(mvm, vif);
/* /*
...@@ -984,9 +1000,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ...@@ -984,9 +1000,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
mvmvif->phy_ctxt->channel->band); mvmvif->phy_ctxt->channel->band);
} else if (old_state == IEEE80211_STA_ASSOC && } else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) { new_state == IEEE80211_STA_AUTHORIZED) {
/* enable beacon filtering */
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
ret = 0; ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED && } else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) { new_state == IEEE80211_STA_ASSOC) {
/* disable beacon filtering */
WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif));
ret = 0; ret = 0;
} else if (old_state == IEEE80211_STA_ASSOC && } else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH) { new_state == IEEE80211_STA_AUTH) {
......
...@@ -266,6 +266,12 @@ struct iwl_mvm { ...@@ -266,6 +266,12 @@ struct iwl_mvm {
unsigned long status; 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; enum iwl_ucode_type cur_ucode;
bool ucode_loaded; bool ucode_loaded;
bool init_ucode_run; bool init_ucode_run;
...@@ -533,4 +539,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -533,4 +539,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event); enum ieee80211_rssi_event rssi_event);
void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); 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__ */ #endif /* __IWL_MVM_H__ */
...@@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { ...@@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BT_COEX_PROT_ENV), CMD(BT_COEX_PROT_ENV),
CMD(BT_PROFILE_NOTIFICATION), CMD(BT_PROFILE_NOTIFICATION),
CMD(BT_CONFIG), CMD(BT_CONFIG),
CMD(REPLY_BEACON_FILTERING_CMD),
}; };
#undef CMD #undef CMD
......
...@@ -178,3 +178,70 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -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, return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
sizeof(cmd), &cmd); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment