diff mbox series

[06/20] wifi: iwlwifi: mvm: handle TPE advertised by AP

Message ID 20240527190228.32f1e2e1447c.I58ac91c38585362aa42bb4a8a59c7d88e67bc40b@changeid
State New
Headers show
Series wifi: iwlwifi: updates - 2024-05-27 | expand

Commit Message

Korenblit, Miriam Rachel May 27, 2024, 4:06 p.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

6 GHz BSS SP client shall respect TX power limits advertised
by the AP in TPE elements, send the data to the firmware using
the AP_TX_POWER_CONSTRAINTS_CMD command, so do that.

Co-developed-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
Signed-off-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 ++++
 .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 55 ++++++++++++++++---
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h  |  6 ++
 3 files changed, 63 insertions(+), 9 deletions(-)

Comments

Rory Little Aug. 9, 2024, 6:25 p.m. UTC | #1
Hi,

We noticed that our transmit throughput dropped by ~20-30% and bisected 
the issue to this patch. We will dig around a bit more to investigate 
why this seems to be happening...

- Rory

On 5/27/24 09:06, Miri Korenblit wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> 6 GHz BSS SP client shall respect TX power limits advertised
> by the AP in TPE elements, send the data to the firmware using
> the AP_TX_POWER_CONSTRAINTS_CMD command, so do that.
> 
> Co-developed-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
> Signed-off-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
> ---
>   .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 ++++
>   .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 55 ++++++++++++++++---
>   drivers/net/wireless/intel/iwlwifi/mvm/mvm.h  |  6 ++
>   3 files changed, 63 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
> index 752fdb6a783f..88bc0baabf7e 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
> @@ -2768,6 +2768,13 @@ iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm,
>   
>   	if (changes & BSS_CHANGED_BANDWIDTH)
>   		iwl_mvm_update_link_smps(vif, link_conf);
> +
> +	if (changes & BSS_CHANGED_TPE) {
> +		IWL_DEBUG_CALIB(mvm, "Changing TPE\n");
> +		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
> +							link_conf,
> +							false);
> +	}
>   }
>   
>   static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
> @@ -5122,6 +5129,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
>   		}
>   
>   		iwl_mvm_update_quotas(mvm, false, NULL);
> +
> +		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
> +							link_conf,
> +							false);
>   	}
>   
>   	goto out;
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
> index 00433d1c8564..b2b6dbdcc44f 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
> @@ -345,6 +345,11 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
>   		rcu_read_unlock();
>   	}
>   
> +	if (vif->type == NL80211_IFTYPE_STATION)
> +		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
> +							link_conf,
> +							false);
> +
>   	/* then activate */
>   	ret = iwl_mvm_link_changed(mvm, vif, link_conf,
>   				   LINK_CONTEXT_MODIFY_ACTIVE |
> @@ -524,9 +529,37 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
>   }
>   
>   static void
> +iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,
> +			 const struct ieee80211_bss_conf *bss_info)
> +{
> +	u8 i;
> +
> +	/*
> +	 * NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT,
> +	 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE
> +	 */
> +
> +	BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) !=
> +		     ARRAY_SIZE(bss_info->tpe.psd_local[0].power));
> +
> +	/* if not valid, mac80211 puts default (max value) */
> +	for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++)
> +		cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i],
> +				      bss_info->tpe.psd_reg_client[0].power[i]);
> +
> +	BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) !=
> +		     ARRAY_SIZE(bss_info->tpe.max_local[0].power));
> +
> +	for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++)
> +		cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i],
> +				       bss_info->tpe.max_reg_client[0].power[i]);
> +}
> +
> +void
>   iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
>   					struct ieee80211_vif *vif,
> -					struct ieee80211_bss_conf *bss_conf)
> +					struct ieee80211_bss_conf *bss_conf,
> +					bool is_ap)
>   {
>   	struct iwl_txpower_constraints_cmd cmd = {};
>   	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
> @@ -546,19 +579,22 @@ iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
>   	    link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
>   		return;
>   
> -	if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ ||
> -	    bss_conf->chanreq.oper.chan->flags &
> -		    IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT)
> +	if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ)
>   		return;
>   
>   	cmd.link_id = cpu_to_le16(link_info->fw_link_id);
> -	/*
> -	 * Currently supporting VLP Soft AP only.
> -	 */
> -	cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
>   	memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));
>   	memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));
>   
> +	if (is_ap) {
> +		cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
> +	} else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) {
> +		return;
> +	} else {
> +		cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1);
> +		iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf);
> +	}
> +
>   	ret = iwl_mvm_send_cmd_pdu(mvm,
>   				   WIDE_ID(PHY_OPS_GROUP,
>   					   AP_TX_POWER_CONSTRAINTS_CMD),
> @@ -580,7 +616,8 @@ static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,
>   	guard(mvm)(mvm);
>   
>   	if (vif->type == NL80211_IFTYPE_AP)
> -		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, link_conf);
> +		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
> +							link_conf, true);
>   
>   	/* Send the beacon template */
>   	ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
> index f3d9b8355c6b..9b939225990a 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
> @@ -2962,4 +2962,10 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,
>   				   bool primary);
>   int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
>   			     unsigned int link_id, bool active);
> +
> +void
> +iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
> +					struct ieee80211_vif *vif,
> +					struct ieee80211_bss_conf *bss_conf,
> +					bool is_ap);
>   #endif /* __IWL_MVM_H__ */
Linux regression tracking (Thorsten Leemhuis) Sept. 2, 2024, 12:59 p.m. UTC | #2
On 09.08.24 20:25, Rory Little wrote:
>
> We noticed that our transmit throughput dropped by ~20-30% and bisected
> the issue to this patch. We will dig around a bit more to investigate
> why this seems to be happening...

Rory Little: was this ever resolved? I noticed the patch you send to
which Johannes replied to stating a similar fix is already in -rc1. But
you reported this a few days after -rc1 was out, which makes me wonder
if this really is resolved.

If it is: apologies for the noise in advance.

Ciao, Thorsten (wearing his 'the Linux kernel's regression tracker' hat)

> On 5/27/24 09:06, Miri Korenblit wrote:
>> From: Johannes Berg <johannes.berg@intel.com>
>>
>> 6 GHz BSS SP client shall respect TX power limits advertised
>> by the AP in TPE elements, send the data to the firmware using
>> the AP_TX_POWER_CONSTRAINTS_CMD command, so do that.
>>
>> Co-developed-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
>> Signed-off-by: Mukesh Sisodiya <mukesh.sisodiya@intel.com>
>> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
>> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
>> ---
>>   .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 ++++
>>   .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 55 ++++++++++++++++---
>>   drivers/net/wireless/intel/iwlwifi/mvm/mvm.h  |  6 ++
>>   3 files changed, 63 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
>> b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
>> index 752fdb6a783f..88bc0baabf7e 100644
>> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
>> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
>> @@ -2768,6 +2768,13 @@ iwl_mvm_bss_info_changed_station_common(struct
>> iwl_mvm *mvm,
>>         if (changes & BSS_CHANGED_BANDWIDTH)
>>           iwl_mvm_update_link_smps(vif, link_conf);
>> +
>> +    if (changes & BSS_CHANGED_TPE) {
>> +        IWL_DEBUG_CALIB(mvm, "Changing TPE\n");
>> +        iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
>> +                            link_conf,
>> +                            false);
>> +    }
>>   }
>>     static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
>> @@ -5122,6 +5129,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct
>> iwl_mvm *mvm,
>>           }
>>             iwl_mvm_update_quotas(mvm, false, NULL);
>> +
>> +        iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
>> +                            link_conf,
>> +                            false);
>>       }
>>         goto out;
>> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
>> b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
>> index 00433d1c8564..b2b6dbdcc44f 100644
>> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
>> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
>> @@ -345,6 +345,11 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm
>> *mvm,
>>           rcu_read_unlock();
>>       }
>>   +    if (vif->type == NL80211_IFTYPE_STATION)
>> +        iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
>> +                            link_conf,
>> +                            false);
>> +
>>       /* then activate */
>>       ret = iwl_mvm_link_changed(mvm, vif, link_conf,
>>                      LINK_CONTEXT_MODIFY_ACTIVE |
>> @@ -524,9 +529,37 @@ static void
>> iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
>>   }
>>     static void
>> +iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,
>> +             const struct ieee80211_bss_conf *bss_info)
>> +{
>> +    u8 i;
>> +
>> +    /*
>> +     * NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT,
>> +     * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE
>> +     */
>> +
>> +    BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) !=
>> +             ARRAY_SIZE(bss_info->tpe.psd_local[0].power));
>> +
>> +    /* if not valid, mac80211 puts default (max value) */
>> +    for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++)
>> +        cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i],
>> +                      bss_info->tpe.psd_reg_client[0].power[i]);
>> +
>> +    BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) !=
>> +             ARRAY_SIZE(bss_info->tpe.max_local[0].power));
>> +
>> +    for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++)
>> +        cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i],
>> +                       bss_info->tpe.max_reg_client[0].power[i]);
>> +}
>> +
>> +void
>>   iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
>>                       struct ieee80211_vif *vif,
>> -                    struct ieee80211_bss_conf *bss_conf)
>> +                    struct ieee80211_bss_conf *bss_conf,
>> +                    bool is_ap)
>>   {
>>       struct iwl_txpower_constraints_cmd cmd = {};
>>       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
>> @@ -546,19 +579,22 @@ iwl_mvm_send_ap_tx_power_constraint_cmd(struct
>> iwl_mvm *mvm,
>>           link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
>>           return;
>>   -    if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ ||
>> -        bss_conf->chanreq.oper.chan->flags &
>> -            IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT)
>> +    if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ)
>>           return;
>>         cmd.link_id = cpu_to_le16(link_info->fw_link_id);
>> -    /*
>> -     * Currently supporting VLP Soft AP only.
>> -     */
>> -    cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
>>       memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));
>>       memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));
>>   +    if (is_ap) {
>> +        cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
>> +    } else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) {
>> +        return;
>> +    } else {
>> +        cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1);
>> +        iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf);
>> +    }
>> +
>>       ret = iwl_mvm_send_cmd_pdu(mvm,
>>                      WIDE_ID(PHY_OPS_GROUP,
>>                          AP_TX_POWER_CONSTRAINTS_CMD),
>> @@ -580,7 +616,8 @@ static int iwl_mvm_mld_start_ap_ibss(struct
>> ieee80211_hw *hw,
>>       guard(mvm)(mvm);
>>         if (vif->type == NL80211_IFTYPE_AP)
>> -        iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, link_conf);
>> +        iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
>> +                            link_conf, true);
>>         /* Send the beacon template */
>>       ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
>> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
>> b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
>> index f3d9b8355c6b..9b939225990a 100644
>> --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
>> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
>> @@ -2962,4 +2962,10 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct
>> iwl_mvm *mvm,
>>                      bool primary);
>>   int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct
>> ieee80211_vif *vif,
>>                    unsigned int link_id, bool active);
>> +
>> +void
>> +iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
>> +                    struct ieee80211_vif *vif,
>> +                    struct ieee80211_bss_conf *bss_conf,
>> +                    bool is_ap);
>>   #endif /* __IWL_MVM_H__ */
> 

--
Everything you wanna know about Linux kernel regression tracking:
https://linux-regtracking.leemhuis.info/about/#tldr
If I did something stupid, please tell me, as explained on that page.

#regzbot poke
Rory Little Oct. 16, 2024, 10:10 p.m. UTC | #3
On 9/2/24 05:59, Linux regression tracking (Thorsten Leemhuis) wrote:
> Rory Little: was this ever resolved? I noticed the patch you send to
> which Johannes replied to stating a similar fix is already in -rc1. But
> you reported this a few days after -rc1 was out, which makes me wonder
> if this really is resolved.

It was resolved. We independently pulled in this patch series without 
the earlier fix, which caused an issue only in our forked kernel, and 
the confusion on our end. My mistake for reporting the issue here.

- Rory
diff mbox series

Patch

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 752fdb6a783f..88bc0baabf7e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2768,6 +2768,13 @@  iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm,
 
 	if (changes & BSS_CHANGED_BANDWIDTH)
 		iwl_mvm_update_link_smps(vif, link_conf);
+
+	if (changes & BSS_CHANGED_TPE) {
+		IWL_DEBUG_CALIB(mvm, "Changing TPE\n");
+		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
+							link_conf,
+							false);
+	}
 }
 
 static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
@@ -5122,6 +5129,10 @@  static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
 		}
 
 		iwl_mvm_update_quotas(mvm, false, NULL);
+
+		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
+							link_conf,
+							false);
 	}
 
 	goto out;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 00433d1c8564..b2b6dbdcc44f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -345,6 +345,11 @@  __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
 		rcu_read_unlock();
 	}
 
+	if (vif->type == NL80211_IFTYPE_STATION)
+		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
+							link_conf,
+							false);
+
 	/* then activate */
 	ret = iwl_mvm_link_changed(mvm, vif, link_conf,
 				   LINK_CONTEXT_MODIFY_ACTIVE |
@@ -524,9 +529,37 @@  static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
 }
 
 static void
+iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,
+			 const struct ieee80211_bss_conf *bss_info)
+{
+	u8 i;
+
+	/*
+	 * NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT,
+	 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE
+	 */
+
+	BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) !=
+		     ARRAY_SIZE(bss_info->tpe.psd_local[0].power));
+
+	/* if not valid, mac80211 puts default (max value) */
+	for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++)
+		cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i],
+				      bss_info->tpe.psd_reg_client[0].power[i]);
+
+	BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) !=
+		     ARRAY_SIZE(bss_info->tpe.max_local[0].power));
+
+	for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++)
+		cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i],
+				       bss_info->tpe.max_reg_client[0].power[i]);
+}
+
+void
 iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
 					struct ieee80211_vif *vif,
-					struct ieee80211_bss_conf *bss_conf)
+					struct ieee80211_bss_conf *bss_conf,
+					bool is_ap)
 {
 	struct iwl_txpower_constraints_cmd cmd = {};
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -546,19 +579,22 @@  iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
 	    link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
 		return;
 
-	if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ ||
-	    bss_conf->chanreq.oper.chan->flags &
-		    IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT)
+	if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ)
 		return;
 
 	cmd.link_id = cpu_to_le16(link_info->fw_link_id);
-	/*
-	 * Currently supporting VLP Soft AP only.
-	 */
-	cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
 	memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));
 	memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));
 
+	if (is_ap) {
+		cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
+	} else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) {
+		return;
+	} else {
+		cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1);
+		iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf);
+	}
+
 	ret = iwl_mvm_send_cmd_pdu(mvm,
 				   WIDE_ID(PHY_OPS_GROUP,
 					   AP_TX_POWER_CONSTRAINTS_CMD),
@@ -580,7 +616,8 @@  static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,
 	guard(mvm)(mvm);
 
 	if (vif->type == NL80211_IFTYPE_AP)
-		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, link_conf);
+		iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
+							link_conf, true);
 
 	/* Send the beacon template */
 	ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index f3d9b8355c6b..9b939225990a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2962,4 +2962,10 @@  iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,
 				   bool primary);
 int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 			     unsigned int link_id, bool active);
+
+void
+iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					struct ieee80211_bss_conf *bss_conf,
+					bool is_ap);
 #endif /* __IWL_MVM_H__ */