]> Git Repo - linux.git/commitdiff
wifi: ath11k: fill parameters for vdev set tpc power WMI command
authorWen Gong <[email protected]>
Thu, 11 Jan 2024 13:56:58 +0000 (15:56 +0200)
committerKalle Valo <[email protected]>
Sun, 14 Jan 2024 14:59:10 +0000 (16:59 +0200)
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: Wen Gong <[email protected]>
Acked-by: Jeff Johnson <[email protected]>
Signed-off-by: Baochen Qiang <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
Link: https://msgid.link/[email protected]
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/mac.h

index 4be5b2a35ec99a44d84d9364288ca5ae724a3756..f812a6f44b82122d316746a2f44ed55ebea006e9 100644 (file)
@@ -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)
index 0dfdeed5177b88f74480ebf0e47d3055ba17e10c..f5800fbecff89e0a8e509cdbee005f3858d6b97a 100644 (file)
@@ -1,7 +1,7 @@
 /* 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
This page took 0.089265 seconds and 4 git commands to generate.