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