0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/etherdevice.h>
0011
0012 #include <net/mac80211.h>
0013
0014 #include "iwl-debug.h"
0015 #include "mvm.h"
0016 #include "iwl-modparams.h"
0017 #include "fw/api/power.h"
0018
0019 #define POWER_KEEP_ALIVE_PERIOD_SEC 25
0020
0021 static
0022 int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
0023 struct iwl_beacon_filter_cmd *cmd,
0024 u32 flags)
0025 {
0026 u16 len;
0027
0028 IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
0029 le32_to_cpu(cmd->ba_enable_beacon_abort));
0030 IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
0031 le32_to_cpu(cmd->ba_escape_timer));
0032 IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
0033 le32_to_cpu(cmd->bf_debug_flag));
0034 IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
0035 le32_to_cpu(cmd->bf_enable_beacon_filter));
0036 IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
0037 le32_to_cpu(cmd->bf_energy_delta));
0038 IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
0039 le32_to_cpu(cmd->bf_escape_timer));
0040 IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
0041 le32_to_cpu(cmd->bf_roaming_energy_delta));
0042 IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
0043 le32_to_cpu(cmd->bf_roaming_state));
0044 IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",
0045 le32_to_cpu(cmd->bf_temp_threshold));
0046 IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",
0047 le32_to_cpu(cmd->bf_temp_fast_filter));
0048 IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
0049 le32_to_cpu(cmd->bf_temp_slow_filter));
0050 IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_low is: %d, %d\n",
0051 le32_to_cpu(cmd->bf_threshold_absolute_low[0]),
0052 le32_to_cpu(cmd->bf_threshold_absolute_low[1]));
0053
0054 IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_high is: %d, %d\n",
0055 le32_to_cpu(cmd->bf_threshold_absolute_high[0]),
0056 le32_to_cpu(cmd->bf_threshold_absolute_high[1]));
0057
0058 if (fw_has_api(&mvm->fw->ucode_capa,
0059 IWL_UCODE_TLV_API_BEACON_FILTER_V4))
0060 len = sizeof(struct iwl_beacon_filter_cmd);
0061 else
0062 len = offsetof(struct iwl_beacon_filter_cmd,
0063 bf_threshold_absolute_low);
0064
0065 return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
0066 len, cmd);
0067 }
0068
0069 static
0070 void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm,
0071 struct ieee80211_vif *vif,
0072 struct iwl_beacon_filter_cmd *cmd)
0073 {
0074 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0075
0076 if (vif->bss_conf.cqm_rssi_thold) {
0077 cmd->bf_energy_delta =
0078 cpu_to_le32(vif->bss_conf.cqm_rssi_hyst);
0079
0080 cmd->bf_roaming_state =
0081 cpu_to_le32(-vif->bss_conf.cqm_rssi_thold);
0082 }
0083 cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled);
0084 }
0085
0086 static void iwl_mvm_power_log(struct iwl_mvm *mvm,
0087 struct iwl_mac_power_cmd *cmd)
0088 {
0089 IWL_DEBUG_POWER(mvm,
0090 "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
0091 cmd->id_and_color, iwlmvm_mod_params.power_scheme,
0092 le16_to_cpu(cmd->flags));
0093 IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
0094 le16_to_cpu(cmd->keep_alive_seconds));
0095
0096 if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) {
0097 IWL_DEBUG_POWER(mvm, "Disable power management\n");
0098 return;
0099 }
0100
0101 IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
0102 le32_to_cpu(cmd->rx_data_timeout));
0103 IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
0104 le32_to_cpu(cmd->tx_data_timeout));
0105 if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))
0106 IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",
0107 cmd->skip_dtim_periods);
0108 if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
0109 IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
0110 cmd->lprx_rssi_threshold);
0111 if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
0112 IWL_DEBUG_POWER(mvm, "uAPSD enabled\n");
0113 IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
0114 le32_to_cpu(cmd->rx_data_timeout_uapsd));
0115 IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n",
0116 le32_to_cpu(cmd->tx_data_timeout_uapsd));
0117 IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid);
0118 IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags);
0119 IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp);
0120 }
0121 }
0122
0123 static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
0124 struct ieee80211_vif *vif,
0125 struct iwl_mac_power_cmd *cmd)
0126 {
0127 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0128 enum ieee80211_ac_numbers ac;
0129 bool tid_found = false;
0130
0131 if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ||
0132 cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
0133 cmd->rx_data_timeout_uapsd =
0134 cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
0135 cmd->tx_data_timeout_uapsd =
0136 cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
0137 } else {
0138 cmd->rx_data_timeout_uapsd =
0139 cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
0140 cmd->tx_data_timeout_uapsd =
0141 cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
0142 }
0143
0144 #ifdef CONFIG_IWLWIFI_DEBUGFS
0145
0146 if (mvmvif->dbgfs_pm.use_ps_poll) {
0147 cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
0148 return;
0149 }
0150 #endif
0151
0152 for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
0153 if (!mvmvif->queue_params[ac].uapsd)
0154 continue;
0155
0156 if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))
0157 cmd->flags |=
0158 cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
0159
0160 cmd->uapsd_ac_flags |= BIT(ac);
0161
0162
0163 if (!tid_found && !mvmvif->queue_params[ac].acm) {
0164 tid_found = true;
0165 switch (ac) {
0166 case IEEE80211_AC_VO:
0167 cmd->qndp_tid = 6;
0168 break;
0169 case IEEE80211_AC_VI:
0170 cmd->qndp_tid = 5;
0171 break;
0172 case IEEE80211_AC_BE:
0173 cmd->qndp_tid = 0;
0174 break;
0175 case IEEE80211_AC_BK:
0176 cmd->qndp_tid = 1;
0177 break;
0178 }
0179 }
0180 }
0181
0182 cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
0183
0184 if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
0185 BIT(IEEE80211_AC_VI) |
0186 BIT(IEEE80211_AC_BE) |
0187 BIT(IEEE80211_AC_BK))) {
0188 cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
0189 cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
0190 cmd->snooze_window =
0191 test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?
0192 cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
0193 cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
0194 }
0195
0196 cmd->uapsd_max_sp = mvm->hw->uapsd_max_sp_len;
0197
0198 if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
0199 cmd->heavy_tx_thld_packets =
0200 IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
0201 cmd->heavy_rx_thld_packets =
0202 IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
0203 } else {
0204 cmd->heavy_tx_thld_packets =
0205 IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
0206 cmd->heavy_rx_thld_packets =
0207 IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
0208 }
0209 cmd->heavy_tx_thld_percentage =
0210 IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
0211 cmd->heavy_rx_thld_percentage =
0212 IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
0213 }
0214
0215 static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac,
0216 struct ieee80211_vif *vif)
0217 {
0218 bool *is_p2p_standalone = _data;
0219
0220 switch (ieee80211_vif_type_p2p(vif)) {
0221 case NL80211_IFTYPE_P2P_GO:
0222 case NL80211_IFTYPE_AP:
0223 *is_p2p_standalone = false;
0224 break;
0225 case NL80211_IFTYPE_STATION:
0226 if (vif->cfg.assoc)
0227 *is_p2p_standalone = false;
0228 break;
0229
0230 default:
0231 break;
0232 }
0233 }
0234
0235 static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
0236 struct ieee80211_vif *vif)
0237 {
0238 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0239
0240 if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
0241 ETH_ALEN))
0242 return false;
0243
0244
0245
0246
0247
0248 if (vif->p2p &&
0249 (vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
0250 IEEE80211_P2P_OPPPS_ENABLE_BIT))
0251 return false;
0252
0253
0254
0255
0256
0257 if (iwl_mvm_phy_ctx_count(mvm) >= 2)
0258 return false;
0259
0260 if (vif->p2p) {
0261
0262 bool is_p2p_standalone = true;
0263
0264 if (!iwl_mvm_is_p2p_scm_uapsd_supported(mvm))
0265 return false;
0266
0267 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0268 IEEE80211_IFACE_ITER_NORMAL,
0269 iwl_mvm_p2p_standalone_iterator,
0270 &is_p2p_standalone);
0271
0272 if (!is_p2p_standalone)
0273 return false;
0274 }
0275
0276 return true;
0277 }
0278
0279 static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
0280 {
0281 struct ieee80211_chanctx_conf *chanctx_conf;
0282 struct ieee80211_channel *chan;
0283 bool radar_detect = false;
0284
0285 rcu_read_lock();
0286 chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
0287 WARN_ON(!chanctx_conf);
0288 if (chanctx_conf) {
0289 chan = chanctx_conf->def.chan;
0290 radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
0291 }
0292 rcu_read_unlock();
0293
0294 return radar_detect;
0295 }
0296
0297 static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
0298 struct ieee80211_vif *vif,
0299 struct iwl_mac_power_cmd *cmd)
0300 {
0301 int dtimper = vif->bss_conf.dtim_period ?: 1;
0302 int skip;
0303
0304
0305 cmd->skip_dtim_periods = 0;
0306 cmd->flags &= ~cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
0307
0308 if (iwl_mvm_power_is_radar(vif))
0309 return;
0310
0311 if (dtimper >= 10)
0312 return;
0313
0314 if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {
0315 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP)
0316 return;
0317 skip = 2;
0318 } else {
0319 int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
0320
0321 if (WARN_ON(!dtimper_tu))
0322 return;
0323
0324 skip = max_t(u8, 1, 306 / dtimper_tu);
0325 }
0326
0327
0328 cmd->skip_dtim_periods = 1 + skip;
0329 cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
0330 }
0331
0332 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
0333 struct ieee80211_vif *vif,
0334 struct iwl_mac_power_cmd *cmd)
0335 {
0336 int dtimper, bi;
0337 int keep_alive;
0338 struct iwl_mvm_vif *mvmvif __maybe_unused =
0339 iwl_mvm_vif_from_mac80211(vif);
0340
0341 cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
0342 mvmvif->color));
0343 dtimper = vif->bss_conf.dtim_period;
0344 bi = vif->bss_conf.beacon_int;
0345
0346
0347
0348
0349
0350
0351
0352 keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi),
0353 USEC_PER_SEC);
0354 keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC);
0355 cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
0356
0357 if (mvm->ps_disabled)
0358 return;
0359
0360 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
0361
0362 if (!vif->cfg.ps || !mvmvif->pm_enabled)
0363 return;
0364
0365 if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
0366 (!fw_has_capa(&mvm->fw->ucode_capa,
0367 IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS) ||
0368 !IWL_MVM_P2P_LOWLATENCY_PS_ENABLE))
0369 return;
0370
0371 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
0372
0373 if (vif->bss_conf.beacon_rate &&
0374 (vif->bss_conf.beacon_rate->bitrate == 10 ||
0375 vif->bss_conf.beacon_rate->bitrate == 60)) {
0376 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
0377 cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD;
0378 }
0379
0380 iwl_mvm_power_config_skip_dtim(mvm, vif, cmd);
0381
0382 if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {
0383 cmd->rx_data_timeout =
0384 cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
0385 cmd->tx_data_timeout =
0386 cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
0387 } else if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
0388 fw_has_capa(&mvm->fw->ucode_capa,
0389 IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS)) {
0390 cmd->tx_data_timeout =
0391 cpu_to_le32(IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT);
0392 cmd->rx_data_timeout =
0393 cpu_to_le32(IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT);
0394 } else {
0395 cmd->rx_data_timeout =
0396 cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);
0397 cmd->tx_data_timeout =
0398 cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);
0399 }
0400
0401 if (iwl_mvm_power_allow_uapsd(mvm, vif))
0402 iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
0403
0404 #ifdef CONFIG_IWLWIFI_DEBUGFS
0405 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
0406 cmd->keep_alive_seconds =
0407 cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds);
0408 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) {
0409 if (mvmvif->dbgfs_pm.skip_over_dtim)
0410 cmd->flags |=
0411 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
0412 else
0413 cmd->flags &=
0414 cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK);
0415 }
0416 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT)
0417 cmd->rx_data_timeout =
0418 cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout);
0419 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT)
0420 cmd->tx_data_timeout =
0421 cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout);
0422 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)
0423 cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods;
0424 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) {
0425 if (mvmvif->dbgfs_pm.lprx_ena)
0426 cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
0427 else
0428 cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK);
0429 }
0430 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD)
0431 cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold;
0432 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) {
0433 if (mvmvif->dbgfs_pm.snooze_ena)
0434 cmd->flags |=
0435 cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
0436 else
0437 cmd->flags &=
0438 cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);
0439 }
0440 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {
0441 u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;
0442 if (mvmvif->dbgfs_pm.uapsd_misbehaving)
0443 cmd->flags |= cpu_to_le16(flag);
0444 else
0445 cmd->flags &= cpu_to_le16(flag);
0446 }
0447 #endif
0448 }
0449
0450 static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
0451 struct ieee80211_vif *vif)
0452 {
0453 struct iwl_mac_power_cmd cmd = {};
0454
0455 iwl_mvm_power_build_cmd(mvm, vif, &cmd);
0456 iwl_mvm_power_log(mvm, &cmd);
0457 #ifdef CONFIG_IWLWIFI_DEBUGFS
0458 memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));
0459 #endif
0460
0461 return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0,
0462 sizeof(cmd), &cmd);
0463 }
0464
0465 int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
0466 {
0467 struct iwl_device_power_cmd cmd = {
0468 .flags = 0,
0469 };
0470
0471 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
0472 mvm->ps_disabled = true;
0473
0474 if (!mvm->ps_disabled)
0475 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
0476
0477 #ifdef CONFIG_IWLWIFI_DEBUGFS
0478 if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ?
0479 mvm->disable_power_off_d3 : mvm->disable_power_off)
0480 cmd.flags &=
0481 cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
0482 #endif
0483 if (mvm->ext_clock_valid)
0484 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK);
0485
0486 IWL_DEBUG_POWER(mvm,
0487 "Sending device power command with flags = 0x%X\n",
0488 cmd.flags);
0489
0490 return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, 0, sizeof(cmd),
0491 &cmd);
0492 }
0493
0494 void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0495 {
0496 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0497
0498 if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
0499 ETH_ALEN))
0500 eth_zero_addr(mvmvif->uapsd_misbehaving_bssid);
0501 }
0502
0503 static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
0504 struct ieee80211_vif *vif)
0505 {
0506 u8 *ap_sta_id = _data;
0507 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0508
0509
0510
0511
0512 if (mvmvif->ap_sta_id == *ap_sta_id)
0513 memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
0514 ETH_ALEN);
0515 }
0516
0517 void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
0518 struct iwl_rx_cmd_buffer *rxb)
0519 {
0520 struct iwl_rx_packet *pkt = rxb_addr(rxb);
0521 struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
0522 u8 ap_sta_id = le32_to_cpu(notif->sta_id);
0523
0524 ieee80211_iterate_active_interfaces_atomic(
0525 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
0526 iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
0527 }
0528
0529 struct iwl_power_vifs {
0530 struct iwl_mvm *mvm;
0531 struct ieee80211_vif *bss_vif;
0532 struct ieee80211_vif *p2p_vif;
0533 struct ieee80211_vif *ap_vif;
0534 struct ieee80211_vif *monitor_vif;
0535 bool p2p_active;
0536 bool bss_active;
0537 bool ap_active;
0538 bool monitor_active;
0539 };
0540
0541 static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
0542 struct ieee80211_vif *vif)
0543 {
0544 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0545
0546 mvmvif->pm_enabled = false;
0547 }
0548
0549 static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
0550 struct ieee80211_vif *vif)
0551 {
0552 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0553 bool *disable_ps = _data;
0554
0555 if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX)
0556 *disable_ps |= mvmvif->ps_disabled;
0557 }
0558
0559 static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
0560 struct ieee80211_vif *vif)
0561 {
0562 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0563 struct iwl_power_vifs *power_iterator = _data;
0564 bool active = mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX;
0565
0566 if (!mvmvif->uploaded)
0567 return;
0568
0569 switch (ieee80211_vif_type_p2p(vif)) {
0570 case NL80211_IFTYPE_P2P_DEVICE:
0571 break;
0572
0573 case NL80211_IFTYPE_P2P_GO:
0574 case NL80211_IFTYPE_AP:
0575
0576 WARN_ON(power_iterator->ap_vif);
0577 power_iterator->ap_vif = vif;
0578 if (active)
0579 power_iterator->ap_active = true;
0580 break;
0581
0582 case NL80211_IFTYPE_MONITOR:
0583
0584 WARN_ON(power_iterator->monitor_vif);
0585 power_iterator->monitor_vif = vif;
0586 if (active)
0587 power_iterator->monitor_active = true;
0588 break;
0589
0590 case NL80211_IFTYPE_P2P_CLIENT:
0591
0592 WARN_ON(power_iterator->p2p_vif);
0593 power_iterator->p2p_vif = vif;
0594 if (active)
0595 power_iterator->p2p_active = true;
0596 break;
0597
0598 case NL80211_IFTYPE_STATION:
0599 power_iterator->bss_vif = vif;
0600 if (active)
0601 power_iterator->bss_active = true;
0602 break;
0603
0604 default:
0605 break;
0606 }
0607 }
0608
0609 static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
0610 struct iwl_power_vifs *vifs)
0611 {
0612 struct iwl_mvm_vif *bss_mvmvif = NULL;
0613 struct iwl_mvm_vif *p2p_mvmvif = NULL;
0614 struct iwl_mvm_vif *ap_mvmvif = NULL;
0615 bool client_same_channel = false;
0616 bool ap_same_channel = false;
0617
0618 lockdep_assert_held(&mvm->mutex);
0619
0620
0621 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0622 IEEE80211_IFACE_ITER_NORMAL,
0623 iwl_mvm_power_disable_pm_iterator,
0624 NULL);
0625
0626 if (vifs->bss_vif)
0627 bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
0628
0629 if (vifs->p2p_vif)
0630 p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif);
0631
0632 if (vifs->ap_vif)
0633 ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
0634
0635
0636 if (iwl_mvm_tdls_sta_count(mvm, NULL))
0637 return;
0638
0639
0640 if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
0641 bss_mvmvif->pm_enabled = true;
0642 return;
0643 }
0644
0645
0646 if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
0647 p2p_mvmvif->pm_enabled = true;
0648 return;
0649 }
0650
0651 if (vifs->bss_active && vifs->p2p_active)
0652 client_same_channel = (bss_mvmvif->phy_ctxt->id ==
0653 p2p_mvmvif->phy_ctxt->id);
0654 if (vifs->bss_active && vifs->ap_active)
0655 ap_same_channel = (bss_mvmvif->phy_ctxt->id ==
0656 ap_mvmvif->phy_ctxt->id);
0657
0658
0659 if (!(client_same_channel || ap_same_channel)) {
0660 if (vifs->bss_active)
0661 bss_mvmvif->pm_enabled = true;
0662 if (vifs->p2p_active)
0663 p2p_mvmvif->pm_enabled = true;
0664 return;
0665 }
0666
0667
0668
0669
0670
0671 if (client_same_channel && !vifs->ap_active) {
0672
0673 bss_mvmvif->pm_enabled = true;
0674 p2p_mvmvif->pm_enabled = true;
0675 }
0676 }
0677
0678 #ifdef CONFIG_IWLWIFI_DEBUGFS
0679 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
0680 struct ieee80211_vif *vif, char *buf,
0681 int bufsz)
0682 {
0683 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0684 struct iwl_mac_power_cmd cmd = {};
0685 int pos = 0;
0686
0687 mutex_lock(&mvm->mutex);
0688 memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));
0689 mutex_unlock(&mvm->mutex);
0690
0691 pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
0692 iwlmvm_mod_params.power_scheme);
0693 pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
0694 le16_to_cpu(cmd.flags));
0695 pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
0696 le16_to_cpu(cmd.keep_alive_seconds));
0697
0698 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
0699 return pos;
0700
0701 pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
0702 (cmd.flags &
0703 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
0704 pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
0705 cmd.skip_dtim_periods);
0706 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
0707 pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
0708 le32_to_cpu(cmd.rx_data_timeout));
0709 pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
0710 le32_to_cpu(cmd.tx_data_timeout));
0711 }
0712 if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
0713 pos += scnprintf(buf+pos, bufsz-pos,
0714 "lprx_rssi_threshold = %d\n",
0715 cmd.lprx_rssi_threshold);
0716
0717 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
0718 return pos;
0719
0720 pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
0721 le32_to_cpu(cmd.rx_data_timeout_uapsd));
0722 pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
0723 le32_to_cpu(cmd.tx_data_timeout_uapsd));
0724 pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
0725 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
0726 cmd.uapsd_ac_flags);
0727 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
0728 cmd.uapsd_max_sp);
0729 pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
0730 cmd.heavy_tx_thld_packets);
0731 pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
0732 cmd.heavy_rx_thld_packets);
0733 pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
0734 cmd.heavy_tx_thld_percentage);
0735 pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
0736 cmd.heavy_rx_thld_percentage);
0737 pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
0738 (cmd.flags &
0739 cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
0740 1 : 0);
0741
0742 if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
0743 return pos;
0744
0745 pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
0746 cmd.snooze_interval);
0747 pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
0748 cmd.snooze_window);
0749
0750 return pos;
0751 }
0752
0753 void
0754 iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
0755 struct iwl_beacon_filter_cmd *cmd)
0756 {
0757 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0758 struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
0759
0760 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)
0761 cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta);
0762 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)
0763 cmd->bf_roaming_energy_delta =
0764 cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta);
0765 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)
0766 cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state);
0767 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD)
0768 cmd->bf_temp_threshold =
0769 cpu_to_le32(dbgfs_bf->bf_temp_threshold);
0770 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER)
0771 cmd->bf_temp_fast_filter =
0772 cpu_to_le32(dbgfs_bf->bf_temp_fast_filter);
0773 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER)
0774 cmd->bf_temp_slow_filter =
0775 cpu_to_le32(dbgfs_bf->bf_temp_slow_filter);
0776 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)
0777 cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag);
0778 if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)
0779 cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);
0780 if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)
0781 cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);
0782 if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)
0783 cmd->ba_enable_beacon_abort =
0784 cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort);
0785 }
0786 #endif
0787
0788 static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
0789 struct ieee80211_vif *vif,
0790 struct iwl_beacon_filter_cmd *cmd,
0791 u32 cmd_flags)
0792 {
0793 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0794 int ret;
0795
0796 if (mvmvif != mvm->bf_allowed_vif || !vif->bss_conf.dtim_period ||
0797 vif->type != NL80211_IFTYPE_STATION || vif->p2p)
0798 return 0;
0799
0800 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);
0801 iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);
0802 ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags);
0803
0804 if (!ret)
0805 mvmvif->bf_data.bf_enabled = true;
0806
0807 return ret;
0808 }
0809
0810 int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
0811 struct ieee80211_vif *vif,
0812 u32 flags)
0813 {
0814 struct iwl_beacon_filter_cmd cmd = {
0815 IWL_BF_CMD_CONFIG_DEFAULTS,
0816 .bf_enable_beacon_filter = cpu_to_le32(1),
0817 };
0818
0819 return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags);
0820 }
0821
0822 static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
0823 struct ieee80211_vif *vif,
0824 u32 flags)
0825 {
0826 struct iwl_beacon_filter_cmd cmd = {};
0827 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0828 int ret;
0829
0830 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
0831 return 0;
0832
0833 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
0834
0835 if (!ret)
0836 mvmvif->bf_data.bf_enabled = false;
0837
0838 return ret;
0839 }
0840
0841 int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
0842 struct ieee80211_vif *vif,
0843 u32 flags)
0844 {
0845 return _iwl_mvm_disable_beacon_filter(mvm, vif, flags);
0846 }
0847
0848 static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
0849 {
0850 bool disable_ps;
0851 int ret;
0852
0853
0854 disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
0855
0856 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0857 IEEE80211_IFACE_ITER_NORMAL,
0858 iwl_mvm_power_ps_disabled_iterator,
0859 &disable_ps);
0860
0861
0862 if (mvm->ps_disabled != disable_ps) {
0863 bool old_ps_disabled = mvm->ps_disabled;
0864
0865 mvm->ps_disabled = disable_ps;
0866 ret = iwl_mvm_power_update_device(mvm);
0867 if (ret) {
0868 mvm->ps_disabled = old_ps_disabled;
0869 return ret;
0870 }
0871 }
0872
0873 return 0;
0874 }
0875
0876 static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
0877 struct ieee80211_vif *vif)
0878 {
0879 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0880 struct iwl_beacon_filter_cmd cmd = {
0881 IWL_BF_CMD_CONFIG_DEFAULTS,
0882 .bf_enable_beacon_filter = cpu_to_le32(1),
0883 };
0884
0885 if (!mvmvif->bf_data.bf_enabled)
0886 return 0;
0887
0888 if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))
0889 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
0890
0891 mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled ||
0892 mvm->ps_disabled ||
0893 !vif->cfg.ps ||
0894 iwl_mvm_vif_low_latency(mvmvif));
0895
0896 return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0);
0897 }
0898
0899 int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
0900 {
0901 struct iwl_power_vifs vifs = {
0902 .mvm = mvm,
0903 };
0904 int ret;
0905
0906 lockdep_assert_held(&mvm->mutex);
0907
0908
0909 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0910 IEEE80211_IFACE_ITER_NORMAL,
0911 iwl_mvm_power_get_vifs_iterator, &vifs);
0912
0913 ret = iwl_mvm_power_set_ps(mvm);
0914 if (ret)
0915 return ret;
0916
0917 if (vifs.bss_vif)
0918 return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
0919
0920 return 0;
0921 }
0922
0923 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
0924 {
0925 struct iwl_power_vifs vifs = {
0926 .mvm = mvm,
0927 };
0928 int ret;
0929
0930 lockdep_assert_held(&mvm->mutex);
0931
0932
0933 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0934 IEEE80211_IFACE_ITER_NORMAL,
0935 iwl_mvm_power_get_vifs_iterator, &vifs);
0936
0937 iwl_mvm_power_set_pm(mvm, &vifs);
0938
0939 ret = iwl_mvm_power_set_ps(mvm);
0940 if (ret)
0941 return ret;
0942
0943 if (vifs.bss_vif) {
0944 ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
0945 if (ret)
0946 return ret;
0947 }
0948
0949 if (vifs.p2p_vif) {
0950 ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif);
0951 if (ret)
0952 return ret;
0953 }
0954
0955 if (vifs.bss_vif)
0956 return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
0957
0958 return 0;
0959 }