The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/mvm/power.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation
    4  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
    5  * Copyright (C) 2015-2017 Intel Deutschland GmbH
    6  */
    7 #include <linux/kernel.h>
    8 #include <linux/module.h>
    9 #include <linux/slab.h>
   10 #include <linux/etherdevice.h>
   11 
   12 #include <net/mac80211.h>
   13 
   14 #include "iwl-debug.h"
   15 #include "mvm.h"
   16 #include "iwl-modparams.h"
   17 #include "fw/api/power.h"
   18 
   19 #define POWER_KEEP_ALIVE_PERIOD_SEC    25
   20 
   21 static
   22 int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
   23                                    struct iwl_beacon_filter_cmd *cmd,
   24                                    u32 flags)
   25 {
   26         u16 len;
   27 
   28         IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
   29                         le32_to_cpu(cmd->ba_enable_beacon_abort));
   30         IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
   31                         le32_to_cpu(cmd->ba_escape_timer));
   32         IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
   33                         le32_to_cpu(cmd->bf_debug_flag));
   34         IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
   35                         le32_to_cpu(cmd->bf_enable_beacon_filter));
   36         IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
   37                         le32_to_cpu(cmd->bf_energy_delta));
   38         IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
   39                         le32_to_cpu(cmd->bf_escape_timer));
   40         IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
   41                         le32_to_cpu(cmd->bf_roaming_energy_delta));
   42         IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
   43                         le32_to_cpu(cmd->bf_roaming_state));
   44         IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",
   45                         le32_to_cpu(cmd->bf_temp_threshold));
   46         IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",
   47                         le32_to_cpu(cmd->bf_temp_fast_filter));
   48         IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
   49                         le32_to_cpu(cmd->bf_temp_slow_filter));
   50         IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_low is: %d, %d\n",
   51                         le32_to_cpu(cmd->bf_threshold_absolute_low[0]),
   52                         le32_to_cpu(cmd->bf_threshold_absolute_low[1]));
   53 
   54         IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_high is: %d, %d\n",
   55                         le32_to_cpu(cmd->bf_threshold_absolute_high[0]),
   56                         le32_to_cpu(cmd->bf_threshold_absolute_high[1]));
   57 
   58         if (fw_has_api(&mvm->fw->ucode_capa,
   59                        IWL_UCODE_TLV_API_BEACON_FILTER_V4))
   60                 len = sizeof(struct iwl_beacon_filter_cmd);
   61         else
   62                 len = offsetof(struct iwl_beacon_filter_cmd,
   63                                bf_threshold_absolute_low);
   64 
   65         return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
   66                                     len, cmd);
   67 }
   68 
   69 static
   70 void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm,
   71                                           struct ieee80211_vif *vif,
   72                                           struct iwl_beacon_filter_cmd *cmd)
   73 {
   74         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
   75 
   76         if (vif->bss_conf.cqm_rssi_thold) {
   77                 cmd->bf_energy_delta =
   78                         cpu_to_le32(vif->bss_conf.cqm_rssi_hyst);
   79                 /* fw uses an absolute value for this */
   80                 cmd->bf_roaming_state =
   81                         cpu_to_le32(-vif->bss_conf.cqm_rssi_thold);
   82         }
   83         cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled);
   84 }
   85 
   86 static void iwl_mvm_power_log(struct iwl_mvm *mvm,
   87                               struct iwl_mac_power_cmd *cmd)
   88 {
   89         IWL_DEBUG_POWER(mvm,
   90                         "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
   91                         cmd->id_and_color, iwlmvm_mod_params.power_scheme,
   92                         le16_to_cpu(cmd->flags));
   93         IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
   94                         le16_to_cpu(cmd->keep_alive_seconds));
   95 
   96         if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) {
   97                 IWL_DEBUG_POWER(mvm, "Disable power management\n");
   98                 return;
   99         }
  100 
  101         IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
  102                         le32_to_cpu(cmd->rx_data_timeout));
  103         IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
  104                         le32_to_cpu(cmd->tx_data_timeout));
  105         if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))
  106                 IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",
  107                                 cmd->skip_dtim_periods);
  108         if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
  109                 IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
  110                                 cmd->lprx_rssi_threshold);
  111         if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
  112                 IWL_DEBUG_POWER(mvm, "uAPSD enabled\n");
  113                 IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
  114                                 le32_to_cpu(cmd->rx_data_timeout_uapsd));
  115                 IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n",
  116                                 le32_to_cpu(cmd->tx_data_timeout_uapsd));
  117                 IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid);
  118                 IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags);
  119                 IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp);
  120         }
  121 }
  122 
  123 static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
  124                                           struct ieee80211_vif *vif,
  125                                           struct iwl_mac_power_cmd *cmd)
  126 {
  127         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  128         enum ieee80211_ac_numbers ac;
  129         bool tid_found = false;
  130 
  131         if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ||
  132             cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
  133                 cmd->rx_data_timeout_uapsd =
  134                         cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
  135                 cmd->tx_data_timeout_uapsd =
  136                         cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
  137         } else {
  138                 cmd->rx_data_timeout_uapsd =
  139                         cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
  140                 cmd->tx_data_timeout_uapsd =
  141                         cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
  142         }
  143 
  144 #ifdef CONFIG_IWLWIFI_DEBUGFS
  145         /* set advanced pm flag with no uapsd ACs to enable ps-poll */
  146         if (mvmvif->dbgfs_pm.use_ps_poll) {
  147                 cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
  148                 return;
  149         }
  150 #endif
  151 
  152         for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
  153                 if (!mvmvif->queue_params[ac].uapsd)
  154                         continue;
  155 
  156                 if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))
  157                         cmd->flags |=
  158                                 cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
  159 
  160                 cmd->uapsd_ac_flags |= BIT(ac);
  161 
  162                 /* QNDP TID - the highest TID with no admission control */
  163                 if (!tid_found && !mvmvif->queue_params[ac].acm) {
  164                         tid_found = true;
  165                         switch (ac) {
  166                         case IEEE80211_AC_VO:
  167                                 cmd->qndp_tid = 6;
  168                                 break;
  169                         case IEEE80211_AC_VI:
  170                                 cmd->qndp_tid = 5;
  171                                 break;
  172                         case IEEE80211_AC_BE:
  173                                 cmd->qndp_tid = 0;
  174                                 break;
  175                         case IEEE80211_AC_BK:
  176                                 cmd->qndp_tid = 1;
  177                                 break;
  178                         }
  179                 }
  180         }
  181 
  182         cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
  183 
  184         if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
  185                                     BIT(IEEE80211_AC_VI) |
  186                                     BIT(IEEE80211_AC_BE) |
  187                                     BIT(IEEE80211_AC_BK))) {
  188                 cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
  189                 cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
  190                 cmd->snooze_window =
  191                         test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?
  192                                 cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
  193                                 cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
  194         }
  195 
  196         cmd->uapsd_max_sp = mvm->hw->uapsd_max_sp_len;
  197 
  198         if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
  199                 cmd->heavy_tx_thld_packets =
  200                         IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
  201                 cmd->heavy_rx_thld_packets =
  202                         IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
  203         } else {
  204                 cmd->heavy_tx_thld_packets =
  205                         IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
  206                 cmd->heavy_rx_thld_packets =
  207                         IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
  208         }
  209         cmd->heavy_tx_thld_percentage =
  210                 IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
  211         cmd->heavy_rx_thld_percentage =
  212                 IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
  213 }
  214 
  215 static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac,
  216                                             struct ieee80211_vif *vif)
  217 {
  218         bool *is_p2p_standalone = _data;
  219 
  220         switch (ieee80211_vif_type_p2p(vif)) {
  221         case NL80211_IFTYPE_P2P_GO:
  222         case NL80211_IFTYPE_AP:
  223                 *is_p2p_standalone = false;
  224                 break;
  225         case NL80211_IFTYPE_STATION:
  226                 if (vif->bss_conf.assoc)
  227                         *is_p2p_standalone = false;
  228                 break;
  229 
  230         default:
  231                 break;
  232         }
  233 }
  234 
  235 static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
  236                                        struct ieee80211_vif *vif)
  237 {
  238         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  239 
  240         if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
  241                     ETH_ALEN))
  242                 return false;
  243 
  244         /*
  245          * Avoid using uAPSD if P2P client is associated to GO that uses
  246          * opportunistic power save. This is due to current FW limitation.
  247          */
  248         if (vif->p2p &&
  249             (vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
  250             IEEE80211_P2P_OPPPS_ENABLE_BIT))
  251                 return false;
  252 
  253         /*
  254          * Avoid using uAPSD if client is in DCM -
  255          * low latency issue in Miracast
  256          */
  257         if (iwl_mvm_phy_ctx_count(mvm) >= 2)
  258                 return false;
  259 
  260         if (vif->p2p) {
  261                 /* Allow U-APSD only if p2p is stand alone */
  262                 bool is_p2p_standalone = true;
  263 
  264                 if (!iwl_mvm_is_p2p_scm_uapsd_supported(mvm))
  265                         return false;
  266 
  267                 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
  268                                         IEEE80211_IFACE_ITER_NORMAL,
  269                                         iwl_mvm_p2p_standalone_iterator,
  270                                         &is_p2p_standalone);
  271 
  272                 if (!is_p2p_standalone)
  273                         return false;
  274         }
  275 
  276         return true;
  277 }
  278 
  279 static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
  280 {
  281         struct ieee80211_chanctx_conf *chanctx_conf;
  282         struct ieee80211_channel *chan;
  283         bool radar_detect = false;
  284 
  285         rcu_read_lock();
  286         chanctx_conf = rcu_dereference(vif->chanctx_conf);
  287         WARN_ON(!chanctx_conf);
  288         if (chanctx_conf) {
  289                 chan = chanctx_conf->def.chan;
  290                 radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
  291         }
  292         rcu_read_unlock();
  293 
  294         return radar_detect;
  295 }
  296 
  297 static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
  298                                            struct ieee80211_vif *vif,
  299                                            struct iwl_mac_power_cmd *cmd)
  300 {
  301         int dtimper = vif->bss_conf.dtim_period ?: 1;
  302         int skip;
  303 
  304         /* disable, in case we're supposed to override */
  305         cmd->skip_dtim_periods = 0;
  306         cmd->flags &= ~cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
  307 
  308         if (iwl_mvm_power_is_radar(vif))
  309                 return;
  310 
  311         if (dtimper >= 10)
  312                 return;
  313 
  314         if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {
  315                 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP)
  316                         return;
  317                 skip = 2;
  318         } else {
  319                 int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
  320 
  321                 if (WARN_ON(!dtimper_tu))
  322                         return;
  323                 /* configure skip over dtim up to 306TU - 314 msec */
  324                 skip = max_t(u8, 1, 306 / dtimper_tu);
  325         }
  326 
  327         /* the firmware really expects "look at every X DTIMs", so add 1 */
  328         cmd->skip_dtim_periods = 1 + skip;
  329         cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
  330 }
  331 
  332 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
  333                                     struct ieee80211_vif *vif,
  334                                     struct iwl_mac_power_cmd *cmd)
  335 {
  336         int dtimper, bi;
  337         int keep_alive;
  338         struct iwl_mvm_vif *mvmvif __maybe_unused =
  339                 iwl_mvm_vif_from_mac80211(vif);
  340 
  341         cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
  342                                                             mvmvif->color));
  343         dtimper = vif->bss_conf.dtim_period;
  344         bi = vif->bss_conf.beacon_int;
  345 
  346         /*
  347          * Regardless of power management state the driver must set
  348          * keep alive period. FW will use it for sending keep alive NDPs
  349          * immediately after association. Check that keep alive period
  350          * is at least 3 * DTIM
  351          */
  352         keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi),
  353                                   USEC_PER_SEC);
  354         keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC);
  355         cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
  356 
  357         if (mvm->ps_disabled)
  358                 return;
  359 
  360         cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
  361 
  362         if (!vif->bss_conf.ps || !mvmvif->pm_enabled)
  363                 return;
  364 
  365         if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
  366             (!fw_has_capa(&mvm->fw->ucode_capa,
  367                          IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS) ||
  368              !IWL_MVM_P2P_LOWLATENCY_PS_ENABLE))
  369                 return;
  370 
  371         cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
  372 
  373         if (vif->bss_conf.beacon_rate &&
  374             (vif->bss_conf.beacon_rate->bitrate == 10 ||
  375              vif->bss_conf.beacon_rate->bitrate == 60)) {
  376                 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
  377                 cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD;
  378         }
  379 
  380         iwl_mvm_power_config_skip_dtim(mvm, vif, cmd);
  381 
  382         if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {
  383                 cmd->rx_data_timeout =
  384                         cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
  385                 cmd->tx_data_timeout =
  386                         cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
  387         } else if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
  388                    fw_has_capa(&mvm->fw->ucode_capa,
  389                                IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS)) {
  390                 cmd->tx_data_timeout =
  391                         cpu_to_le32(IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT);
  392                 cmd->rx_data_timeout =
  393                         cpu_to_le32(IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT);
  394         } else {
  395                 cmd->rx_data_timeout =
  396                         cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);
  397                 cmd->tx_data_timeout =
  398                         cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);
  399         }
  400 
  401         if (iwl_mvm_power_allow_uapsd(mvm, vif))
  402                 iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
  403 
  404 #ifdef CONFIG_IWLWIFI_DEBUGFS
  405         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
  406                 cmd->keep_alive_seconds =
  407                         cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds);
  408         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) {
  409                 if (mvmvif->dbgfs_pm.skip_over_dtim)
  410                         cmd->flags |=
  411                                 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
  412                 else
  413                         cmd->flags &=
  414                                 cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK);
  415         }
  416         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT)
  417                 cmd->rx_data_timeout =
  418                         cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout);
  419         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT)
  420                 cmd->tx_data_timeout =
  421                         cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout);
  422         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)
  423                 cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods;
  424         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) {
  425                 if (mvmvif->dbgfs_pm.lprx_ena)
  426                         cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
  427                 else
  428                         cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK);
  429         }
  430         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD)
  431                 cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold;
  432         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) {
  433                 if (mvmvif->dbgfs_pm.snooze_ena)
  434                         cmd->flags |=
  435                                 cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
  436                 else
  437                         cmd->flags &=
  438                                 cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);
  439         }
  440         if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {
  441                 u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;
  442                 if (mvmvif->dbgfs_pm.uapsd_misbehaving)
  443                         cmd->flags |= cpu_to_le16(flag);
  444                 else
  445                         cmd->flags &= cpu_to_le16(flag);
  446         }
  447 #endif /* CONFIG_IWLWIFI_DEBUGFS */
  448 }
  449 
  450 static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
  451                                          struct ieee80211_vif *vif)
  452 {
  453         struct iwl_mac_power_cmd cmd = {};
  454 
  455         iwl_mvm_power_build_cmd(mvm, vif, &cmd);
  456         iwl_mvm_power_log(mvm, &cmd);
  457 #ifdef CONFIG_IWLWIFI_DEBUGFS
  458         memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));
  459 #endif
  460 
  461         return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0,
  462                                     sizeof(cmd), &cmd);
  463 }
  464 
  465 int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
  466 {
  467         struct iwl_device_power_cmd cmd = {
  468                 .flags = 0,
  469         };
  470 
  471         if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
  472                 mvm->ps_disabled = true;
  473 
  474         if (!mvm->ps_disabled)
  475                 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
  476 
  477 #ifdef CONFIG_IWLWIFI_DEBUGFS
  478         if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?
  479                         mvm->disable_power_off_d3 : mvm->disable_power_off)
  480                 cmd.flags &=
  481                         cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
  482 #endif
  483         if (mvm->ext_clock_valid)
  484                 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK);
  485 
  486         IWL_DEBUG_POWER(mvm,
  487                         "Sending device power command with flags = 0x%X\n",
  488                         cmd.flags);
  489 
  490         return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, 0, sizeof(cmd),
  491                                     &cmd);
  492 }
  493 
  494 void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
  495 {
  496         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  497 
  498         if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
  499                    ETH_ALEN))
  500                 eth_zero_addr(mvmvif->uapsd_misbehaving_bssid);
  501 }
  502 
  503 static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
  504                                                      struct ieee80211_vif *vif)
  505 {
  506         u8 *ap_sta_id = _data;
  507         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  508 
  509         /* The ap_sta_id is not expected to change during current association
  510          * so no explicit protection is needed
  511          */
  512         if (mvmvif->ap_sta_id == *ap_sta_id)
  513                 memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
  514                        ETH_ALEN);
  515 }
  516 
  517 void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
  518                                               struct iwl_rx_cmd_buffer *rxb)
  519 {
  520         struct iwl_rx_packet *pkt = rxb_addr(rxb);
  521         struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
  522         u8 ap_sta_id = le32_to_cpu(notif->sta_id);
  523 
  524         ieee80211_iterate_active_interfaces_atomic(
  525                 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  526                 iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
  527 }
  528 
  529 struct iwl_power_vifs {
  530         struct iwl_mvm *mvm;
  531         struct ieee80211_vif *bss_vif;
  532         struct ieee80211_vif *p2p_vif;
  533         struct ieee80211_vif *ap_vif;
  534         struct ieee80211_vif *monitor_vif;
  535         bool p2p_active;
  536         bool bss_active;
  537         bool ap_active;
  538         bool monitor_active;
  539 };
  540 
  541 static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
  542                                               struct ieee80211_vif *vif)
  543 {
  544         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  545 
  546         mvmvif->pm_enabled = false;
  547 }
  548 
  549 static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
  550                                                struct ieee80211_vif *vif)
  551 {
  552         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  553         bool *disable_ps = _data;
  554 
  555         if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX)
  556                 *disable_ps |= mvmvif->ps_disabled;
  557 }
  558 
  559 static 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         bool active = mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX;
  565 
  566         switch (ieee80211_vif_type_p2p(vif)) {
  567         case NL80211_IFTYPE_P2P_DEVICE:
  568                 break;
  569 
  570         case NL80211_IFTYPE_P2P_GO:
  571         case NL80211_IFTYPE_AP:
  572                 /* only a single MAC of the same type */
  573                 WARN_ON(power_iterator->ap_vif);
  574                 power_iterator->ap_vif = vif;
  575                 if (active)
  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 (active)
  584                         power_iterator->monitor_active = true;
  585                 break;
  586 
  587         case NL80211_IFTYPE_P2P_CLIENT:
  588                 /* only a single MAC of the same type */
  589                 WARN_ON(power_iterator->p2p_vif);
  590                 power_iterator->p2p_vif = vif;
  591                 if (active)
  592                         power_iterator->p2p_active = true;
  593                 break;
  594 
  595         case NL80211_IFTYPE_STATION:
  596                 power_iterator->bss_vif = vif;
  597                 if (active)
  598                         power_iterator->bss_active = true;
  599                 break;
  600 
  601         default:
  602                 break;
  603         }
  604 }
  605 
  606 static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
  607                                  struct iwl_power_vifs *vifs)
  608 {
  609         struct iwl_mvm_vif *bss_mvmvif = NULL;
  610         struct iwl_mvm_vif *p2p_mvmvif = NULL;
  611         struct iwl_mvm_vif *ap_mvmvif = NULL;
  612         bool client_same_channel = false;
  613         bool ap_same_channel = false;
  614 
  615         lockdep_assert_held(&mvm->mutex);
  616 
  617         /* set pm_enable to false */
  618         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
  619                                         IEEE80211_IFACE_ITER_NORMAL,
  620                                         iwl_mvm_power_disable_pm_iterator,
  621                                         NULL);
  622 
  623         if (vifs->bss_vif)
  624                 bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
  625 
  626         if (vifs->p2p_vif)
  627                 p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif);
  628 
  629         if (vifs->ap_vif)
  630                 ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
  631 
  632         /* don't allow PM if any TDLS stations exist */
  633         if (iwl_mvm_tdls_sta_count(mvm, NULL))
  634                 return;
  635 
  636         /* enable PM on bss if bss stand alone */
  637         if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
  638                 bss_mvmvif->pm_enabled = true;
  639                 return;
  640         }
  641 
  642         /* enable PM on p2p if p2p stand alone */
  643         if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
  644                 p2p_mvmvif->pm_enabled = true;
  645                 return;
  646         }
  647 
  648         if (vifs->bss_active && vifs->p2p_active)
  649                 client_same_channel = (bss_mvmvif->phy_ctxt->id ==
  650                                        p2p_mvmvif->phy_ctxt->id);
  651         if (vifs->bss_active && vifs->ap_active)
  652                 ap_same_channel = (bss_mvmvif->phy_ctxt->id ==
  653                                    ap_mvmvif->phy_ctxt->id);
  654 
  655         /* clients are not stand alone: enable PM if DCM */
  656         if (!(client_same_channel || ap_same_channel)) {
  657                 if (vifs->bss_active)
  658                         bss_mvmvif->pm_enabled = true;
  659                 if (vifs->p2p_active)
  660                         p2p_mvmvif->pm_enabled = true;
  661                 return;
  662         }
  663 
  664         /*
  665          * There is only one channel in the system and there are only
  666          * bss and p2p clients that share it
  667          */
  668         if (client_same_channel && !vifs->ap_active) {
  669                 /* share same channel*/
  670                 bss_mvmvif->pm_enabled = true;
  671                 p2p_mvmvif->pm_enabled = true;
  672         }
  673 }
  674 
  675 #ifdef CONFIG_IWLWIFI_DEBUGFS
  676 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
  677                                  struct ieee80211_vif *vif, char *buf,
  678                                  int bufsz)
  679 {
  680         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  681         struct iwl_mac_power_cmd cmd = {};
  682         int pos = 0;
  683 
  684         mutex_lock(&mvm->mutex);
  685         memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));
  686         mutex_unlock(&mvm->mutex);
  687 
  688         pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
  689                          iwlmvm_mod_params.power_scheme);
  690         pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
  691                          le16_to_cpu(cmd.flags));
  692         pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
  693                          le16_to_cpu(cmd.keep_alive_seconds));
  694 
  695         if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
  696                 return pos;
  697 
  698         pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
  699                          (cmd.flags &
  700                          cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
  701         pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
  702                          cmd.skip_dtim_periods);
  703         if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
  704                 pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
  705                                  le32_to_cpu(cmd.rx_data_timeout));
  706                 pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
  707                                  le32_to_cpu(cmd.tx_data_timeout));
  708         }
  709         if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
  710                 pos += scnprintf(buf+pos, bufsz-pos,
  711                                  "lprx_rssi_threshold = %d\n",
  712                                  cmd.lprx_rssi_threshold);
  713 
  714         if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
  715                 return pos;
  716 
  717         pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
  718                          le32_to_cpu(cmd.rx_data_timeout_uapsd));
  719         pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
  720                          le32_to_cpu(cmd.tx_data_timeout_uapsd));
  721         pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
  722         pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
  723                          cmd.uapsd_ac_flags);
  724         pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
  725                          cmd.uapsd_max_sp);
  726         pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
  727                          cmd.heavy_tx_thld_packets);
  728         pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
  729                          cmd.heavy_rx_thld_packets);
  730         pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
  731                          cmd.heavy_tx_thld_percentage);
  732         pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
  733                          cmd.heavy_rx_thld_percentage);
  734         pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
  735                          (cmd.flags &
  736                           cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
  737                          1 : 0);
  738 
  739         if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
  740                 return pos;
  741 
  742         pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
  743                          cmd.snooze_interval);
  744         pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
  745                          cmd.snooze_window);
  746 
  747         return pos;
  748 }
  749 
  750 void
  751 iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
  752                                          struct iwl_beacon_filter_cmd *cmd)
  753 {
  754         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  755         struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
  756 
  757         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)
  758                 cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta);
  759         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)
  760                 cmd->bf_roaming_energy_delta =
  761                                 cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta);
  762         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)
  763                 cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state);
  764         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD)
  765                 cmd->bf_temp_threshold =
  766                                 cpu_to_le32(dbgfs_bf->bf_temp_threshold);
  767         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER)
  768                 cmd->bf_temp_fast_filter =
  769                                 cpu_to_le32(dbgfs_bf->bf_temp_fast_filter);
  770         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER)
  771                 cmd->bf_temp_slow_filter =
  772                                 cpu_to_le32(dbgfs_bf->bf_temp_slow_filter);
  773         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)
  774                 cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag);
  775         if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)
  776                 cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);
  777         if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)
  778                 cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);
  779         if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)
  780                 cmd->ba_enable_beacon_abort =
  781                                 cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort);
  782 }
  783 #endif
  784 
  785 static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
  786                                          struct ieee80211_vif *vif,
  787                                          struct iwl_beacon_filter_cmd *cmd,
  788                                          u32 cmd_flags)
  789 {
  790         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  791         int ret;
  792 
  793         if (mvmvif != mvm->bf_allowed_vif || !vif->bss_conf.dtim_period ||
  794             vif->type != NL80211_IFTYPE_STATION || vif->p2p)
  795                 return 0;
  796 
  797         iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);
  798         iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);
  799         ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags);
  800 
  801         if (!ret)
  802                 mvmvif->bf_data.bf_enabled = true;
  803 
  804         return ret;
  805 }
  806 
  807 int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
  808                                  struct ieee80211_vif *vif,
  809                                  u32 flags)
  810 {
  811         struct iwl_beacon_filter_cmd cmd = {
  812                 IWL_BF_CMD_CONFIG_DEFAULTS,
  813                 .bf_enable_beacon_filter = cpu_to_le32(1),
  814         };
  815 
  816         return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags);
  817 }
  818 
  819 static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
  820                                           struct ieee80211_vif *vif,
  821                                           u32 flags)
  822 {
  823         struct iwl_beacon_filter_cmd cmd = {};
  824         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  825         int ret;
  826 
  827         if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
  828                 return 0;
  829 
  830         ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
  831 
  832         if (!ret)
  833                 mvmvif->bf_data.bf_enabled = false;
  834 
  835         return ret;
  836 }
  837 
  838 int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
  839                                   struct ieee80211_vif *vif,
  840                                   u32 flags)
  841 {
  842         return _iwl_mvm_disable_beacon_filter(mvm, vif, flags);
  843 }
  844 
  845 static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
  846 {
  847         bool disable_ps;
  848         int ret;
  849 
  850         /* disable PS if CAM */
  851         disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
  852         /* ...or if any of the vifs require PS to be off */
  853         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
  854                                         IEEE80211_IFACE_ITER_NORMAL,
  855                                         iwl_mvm_power_ps_disabled_iterator,
  856                                         &disable_ps);
  857 
  858         /* update device power state if it has changed */
  859         if (mvm->ps_disabled != disable_ps) {
  860                 bool old_ps_disabled = mvm->ps_disabled;
  861 
  862                 mvm->ps_disabled = disable_ps;
  863                 ret = iwl_mvm_power_update_device(mvm);
  864                 if (ret) {
  865                         mvm->ps_disabled = old_ps_disabled;
  866                         return ret;
  867                 }
  868         }
  869 
  870         return 0;
  871 }
  872 
  873 static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
  874                                 struct ieee80211_vif *vif)
  875 {
  876         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  877         struct iwl_beacon_filter_cmd cmd = {
  878                 IWL_BF_CMD_CONFIG_DEFAULTS,
  879                 .bf_enable_beacon_filter = cpu_to_le32(1),
  880         };
  881 
  882         if (!mvmvif->bf_data.bf_enabled)
  883                 return 0;
  884 
  885         if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))
  886                 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
  887 
  888         mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled ||
  889                                        mvm->ps_disabled ||
  890                                        !vif->bss_conf.ps ||
  891                                        iwl_mvm_vif_low_latency(mvmvif));
  892 
  893         return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0);
  894 }
  895 
  896 int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
  897 {
  898         struct iwl_power_vifs vifs = {
  899                 .mvm = mvm,
  900         };
  901         int ret;
  902 
  903         lockdep_assert_held(&mvm->mutex);
  904 
  905         /* get vifs info */
  906         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
  907                                         IEEE80211_IFACE_ITER_NORMAL,
  908                                         iwl_mvm_power_get_vifs_iterator, &vifs);
  909 
  910         ret = iwl_mvm_power_set_ps(mvm);
  911         if (ret)
  912                 return ret;
  913 
  914         if (vifs.bss_vif)
  915                 return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
  916 
  917         return 0;
  918 }
  919 
  920 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
  921 {
  922         struct iwl_power_vifs vifs = {
  923                 .mvm = mvm,
  924         };
  925         int ret;
  926 
  927         lockdep_assert_held(&mvm->mutex);
  928 
  929         /* get vifs info */
  930         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
  931                                         IEEE80211_IFACE_ITER_NORMAL,
  932                                         iwl_mvm_power_get_vifs_iterator, &vifs);
  933 
  934         iwl_mvm_power_set_pm(mvm, &vifs);
  935 
  936         ret = iwl_mvm_power_set_ps(mvm);
  937         if (ret)
  938                 return ret;
  939 
  940         if (vifs.bss_vif) {
  941                 ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
  942                 if (ret)
  943                         return ret;
  944         }
  945 
  946         if (vifs.p2p_vif) {
  947                 ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif);
  948                 if (ret)
  949                         return ret;
  950         }
  951 
  952         if (vifs.bss_vif)
  953                 return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
  954 
  955         return 0;
  956 }

Cache object: 4cd030975100632ef66a3b5272c0cb5d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.