Commit 92425f78 authored by Wen Gong's avatar Wen Gong Committed by Kalle Valo
Browse files

wifi: ath11k: fill parameters for vdev set tpc power WMI command



Prepare the parameters which are needed for WMI command WMI_VDEV_SET_TPC_POWER_CMDID.

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23

Signed-off-by: default avatarWen Gong <quic_wgong@quicinc.com>
Acked-by: default avatarJeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: default avatarBaochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20231218085844.2658-10-quic_bqiang@quicinc.com
parent 46f20de2
Loading
Loading
Loading
Loading
+284 −0
Original line number Diff line number Diff line
@@ -7667,6 +7667,290 @@ static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
	}
}

static u16 ath11k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
{
	u16 diff_seq;

	/* It is to get the lowest channel number's center frequency of the chan.
	 * For example,
	 * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
	 * with center frequency 5955, its diff is 5965 - 5955 = 10.
	 * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
	 * with center frequency 5955, its diff is 5985 - 5955 = 30.
	 * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
	 * with center frequency 5955, its diff is 6025 - 5955 = 70.
	 */
	switch (chan_def->width) {
	case NL80211_CHAN_WIDTH_160:
		diff_seq = 70;
		break;
	case NL80211_CHAN_WIDTH_80:
	case NL80211_CHAN_WIDTH_80P80:
		diff_seq = 30;
		break;
	case NL80211_CHAN_WIDTH_40:
		diff_seq = 10;
		break;
	default:
		diff_seq = 0;
	}

	return chan_def->center_freq1 - diff_seq;
}

static u16 ath11k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
				   u16 start_seq, u8 seq)
{
	u16 seg_seq;

	/* It is to get the center frequency of the specific bandwidth.
	 * start_seq means the lowest channel number's center frequency.
	 * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz&80P80.
	 * For example,
	 * lowest channel is 1, its center frequency 5955,
	 * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
	 * lowest channel is 1, its center frequency 5955,
	 * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
	 * lowest channel is 1, its center frequency 5955,
	 * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
	 * lowest channel is 1, its center frequency 5955,
	 * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
	 */
	if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
		return chan_def->center_freq2;

	seg_seq = 10 * (BIT(seq) - 1);
	return seg_seq + start_seq;
}

static void ath11k_mac_get_psd_channel(struct ath11k *ar,
				       u16 step_freq,
				       u16 *start_freq,
				       u16 *center_freq,
				       u8 i,
				       struct ieee80211_channel **temp_chan,
				       s8 *tx_power)
{
	/* It is to get the center frequency for each 20 MHz.
	 * For example, if the chan is 160 MHz and center frequency is 6025,
	 * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
	 * channel number 1's center frequency is 5955, it is parameter start_freq.
	 * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
	 * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
	 * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
	 * the gap is 20 for each channel, parameter step_freq means the gap.
	 * after get the center frequency of each channel, it is easy to find the
	 * struct ieee80211_channel of it and get the max_reg_power.
	 */
	*center_freq = *start_freq + i * step_freq;
	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
	*tx_power = (*temp_chan)->max_reg_power;
}

static void ath11k_mac_get_eirp_power(struct ath11k *ar,
				      u16 *start_freq,
				      u16 *center_freq,
				      u8 i,
				      struct ieee80211_channel **temp_chan,
				      struct cfg80211_chan_def *def,
				      s8 *tx_power)
{
	/* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
	 * 160 MHz&80P80 bandwidth, and then plus 10 to the center frequency,
	 * it is the center frequency of a channel number.
	 * For example, when configured channel number is 1.
	 * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
	 * then it is channel number 5.
	 * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
	 * then it is channel number 9.
	 * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
	 * then it is channel number 17.
	 * after get the center frequency of each channel, it is easy to find the
	 * struct ieee80211_channel of it and get the max_reg_power.
	 */
	*center_freq = ath11k_mac_get_seg_freq(def, *start_freq, i);

	/* For the 20 MHz, its center frequency is same with same channel */
	if (i != 0)
		*center_freq += 10;

	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
	*tx_power = (*temp_chan)->max_reg_power;
}

void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar,
				  struct ieee80211_vif *vif,
				  struct ieee80211_chanctx_conf *ctx)
{
	struct ath11k_base *ab = ar->ab;
	struct ath11k_vif *arvif = (void *)vif->drv_priv;
	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
	struct ath11k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
	struct ieee80211_channel *chan, *temp_chan;
	u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
	bool is_psd_power = false, is_tpe_present = false;
	s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
		psd_power, tx_power, eirp_power;
	u16 start_freq, center_freq;

	chan = ctx->def.chan;
	start_freq = ath11k_mac_get_6ghz_start_frequency(&ctx->def);
	pwr_reduction = bss_conf->pwr_reduction;

	if (arvif->reg_tpc_info.num_pwr_levels) {
		is_tpe_present = true;
		num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
	} else {
		num_pwr_levels = ath11k_mac_get_num_pwr_levels(&ctx->def);
	}

	for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
		/* STA received TPE IE*/
		if (is_tpe_present) {
			/* local power is PSD power*/
			if (chan->flags & IEEE80211_CHAN_PSD) {
				/* Connecting AP is psd power */
				if (reg_tpc_info->is_psd_power) {
					is_psd_power = true;
					ath11k_mac_get_psd_channel(ar, 20,
								   &start_freq,
								   &center_freq,
								   pwr_lvl_idx,
								   &temp_chan,
								   &tx_power);
					psd_power = temp_chan->psd;
					eirp_power = tx_power;
					max_tx_power[pwr_lvl_idx] =
						min_t(s8,
						      psd_power,
						      reg_tpc_info->tpe[pwr_lvl_idx]);
				/* Connecting AP is not psd power */
				} else {
					ath11k_mac_get_eirp_power(ar,
								  &start_freq,
								  &center_freq,
								  pwr_lvl_idx,
								  &temp_chan,
								  &ctx->def,
								  &tx_power);
					psd_power = temp_chan->psd;
					/* convert psd power to EIRP power based
					 * on channel width
					 */
					tx_power =
						min_t(s8, tx_power,
						      psd_power + 13 + pwr_lvl_idx * 3);
					max_tx_power[pwr_lvl_idx] =
						min_t(s8,
						      tx_power,
						      reg_tpc_info->tpe[pwr_lvl_idx]);
				}
			/* local power is not PSD power */
			} else {
				/* Connecting AP is psd power */
				if (reg_tpc_info->is_psd_power) {
					is_psd_power = true;
					ath11k_mac_get_psd_channel(ar, 20,
								   &start_freq,
								   &center_freq,
								   pwr_lvl_idx,
								   &temp_chan,
								   &tx_power);
					eirp_power = tx_power;
					max_tx_power[pwr_lvl_idx] =
						reg_tpc_info->tpe[pwr_lvl_idx];
				/* Connecting AP is not psd power */
				} else {
					ath11k_mac_get_eirp_power(ar,
								  &start_freq,
								  &center_freq,
								  pwr_lvl_idx,
								  &temp_chan,
								  &ctx->def,
								  &tx_power);
					max_tx_power[pwr_lvl_idx] =
						min_t(s8,
						      tx_power,
						      reg_tpc_info->tpe[pwr_lvl_idx]);
				}
			}
		/* STA not received TPE IE */
		} else {
			/* local power is PSD power*/
			if (chan->flags & IEEE80211_CHAN_PSD) {
				is_psd_power = true;
				ath11k_mac_get_psd_channel(ar, 20,
							   &start_freq,
							   &center_freq,
							   pwr_lvl_idx,
							   &temp_chan,
							   &tx_power);
				psd_power = temp_chan->psd;
				eirp_power = tx_power;
				max_tx_power[pwr_lvl_idx] = psd_power;
			} else {
				ath11k_mac_get_eirp_power(ar,
							  &start_freq,
							  &center_freq,
							  pwr_lvl_idx,
							  &temp_chan,
							  &ctx->def,
							  &tx_power);
				max_tx_power[pwr_lvl_idx] = tx_power;
			}
		}

		if (is_psd_power) {
			/* If AP local power constraint is present */
			if (pwr_reduction)
				eirp_power = eirp_power - pwr_reduction;

			/* If firmware updated max tx power is non zero, then take
			 * the min of firmware updated ap tx power
			 * and max power derived from above mentioned parameters.
			 */
			ath11k_dbg(ab, ATH11K_DBG_MAC,
				   "eirp power : %d firmware report power : %d\n",
				   eirp_power, ar->max_allowed_tx_power);
			/* Firmware reports lower max_allowed_tx_power during vdev
			 * start response. In case of 6 GHz, firmware is not aware
			 * of EIRP power unless driver sets EIRP power through WMI
			 * TPC command. So radio which does not support idle power
			 * save can set maximum calculated EIRP power directly to
			 * firmware through TPC command without min comparison with
			 * vdev start response's max_allowed_tx_power.
			 */
			if (ar->max_allowed_tx_power && ab->hw_params.idle_ps)
				eirp_power = min_t(s8,
						   eirp_power,
						   ar->max_allowed_tx_power);
		} else {
			/* If AP local power constraint is present */
			if (pwr_reduction)
				max_tx_power[pwr_lvl_idx] =
					max_tx_power[pwr_lvl_idx] - pwr_reduction;
			/* If firmware updated max tx power is non zero, then take
			 * the min of firmware updated ap tx power
			 * and max power derived from above mentioned parameters.
			 */
			if (ar->max_allowed_tx_power && ab->hw_params.idle_ps)
				max_tx_power[pwr_lvl_idx] =
					min_t(s8,
					      max_tx_power[pwr_lvl_idx],
					      ar->max_allowed_tx_power);
		}
		reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
		reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
			max_tx_power[pwr_lvl_idx];
	}

	reg_tpc_info->num_pwr_levels = num_pwr_levels;
	reg_tpc_info->is_psd_power = is_psd_power;
	reg_tpc_info->eirp_power = eirp_power;
	reg_tpc_info->ap_power_type =
		ath11k_reg_ap_pwr_convert(vif->bss_conf.power_type);
}

static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar,
					struct ieee80211_vif *vif,
					struct ieee80211_chanctx_conf *ctx)
+4 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#ifndef ATH11K_MAC_H
@@ -176,4 +176,7 @@ int ath11k_mac_wait_tx_complete(struct ath11k *ar);
int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif,
				 enum wmi_sta_keepalive_method method,
				 u32 interval);
void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar,
				  struct ieee80211_vif *vif,
				  struct ieee80211_chanctx_conf *ctx);
#endif