static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) { int dtimper, bi; int keep_alive; bool radar_detect = false; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); dtimper = vif->bss_conf.dtim_period; bi = vif->bss_conf.beacon_int; /* * Regardless of power management state the driver must set * keep alive period. FW will use it for sending keep alive NDPs * immediately after association. Check that keep alive period * is at least 3 * DTIM */ keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi), USEC_PER_SEC); keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC); cmd->keep_alive_seconds = cpu_to_le16(keep_alive); if (mvm->ps_disabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); if (vif->bss_conf.beacon_rate && (vif->bss_conf.beacon_rate->bitrate == 10 || vif->bss_conf.beacon_rate->bitrate == 60)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; } /* Check if radar detection is required on current channel */ radar_detect = iwl_mvm_power_is_radar(vif); /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper < 10) && (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || mvm->cur_ucode == IWL_UCODE_WOWLAN)) { cmd->skip_dtim_periods = iwl_mvm_power_get_skip_over_dtim(dtimper, bi); if (cmd->skip_dtim_periods) cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); } if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { cmd->rx_data_timeout = cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); cmd->tx_data_timeout = cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); } else { cmd->rx_data_timeout = cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); cmd->tx_data_timeout = cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); } if (iwl_mvm_power_allow_uapsd(mvm, vif)) iwl_mvm_power_configure_uapsd(mvm, vif, cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) cmd->keep_alive_seconds = cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { if (mvmvif->dbgfs_pm.skip_over_dtim) cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) cmd->rx_data_timeout = cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) cmd->tx_data_timeout = cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { if (mvmvif->dbgfs_pm.lprx_ena) cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) { if (mvmvif->dbgfs_pm.snooze_ena) cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) { u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK; if (mvmvif->dbgfs_pm.uapsd_misbehaving) cmd->flags |= cpu_to_le16(flag); else cmd->flags &= cpu_to_le16(flag); } #endif /* CONFIG_IWLWIFI_DEBUGFS */ }
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) { struct ieee80211_hw *hw = mvm->hw; struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *chan; int dtimper, dtimper_msec; int keep_alive; bool radar_detect = false; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); bool allow_uapsd = true; cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); dtimper = hw->conf.ps_dtim_period ?: 1; /* * Regardless of power management state the driver must set * keep alive period. FW will use it for sending keep alive NDPs * immediately after association. Check that keep alive period * is at least 3 * DTIM */ dtimper_msec = dtimper * vif->bss_conf.beacon_int; keep_alive = max_t(int, 3 * dtimper_msec, MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); cmd->keep_alive_seconds = cpu_to_le16(keep_alive); if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || mvm->ps_prevented) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); #ifdef CPTCFG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && mvmvif->dbgfs_pm.disable_power_off) cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif if (!vif->bss_conf.ps || mvmvif->pm_prevented || iwl_mvm_vif_low_latency(mvmvif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); if (vif->bss_conf.beacon_rate && (vif->bss_conf.beacon_rate->bitrate == 10 || vif->bss_conf.beacon_rate->bitrate == 60)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; } /* Check if radar detection is required on current channel */ rcu_read_lock(); chanctx_conf = rcu_dereference(vif->chanctx_conf); WARN_ON(!chanctx_conf); if (chanctx_conf) { chan = chanctx_conf->def.chan; radar_detect = chan->flags & IEEE80211_CHAN_RADAR; } rcu_read_unlock(); /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper <= 10) && (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || mvm->cur_ucode == IWL_UCODE_WOWLAN)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); cmd->skip_dtim_periods = 3; } if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { cmd->rx_data_timeout = cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); cmd->tx_data_timeout = cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); } else { cmd->rx_data_timeout = cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); cmd->tx_data_timeout = cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); } if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, ETH_ALEN)) allow_uapsd = false; if (vif->p2p && !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD)) allow_uapsd = false; /* * Avoid using uAPSD if P2P client is associated to GO that uses * opportunistic power save. This is due to current FW limitation. */ if (vif->p2p && vif->bss_conf.p2p_noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) allow_uapsd = false; if (allow_uapsd) iwl_mvm_power_configure_uapsd(mvm, vif, cmd); #ifdef CPTCFG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) cmd->keep_alive_seconds = cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { if (mvmvif->dbgfs_pm.skip_over_dtim) cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) cmd->rx_data_timeout = cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) cmd->tx_data_timeout = cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { if (mvmvif->dbgfs_pm.lprx_ena) cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) { if (mvmvif->dbgfs_pm.snooze_ena) cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); else cmd->flags &= cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) { u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK; if (mvmvif->dbgfs_pm.uapsd_misbehaving) cmd->flags |= cpu_to_le16(flag); else cmd->flags &= cpu_to_le16(flag); } #endif /* CPTCFG_IWLWIFI_DEBUGFS */ }