diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/power.c | 169 |
1 files changed, 99 insertions, 70 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5671b83e0ac4..4da1ea44f39a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -298,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, 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) + if (mvm->ps_disabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); @@ -309,8 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, mvmvif->dbgfs_pm.disable_power_off) cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif - if (!vif->bss_conf.ps || mvm->bound_vif_cnt > 1 || - iwl_mvm_vif_low_latency(mvmvif)) + if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || + mvm->pm_disabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -417,7 +416,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, #endif /* CONFIG_IWLWIFI_DEBUGFS */ } -static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, +static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; @@ -439,39 +438,22 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, sizeof(cmd), &cmd); } -int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) - -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool ba_enable; - int ret; - - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - ret = _iwl_mvm_power_mac_update_mode(mvm, vif); - if (ret) - return ret; - - ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - mvm->ps_prevented || mvm->bound_vif_cnt > 1 || - !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - - return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); -} - -static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) +int iwl_mvm_power_update_device(struct iwl_mvm *mvm) { struct iwl_device_power_cmd cmd = { .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return 0; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) return 0; - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - force_disable) + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) + mvm->ps_disabled = true; + + if (mvm->ps_disabled) cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -488,14 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) &cmd); } -int iwl_mvm_power_update_device(struct iwl_mvm *mvm) -{ - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - return _iwl_mvm_power_update_device(mvm, false); -} - void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -534,64 +508,119 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, return 0; } -struct iwl_mvm_power_iterator { - struct iwl_mvm *mvm; +struct iwl_power_constraint { struct ieee80211_vif *bf_vif; + struct ieee80211_vif *bss_vif; + bool pm_disabled; + bool ps_disabled; }; -static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_power_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_power_iterator *power_iterator = _data; - struct iwl_mvm *mvm = power_iterator->mvm; - int ret; + struct iwl_power_constraint *power_iterator = _data; + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_DEVICE: + break; + + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + /* no BSS power mgmt if we have an active AP */ + if (mvmvif->ap_ibss_active) + power_iterator->pm_disabled = true; + break; + + case NL80211_IFTYPE_MONITOR: + /* no BSS power mgmt and no device power save */ + power_iterator->pm_disabled = true; + power_iterator->ps_disabled = true; + break; + + case NL80211_IFTYPE_P2P_CLIENT: + /* no BSS power mgmt if we have a P2P client*/ + power_iterator->pm_disabled = true; + break; + + case NL80211_IFTYPE_STATION: + /* we should have only one BSS vif */ + WARN_ON(power_iterator->bss_vif); + power_iterator->bss_vif = vif; + + if (mvmvif->bf_data.bf_enabled && + !WARN_ON(power_iterator->bf_vif)) + power_iterator->bf_vif = vif; + break; + + default: + break; + } +} - ret = _iwl_mvm_power_mac_update_mode(mvm, vif); +static void +iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, + struct iwl_power_constraint *constraint) +{ + lockdep_assert_held(&mvm->mutex); + + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { + constraint->pm_disabled = true; + constraint->ps_disabled = true; + } - if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif)) - power_iterator->bf_vif = vif; + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_iterator, constraint); - WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); + /* TODO: remove this and determine this variable in the iterator */ + if (mvm->bound_vif_cnt > 1) + constraint->pm_disabled = true; } -void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, bool assign) +int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - bool ba_enable; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_power_iterator power_it = { - .mvm = mvm, - }; + struct iwl_power_constraint constraint = {}; + bool ba_enable; + int ret; lockdep_assert_held(&mvm->mutex); if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return; + return 0; + + iwl_mvm_power_get_global_constraint(mvm, &constraint); + mvm->ps_disabled = constraint.ps_disabled; + mvm->pm_disabled = constraint.pm_disabled; + /* don't update device power state unless we add / remove monitor */ if (vif->type == NL80211_IFTYPE_MONITOR) { - int ret = _iwl_mvm_power_update_device(mvm, assign); - mvm->ps_prevented = assign; - WARN_ONCE(ret, "Failed to update power device state\n"); + ret = iwl_mvm_power_update_device(mvm); + if (ret) + return ret; } - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_binding_iterator, - &power_it); + ret = iwl_mvm_power_send_cmd(mvm, vif); + if (ret) + return ret; - if (!power_it.bf_vif) - return; + if (constraint.bss_vif && vif != constraint.bss_vif) { + ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); + if (ret) + return ret; + } + + if (!constraint.bf_vif) + return 0; - vif = power_it.bf_vif; + vif = constraint.bf_vif; mvmvif = iwl_mvm_vif_from_mac80211(vif); - ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - mvm->ps_prevented || mvm->bound_vif_cnt > 1 || + ba_enable = !(constraint.pm_disabled || constraint.ps_disabled || !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - WARN_ON_ONCE(iwl_mvm_update_beacon_abort(mvm, power_it.bf_vif, - ba_enable)); + return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable); } #ifdef CONFIG_IWLWIFI_DEBUGFS |