Commit e5e7aa8e authored by Emmanuel Grumbach's avatar Emmanuel Grumbach

iwlwifi: mvm: refactor power code

The main complexity of the power code is that it needs to
take into account the firmware limitations.
These limitations state that we need to have a global
picture of the vifs present in the system to be able to
decide if we can enable power management on a specific vif.

Even device power save (as opposed to vif power management)
must be disabled in certain circumstances (monitor vif).

Refactor the current code to make this clearer by defining
a function that explicitely computes these constraints.
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 6345061f
...@@ -1195,7 +1195,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, ...@@ -1195,7 +1195,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if (ret) if (ret)
goto out; goto out;
ret = iwl_mvm_power_mac_update_mode(mvm, vif); ret = iwl_mvm_power_update_mac(mvm, vif);
if (ret) if (ret)
goto out; goto out;
......
...@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, ...@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
iwl_dbgfs_update_pm(mvm, vif, param, val); iwl_dbgfs_update_pm(mvm, vif, param, val);
ret = iwl_mvm_power_mac_update_mode(mvm, vif); ret = iwl_mvm_power_update_mac(mvm, vif);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
return ret ?: count; return ret ?: count;
......
...@@ -717,7 +717,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ...@@ -717,7 +717,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret) if (ret)
goto out_release; goto out_release;
iwl_mvm_power_mac_update_mode(mvm, vif); ret = iwl_mvm_power_update_mac(mvm, vif);
if (ret)
goto out_release;
/* beacon filtering */ /* beacon filtering */
ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
...@@ -867,6 +869,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, ...@@ -867,6 +869,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--; mvm->vif_count--;
iwl_mvm_power_update_mac(mvm, vif);
iwl_mvm_mac_ctxt_remove(mvm, vif); iwl_mvm_mac_ctxt_remove(mvm, vif);
out_release: out_release:
...@@ -1231,7 +1234,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ...@@ -1231,7 +1234,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
&mvmvif->time_event_data); &mvmvif->time_event_data);
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
BSS_CHANGED_QOS)) { BSS_CHANGED_QOS)) {
ret = iwl_mvm_power_mac_update_mode(mvm, vif); ret = iwl_mvm_power_update_mac(mvm, vif);
if (ret) if (ret)
IWL_ERR(mvm, "failed to update power mode\n"); IWL_ERR(mvm, "failed to update power mode\n");
} }
...@@ -1298,7 +1301,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, ...@@ -1298,7 +1301,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
/* power updated needs to be done before quotas */ /* power updated needs to be done before quotas */
mvm->bound_vif_cnt++; mvm->bound_vif_cnt++;
iwl_mvm_power_update_binding(mvm, vif, true); iwl_mvm_power_update_mac(mvm, vif);
ret = iwl_mvm_update_quotas(mvm, vif); ret = iwl_mvm_update_quotas(mvm, vif);
if (ret) if (ret)
...@@ -1317,7 +1320,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, ...@@ -1317,7 +1320,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
out_quota_failed: out_quota_failed:
mvm->bound_vif_cnt--; mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false); iwl_mvm_power_update_mac(mvm, vif);
mvmvif->ap_ibss_active = false; mvmvif->ap_ibss_active = false;
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
out_unbind: out_unbind:
...@@ -1354,7 +1357,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, ...@@ -1354,7 +1357,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif);
mvm->bound_vif_cnt--; mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false); iwl_mvm_power_update_mac(mvm, vif);
iwl_mvm_mac_ctxt_remove(mvm, vif); iwl_mvm_mac_ctxt_remove(mvm, vif);
...@@ -2088,7 +2091,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, ...@@ -2088,7 +2091,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
* otherwise fw will complain. * otherwise fw will complain.
*/ */
mvm->bound_vif_cnt++; mvm->bound_vif_cnt++;
iwl_mvm_power_update_binding(mvm, vif, true); iwl_mvm_power_update_mac(mvm, vif);
/* Setting the quota at this stage is only required for monitor /* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow * interfaces. For the other types, the bss_info changed flow
...@@ -2106,7 +2109,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, ...@@ -2106,7 +2109,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
out_remove_binding: out_remove_binding:
iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif);
mvm->bound_vif_cnt--; mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false); iwl_mvm_power_update_mac(mvm, vif);
out_unlock: out_unlock:
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
if (ret) if (ret)
...@@ -2139,7 +2142,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, ...@@ -2139,7 +2142,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif);
mvm->bound_vif_cnt--; mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false); iwl_mvm_power_update_mac(mvm, vif);
out_unlock: out_unlock:
mvmvif->phy_ctxt = NULL; mvmvif->phy_ctxt = NULL;
......
...@@ -588,7 +588,9 @@ struct iwl_mvm { ...@@ -588,7 +588,9 @@ struct iwl_mvm {
u8 bound_vif_cnt; u8 bound_vif_cnt;
/* Indicate if device power save is allowed */ /* Indicate if device power save is allowed */
bool ps_prevented; bool ps_disabled;
/* Indicate if device power management is allowed */
bool pm_disabled;
}; };
/* Extract MVM priv from op_mode and _hw */ /* Extract MVM priv from op_mode and _hw */
...@@ -812,11 +814,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); ...@@ -812,11 +814,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
/* power management */ /* power management */
int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_power_update_device(struct iwl_mvm *mvm); int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
struct ieee80211_vif *vif, bool assign);
int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz); char *buf, int bufsz);
......
...@@ -298,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -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); keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = cpu_to_le16(keep_alive); cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || if (mvm->ps_disabled)
mvm->ps_prevented)
return; return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); 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, ...@@ -309,8 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif->dbgfs_pm.disable_power_off) mvmvif->dbgfs_pm.disable_power_off)
cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif #endif
if (!vif->bss_conf.ps || mvm->bound_vif_cnt > 1 || if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
iwl_mvm_vif_low_latency(mvmvif)) mvm->pm_disabled)
return; return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 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, ...@@ -417,7 +416,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #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 ieee80211_vif *vif)
{ {
struct iwl_mac_power_cmd cmd = {}; struct iwl_mac_power_cmd cmd = {};
...@@ -439,39 +438,22 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, ...@@ -439,39 +438,22 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
} }
int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, int iwl_mvm_power_update_device(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)
{ {
struct iwl_device_power_cmd cmd = { struct iwl_device_power_cmd cmd = {
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), .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)) if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
return 0; return 0;
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
force_disable) mvm->ps_disabled = true;
if (mvm->ps_disabled)
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
...@@ -488,14 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) ...@@ -488,14 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
&cmd); &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) 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); 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, ...@@ -534,64 +508,119 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
return 0; return 0;
} }
struct iwl_mvm_power_iterator { struct iwl_power_constraint {
struct iwl_mvm *mvm;
struct ieee80211_vif *bf_vif; 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, static void iwl_mvm_power_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_power_iterator *power_iterator = _data; struct iwl_power_constraint *power_iterator = _data;
struct iwl_mvm *mvm = power_iterator->mvm;
int ret; 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)) ieee80211_iterate_active_interfaces_atomic(mvm->hw,
power_iterator->bf_vif = vif; 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, int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
struct ieee80211_vif *vif, bool assign)
{ {
bool ba_enable;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_power_iterator power_it = { struct iwl_power_constraint constraint = {};
.mvm = mvm, bool ba_enable;
}; int ret;
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) 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) { if (vif->type == NL80211_IFTYPE_MONITOR) {
int ret = _iwl_mvm_power_update_device(mvm, assign); ret = iwl_mvm_power_update_device(mvm);
mvm->ps_prevented = assign; if (ret)
WARN_ONCE(ret, "Failed to update power device state\n"); return ret;
} }
ieee80211_iterate_active_interfaces(mvm->hw, ret = iwl_mvm_power_send_cmd(mvm, vif);
IEEE80211_IFACE_ITER_NORMAL, if (ret)
iwl_mvm_power_binding_iterator, return ret;
&power_it);
if (!power_it.bf_vif) if (constraint.bss_vif && vif != constraint.bss_vif) {
return; 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); mvmvif = iwl_mvm_vif_from_mac80211(vif);
ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || ba_enable = !(constraint.pm_disabled || constraint.ps_disabled ||
mvm->ps_prevented || mvm->bound_vif_cnt > 1 ||
!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
WARN_ON_ONCE(iwl_mvm_update_beacon_abort(mvm, power_it.bf_vif, return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable);
ba_enable));
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
......
...@@ -564,5 +564,5 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -564,5 +564,5 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_bt_coex_vif_change(mvm); iwl_mvm_bt_coex_vif_change(mvm);
return iwl_mvm_power_mac_update_mode(mvm, vif); return iwl_mvm_power_update_mac(mvm, vif);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment