1/****************************************************************************** 2 * 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * GPL LICENSE SUMMARY 7 * 8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 23 * USA 24 * 25 * The full GNU General Public License is included in this distribution 26 * in the file called COPYING. 27 * 28 * Contact Information: 29 * Intel Linux Wireless <ilw@linux.intel.com> 30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 31 * 32 * BSD LICENSE 33 * 34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 42 * * Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * * Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in 46 * the documentation and/or other materials provided with the 47 * distribution. 48 * * Neither the name Intel Corporation nor the names of its 49 * contributors may be used to endorse or promote products derived 50 * from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 * 64 *****************************************************************************/ 65 66#include <linux/kernel.h> 67#include <linux/module.h> 68#include <linux/slab.h> 69#include <linux/etherdevice.h> 70 71#include <net/mac80211.h> 72 73#include "iwl-debug.h" 74#include "mvm.h" 75#include "iwl-modparams.h" 76#include "fw-api-power.h" 77 78#define POWER_KEEP_ALIVE_PERIOD_SEC 25 79 80static 81int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, 82 struct iwl_beacon_filter_cmd *cmd, 83 u32 flags) 84{ 85 IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", 86 le32_to_cpu(cmd->ba_enable_beacon_abort)); 87 IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", 88 le32_to_cpu(cmd->ba_escape_timer)); 89 IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", 90 le32_to_cpu(cmd->bf_debug_flag)); 91 IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", 92 le32_to_cpu(cmd->bf_enable_beacon_filter)); 93 IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", 94 le32_to_cpu(cmd->bf_energy_delta)); 95 IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", 96 le32_to_cpu(cmd->bf_escape_timer)); 97 IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", 98 le32_to_cpu(cmd->bf_roaming_energy_delta)); 99 IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", 100 le32_to_cpu(cmd->bf_roaming_state)); 101 IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", 102 le32_to_cpu(cmd->bf_temp_threshold)); 103 IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", 104 le32_to_cpu(cmd->bf_temp_fast_filter)); 105 IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", 106 le32_to_cpu(cmd->bf_temp_slow_filter)); 107 108 return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, 109 sizeof(struct iwl_beacon_filter_cmd), cmd); 110} 111 112static 113void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm, 114 struct ieee80211_vif *vif, 115 struct iwl_beacon_filter_cmd *cmd) 116{ 117 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 118 119 if (vif->bss_conf.cqm_rssi_thold) { 120 cmd->bf_energy_delta = 121 cpu_to_le32(vif->bss_conf.cqm_rssi_hyst); 122 /* fw uses an absolute value for this */ 123 cmd->bf_roaming_state = 124 cpu_to_le32(-vif->bss_conf.cqm_rssi_thold); 125 } 126 cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled); 127} 128 129static void iwl_mvm_power_log(struct iwl_mvm *mvm, 130 struct iwl_mac_power_cmd *cmd) 131{ 132 IWL_DEBUG_POWER(mvm, 133 "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", 134 cmd->id_and_color, iwlmvm_mod_params.power_scheme, 135 le16_to_cpu(cmd->flags)); 136 IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", 137 le16_to_cpu(cmd->keep_alive_seconds)); 138 139 if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) { 140 IWL_DEBUG_POWER(mvm, "Disable power management\n"); 141 return; 142 } 143 144 IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", 145 le32_to_cpu(cmd->rx_data_timeout)); 146 IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", 147 le32_to_cpu(cmd->tx_data_timeout)); 148 if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) 149 IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", 150 cmd->skip_dtim_periods); 151 if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) 152 IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", 153 cmd->lprx_rssi_threshold); 154 if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { 155 IWL_DEBUG_POWER(mvm, "uAPSD enabled\n"); 156 IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", 157 le32_to_cpu(cmd->rx_data_timeout_uapsd)); 158 IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n", 159 le32_to_cpu(cmd->tx_data_timeout_uapsd)); 160 IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid); 161 IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags); 162 IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp); 163 } 164} 165 166static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, 167 struct ieee80211_vif *vif, 168 struct iwl_mac_power_cmd *cmd) 169{ 170 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 171 enum ieee80211_ac_numbers ac; 172 bool tid_found = false; 173 174 for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) { 175 if (!mvmvif->queue_params[ac].uapsd) 176 continue; 177 178 if (mvm->cur_ucode != IWL_UCODE_WOWLAN) 179 cmd->flags |= 180 cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); 181 182 cmd->uapsd_ac_flags |= BIT(ac); 183 184 /* QNDP TID - the highest TID with no admission control */ 185 if (!tid_found && !mvmvif->queue_params[ac].acm) { 186 tid_found = true; 187 switch (ac) { 188 case IEEE80211_AC_VO: 189 cmd->qndp_tid = 6; 190 break; 191 case IEEE80211_AC_VI: 192 cmd->qndp_tid = 5; 193 break; 194 case IEEE80211_AC_BE: 195 cmd->qndp_tid = 0; 196 break; 197 case IEEE80211_AC_BK: 198 cmd->qndp_tid = 1; 199 break; 200 } 201 } 202 } 203 204 if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { 205#ifdef CONFIG_IWLWIFI_DEBUGFS 206 /* set advanced pm flag with no uapsd ACs to enable ps-poll */ 207 if (mvmvif->dbgfs_pm.use_ps_poll) 208 cmd->flags |= 209 cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); 210#endif 211 return; 212 } 213 214 cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK); 215 216 if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | 217 BIT(IEEE80211_AC_VI) | 218 BIT(IEEE80211_AC_BE) | 219 BIT(IEEE80211_AC_BK))) { 220 cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); 221 cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL); 222 cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ? 223 cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) : 224 cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW); 225 } 226 227 cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; 228 229 if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags & 230 cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { 231 cmd->rx_data_timeout_uapsd = 232 cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); 233 cmd->tx_data_timeout_uapsd = 234 cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); 235 } else { 236 cmd->rx_data_timeout_uapsd = 237 cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); 238 cmd->tx_data_timeout_uapsd = 239 cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); 240 } 241 242 if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { 243 cmd->heavy_tx_thld_packets = 244 IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS; 245 cmd->heavy_rx_thld_packets = 246 IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS; 247 } else { 248 cmd->heavy_tx_thld_packets = 249 IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; 250 cmd->heavy_rx_thld_packets = 251 IWL_MVM_PS_HEAVY_RX_THLD_PACKETS; 252 } 253 cmd->heavy_tx_thld_percentage = 254 IWL_MVM_PS_HEAVY_TX_THLD_PERCENT; 255 cmd->heavy_rx_thld_percentage = 256 IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; 257} 258 259static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, 260 struct ieee80211_vif *vif) 261{ 262 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 263 264 if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, 265 ETH_ALEN)) 266 return false; 267 268 if (vif->p2p && 269 !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD)) 270 return false; 271 /* 272 * Avoid using uAPSD if P2P client is associated to GO that uses 273 * opportunistic power save. This is due to current FW limitation. 274 */ 275 if (vif->p2p && 276 (vif->bss_conf.p2p_noa_attr.oppps_ctwindow & 277 IEEE80211_P2P_OPPPS_ENABLE_BIT)) 278 return false; 279 280 /* 281 * Avoid using uAPSD if client is in DCM - 282 * low latency issue in Miracast 283 */ 284 if (iwl_mvm_phy_ctx_count(mvm) >= 2) 285 return false; 286 287 return true; 288} 289 290static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) 291{ 292 int numerator; 293 int dtim_interval = dtimper * bi; 294 295 if (WARN_ON(!dtim_interval)) 296 return 0; 297 298 if (dtimper == 1) { 299 if (bi > 100) 300 numerator = 408; 301 else 302 numerator = 510; 303 } else if (dtimper < 10) { 304 numerator = 612; 305 } else { 306 return 0; 307 } 308 return max(1, (numerator / dtim_interval)); 309} 310 311static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) 312{ 313 struct ieee80211_chanctx_conf *chanctx_conf; 314 struct ieee80211_channel *chan; 315 bool radar_detect = false; 316 317 rcu_read_lock(); 318 chanctx_conf = rcu_dereference(vif->chanctx_conf); 319 WARN_ON(!chanctx_conf); 320 if (chanctx_conf) { 321 chan = chanctx_conf->def.chan; 322 radar_detect = chan->flags & IEEE80211_CHAN_RADAR; 323 } 324 rcu_read_unlock(); 325 326 return radar_detect; 327} 328 329static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, 330 struct ieee80211_vif *vif, 331 struct iwl_mac_power_cmd *cmd) 332{ 333 int dtimper, bi; 334 int keep_alive; 335 bool radar_detect = false; 336 struct iwl_mvm_vif *mvmvif __maybe_unused = 337 iwl_mvm_vif_from_mac80211(vif); 338 339 cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, 340 mvmvif->color)); 341 dtimper = vif->bss_conf.dtim_period; 342 bi = vif->bss_conf.beacon_int; 343 344 /* 345 * Regardless of power management state the driver must set 346 * keep alive period. FW will use it for sending keep alive NDPs 347 * immediately after association. Check that keep alive period 348 * is at least 3 * DTIM 349 */ 350 keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi), 351 USEC_PER_SEC); 352 keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC); 353 cmd->keep_alive_seconds = cpu_to_le16(keep_alive); 354 355 if (mvm->ps_disabled) 356 return; 357 358 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); 359 360 if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || 361 !mvmvif->pm_enabled) 362 return; 363 364 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 365 366 if (vif->bss_conf.beacon_rate && 367 (vif->bss_conf.beacon_rate->bitrate == 10 || 368 vif->bss_conf.beacon_rate->bitrate == 60)) { 369 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); 370 cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; 371 } 372 373 /* Check if radar detection is required on current channel */ 374 radar_detect = iwl_mvm_power_is_radar(vif); 375 376 /* Check skip over DTIM conditions */ 377 if (!radar_detect && (dtimper < 10) && 378 (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || 379 mvm->cur_ucode == IWL_UCODE_WOWLAN)) { 380 cmd->skip_dtim_periods = 381 iwl_mvm_power_get_skip_over_dtim(dtimper, bi); 382 if (cmd->skip_dtim_periods) 383 cmd->flags |= 384 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); 385 } 386 387 if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { 388 cmd->rx_data_timeout = 389 cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); 390 cmd->tx_data_timeout = 391 cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); 392 } else { 393 cmd->rx_data_timeout = 394 cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); 395 cmd->tx_data_timeout = 396 cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); 397 } 398 399 if (iwl_mvm_power_allow_uapsd(mvm, vif)) 400 iwl_mvm_power_configure_uapsd(mvm, vif, cmd); 401 402#ifdef CONFIG_IWLWIFI_DEBUGFS 403 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) 404 cmd->keep_alive_seconds = 405 cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); 406 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { 407 if (mvmvif->dbgfs_pm.skip_over_dtim) 408 cmd->flags |= 409 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); 410 else 411 cmd->flags &= 412 cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); 413 } 414 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) 415 cmd->rx_data_timeout = 416 cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); 417 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) 418 cmd->tx_data_timeout = 419 cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); 420 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) 421 cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; 422 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { 423 if (mvmvif->dbgfs_pm.lprx_ena) 424 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); 425 else 426 cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); 427 } 428 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) 429 cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; 430 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) { 431 if (mvmvif->dbgfs_pm.snooze_ena) 432 cmd->flags |= 433 cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); 434 else 435 cmd->flags &= 436 cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK); 437 } 438 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) { 439 u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK; 440 if (mvmvif->dbgfs_pm.uapsd_misbehaving) 441 cmd->flags |= cpu_to_le16(flag); 442 else 443 cmd->flags &= cpu_to_le16(flag); 444 } 445#endif /* CONFIG_IWLWIFI_DEBUGFS */ 446} 447 448static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, 449 struct ieee80211_vif *vif) 450{ 451 struct iwl_mac_power_cmd cmd = {}; 452 453 iwl_mvm_power_build_cmd(mvm, vif, &cmd); 454 iwl_mvm_power_log(mvm, &cmd); 455#ifdef CONFIG_IWLWIFI_DEBUGFS 456 memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); 457#endif 458 459 return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0, 460 sizeof(cmd), &cmd); 461} 462 463int iwl_mvm_power_update_device(struct iwl_mvm *mvm) 464{ 465 struct iwl_device_power_cmd cmd = { 466 .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), 467 }; 468 469 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) 470 mvm->ps_disabled = true; 471 472 if (mvm->ps_disabled) 473 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); 474 475#ifdef CONFIG_IWLWIFI_DEBUGFS 476 if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : 477 mvm->disable_power_off) 478 cmd.flags &= 479 cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); 480#endif 481 IWL_DEBUG_POWER(mvm, 482 "Sending device power command with flags = 0x%X\n", 483 cmd.flags); 484 485 return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, 0, sizeof(cmd), 486 &cmd); 487} 488 489void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 490{ 491 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 492 493 if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid, 494 ETH_ALEN)) 495 eth_zero_addr(mvmvif->uapsd_misbehaving_bssid); 496} 497 498static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, 499 struct ieee80211_vif *vif) 500{ 501 u8 *ap_sta_id = _data; 502 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 503 504 /* The ap_sta_id is not expected to change during current association 505 * so no explicit protection is needed 506 */ 507 if (mvmvif->ap_sta_id == *ap_sta_id) 508 memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, 509 ETH_ALEN); 510} 511 512int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, 513 struct iwl_rx_cmd_buffer *rxb, 514 struct iwl_device_cmd *cmd) 515{ 516 struct iwl_rx_packet *pkt = rxb_addr(rxb); 517 struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data; 518 u8 ap_sta_id = le32_to_cpu(notif->sta_id); 519 520 ieee80211_iterate_active_interfaces_atomic( 521 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 522 iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id); 523 524 return 0; 525} 526 527struct iwl_power_vifs { 528 struct iwl_mvm *mvm; 529 struct ieee80211_vif *bf_vif; 530 struct ieee80211_vif *bss_vif; 531 struct ieee80211_vif *p2p_vif; 532 struct ieee80211_vif *ap_vif; 533 struct ieee80211_vif *monitor_vif; 534 bool p2p_active; 535 bool bss_active; 536 bool ap_active; 537 bool monitor_active; 538}; 539 540static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, 541 struct ieee80211_vif *vif) 542{ 543 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 544 545 mvmvif->pm_enabled = false; 546} 547 548static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac, 549 struct ieee80211_vif *vif) 550{ 551 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 552 bool *disable_ps = _data; 553 554 if (mvmvif->phy_ctxt) 555 if (mvmvif->phy_ctxt->id < MAX_PHYS) 556 *disable_ps |= mvmvif->ps_disabled; 557} 558 559static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, 560 struct ieee80211_vif *vif) 561{ 562 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 563 struct iwl_power_vifs *power_iterator = _data; 564 565 switch (ieee80211_vif_type_p2p(vif)) { 566 case NL80211_IFTYPE_P2P_DEVICE: 567 break; 568 569 case NL80211_IFTYPE_P2P_GO: 570 case NL80211_IFTYPE_AP: 571 /* only a single MAC of the same type */ 572 WARN_ON(power_iterator->ap_vif); 573 power_iterator->ap_vif = vif; 574 if (mvmvif->phy_ctxt) 575 if (mvmvif->phy_ctxt->id < MAX_PHYS) 576 power_iterator->ap_active = true; 577 break; 578 579 case NL80211_IFTYPE_MONITOR: 580 /* only a single MAC of the same type */ 581 WARN_ON(power_iterator->monitor_vif); 582 power_iterator->monitor_vif = vif; 583 if (mvmvif->phy_ctxt) 584 if (mvmvif->phy_ctxt->id < MAX_PHYS) 585 power_iterator->monitor_active = true; 586 break; 587 588 case NL80211_IFTYPE_P2P_CLIENT: 589 /* only a single MAC of the same type */ 590 WARN_ON(power_iterator->p2p_vif); 591 power_iterator->p2p_vif = vif; 592 if (mvmvif->phy_ctxt) 593 if (mvmvif->phy_ctxt->id < MAX_PHYS) 594 power_iterator->p2p_active = true; 595 break; 596 597 case NL80211_IFTYPE_STATION: 598 /* only a single MAC of the same type */ 599 WARN_ON(power_iterator->bss_vif); 600 power_iterator->bss_vif = vif; 601 if (mvmvif->phy_ctxt) 602 if (mvmvif->phy_ctxt->id < MAX_PHYS) 603 power_iterator->bss_active = true; 604 605 if (mvmvif->bf_data.bf_enabled && 606 !WARN_ON(power_iterator->bf_vif)) 607 power_iterator->bf_vif = vif; 608 609 break; 610 611 default: 612 break; 613 } 614} 615 616static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, 617 struct iwl_power_vifs *vifs) 618{ 619 struct iwl_mvm_vif *bss_mvmvif = NULL; 620 struct iwl_mvm_vif *p2p_mvmvif = NULL; 621 struct iwl_mvm_vif *ap_mvmvif = NULL; 622 bool client_same_channel = false; 623 bool ap_same_channel = false; 624 625 lockdep_assert_held(&mvm->mutex); 626 627 /* set pm_enable to false */ 628 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 629 IEEE80211_IFACE_ITER_NORMAL, 630 iwl_mvm_power_disable_pm_iterator, 631 NULL); 632 633 if (vifs->bss_vif) 634 bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif); 635 636 if (vifs->p2p_vif) 637 p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif); 638 639 if (vifs->ap_vif) 640 ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); 641 642 /* don't allow PM if any TDLS stations exist */ 643 if (iwl_mvm_tdls_sta_count(mvm, NULL)) 644 return; 645 646 /* enable PM on bss if bss stand alone */ 647 if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { 648 bss_mvmvif->pm_enabled = true; 649 return; 650 } 651 652 /* enable PM on p2p if p2p stand alone */ 653 if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { 654 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) 655 p2p_mvmvif->pm_enabled = true; 656 return; 657 } 658 659 if (vifs->bss_active && vifs->p2p_active) 660 client_same_channel = (bss_mvmvif->phy_ctxt->id == 661 p2p_mvmvif->phy_ctxt->id); 662 if (vifs->bss_active && vifs->ap_active) 663 ap_same_channel = (bss_mvmvif->phy_ctxt->id == 664 ap_mvmvif->phy_ctxt->id); 665 666 /* clients are not stand alone: enable PM if DCM */ 667 if (!(client_same_channel || ap_same_channel) && 668 (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) { 669 if (vifs->bss_active) 670 bss_mvmvif->pm_enabled = true; 671 if (vifs->p2p_active && 672 (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)) 673 p2p_mvmvif->pm_enabled = true; 674 return; 675 } 676 677 /* 678 * There is only one channel in the system and there are only 679 * bss and p2p clients that share it 680 */ 681 if (client_same_channel && !vifs->ap_active && 682 (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM)) { 683 /* share same channel*/ 684 bss_mvmvif->pm_enabled = true; 685 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) 686 p2p_mvmvif->pm_enabled = true; 687 } 688} 689 690#ifdef CONFIG_IWLWIFI_DEBUGFS 691int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, 692 struct ieee80211_vif *vif, char *buf, 693 int bufsz) 694{ 695 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 696 struct iwl_mac_power_cmd cmd = {}; 697 int pos = 0; 698 699 mutex_lock(&mvm->mutex); 700 memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd)); 701 mutex_unlock(&mvm->mutex); 702 703 pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", 704 iwlmvm_mod_params.power_scheme); 705 pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", 706 le16_to_cpu(cmd.flags)); 707 pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", 708 le16_to_cpu(cmd.keep_alive_seconds)); 709 710 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) 711 return pos; 712 713 pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", 714 (cmd.flags & 715 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0); 716 pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", 717 cmd.skip_dtim_periods); 718 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { 719 pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", 720 le32_to_cpu(cmd.rx_data_timeout)); 721 pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", 722 le32_to_cpu(cmd.tx_data_timeout)); 723 } 724 if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) 725 pos += scnprintf(buf+pos, bufsz-pos, 726 "lprx_rssi_threshold = %d\n", 727 cmd.lprx_rssi_threshold); 728 729 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) 730 return pos; 731 732 pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n", 733 le32_to_cpu(cmd.rx_data_timeout_uapsd)); 734 pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n", 735 le32_to_cpu(cmd.tx_data_timeout_uapsd)); 736 pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid); 737 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n", 738 cmd.uapsd_ac_flags); 739 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n", 740 cmd.uapsd_max_sp); 741 pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n", 742 cmd.heavy_tx_thld_packets); 743 pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n", 744 cmd.heavy_rx_thld_packets); 745 pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n", 746 cmd.heavy_tx_thld_percentage); 747 pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n", 748 cmd.heavy_rx_thld_percentage); 749 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n", 750 (cmd.flags & 751 cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ? 752 1 : 0); 753 754 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK))) 755 return pos; 756 757 pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n", 758 cmd.snooze_interval); 759 pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n", 760 cmd.snooze_window); 761 762 return pos; 763} 764 765void 766iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, 767 struct iwl_beacon_filter_cmd *cmd) 768{ 769 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 770 struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; 771 772 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) 773 cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta); 774 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) 775 cmd->bf_roaming_energy_delta = 776 cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta); 777 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) 778 cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state); 779 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD) 780 cmd->bf_temp_threshold = 781 cpu_to_le32(dbgfs_bf->bf_temp_threshold); 782 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER) 783 cmd->bf_temp_fast_filter = 784 cpu_to_le32(dbgfs_bf->bf_temp_fast_filter); 785 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER) 786 cmd->bf_temp_slow_filter = 787 cpu_to_le32(dbgfs_bf->bf_temp_slow_filter); 788 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) 789 cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag); 790 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) 791 cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); 792 if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) 793 cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); 794 if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) 795 cmd->ba_enable_beacon_abort = 796 cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort); 797} 798#endif 799 800static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, 801 struct ieee80211_vif *vif, 802 struct iwl_beacon_filter_cmd *cmd, 803 u32 cmd_flags, 804 bool d0i3) 805{ 806 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 807 int ret; 808 809 if (mvmvif != mvm->bf_allowed_vif || !vif->bss_conf.dtim_period || 810 vif->type != NL80211_IFTYPE_STATION || vif->p2p) 811 return 0; 812 813 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); 814 if (!d0i3) 815 iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); 816 ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); 817 818 /* don't change bf_enabled in case of temporary d0i3 configuration */ 819 if (!ret && !d0i3) 820 mvmvif->bf_data.bf_enabled = true; 821 822 return ret; 823} 824 825int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, 826 struct ieee80211_vif *vif, 827 u32 flags) 828{ 829 struct iwl_beacon_filter_cmd cmd = { 830 IWL_BF_CMD_CONFIG_DEFAULTS, 831 .bf_enable_beacon_filter = cpu_to_le32(1), 832 }; 833 834 return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false); 835} 836 837static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, 838 struct ieee80211_vif *vif, 839 bool enable) 840{ 841 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 842 struct iwl_beacon_filter_cmd cmd = { 843 IWL_BF_CMD_CONFIG_DEFAULTS, 844 .bf_enable_beacon_filter = cpu_to_le32(1), 845 }; 846 847 if (!mvmvif->bf_data.bf_enabled) 848 return 0; 849 850 if (mvm->cur_ucode == IWL_UCODE_WOWLAN) 851 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); 852 853 mvmvif->bf_data.ba_enabled = enable; 854 return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false); 855} 856 857int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, 858 struct ieee80211_vif *vif, 859 u32 flags) 860{ 861 struct iwl_beacon_filter_cmd cmd = {}; 862 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 863 int ret; 864 865 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) 866 return 0; 867 868 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); 869 870 if (!ret) 871 mvmvif->bf_data.bf_enabled = false; 872 873 return ret; 874} 875 876static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) 877{ 878 bool disable_ps; 879 int ret; 880 881 /* disable PS if CAM */ 882 disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); 883 /* ...or if any of the vifs require PS to be off */ 884 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 885 IEEE80211_IFACE_ITER_NORMAL, 886 iwl_mvm_power_ps_disabled_iterator, 887 &disable_ps); 888 889 /* update device power state if it has changed */ 890 if (mvm->ps_disabled != disable_ps) { 891 bool old_ps_disabled = mvm->ps_disabled; 892 893 mvm->ps_disabled = disable_ps; 894 ret = iwl_mvm_power_update_device(mvm); 895 if (ret) { 896 mvm->ps_disabled = old_ps_disabled; 897 return ret; 898 } 899 } 900 901 return 0; 902} 903 904static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, 905 struct iwl_power_vifs *vifs) 906{ 907 struct iwl_mvm_vif *mvmvif; 908 bool ba_enable; 909 910 if (!vifs->bf_vif) 911 return 0; 912 913 mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif); 914 915 ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || 916 !vifs->bf_vif->bss_conf.ps || 917 iwl_mvm_vif_low_latency(mvmvif)); 918 919 return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable); 920} 921 922int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) 923{ 924 struct iwl_power_vifs vifs = { 925 .mvm = mvm, 926 }; 927 int ret; 928 929 lockdep_assert_held(&mvm->mutex); 930 931 /* get vifs info */ 932 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 933 IEEE80211_IFACE_ITER_NORMAL, 934 iwl_mvm_power_get_vifs_iterator, &vifs); 935 936 ret = iwl_mvm_power_set_ps(mvm); 937 if (ret) 938 return ret; 939 940 return iwl_mvm_power_set_ba(mvm, &vifs); 941} 942 943int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) 944{ 945 struct iwl_power_vifs vifs = { 946 .mvm = mvm, 947 }; 948 int ret; 949 950 lockdep_assert_held(&mvm->mutex); 951 952 /* get vifs info */ 953 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 954 IEEE80211_IFACE_ITER_NORMAL, 955 iwl_mvm_power_get_vifs_iterator, &vifs); 956 957 iwl_mvm_power_set_pm(mvm, &vifs); 958 959 ret = iwl_mvm_power_set_ps(mvm); 960 if (ret) 961 return ret; 962 963 if (vifs.bss_vif) { 964 ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif); 965 if (ret) 966 return ret; 967 } 968 969 if (vifs.p2p_vif) { 970 ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif); 971 if (ret) 972 return ret; 973 } 974 975 return iwl_mvm_power_set_ba(mvm, &vifs); 976} 977 978int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, 979 struct ieee80211_vif *vif, 980 bool enable, u32 flags) 981{ 982 int ret; 983 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 984 struct iwl_mac_power_cmd cmd = {}; 985 986 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) 987 return 0; 988 989 if (!vif->bss_conf.assoc) 990 return 0; 991 992 iwl_mvm_power_build_cmd(mvm, vif, &cmd); 993 if (enable) { 994 /* configure skip over dtim up to 306TU - 314 msec */ 995 int dtimper = vif->bss_conf.dtim_period ?: 1; 996 int dtimper_tu = dtimper * vif->bss_conf.beacon_int; 997 bool radar_detect = iwl_mvm_power_is_radar(vif); 998 999 if (WARN_ON(!dtimper_tu)) 1000 return 0; 1001 1002 /* Check skip over DTIM conditions */ 1003 /* TODO: check that multicast wake lock is off */ 1004 if (!radar_detect && (dtimper < 10)) { 1005 cmd.skip_dtim_periods = 306 / dtimper_tu; 1006 if (cmd.skip_dtim_periods) 1007 cmd.flags |= cpu_to_le16( 1008 POWER_FLAGS_SKIP_OVER_DTIM_MSK); 1009 } 1010 } 1011 iwl_mvm_power_log(mvm, &cmd); 1012#ifdef CONFIG_IWLWIFI_DEBUGFS 1013 memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); 1014#endif 1015 ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, 1016 sizeof(cmd), &cmd); 1017 if (ret) 1018 return ret; 1019 1020 /* configure beacon filtering */ 1021 if (mvmvif != mvm->bf_allowed_vif) 1022 return 0; 1023 1024 if (enable) { 1025 struct iwl_beacon_filter_cmd cmd_bf = { 1026 IWL_BF_CMD_CONFIG_D0I3, 1027 .bf_enable_beacon_filter = cpu_to_le32(1), 1028 }; 1029 ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, 1030 flags, true); 1031 } else { 1032 if (mvmvif->bf_data.bf_enabled) 1033 ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags); 1034 else 1035 ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags); 1036 } 1037 1038 return ret; 1039} 1040